[{"data":1,"prerenderedAt":15997},["ShallowReactive",2],{"navigation":3,"index":204,"\u002F":287},[4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,140,144,148,152,156,160,164,168,172,176,180,184,188,192,196,200],{"title":5,"path":6,"stem":7},"You do not have time to not have tests","\u002Fblog\u002Fyou-do-not-have-time-to-not-have-tests","2.blog\u002F20211217.you-do-not-have-time-to-not-have-tests",{"title":9,"path":10,"stem":11},"Migrate Vue 2 with Vuetify and Jest to Vite and Vitest","\u002Fblog\u002Fmigrate-vue-2-with-vuetify-and-jest-to-vite-and-vitest","2.blog\u002F20220109.migrate-vue-2-with-vuetify-and-jest-to-vite-and-vitest",{"title":13,"path":14,"stem":15},"I am a Dark Matter Developer","\u002Fblog\u002Fi-am-a-dark-matter-developer","2.blog\u002F20220626.i-am-a-dark-matter-developer",{"title":17,"path":18,"stem":19},"Why using Conventional commits is useful","\u002Fblog\u002Fusing-conventional-commits","2.blog\u002F20240623.using-conventional-commits",{"title":21,"path":22,"stem":23},"Why you should make a toolbox repository","\u002Fblog\u002Fwhy-you-should-make-a-toolbox-repository","2.blog\u002F20240630.Why-you-should-make-a-toolbox-repository",{"title":25,"path":26,"stem":27},"Apache Airflow Part 1 - Why and Goals for a near Serverless ELT","\u002Fblog\u002Fapache-airflow-part-1-why-and-goals","2.blog\u002F20240710.apache-airflow-part-1-why-and-goals",{"title":29,"path":30,"stem":31},"Oh My Zsh on your server","\u002Fblog\u002Foh-my-zsh-on-your-server","2.blog\u002F20240711.oh-my-zsh-on-your-server",{"title":33,"path":34,"stem":35},"Fire tablet and YouTube Kids","\u002Fblog\u002Ffire-tablet-and-youtube-kids","2.blog\u002F20240714.fire-tablet-and-youtube-kids",{"title":37,"path":38,"stem":39},"Using Ollama and Continue as a GitHub Copilot Alternative","\u002Fblog\u002Fusing-ollama-and-continue-as-github-copilot-alternative","2.blog\u002F20240723.using-ollama-and-continue-as-github-copilot-alternative",{"title":41,"path":42,"stem":43},"Debugging Local Packages Made Easy with pnpm","\u002Fblog\u002Fdebugging-local-packages-with-pnpm-link","2.blog\u002F20250422.debugging local-packages-with-pnpm-link",{"title":45,"path":46,"stem":47},"Two Weeks with Cloudflare AI and Tools","\u002Fblog\u002Ftwo-weeks-with-cloudflare-ai-and-tools","2.blog\u002F20250509.two-weeks-with-cloudflare-aI-and-tools",{"title":49,"path":50,"stem":51},"Adding Prompts to VS Code - How I Learned to Stop Worrying and Love AI Context","\u002Fblog\u002Fadding-prompts-to-vscode","2.blog\u002F20250528.adding-prompts-to-vscode",{"title":53,"path":54,"stem":55},"My Best Practices","\u002Fblog\u002Fmy-best-practicies","2.blog\u002F20250607.my-best-practicies",{"title":57,"path":58,"stem":59},"Creating my own CLI Tool - Towles Tool","\u002Fblog\u002Ftowles-tool","2.blog\u002F20250607.towles-tool",{"title":61,"path":62,"stem":63},"Software Development Best Practices & ITIL","\u002Fblog\u002Fsoftware-engineering-and-itil-best-practices","2.blog\u002F20250612.software-engineering-and-itil-best-practices",{"title":65,"path":66,"stem":67},"Voice to Text","\u002Fblog\u002Fvoice-to-text","2.blog\u002F20250622.voice-to-text",{"title":69,"path":70,"stem":71},"Setting Up ComfyUI - A Better Alternative to Fooocus","\u002Fblog\u002Fcomfy-ui-setup","2.blog\u002F20250628.comfy-ui-setup",{"title":73,"path":74,"stem":75},"Voice to System","\u002Fblog\u002Fvoice-to-system","2.blog\u002F20250705.voice-to-system",{"title":77,"path":78,"stem":79},"Tips for Claude Code","\u002Fblog\u002Ftips-for-claude-code","2.blog\u002F20250713.tips-for-claude-code",{"title":81,"path":82,"stem":83},"Review That AI Code: Why I Read Every Line Generated Code","\u002Fblog\u002Freview-that-ai-code","2.blog\u002F20250720.review-that-ai-code",{"title":85,"path":86,"stem":87},"My Context Engineering Journey: From Dev Scripts to AI Collaboration","\u002Fblog\u002F20250803-1.my-context-engineering-journey","2.blog\u002F20250803-1.my-context-engineering-journey",{"title":89,"path":90,"stem":91},"Context Engineering at Scale: Enterprise Lessons and the Future of Development","\u002Fblog\u002F20250803-2.context-engineering-at-scale","2.blog\u002F20250803-2.context-engineering-at-scale",{"title":93,"path":94,"stem":95},"Check That Your Tools and Linters Do Not Burn Tokens","\u002Fblog\u002Fcheck-that-your-tools-and-linters-do-not-burn-tokens","2.blog\u002F20250806.check-that-your-tools-and-linters-do-not-burn-tokens",{"title":97,"path":98,"stem":99},"Markdown + AI: The Communication Protocol That Changes Everything","\u002Fblog\u002Fmarkdown-plus-ai-the-communication-protocol-that-changes-everything","2.blog\u002F20250814.markdown-plus-ai-the-communication-protocol-that-changes-everything",{"title":101,"path":102,"stem":103},"Finally: Type-Safe AI in Production (And Why I'm Here For It)","\u002Fblog\u002Ffinally-type-safe-ai-in-production-and-why-im-here-for-it","2.blog\u002F20250819.finally-type-safe-ai-in-production-and-why-im-here-for-it",{"title":105,"path":106,"stem":107},"Dotfiles: Masterpiece or Late Stage Picasso?","\u002Fblog\u002Fdotfiles-masterpiece-or-late-stage-picasso","2.blog\u002F20250822.dotfiles-masterpiece-or-late-stage-picasso",{"title":109,"path":110,"stem":111},"Beyond API Wrappers: Building State-Driven MCP Servers for Long-Horizon Agent Orchestration","\u002Fblog\u002Fbeyond-api-wrappers-mcp-servers","2.blog\u002F20250907.beyond-api-wrappers-mcp-servers",{"title":113,"path":114,"stem":115},"Why Vertical Integration Wins: A Software Engineer's Case for Owning Your Stack","\u002Fblog\u002Fwhy-i-bought-tesla-model-3-vertical-integration","2.blog\u002F20250928.why-i-bought-tesla-model-3-vertical-integration",{"title":117,"path":118,"stem":119},"The Min-Maxer's Trifecta: Building Tools for the Game You Actually Play","\u002Fblog\u002Fmin-maxer-trifecta","2.blog\u002F20251004.min-maxer-trifecta",{"title":121,"path":122,"stem":123},"Read The Source: Learning by Cutting Out The Middleman and RTFM","\u002Fblog\u002Fread-the-source","2.blog\u002F20251010.read-the-source",{"title":125,"path":126,"stem":127},"The Exponential Shift: Why AI Progress Feels Different Now","\u002Fblog\u002Fthe-exponential-shift","2.blog\u002F20251015.the-exponential-shift",{"title":129,"path":130,"stem":131},"Plan Mode for Your Problems, Edit Mode for Claude's","\u002Fblog\u002Fplan-mode-problems-edit-mode-solutions","2.blog\u002F20251019.plan-mode-problems-edit-mode-solutions",{"title":133,"path":134,"stem":135},"AWS Aurora DSQL Looked Perfect Until I Needed the Connection String","\u002Fblog\u002Faws-aurora-dsql-postgres-serverless-authentication","2.blog\u002F20251028.aws-aurora-dsql-postgres-serverless-authentication",{"title":137,"path":138,"stem":139},"Switchback: Browser History for Your Thoughts","\u002Fblog\u002Fswitchback-second-order-reasoning","2.blog\u002F20251205.switchback-second-order-reasoning",{"title":141,"path":142,"stem":143},"AI Pairing: Notes to Self","\u002Fblog\u002Fai-pairing-notes-to-self","2.blog\u002F20251216.ai-pairing-notes-to-self",{"title":145,"path":146,"stem":147},"I've Been Sleeping on Zellij","\u002Fblog\u002Fsleeping-on-zellij","2.blog\u002F20251229.sleeping-on-zellij",{"title":149,"path":150,"stem":151},"Implementing a Ralph Wiggum Loop: The Secret is Session Markers","\u002Fblog\u002Fimplementing-ralph-wiggum-loop-for-autonomous-ai-coding","2.blog\u002F20260114.implementing-ralph-wiggum-loop-for-autonomous-ai-coding",{"title":153,"path":154,"stem":155},"Goodhart's Law Ate My Context Window","\u002Fblog\u002Fgoodharts-law-ate-my-context-window","2.blog\u002F20260119.goodharts-law-ate-my-context-window",{"title":157,"path":158,"stem":159},"Claude Code's Hidden Multi-Agent System Is Real","\u002Fblog\u002Fclaude-code-hidden-multi-agent-system","2.blog\u002F20260124.claude-code-hidden-multi-agent-system",{"title":161,"path":162,"stem":163},"Free Printable Math Sheets for Kids — Number Chart, Skip Counting, Multiplication, and More","\u002Fblog\u002Ffree-printable-number-chart-and-coin-sheets","2.blog\u002F20260214.free-printable-number-chart-and-coin-sheets",{"title":165,"path":166,"stem":167},"We Are Near the End of the Exponential","\u002Fblog\u002Fnear-the-end-of-the-exponential","2.blog\u002F20260214.near-the-end-of-the-exponential",{"title":169,"path":170,"stem":171},"Free Printable Language Arts Sheets for Kids — Sight Words, Parts of Speech, Homophones, and More","\u002Fblog\u002Ffree-printable-sight-words-and-grammar-sheets","2.blog\u002F20260215.free-printable-sight-words-and-grammar-sheets",{"title":173,"path":174,"stem":175},"Interactive Code Execution with Artifacts","\u002Fblog\u002Finteractive-code-execution-with-artifacts","2.blog\u002F20260215.interactive-code-execution-with-artifacts",{"title":177,"path":178,"stem":179},"Free Printable Telling Time Worksheet for Kids — Clock Reference & Practice Sheet","\u002Fblog\u002Ffree-printable-telling-time-worksheet","2.blog\u002F20260216.free-printable-telling-time-worksheet",{"title":181,"path":182,"stem":183},"Claude Code Skills: Teaching AI Your Playbook","\u002Fblog\u002Fclaude-code-skills-guide","2.blog\u002F20260221.claude-code-skills-guide",{"title":185,"path":186,"stem":187},"Building a Multi-Agent Loan Approval System with Human-in-the-Loop","\u002Fblog\u002Fmulti-agent-loan-approval-human-in-the-loop","2.blog\u002F20260225.multi-agent-loan-approval-human-in-the-loop",{"title":189,"path":190,"stem":191},"The Inception of AI Infrastructure: Bottlenecks All the Way Down","\u002Fblog\u002Fbiggest-bottleneck-scaling-ai-compute","2.blog\u002F20260313.biggest-bottleneck-scaling-ai-compute",{"title":193,"path":194,"stem":195},"What I Tell Teams About Claude Code","\u002Fblog\u002Fwhat-i-tell-teams-about-claude-code","2.blog\u002F20260314.what-i-tell-teams-about-claude-code",{"title":197,"path":198,"stem":199},"The Hardest Part of AI Isn't the AI","\u002Fblog\u002Fthe-hardest-part-of-ai-isnt-the-ai","2.blog\u002F20260327.the-hardest-part-of-ai-isnt-the-ai",{"title":201,"path":202,"stem":203},"Claude Code Hooks: The Capability I Left on the Table","\u002Fblog\u002Fclaude-code-hooks-capability-left-on-the-table","2.blog\u002F20260401.claude-code-hooks-capability-left-on-the-table",{"id":205,"title":206,"description":207,"extension":208,"features":209,"hero":225,"logos":241,"meta":284,"stem":285,"__hash__":286},"index\u002F0.index.yml","Chris Towles's - Blog","Usually in AWS, AI, Python, Typescript, and tinkering with everything else","yml",{"title":210,"description":211,"items":212},"Why should you listen to me?","Because I've been doing this for over 20 years and learned a thing or two the hard way.",[213,217,221],{"title":214,"description":215,"icon":216},"Take Notes","Always take notes. You will forget given time. Leave a clue for future you.","i-heroicons-pencil-square",{"title":218,"description":219,"icon":220},"Setup CI\u002FCD","if its worth deploying, its worth doing so in a repeatable way.","i-heroicons-rocket-launch",{"title":222,"description":223,"icon":224},"Tests","tests help you! Want to refactor and improve things? Tests let you do that!","i-heroicons-academic-cap-solid",{"title":226,"description":227,"links":228},"Chris Towles's Blog","I'm a Principal Architect for Cloud AI at GE Aerospace and full stack developer. Usually in AWS, AI, Python, Typescript, and tinkering with everything else.",[229,236],{"label":230,"icon":231,"trailing":232,"to":233,"size":234,"variant":235},"Blog","i-lucide-notebook-text",false,"blog","xl","outline",{"label":237,"icon":238,"trailing":232,"to":239,"size":234,"variant":240},"AI Chat","i-heroicons-chat-bubble-left-right","chat","solid",{"title":242,"links":243},"My thoughts are my own as I write about...",[244,248,252,256,260,264,268,272,276,280],{"label":245,"to":246,"icon":247},"Amazon AWS","https:\u002F\u002Faws.amazon.com","i-simple-icons-amazonaws",{"label":249,"to":250,"icon":251},"Node.js","https:\u002F\u002Fnodejs.org","i-simple-icons-nodedotjs",{"label":253,"to":254,"icon":255},"Anthropic","https:\u002F\u002Fwww.anthropic.com","i-simple-icons-anthropic",{"label":257,"to":258,"icon":259},"OpenAI","https:\u002F\u002Fwww.openai.com","i-simple-icons-openai",{"label":261,"to":262,"icon":263},"Cloudflare","https:\u002F\u002Fwww.cloudflare.com","i-simple-icons-cloudflare",{"label":265,"to":266,"icon":267},"Google Cloud","https:\u002F\u002Fcloud.google.com","i-simple-icons-googlecloud",{"label":269,"to":270,"icon":271},"Typescript","https:\u002F\u002Fwww.typescriptlang.org","i-simple-icons-typescript",{"label":273,"to":274,"icon":275},"Python","https:\u002F\u002Fwww.python.org","i-simple-icons-python",{"label":277,"to":278,"icon":279},"Nuxt.js","https:\u002F\u002Fnuxtjs.org","i-simple-icons-nuxtdotjs",{"label":281,"to":282,"icon":283},"Vue","https:\u002F\u002Fvuejs.org","i-simple-icons-vuedotjs",{"navigation":232},"0.index","TNUHM6-qpY550wzMPP54W7vVAFwFIPp1X_4W92wjq4k",[288,542,823,1083,1726,3175,3366,3790,3930,4260,4581,5432,5557,6339,6492,6680,7008,7185,7312,7576,7784,7949,8197,8284,8510,8883,9733,9898,10160,10542,10882,11068,11198,11512,11617,12221,12314,12468,12822,12981,13310,13783,14123,14665,14866,15007,15310,15609,15916],{"id":289,"title":197,"authors":290,"badge":296,"body":298,"date":531,"description":532,"extension":533,"image":534,"meta":537,"navigation":538,"path":198,"seo":539,"status":540,"stem":199,"__hash__":541},"posts\u002F2.blog\u002F20260327.the-hardest-part-of-ai-isnt-the-ai.md",[291],{"name":292,"to":293,"avatar":294},"Chris Towles","https:\u002F\u002Ftwitter.com\u002FChris_Towles",{"src":295},"\u002Fimages\u002Fctowles-profile-512x512.png",{"label":297},"AI",{"type":299,"value":300,"toc":514},"minimark",[301,305,308,311,314,317,322,329,338,341,347,350,357,361,364,367,386,393,397,400,405,411,414,417,421,424,427,431,434,437,441,444,447,451,454,464,471,474,478,485,488,492,495,498,501,505,508,511],[302,303,304],"p",{},"Last week I caught myself explaining agent orchestration patterns to a coworker who'd used ChatGPT twice. His eyes glazed over somewhere around \"tool calling.\" I kept going anyway.",[302,306,307],{},"That's the moment I realized I'd become the problem.",[302,309,310],{},"Since 2024 I've been going deeper into AI every single day. Context windows, KV caches, how models actually work under the hood. I know what tasks to give agents, how skills work, what the latest papers say. I follow the sharpest people in the field and read research directly from Anthropic, OpenAI, and DeepMind.",[302,312,313],{},"And none of that matters if I can't meet people where they are. I skip the fundamentals and jump straight to where I am today — talking about agent orchestration when they're still wondering why the chatbot hallucinated their lunch order. I forget that I had to learn all of this one piece at a time, and I try to shortcut that journey for others by just... skipping it.",[302,315,316],{},"That's a personality-level failure. And it got me thinking about what actually matters when you're building AI products.",[318,319,321],"h2",{"id":320},"the-thread-that-crystallized-it","The Thread That Crystallized It",[302,323,324,325],{},"Rahul Sengottuvelu (head of applied AI at Ramp) recently dropped a thread that maps exactly to this problem: ",[326,327,328],"strong",{},"the most valuable thing you can build in AI isn't the AI part.",[330,331,334],"blockquote",{"className":332},[333],"twitter-tweet",[335,336],"a",{"href":337},"https:\u002F\u002Fx.com\u002Frahulgs\u002Fstatus\u002F2036857870042411438",[302,339,340],{},"Even Evan You agrees — excited for Void+.",[330,342,344],{"className":343},[333],[335,345],{"href":346},"https:\u002F\u002Fx.com\u002Fyouyuxi\u002Fstatus\u002F2037372365580148948",[302,348,349],{},"WAGMI stands for \"We're All Gonna Make It\" — crypto slang I had no idea about before this thread. NGMI is the counterpart: \"Not Gonna Make It.\" In this context, WAGMI strategies build durable value in AI products by focusing on things that evolve slowly, even as frontier models improve at breakneck speed on context windows, reasoning, and token costs.",[302,351,352,353,356],{},"The core idea: ",[326,354,355],{},"AI model capabilities are commoditizing quickly."," The advantages from squeezing marginal gains out of today's models evaporate with the next release. The lasting wins come from building around stable fundamentals.",[318,358,360],{"id":359},"whats-ngmi","What's NGMI",[302,362,363],{},"Before getting into what works, it's worth naming what doesn't.",[302,365,366],{},"NGMI tactics feel productive but become irrelevant as models get smarter and cheaper:",[368,369,370,374,377,380,383],"ul",{},[371,372,373],"li",{},"Custom context window optimizations",[371,375,376],{},"Hybrid retrieval pipeline tweaks",[371,378,379],{},"Specialized fine-tunes for narrow tasks",[371,381,382],{},"Bespoke memory systems and context graphs",[371,384,385],{},"In-house RL models chasing benchmark gains",[302,387,388,389,392],{},"These all share the same problem: ",[326,390,391],{},"you're competing on the same axis the frontier labs are improving on."," Every dollar spent on a clever RAG pipeline is a dollar that GPT-next or Claude-next will make unnecessary. The foundation shifts underneath you.",[318,394,396],{"id":395},"the-wagmi-playbook","The WAGMI Playbook",[302,398,399],{},"Here's Rahul's thread distilled, with my own experience layered in.",[401,402,404],"h3",{"id":403},"_1-product-and-ui","1. Product and UI",[302,406,407,408],{},"The bottleneck is shifting from \"can the AI do it?\" to ",[326,409,410],{},"\"can users easily and enjoyably use it?\"",[302,412,413],{},"Great UI turns raw capability into sticky, habitual products. Nobody switches away from a tool they love using, even if a competitor has a marginally better model underneath.",[302,415,416],{},"I made this mistake at work during the last few months — building a product that does five things well but is confusing to anyone who didn't build it. If users can't figure it out in 30 seconds, the capability is invisible.",[401,418,420],{"id":419},"_2-customer-acquisition","2. Customer Acquisition",[302,422,423],{},"Even the best AI tech is pointless without users benefiting from it.",[302,425,426],{},"This isn't an AI insight — it's the history of technology. VHS beat Betamax. Windows beat OS\u002F2. The technically superior option loses to the one that gets in front of users and keeps them coming back.",[401,428,430],{"id":429},"_3-deep-integrations","3. Deep Integrations",[302,432,433],{},"Connect your AI into users' existing tools, data systems, and workflows. Meeting users where they are reduces friction and builds defensibility through network effects and switching costs.",[302,435,436],{},"This is why tools like Claude Code, Cursor, and Windsurf have such strong positions. The biggest shift for me with Claude Code wasn't any single feature — it was that it worked on my data, where I already worked. I wasn't copying code in and out of a web browser anymore. The integration IS the product.",[401,438,440],{"id":439},"_4-agent-tooling","4. Agent Tooling",[302,442,443],{},"Better linting, CI, skill management, and feedback loops for agents. This is the developer experience layer — not the agent itself, but everything around it that makes agents shippable.",[302,445,446],{},"We're at a point where building a working prototype takes less time than scheduling the meeting to get approval for it. The teams that invest in agent DevEx now are the ones that will iterate fastest when the next model drop changes what's possible overnight.",[401,448,450],{"id":449},"_5-background-agent-infrastructure","5. Background Agent Infrastructure",[302,452,453],{},"Build reliable systems that let agents run asynchronously, in parallel, and at scale. The goal is parallelizing more work without blocking users.",[302,455,456,457,463],{},"A smarter model doesn't help if you can't run 10 of them concurrently on different tasks with proper slot management, failure recovery, and status tracking. I'm working on this now with ",[335,458,462],{"href":459,"rel":460},"https:\u002F\u002Fgithub.com\u002FChrisTowles\u002Ftowles-tool",[461],"nofollow","towles-tool"," — an AgentBoard feature that is a kanban board to work with multiple agents at once without having to tab through terminal windows to find which one needs my direction or review!",[302,465,466],{},[467,468],"img",{"alt":469,"src":470},"towles-tool AgentBoard kanban for managing multiple agents","\u002Fimages\u002Fblog\u002F20260327-hardest-part-of-ai-agentboard.png",[302,472,473],{},"I'm betting we'll all be running k8s instances before the end of the year for our agent swarms!",[401,475,477],{"id":476},"_6-agent-verification-loops","6. Agent Verification Loops",[302,479,480,481,484],{},"Speed up the cycle of testing, validating, and correcting agent behavior in production. The edge comes from ",[326,482,483],{},"how quickly you can observe and improve what agents are doing",", not from raw intelligence.",[302,486,487],{},"The team that can ship, watch, and correct agent behavior in hours instead of months has a massive advantage. The hard part isn't making the agent smarter — it's knowing when it's wrong.",[401,489,491],{"id":490},"_7-training-users-and-connecting-to-their-systems","7. Training Users and Connecting to Their Systems",[302,493,494],{},"This is the one I keep failing at. It's also the one that connects back to my opening story.",[302,496,497],{},"Claude Desktop is the best example I've seen of making AI approachable, and even that is rough for non-technical people. The gap between \"installed the app\" and \"getting value from it daily\" is massive. The more a user invests in learning your tool and connecting their systems, the higher the switching cost — not lock-in through friction, but lock-in through value. Their workflows shape around your product, and that doesn't transfer to a competitor just because they have a newer model.",[302,499,500],{},"The gap between \"this technology is incredible\" and \"I can actually use this in my work\" is enormous. Bridging it is a human problem, not a model problem. No amount of capability improvement fixes the disconnect between an expert builder and a first-time user.",[318,502,504],{"id":503},"the-reframe","The Reframe",[302,506,507],{},"The frontier labs will keep making models smarter and cheaper. That's great — it makes the WAGMI layer more valuable, not less. Every improvement in model capability increases the surface area of what your product can do, as long as you've built the infrastructure to deliver it.",[302,509,510],{},"UI, distribution, integrations, agent infrastructure, user workflows. These are the layers that compound. The model underneath is a commodity — the experience around it isn't.",[302,512,513],{},"I'm still working on that last one. Meeting people where they are instead of where I am. It turns out the hardest part of building AI products isn't the AI. It's the people.",{"title":515,"searchDepth":516,"depth":516,"links":517},"",2,[518,519,520,530],{"id":320,"depth":516,"text":321},{"id":359,"depth":516,"text":360},{"id":395,"depth":516,"text":396,"children":521},[522,524,525,526,527,528,529],{"id":403,"depth":523,"text":404},3,{"id":419,"depth":523,"text":420},{"id":429,"depth":523,"text":430},{"id":439,"depth":523,"text":440},{"id":449,"depth":523,"text":450},{"id":476,"depth":523,"text":477},{"id":490,"depth":523,"text":491},{"id":503,"depth":516,"text":504},"2026-03-27","AI model capabilities are commoditizing fast. The lasting wins come from UI, integrations, agent infrastructure, and user workflows — not squeezing marginal gains from today's models.","md",{"src":535,"alt":536},"\u002Fimages\u002Fblog\u002F20260327-hardest-part-of-ai.png","A software engineer at a crossroads in a futuristic cityscape — cool blue neural network nodes on one path, warm golden screens and collaborating people on the other",{},true,{"title":197,"description":532},"published","1gphiCeR852Bu-yk9_DY1Xu6qpFQsrdGMl_3_353no0",{"id":543,"title":193,"authors":544,"badge":547,"body":549,"date":815,"description":816,"extension":533,"image":817,"meta":820,"navigation":538,"path":194,"seo":821,"status":540,"stem":195,"__hash__":822},"posts\u002F2.blog\u002F20260314.what-i-tell-teams-about-claude-code.md",[545],{"name":292,"to":293,"avatar":546},{"src":295},{"label":548},"Claude Code",{"type":299,"value":550,"toc":806},[551,554,561,565,568,605,609,612,615,624,627,630,634,637,669,678,681,685,688,691,705,708,712,718,755,759,762,769,778,781,785,788,791,800,803],[302,552,553],{},"Honest caveat first: this space is moving so fast that things I would have sworn by a month ago I wouldn't do today. Take anything you read with that in mind, including this post.",[302,555,556,557,560],{},"I wrote a ",[335,558,559],{"href":78},"tips post"," back in July 2025 that covered the tactical side — keybindings, features, tricks. This post is different. It's what I actually tell teams when they're adopting Claude Code and want to know what matters.",[318,562,564],{"id":563},"start-with-primary-sources","Start With Primary Sources",[302,566,567],{},"The one thing that has held up: go to primary sources first. The people actually building Claude Code will tell you exactly how they use it. The Anthropic engineering blog and Boris Cherny's talks have been way more durable signal than anything else out there.",[368,569,570,577,584,591,598],{},[371,571,572],{},[335,573,576],{"href":574,"rel":575},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=We7BZVKbCVw",[461],"What happens after coding is solved — Boris Cherny, Lenny's Podcast",[371,578,579],{},[335,580,583],{"href":581,"rel":582},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=julbw1JuAz0&t=163s",[461],"Building Claude Code — Boris Cherny, The Pragmatic Engineer",[371,585,586],{},[335,587,590],{"href":588,"rel":589},"https:\u002F\u002Fyoutu.be\u002FLue8K2jqfKk?si=rF5CoJAZWiFbAFvN",[461],"Claude Code & the evolution of agentic coding — Boris Cherny, Anthropic",[371,592,593],{},[335,594,597],{"href":595,"rel":596},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=Yf_1w00qIKc",[461],"A conversation on Claude Code — Boris Cherny, Anthropic",[371,599,600],{},[335,601,604],{"href":602,"rel":603},"https:\u002F\u002Fwww.anthropic.com\u002Fengineering\u002Fclaude-code-best-practices?s=09",[461],"Claude Code: Best practices for agentic coding — Boris Cherny, Anthropic",[318,606,608],{"id":607},"its-a-force-multiplier-not-an-equalizer","It's a Force Multiplier, Not an Equalizer",[302,610,611],{},"The developers who were shipping valuable code every day will get dramatically more powerful. It won't turn someone who wasn't into someone who suddenly is. And people pushing code they didn't read or understand just creates a mess that everyone else ends up spending time cleaning up.",[302,613,614],{},"I've seen this firsthand — a developer uses Claude to generate a feature, ships it without reading the diff, and the next person who touches that code spends twice as long understanding it as it would have taken to write it properly. The tool amplifies habits, good and bad.",[302,616,617,618,623],{},"I learned this the hard way myself. I tried using Claude Code on my brother Patrick's (",[335,619,622],{"href":620,"rel":621},"https:\u002F\u002Fgithub.com\u002Fslyedoc",[461],"slyedoc",") Rust repo built on the Bevy game engine. I don't know Rust. I don't know Bevy. The PRs I submitted were worse than harmful — I didn't understand what Claude was generating, and I didn't have the taste to steer it. I couldn't tell when to say \"no, that's wrong\" because I had no baseline for what right looked like. Knowing when to tell Claude \"no\" is the most critical skill, and you can't do that in a domain you don't understand.",[302,625,626],{},"Look hard at GitHub history and what people have actually contributed before picking your cohort. That's a better signal for who will thrive with these tools than almost anything else.",[302,628,629],{},"People level up, but there's no way to skip steps yet. Everyone has to earn the reps.",[318,631,633],{"id":632},"your-codebase-quality-matters-more-than-ever","Your Codebase Quality Matters More Than Ever",[302,635,636],{},"A great codebase before AI makes a great codebase with AI. The same logic that applies to developers applies to the code you give them:",[368,638,639,645,651,657,663],{},[371,640,641,644],{},[326,642,643],{},"Good test coverage"," — the model can verify its own work",[371,646,647,650],{},[326,648,649],{},"Well-structured code"," — clear boundaries, clear responsibility",[371,652,653,656],{},[326,654,655],{},"Multi-tier deployments"," (dev → qa → prod) — safe places to fail",[371,658,659,662],{},[326,660,661],{},"Popular frameworks"," well represented in the model's training data",[371,664,665,668],{},[326,666,667],{},"Conventions over custom one-off solutions"," — patterns the model recognizes",[302,670,671,672,677],{},"We also scope ",[335,673,676],{"href":674,"rel":675},"https:\u002F\u002Fdocs.anthropic.com\u002Fen\u002Fdocs\u002Fclaude-code\u002Fmemory#claudemd",[461],"CLAUDE.md"," files to just the folder level where the information is actually relevant rather than one giant file at the root. The model uses what it needs and isn't wading through noise.",[302,679,680],{},"One more thing: don't let credentials or secrets anywhere near the context. Treat the AI like a junior developer sitting at your desk — give it access to what it needs and nothing more.",[318,682,684],{"id":683},"if-it-cant-measure-it-it-cant-improve","If It Can't Measure It, It Can't Improve",[302,686,687],{},"These agentic workflows work dramatically better when they can evaluate themselves. Tests are the obvious version of this, but it applies everywhere — the more feedback loops you can give the model, the better the output gets without you having to babysit it.",[302,689,690],{},"This means:",[368,692,693,696,699,702],{},[371,694,695],{},"Tests that actually run and assert meaningful behavior",[371,697,698],{},"Linters and type checkers that catch drift",[371,700,701],{},"Screenshots or output captures for visual work",[371,703,704],{},"CLAUDE.md files that tell the model what \"good\" looks like in your project",[302,706,707],{},"The key insight is that Claude Code can run its own tests, check its own types, and iterate on failures. If your project has those feedback loops, the model becomes dramatically more autonomous. If it doesn't, you're back to babysitting.",[318,709,711],{"id":710},"use-every-feature","Use Every Feature",[302,713,714,715,717],{},"Not doing so is leaving power on the table. I covered the full list in my ",[335,716,559],{"href":78},", but the ones that matter most for teams:",[368,719,720,726,732,738,749],{},[371,721,722,725],{},[326,723,724],{},"Dictation"," — every word helps narrow down the task. It's faster than typing and you give more context naturally.",[371,727,728,731],{},[326,729,730],{},"Plan mode"," — align before implementing, especially for non-trivial changes. This is where team leads can steer direction without micromanaging.",[371,733,734,737],{},[326,735,736],{},"Parallel sessions"," — run multiple Claude loops at once. The overhead sounds weird until you try it. Right now as I write this I have two running.",[371,739,740,743,744,748],{},[326,741,742],{},"Skills"," — add them to ",[745,746,747],"code",{},".claude\u002Fskills"," for reuse across the team. Skills give Claude domain knowledge and workflows it can invoke automatically.",[371,750,751,754],{},[326,752,753],{},"Pictures"," — Claude Code can use images. Screenshots of output, UI mockups, error messages — all useful context.",[318,756,758],{"id":757},"the-review-process-has-to-change","The Review Process Has to Change",[302,760,761],{},"When AI generates code, your review process needs to adapt. The reviewer needs to read the diff just as carefully — maybe more carefully — because the code wasn't written by someone who will remember why they made each decision. Treat AI-generated PRs the same way you'd treat a PR from a contractor: thorough review, clear acceptance criteria, and someone who understands the codebase signing off.",[302,763,764,765,768],{},"Here's my litmus test: ",[326,766,767],{},"ask the person who submitted the PR to explain any piece of it."," Pick a function, a conditional, an architectural choice — anything. If they can't explain why it's there and what it does, that's a red flag. It means they shipped code they didn't understand, and code nobody understands is code nobody can maintain.",[302,770,771,772,777],{},"This is what Boris Tane calls ",[335,773,776],{"href":774,"rel":775},"https:\u002F\u002Fboristane.com\u002Fblog\u002Fslop-creep-enshittification-of-software\u002F",[461],"slop creep"," — the gradual degradation of a codebase through individually reasonable but collectively destructive decisions. Every AI-generated change looks fine in isolation. The tests pass, the linter is happy, the feature works. But the accumulated weight of code that nobody deeply understood when it landed creates architectural debt that compounds silently. The agent makes \"confidently, competently wrong\" choices because it can't see the system-level consequences. And without a human who actually read and understood the diff, those choices calcify.",[302,779,780],{},"The old speed limits — the friction of writing code by hand — used to be a natural circuit breaker. You'd feel the pain of a bad abstraction because you had to type through it. AI removes that friction, which is the whole point, but it also removes the forcing function that made you stop and think. So you have to replace it with something deliberate: reviews where people can actually explain what they're approving.",[318,782,784],{"id":783},"build-the-flywheel","Build the Flywheel",[302,786,787],{},"The real unlock isn't any single session with Claude Code. It's building a system that gets better the more you use it.",[302,789,790],{},"Every correct example in your codebase — well-tested code, clean patterns, good CLAUDE.md files — makes the next generation of output better. The model learns from your conventions. Your tests catch its mistakes before they land. Your linter enforces your style. Each iteration tightens the loop. More correct code means better context means more correct code.",[302,792,793,794,799],{},"Karpathy ",[335,795,798],{"href":796,"rel":797},"https:\u002F\u002Fx.com\u002Fkarpathy\u002Fstatus\u002F2031135152349524125",[461],"demonstrated this recently"," with nanochat. He set an agent loose on hyperparameter tuning for two days. It autonomously tried ~700 changes, found ~20 real improvements that stacked up to an 11% speedup — things like attention scaling oversights, missing regularization, conservative banding he forgot to tune. All on top of code he'd already manually optimized. The agent found real improvements because it had a clear metric to optimize and a fast feedback loop to evaluate against.",[302,801,802],{},"That's the flywheel. Any metric you care about that's reasonably efficient to evaluate can be autoresearched by an agent. For most of us, that metric is \"do the tests pass and does the code match our conventions.\" The more of those signals you have, the more autonomous the model becomes, and the better the output gets without you touching it.",[302,804,805],{},"This is where I'd focus if I were starting from scratch: not on prompt engineering, but on building the infrastructure that makes every future session better than the last.",{"title":515,"searchDepth":516,"depth":516,"links":807},[808,809,810,811,812,813,814],{"id":563,"depth":516,"text":564},{"id":607,"depth":516,"text":608},{"id":632,"depth":516,"text":633},{"id":683,"depth":516,"text":684},{"id":710,"depth":516,"text":711},{"id":757,"depth":516,"text":758},{"id":783,"depth":516,"text":784},"2026-03-14","Honest advice for small teams adopting Claude Code — from primary sources to force multipliers to why your codebase quality matters more than ever.",{"src":818,"alt":819},"\u002Fimages\u002Fblog\u002F20260314-1400-what-i-tell-teams-about-claude-code.png","A team of developers collaborating around terminals with AI coding assistants",{},{"title":193,"description":816},"kE68kZAILYkf-pnPuSuHdRa3KB7xiF54vDigDhlJFGY",{"id":824,"title":189,"authors":825,"badge":828,"body":829,"date":1075,"description":1076,"extension":533,"image":1077,"meta":1080,"navigation":538,"path":190,"seo":1081,"status":540,"stem":191,"__hash__":1082},"posts\u002F2.blog\u002F20260313.biggest-bottleneck-scaling-ai-compute.md",[826],{"name":292,"to":293,"avatar":827},{"src":295},{"label":297},{"type":299,"value":830,"toc":1065},[831,834,843,847,850,871,874,878,887,890,916,924,931,935,946,949,953,956,959,963,970,974,985,996,1000,1003,1029,1033,1036,1039,1042,1047],[302,832,833],{},"I just watched Dylan Patel's deep dive on the 3 big bottlenecks to scaling AI compute and I feel like I woke up from another level of Inception. Every time you think you've found the real constraint, you peel back another layer and discover something deeper.",[302,835,836,837,842],{},"Dylan is the founder and CEO of ",[335,838,841],{"href":839,"rel":840},"https:\u002F\u002Fsemianalysis.com\u002F",[461],"SemiAnalysis",", and his analysis of the AI infrastructure buildout is the clearest picture I've seen of what's actually happening beneath the hype.",[318,844,846],{"id":845},"the-three-bottlenecks","The Three Bottlenecks",[302,848,849],{},"The bottlenecks shift over time, but they stack on top of each other:",[851,852,853,859,865],"ol",{},[371,854,855,858],{},[326,856,857],{},"Logic chips"," — GPUs and custom silicon",[371,860,861,864],{},[326,862,863],{},"Memory"," — HBM and DRAM",[371,866,867,870],{},[326,868,869],{},"Power"," — Electrical infrastructure and cooling",[302,872,873],{},"What makes this mind-bending is that solving one bottleneck just reveals the next one. TSMC ramps CoWoS packaging capacity? Great, now you're blocked on HBM supply. Memory vendors scale up? Now you can't get enough power to the data center. Get the power? You still can't get enough EUV lithography tools to make the chips in the first place.",[318,875,877],{"id":876},"asml-the-bottleneck-beneath-all-bottlenecks","ASML: The Bottleneck Beneath All Bottlenecks",[302,879,880,881,886],{},"This is where it gets Inception-level deep. By 2028-2030, Dylan argues the ultimate constraint falls to ",[335,882,885],{"href":883,"rel":884},"https:\u002F\u002Fwww.asml.com\u002F",[461],"ASML"," — the Dutch company that makes the world's most complicated machine: the EUV lithography tool.",[302,888,889],{},"The numbers are staggering:",[368,891,892,898,904,910],{},[371,893,894,895],{},"ASML currently produces ",[326,896,897],{},"~70 EUV tools per year",[371,899,900,901],{},"Even with aggressive scaling, they'll reach maybe ",[326,902,903],{},"100 by end of decade",[371,905,906,907],{},"Each tool costs ",[326,908,909],{},"$300-400 million",[371,911,912,913],{},"A single gigawatt of AI compute requires roughly ",[326,914,915],{},"3.5 EUV tools",[302,917,918,919,923],{},"So if you do the math: ~700 cumulative EUV tools by 2030 yields roughly 200 gigawatts maximum. Meanwhile, Sam Altman is talking about wanting 52 gigawatts ",[920,921,922],"em",{},"per year",". The numbers don't add up.",[302,925,926,927,930],{},"And here's the kicker — each EUV tool has ",[326,928,929],{},"10,000+ suppliers"," across extraordinarily complex subsystems (Zeiss optics, Cymer light sources, mechanical stages with nanometer precision). You can't just throw money at this. The expertise required to build these machines takes years to develop.",[318,932,934],{"id":933},"the-leverage-ratio-that-broke-my-brain","The Leverage Ratio That Broke My Brain",[302,936,937,938,941,942,945],{},"Dylan drops a number that I keep coming back to: a ",[326,939,940],{},"$50 billion gigawatt"," of data center capacity depends on roughly ",[326,943,944],{},"$1.2 billion"," in EUV tooling. That's an insane leverage ratio. One company's production capacity — constrained by physics and supply chain complexity — determines whether tens of billions in infrastructure investment can actually produce useful compute.",[302,947,948],{},"It's like discovering that the entire global economy runs through a single bridge, and that bridge can only handle so many cars per hour.",[318,950,952],{"id":951},"the-gpu-depreciation-myth","The GPU Depreciation Myth",[302,954,955],{},"One counterintuitive insight: GPUs aren't actually depreciating the way people assume. Dylan argues that an H100 is worth more today than when it launched, because newer models and architectures extract more value per chip. The software is getting better at using the hardware.",[302,957,958],{},"This matters because it means the trillion-dollar infrastructure buildout isn't a depreciating asset race. The chips retain value as long as the models keep improving their efficiency on existing hardware.",[318,960,962],{"id":961},"memory-is-about-to-get-expensive","Memory Is About to Get Expensive",[302,964,965,966,969],{},"Memory vendors are expected to ",[326,967,968],{},"double or triple prices"," as HBM demand outstrips supply. The interesting adaptation: some inference workloads may shift to commodity DRAM, accepting latency tradeoffs for non-real-time agent applications. Not everything needs the fastest memory — a background agent processing your emails can wait a few extra milliseconds.",[318,971,973],{"id":972},"power-the-50gw-gap","Power: The 50GW Gap",[302,975,976,977,980,981,984],{},"By 2028, there's an estimated gap of ",[326,978,979],{},"50+ gigawatts"," in power generation for AI data centers. The fundamental problem is a timing mismatch: AI companies want data centers built in 18 months, but adding power generation to the grid takes ",[326,982,983],{},"5+ years"," on average.",[302,986,987,988,991,992,995],{},"Microsoft's annual CapEx is projected to surpass ",[326,989,990],{},"$80 billion"," (up from ~$15 billion five years ago). Total annual AI data center investment could reach ",[326,993,994],{},"$400-500 billion"," by mid-decade. All of it constrained by whether you can actually power the buildings.",[318,997,999],{"id":998},"why-this-matters-for-software-engineers","Why This Matters for Software Engineers",[302,1001,1002],{},"If you're building AI-powered products, this has practical implications:",[368,1004,1005,1011,1017,1023],{},[371,1006,1007,1010],{},[326,1008,1009],{},"Compute costs aren't going down anytime soon."," Plan for expensive inference, especially for real-time applications.",[371,1012,1013,1016],{},[326,1014,1015],{},"Efficiency matters more than scale."," The companies winning will be those extracting more value per FLOP, not just throwing more FLOPs at problems.",[371,1018,1019,1022],{},[326,1020,1021],{},"The agent paradigm helps."," Async, non-real-time agent workloads can use cheaper compute tiers and commodity memory. Design your systems to be latency-tolerant where possible.",[371,1024,1025,1028],{},[326,1026,1027],{},"Edge inference is underrated."," Anything you can push to the device sidesteps the entire data center bottleneck chain.",[318,1030,1032],{"id":1031},"the-inception-feeling","The Inception Feeling",[302,1034,1035],{},"What gave me the Inception feeling isn't any single bottleneck — it's the recursive nesting. You think the problem is chips, but it's actually memory. You think it's memory, but it's actually power. You think it's power, but it's actually the machines that make the chips. And the machines that make the chips depend on optics from a single German company and light sources that push the boundaries of physics.",[302,1037,1038],{},"Each layer seems like the \"real\" world until you zoom out and realize you're still dreaming.",[302,1040,1041],{},"The AI infrastructure buildout is the largest industrial project in human history, and it's constrained by supply chains that were designed for a world that needed far less compute. We're trying to push exponential demand through linear supply chains. Something has to give.",[302,1043,1044],{},[920,1045,1046],{},"Note: Some data points in this post come from supplementary SemiAnalysis research and other Dylan Patel appearances, not solely from this video.",[1048,1049,1051],"callout",{"icon":1050},"i-lucide-youtube",[302,1052,1053,1054,1059,1060],{},"Watch the full conversation: ",[335,1055,1058],{"href":1056,"rel":1057},"https:\u002F\u002Fyoutu.be\u002FmDG_Hx3BSUE",[461],"Dylan Patel — Deep Dive on the 3 Big Bottlenecks to Scaling AI Compute"," or read the ",[335,1061,1064],{"href":1062,"rel":1063},"https:\u002F\u002Fwww.dwarkesh.com\u002Fp\u002Fdylan-patel",[461],"transcript on Dwarkesh Patel's site",{"title":515,"searchDepth":516,"depth":516,"links":1066},[1067,1068,1069,1070,1071,1072,1073,1074],{"id":845,"depth":516,"text":846},{"id":876,"depth":516,"text":877},{"id":933,"depth":516,"text":934},{"id":951,"depth":516,"text":952},{"id":961,"depth":516,"text":962},{"id":972,"depth":516,"text":973},{"id":998,"depth":516,"text":999},{"id":1031,"depth":516,"text":1032},"2026-03-13","Dylan Patel's breakdown of the 3 big bottlenecks to scaling AI compute reveals a supply chain so deeply nested it feels like waking up from another level of Inception.",{"src":1078,"alt":1079},"\u002Fimages\u002Fblog\u002F20260313-1800-ai-compute-bottleneck.png","Nested layers of AI infrastructure bottlenecks",{},{"title":189,"description":1076},"La__ae4uz4BwO7Bp7KBk1plrOMZaPg__Vln7xbckLGw",{"id":1084,"title":185,"authors":1085,"badge":1088,"body":1090,"date":1718,"description":1719,"extension":533,"image":1720,"meta":1723,"navigation":538,"path":186,"seo":1724,"status":540,"stem":187,"__hash__":1725},"posts\u002F2.blog\u002F20260225.multi-agent-loan-approval-human-in-the-loop.md",[1086],{"name":292,"to":293,"avatar":1087},{"src":295},{"label":1089},"Architecture",{"type":299,"value":1091,"toc":1701},[1092,1104,1108,1111,1114,1118,1150,1154,1157,1163,1166,1170,1173,1193,1208,1213,1222,1231,1240,1249,1263,1269,1273,1276,1282,1285,1288,1294,1298,1301,1307,1311,1314,1317,1321,1352,1356,1392,1419,1423,1429,1435,1459,1465,1469,1476,1655,1658,1661,1665,1697],[1048,1093,1095],{"icon":1094},"i-lucide-play",[302,1096,1097,1103],{},[326,1098,1099],{},[335,1100,1102],{"href":1101},"\u002Floan","Try the demo"," — walk through the full workflow yourself. Requires GitHub login.",[318,1105,1107],{"id":1106},"what-i-built","What I Built",[302,1109,1110],{},"A home loan application workflow where AI agents review applications but a human makes the final call. Three specialized AI reviewers analyze every application independently, then a human approves, denies, or flags it — the AI advises, it doesn't decide.",[302,1112,1113],{},"This is a demo\u002Fplayground, not production financial software. But it demonstrates a pattern that matters: multi-agent AI systems that keep humans in the decision loop.",[318,1115,1117],{"id":1116},"the-flow","The Flow",[1119,1120,1124],"pre",{"className":1121,"code":1122,"language":1123,"meta":515,"style":515},"language-mermaid shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","flowchart LR\n    A[Intake Chat] -->|submit| B[AI Review]\n    B -->|3 agents stream| C[Human Decision]\n    C -->|re-review| A\n","mermaid",[745,1125,1126,1134,1139,1144],{"__ignoreMap":515},[1127,1128,1131],"span",{"class":1129,"line":1130},"line",1,[1127,1132,1133],{},"flowchart LR\n",[1127,1135,1136],{"class":1129,"line":516},[1127,1137,1138],{},"    A[Intake Chat] -->|submit| B[AI Review]\n",[1127,1140,1141],{"class":1129,"line":523},[1127,1142,1143],{},"    B -->|3 agents stream| C[Human Decision]\n",[1127,1145,1147],{"class":1129,"line":1146},4,[1127,1148,1149],{},"    C -->|re-review| A\n",[401,1151,1153],{"id":1152},"_1-intake-conversational-data-collection","1. Intake — Conversational Data Collection",[302,1155,1156],{},"The applicant chats with an AI assistant that collects loan details naturally. No forms — just conversation. The AI uses tool calls behind the scenes to extract structured data (name, income, employment, property details, credit score range) and updates a progress bar in real time.",[302,1158,1159],{},[467,1160],{"alt":1161,"src":1162},"Intake chat interface with progress bar showing fields to collect","\u002Fimages\u002Fblog\u002F20260225-loan-intake.png",[302,1164,1165],{},"Once all 12 fields are collected, a \"Submit for Review\" button appears.",[401,1167,1169],{"id":1168},"_2-multi-agent-review-three-independent-ai-reviewers","2. Multi-Agent Review — Three Independent AI Reviewers",[302,1171,1172],{},"Submitting triggers three AI reviewers that run sequentially, each streaming their analysis in real-time via SSE:",[368,1174,1175,1181,1187],{},[371,1176,1177,1180],{},[326,1178,1179],{},"The Bank — Financial Risk",": Evaluates DTI ratio, LTV ratio, credit score, income stability. Conservative risk assessment focused on regulatory compliance.",[371,1182,1183,1186],{},[326,1184,1185],{},"Loan Market — Deal Structure",": Analyzes the deal from a market perspective — is the property fairly valued? Is the loan amount reasonable for the area?",[371,1188,1189,1192],{},[326,1190,1191],{},"Background Checks — Fraud Detection",": Looks for inconsistencies in the application data. Cross-references employment claims, income vs. debt ratios, and flags suspicious patterns.",[302,1194,1195,1196,1199,1200,1203,1204,1207],{},"Each reviewer uses a custom system prompt and independently decides: ",[326,1197,1198],{},"approve",", ",[326,1201,1202],{},"deny",", or ",[326,1205,1206],{},"flag",".",[1209,1210,1212],"h4",{"id":1211},"the-reviewer-prompts","The Reviewer Prompts",[302,1214,1215,1216,1221],{},"Each reviewer's personality and evaluation criteria live in a ",[335,1217,1220],{"href":1218,"rel":1219},"https:\u002F\u002Fdocs.anthropic.com\u002Fen\u002Fdocs\u002Fclaude-code\u002Fskills",[461],"Claude Code Skills"," markdown file. The server loads these at review time as the system prompt for each agent call. Here's the key section from each:",[302,1223,1224,1230],{},[326,1225,1226],{},[335,1227,1179],{"href":1228,"rel":1229},"https:\u002F\u002Fgithub.com\u002FChrisTowles\u002Fblog\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Floan-the-bank\u002FSKILL.md",[461]," evaluates DTI, LTV, credit score, and employment stability. It's told to be conservative: \"It is MORE IMPORTANT to flag issues than to approve.\" Red flags include DTI > 43%, LTV > 95%, subprime credit scores, and employment under 2 years.",[302,1232,1233,1239],{},[326,1234,1235],{},[335,1236,1185],{"href":1237,"rel":1238},"https:\u002F\u002Fgithub.com\u002FChrisTowles\u002Fblog\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Floan-market\u002FSKILL.md",[461]," focuses on the deal economics, not the borrower. It checks property value reasonableness, jumbo loan thresholds, down payment signals, and property type risk profiles. \"Focus on the deal economics. Be specific.\"",[302,1241,1242,1248],{},[326,1243,1244],{},[335,1245,1191],{"href":1246,"rel":1247},"https:\u002F\u002Fgithub.com\u002FChrisTowles\u002Fblog\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Floan-background\u002FSKILL.md",[461]," is the skeptic: \"Assume nothing. Question everything.\" It looks for income\u002Femployment mismatches, suspiciously round numbers, mathematically impossible combinations, and vague employer names.",[302,1250,1251,1252,1199,1255,1258,1259,1262],{},"All three share the same output format — a JSON object with ",[745,1253,1254],{},"decision",[745,1256,1257],{},"flags",", and ",[745,1260,1261],{},"analysis"," — but their evaluation criteria and tone are completely different. This is what makes the multi-agent approach interesting: same input, different lenses.",[302,1264,1265],{},[467,1266],{"alt":1267,"src":1268},"Review page showing The Bank's financial risk analysis with Approved badge","\u002Fimages\u002Fblog\u002F20260225-loan-review-top.png",[401,1270,1272],{"id":1271},"_3-human-decision-ai-recommends-human-decides","3. Human Decision — AI Recommends, Human Decides",[302,1274,1275],{},"After all three reviewers complete, the system shows the AI's aggregate recommendation but keeps the status as \"reviewing.\" The application doesn't move forward until a human clicks Approve, Deny, or Flag.",[302,1277,1278],{},[467,1279],{"alt":1280,"src":1281},"AI Recommendation showing fraud flags and Approve\u002FDeny\u002FFlag buttons","\u002Fimages\u002Fblog\u002F20260225-loan-review-recommendation.png",[302,1283,1284],{},"This is the key design decision. Even if all three AI agents approve unanimously, a human must confirm. The AI recommendation is clearly labeled as advisory.",[302,1286,1287],{},"After deciding, the human can still change their decision or send the application back for a fresh re-review.",[302,1289,1290],{},[467,1291],{"alt":1292,"src":1293},"Landing page for the Agentic Loan Workflow demo","\u002Fimages\u002Fblog\u002F20260225-loan-landing.png",[401,1295,1297],{"id":1296},"_4-admin-dashboard","4. Admin Dashboard",[302,1299,1300],{},"An admin view shows all applications across all users with status counts and a table for quick navigation.",[302,1302,1303],{},[467,1304],{"alt":1305,"src":1306},"Admin dashboard showing all loan applications with status counts","\u002Fimages\u002Fblog\u002F20260225-loan-admin.png",[401,1308,1310],{"id":1309},"_5-re-review","5. Re-review",[302,1312,1313],{},"Hit \"Re-review\" and the system clears all AI reviews, resets to intake status, and sends the user back to the chat. The application data is preserved — they can modify answers or submit again for a fresh set of AI reviews.",[318,1315,1089],{"id":1316},"architecture",[401,1318,1320],{"id":1319},"tech-stack","Tech Stack",[368,1322,1323,1329,1335,1340,1346],{},[371,1324,1325,1328],{},[326,1326,1327],{},"Frontend",": Nuxt 4, Vue 3, Nuxt UI",[371,1330,1331,1334],{},[326,1332,1333],{},"Backend",": Nitro server routes, Drizzle ORM, PostgreSQL",[371,1336,1337,1339],{},[326,1338,297],{},": Anthropic Claude (via SDK), three independent agent calls",[371,1341,1342,1345],{},[326,1343,1344],{},"Streaming",": Server-Sent Events (SSE) for real-time review streaming",[371,1347,1348,1351],{},[326,1349,1350],{},"Hosting",": GCP Cloud Run",[401,1353,1355],{"id":1354},"status-model","Status Model",[1119,1357,1359],{"className":1121,"code":1358,"language":1123,"meta":515,"style":515},"flowchart LR\n    intake -->|submit| reviewing\n    reviewing -->|approve| approved\n    reviewing -->|deny| denied\n    reviewing -->|flag| flagged\n    approved & denied & flagged -->|re-review| intake\n",[745,1360,1361,1365,1370,1375,1380,1386],{"__ignoreMap":515},[1127,1362,1363],{"class":1129,"line":1130},[1127,1364,1133],{},[1127,1366,1367],{"class":1129,"line":516},[1127,1368,1369],{},"    intake -->|submit| reviewing\n",[1127,1371,1372],{"class":1129,"line":523},[1127,1373,1374],{},"    reviewing -->|approve| approved\n",[1127,1376,1377],{"class":1129,"line":1146},[1127,1378,1379],{},"    reviewing -->|deny| denied\n",[1127,1381,1383],{"class":1129,"line":1382},5,[1127,1384,1385],{},"    reviewing -->|flag| flagged\n",[1127,1387,1389],{"class":1129,"line":1388},6,[1127,1390,1391],{},"    approved & denied & flagged -->|re-review| intake\n",[368,1393,1394,1400,1406],{},[371,1395,1396,1399],{},[745,1397,1398],{},"intake"," — collecting application data via chat",[371,1401,1402,1405],{},[745,1403,1404],{},"reviewing"," — AI agents have run, waiting for human decision",[371,1407,1408,1411,1412,1411,1415,1418],{},[745,1409,1410],{},"approved"," \u002F ",[745,1413,1414],{},"denied",[745,1416,1417],{},"flagged"," — human has decided",[401,1420,1422],{"id":1421},"key-design-choices","Key Design Choices",[302,1424,1425,1428],{},[326,1426,1427],{},"AI agents don't share context."," Each reviewer gets the same application data independently. They can't see each other's analysis. This prevents groupthink and ensures genuinely independent assessments.",[302,1430,1431,1434],{},[326,1432,1433],{},"Streaming, not batch."," Reviews stream token-by-token via SSE so the user watches each analysis build in real time. This matters for trust — you see the reasoning unfold, not just a verdict.",[302,1436,1437,1440,1441,1444,1445,1447,1448,1451,1452,1454,1455,1454,1457,1207],{},[326,1438,1439],{},"Human-in-the-loop is mandatory, not optional."," The server never sets a final status automatically. The ",[745,1442,1443],{},"submit"," endpoint leaves status as ",[745,1446,1404],{}," after AI completes. Only the ",[745,1449,1450],{},"status.patch"," endpoint (triggered by human click) sets ",[745,1453,1410],{},"\u002F",[745,1456,1414],{},[745,1458,1417],{},[302,1460,1461,1464],{},[326,1462,1463],{},"Clean analysis, not raw JSON."," During streaming, the user sees plain text as the LLM generates it. Once complete, the server parses the structured JSON response and replaces the raw output with clean analysis text. A \"Show raw response\" toggle is available for debugging.",[401,1466,1468],{"id":1467},"how-skills-become-system-prompts","How Skills Become System Prompts",[302,1470,1471,1472,1475],{},"The reviewer prompts are loaded at runtime from markdown files on disk — not hardcoded in the server code. A utility function strips the YAML frontmatter and passes the body as the ",[745,1473,1474],{},"system"," parameter to the Anthropic SDK:",[1119,1477,1481],{"className":1478,"code":1479,"language":1480,"meta":515,"style":515},"language-typescript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u002F\u002F server\u002Futils\u002Fai\u002Floan-review-utils.ts\nconst systemPrompt = loadApproverPrompt(reviewer);\n\nconst streamResponse = client.messages.stream({\n  model: config.public.model,\n  max_tokens: 4096,\n  system: systemPrompt,\n  messages: [{ role: 'user', content: formattedApplication }],\n});\n","typescript",[745,1482,1483,1489,1513,1518,1546,1571,1584,1597,1645],{"__ignoreMap":515},[1127,1484,1485],{"class":1129,"line":1130},[1127,1486,1488],{"class":1487},"sHwdD","\u002F\u002F server\u002Futils\u002Fai\u002Floan-review-utils.ts\n",[1127,1490,1491,1495,1499,1503,1507,1510],{"class":1129,"line":516},[1127,1492,1494],{"class":1493},"spNyl","const",[1127,1496,1498],{"class":1497},"sTEyZ"," systemPrompt ",[1127,1500,1502],{"class":1501},"sMK4o","=",[1127,1504,1506],{"class":1505},"s2Zo4"," loadApproverPrompt",[1127,1508,1509],{"class":1497},"(reviewer)",[1127,1511,1512],{"class":1501},";\n",[1127,1514,1515],{"class":1129,"line":523},[1127,1516,1517],{"emptyLinePlaceholder":538},"\n",[1127,1519,1520,1522,1525,1527,1530,1532,1535,1537,1540,1543],{"class":1129,"line":1146},[1127,1521,1494],{"class":1493},[1127,1523,1524],{"class":1497}," streamResponse ",[1127,1526,1502],{"class":1501},[1127,1528,1529],{"class":1497}," client",[1127,1531,1207],{"class":1501},[1127,1533,1534],{"class":1497},"messages",[1127,1536,1207],{"class":1501},[1127,1538,1539],{"class":1505},"stream",[1127,1541,1542],{"class":1497},"(",[1127,1544,1545],{"class":1501},"{\n",[1127,1547,1548,1552,1555,1558,1560,1563,1565,1568],{"class":1129,"line":1382},[1127,1549,1551],{"class":1550},"swJcz","  model",[1127,1553,1554],{"class":1501},":",[1127,1556,1557],{"class":1497}," config",[1127,1559,1207],{"class":1501},[1127,1561,1562],{"class":1497},"public",[1127,1564,1207],{"class":1501},[1127,1566,1567],{"class":1497},"model",[1127,1569,1570],{"class":1501},",\n",[1127,1572,1573,1576,1578,1582],{"class":1129,"line":1388},[1127,1574,1575],{"class":1550},"  max_tokens",[1127,1577,1554],{"class":1501},[1127,1579,1581],{"class":1580},"sbssI"," 4096",[1127,1583,1570],{"class":1501},[1127,1585,1587,1590,1592,1595],{"class":1129,"line":1586},7,[1127,1588,1589],{"class":1550},"  system",[1127,1591,1554],{"class":1501},[1127,1593,1594],{"class":1497}," systemPrompt",[1127,1596,1570],{"class":1501},[1127,1598,1600,1603,1605,1608,1611,1614,1616,1619,1623,1626,1629,1632,1634,1637,1640,1643],{"class":1129,"line":1599},8,[1127,1601,1602],{"class":1550},"  messages",[1127,1604,1554],{"class":1501},[1127,1606,1607],{"class":1497}," [",[1127,1609,1610],{"class":1501},"{",[1127,1612,1613],{"class":1550}," role",[1127,1615,1554],{"class":1501},[1127,1617,1618],{"class":1501}," '",[1127,1620,1622],{"class":1621},"sfazB","user",[1127,1624,1625],{"class":1501},"'",[1127,1627,1628],{"class":1501},",",[1127,1630,1631],{"class":1550}," content",[1127,1633,1554],{"class":1501},[1127,1635,1636],{"class":1497}," formattedApplication ",[1127,1638,1639],{"class":1501},"}",[1127,1641,1642],{"class":1497},"]",[1127,1644,1570],{"class":1501},[1127,1646,1648,1650,1653],{"class":1129,"line":1647},9,[1127,1649,1639],{"class":1501},[1127,1651,1652],{"class":1497},")",[1127,1654,1512],{"class":1501},[302,1656,1657],{},"Each reviewer gets the same formatted application data as the user message. The skill file controls their perspective — the bank is conservative, the market analyst cares about deal structure, the fraud investigator is deeply skeptical.",[302,1659,1660],{},"This means you can tweak a reviewer's personality or evaluation criteria by editing a markdown file. No code changes, no redeployment.",[318,1662,1664],{"id":1663},"what-this-demonstrates","What This Demonstrates",[851,1666,1667,1673,1679,1685,1691],{},[371,1668,1669,1672],{},[326,1670,1671],{},"Multi-agent orchestration"," — Multiple specialized AI agents working on the same input independently",[371,1674,1675,1678],{},[326,1676,1677],{},"Human-in-the-loop"," — AI as advisor, not decision-maker",[371,1680,1681,1684],{},[326,1682,1683],{},"Real-time streaming"," — SSE for progressive UI updates during AI processing",[371,1686,1687,1690],{},[326,1688,1689],{},"Conversational data collection"," — Chat-based intake instead of traditional forms",[371,1692,1693,1696],{},[326,1694,1695],{},"Tool use"," — AI extracts structured data from natural language via function calling",[1698,1699,1700],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}",{"title":515,"searchDepth":516,"depth":516,"links":1702},[1703,1704,1711,1717],{"id":1106,"depth":516,"text":1107},{"id":1116,"depth":516,"text":1117,"children":1705},[1706,1707,1708,1709,1710],{"id":1152,"depth":523,"text":1153},{"id":1168,"depth":523,"text":1169},{"id":1271,"depth":523,"text":1272},{"id":1296,"depth":523,"text":1297},{"id":1309,"depth":523,"text":1310},{"id":1316,"depth":516,"text":1089,"children":1712},[1713,1714,1715,1716],{"id":1319,"depth":523,"text":1320},{"id":1354,"depth":523,"text":1355},{"id":1421,"depth":523,"text":1422},{"id":1467,"depth":523,"text":1468},{"id":1663,"depth":516,"text":1664},"2026-02-25","A demo of multi-agent AI orchestration where three specialized reviewers analyze loan applications independently, stream results in real-time via SSE, and a human makes the final call.",{"src":1721,"alt":1722},"\u002Fimages\u002Fblog\u002F20260225-1430-multi-agent-loan-approval-human-in-the-loop.jpeg","Multi-agent loan approval workflow with AI reviewers and human decision",{},{"title":185,"description":1719},"umDB2-Cy7rQMMzRJaPtxuXZAq79byrLSIhtNQzl9gyQ",{"id":1727,"title":181,"authors":1728,"badge":1731,"body":1733,"date":3167,"description":3168,"extension":533,"image":3169,"meta":3172,"navigation":538,"path":182,"seo":3173,"status":540,"stem":183,"__hash__":3174},"posts\u002F2.blog\u002F20260221.claude-code-skills-guide.md",[1729],{"name":292,"to":293,"avatar":1730},{"src":295},{"label":1732},"AI Tools",{"type":299,"value":1734,"toc":3131},[1735,1738,1745,1753,1764,1768,1775,1782,1786,1789,1807,1818,1832,1836,1839,1842,1848,1852,1859,1987,2001,2007,2013,2016,2020,2023,2031,2034,2079,2083,2089,2173,2180,2184,2190,2196,2200,2225,2229,2235,2363,2368,2393,2397,2400,2640,2644,2647,2741,2744,2748,2751,2755,2758,2764,2768,2771,2776,2780,2787,2792,2796,2799,2831,2834,2838,2849,2852,2872,2876,2896,2900,2903,2923,2927,2936,2945,2954,2958,2986,2990,2999,3003,3006,3012,3029,3042,3048,3057,3066,3070,3073,3099,3103,3117,3123,3128],[302,1736,1737],{},"LLMs are impressive generalists. Ask Claude how to deploy a service and you'll get a solid, textbook answer — run tests, build artifacts, deploy, monitor. All correct. All useless if your team deploys by running integration tests against staging, getting sign-off from the on-call engineer, and canarying at 10% traffic for 30 minutes before full rollout.",[302,1739,1740,1741,1744],{},"The gap isn't intelligence. It's ",[920,1742,1743],{},"your"," knowledge. The conventions, processes, and hard-won lessons that exist in your team's heads and nowhere else.",[302,1746,1747,1748,1752],{},"That's exactly what ",[335,1749,742],{"href":1750,"rel":1751},"https:\u002F\u002Fwww.anthropic.com\u002Fnews\u002Fskills",[461]," solve.",[330,1754,1755],{},[302,1756,1757,1758,1763],{},"If you want the deep dive, Anthropic published a 32-page guide: ",[335,1759,1762],{"href":1760,"rel":1761},"https:\u002F\u002Fresources.anthropic.com\u002Fhubfs\u002FThe-Complete-Guide-to-Building-Skill-for-Claude.pdf",[461],"The Complete Guide to Building Skills for Claude (PDF)",". It covers everything from architecture to distribution. This post distills the key concepts and adds a hands-on demo, but the official guide is worth reading cover to cover.",[318,1765,1767],{"id":1766},"what-are-skills","What Are Skills?",[302,1769,1770,1771,1774],{},"A skill is a folder with a markdown file (",[745,1772,1773],{},"SKILL.md",") that tells Claude how to do something specific. That's it. Optionally, you add scripts, templates, or reference docs alongside it. When Claude encounters a task that matches a skill's description, it loads the instructions and follows your playbook instead of improvising.",[302,1776,1777,1778,1781],{},"Think of it like writing an onboarding guide for a new hire. You don't teach them \"what programming is\" — they already know that. You teach them ",[920,1779,1780],{},"how your team does things",": the deploy checklist, the PR review process, the naming conventions that aren't written down anywhere.",[401,1783,1785],{"id":1784},"skills-vs-claudemd-vs-mcp","Skills vs CLAUDE.md vs MCP",[302,1787,1788],{},"These three pieces work together but serve different purposes:",[368,1790,1791,1796,1802],{},[371,1792,1793,1795],{},[326,1794,676],{}," is identity and broad context — \"this is a Nuxt 4 monorepo, here's our project structure, here are the commands\"",[371,1797,1798,1801],{},[326,1799,1800],{},"MCP"," is connectivity — giving Claude access to external tools and services",[371,1803,1804,1806],{},[326,1805,742],{}," are procedural knowledge — step-by-step instructions for specific tasks",[302,1808,1809,1810,1813,1814,1817],{},"The official guide nails the analogy: ",[326,1811,1812],{},"MCP gives Claude the professional kitchen"," — access to tools, ingredients, and equipment. ",[326,1815,1816],{},"Skills give it the recipes"," — step-by-step instructions for creating something valuable. You need both. A kitchen without recipes produces inconsistent results. Recipes without a kitchen are just theory.",[302,1819,1820,1821,1824,1825,1828,1829,1207],{},"CLAUDE.md tells Claude ",[920,1822,1823],{},"where it is",". MCP tells Claude ",[920,1826,1827],{},"what it can reach",". Skills tell Claude ",[920,1830,1831],{},"how to do the job your way",[318,1833,1835],{"id":1834},"try-it-before-and-after","Try It: Before and After",[302,1837,1838],{},"The best way to understand skills is to experience the difference. This interactive demo lets you write a skill with your own team's process and see how it changes Claude's response.",[1840,1841],"skill-demo",{},[302,1843,1844,1845,1847],{},"That's the entire concept. You encoded knowledge Claude didn't have, and now it responds with ",[920,1846,1743],{}," process instead of a generic one.",[318,1849,1851],{"id":1850},"progressive-disclosure-how-skills-stay-lean","Progressive Disclosure: How Skills Stay Lean",[302,1853,1854,1855,1858],{},"The biggest question with skills is context cost. If Claude loads every skill's full instructions at startup, you'd burn through the context window before writing a line of code. Anthropic's solution is what the guide calls ",[326,1856,1857],{},"progressive disclosure"," — a three-level loading system:",[1119,1860,1862],{"className":1121,"code":1861,"language":1123,"meta":515,"style":515},"flowchart TB\n    subgraph L1[\"Level 1 — Always Loaded\"]\n        direction LR\n        F1[\"name: deploy-checklist\"]\n        F2[\"description: Production deploy process...\"]\n    end\n\n    subgraph L2[\"Level 2 — Loaded on Match\"]\n        B[\"Full SKILL.md body\\nInstructions, examples, error handling\"]\n    end\n\n    subgraph L3[\"Level 3 — Loaded on Demand\"]\n        R1[\"references\u002Frunbook.md\"]\n        R2[\"scripts\u002Fcheck-env.sh\"]\n        R3[\"assets\u002Ftemplate.yaml\"]\n    end\n\n    L1 -->|\"Task matches\\ndescription\"| L2\n    L2 -->|\"Instructions reference\\nadditional files\"| L3\n\n    style L1 fill:#0c4a6e,stroke:#38bdf8,color:#e0f2fe\n    style L2 fill:#1e3a5f,stroke:#38bdf8,color:#e0f2fe\n    style L3 fill:#27272a,stroke:#52525b,color:#a1a1aa\n",[745,1863,1864,1869,1874,1879,1884,1889,1894,1898,1903,1908,1913,1918,1924,1930,1936,1942,1947,1952,1958,1964,1969,1975,1981],{"__ignoreMap":515},[1127,1865,1866],{"class":1129,"line":1130},[1127,1867,1868],{},"flowchart TB\n",[1127,1870,1871],{"class":1129,"line":516},[1127,1872,1873],{},"    subgraph L1[\"Level 1 — Always Loaded\"]\n",[1127,1875,1876],{"class":1129,"line":523},[1127,1877,1878],{},"        direction LR\n",[1127,1880,1881],{"class":1129,"line":1146},[1127,1882,1883],{},"        F1[\"name: deploy-checklist\"]\n",[1127,1885,1886],{"class":1129,"line":1382},[1127,1887,1888],{},"        F2[\"description: Production deploy process...\"]\n",[1127,1890,1891],{"class":1129,"line":1388},[1127,1892,1893],{},"    end\n",[1127,1895,1896],{"class":1129,"line":1586},[1127,1897,1517],{"emptyLinePlaceholder":538},[1127,1899,1900],{"class":1129,"line":1599},[1127,1901,1902],{},"    subgraph L2[\"Level 2 — Loaded on Match\"]\n",[1127,1904,1905],{"class":1129,"line":1647},[1127,1906,1907],{},"        B[\"Full SKILL.md body\\nInstructions, examples, error handling\"]\n",[1127,1909,1911],{"class":1129,"line":1910},10,[1127,1912,1893],{},[1127,1914,1916],{"class":1129,"line":1915},11,[1127,1917,1517],{"emptyLinePlaceholder":538},[1127,1919,1921],{"class":1129,"line":1920},12,[1127,1922,1923],{},"    subgraph L3[\"Level 3 — Loaded on Demand\"]\n",[1127,1925,1927],{"class":1129,"line":1926},13,[1127,1928,1929],{},"        R1[\"references\u002Frunbook.md\"]\n",[1127,1931,1933],{"class":1129,"line":1932},14,[1127,1934,1935],{},"        R2[\"scripts\u002Fcheck-env.sh\"]\n",[1127,1937,1939],{"class":1129,"line":1938},15,[1127,1940,1941],{},"        R3[\"assets\u002Ftemplate.yaml\"]\n",[1127,1943,1945],{"class":1129,"line":1944},16,[1127,1946,1893],{},[1127,1948,1950],{"class":1129,"line":1949},17,[1127,1951,1517],{"emptyLinePlaceholder":538},[1127,1953,1955],{"class":1129,"line":1954},18,[1127,1956,1957],{},"    L1 -->|\"Task matches\\ndescription\"| L2\n",[1127,1959,1961],{"class":1129,"line":1960},19,[1127,1962,1963],{},"    L2 -->|\"Instructions reference\\nadditional files\"| L3\n",[1127,1965,1967],{"class":1129,"line":1966},20,[1127,1968,1517],{"emptyLinePlaceholder":538},[1127,1970,1972],{"class":1129,"line":1971},21,[1127,1973,1974],{},"    style L1 fill:#0c4a6e,stroke:#38bdf8,color:#e0f2fe\n",[1127,1976,1978],{"class":1129,"line":1977},22,[1127,1979,1980],{},"    style L2 fill:#1e3a5f,stroke:#38bdf8,color:#e0f2fe\n",[1127,1982,1984],{"class":1129,"line":1983},23,[1127,1985,1986],{},"    style L3 fill:#27272a,stroke:#52525b,color:#a1a1aa\n",[302,1988,1989,1992,1993,1996,1997,2000],{},[326,1990,1991],{},"Level 1: Frontmatter only."," At startup, Claude loads just the ",[745,1994,1995],{},"name"," and ",[745,1998,1999],{},"description"," from every installed skill's YAML frontmatter. This costs roughly 50-100 tokens per skill — cheap enough to have dozens of skills available without impacting performance.",[302,2002,2003,2006],{},[326,2004,2005],{},"Level 2: Full SKILL.md."," When Claude determines a skill matches the current task, it reads the complete SKILL.md body into context — instructions, examples, error handling, all of it.",[302,2008,2009,2012],{},[326,2010,2011],{},"Level 3: Referenced files."," For complex skills, additional files in the skill directory — reference docs, API patterns, templates — are only loaded when the SKILL.md instructions explicitly reference them.",[302,2014,2015],{},"The guide reports that for complex project creation, this system reduced clarification questions from 15 to 2 and cut token consumption from 12,000 to 6,000. That's the difference between a skill that front-loads everything and one that progressively discloses only what's needed.",[401,2017,2019],{"id":2018},"discovery-locations","Discovery Locations",[302,2021,2022],{},"When Claude Code starts, it scans for skills in multiple locations:",[1119,2024,2029],{"className":2025,"code":2027,"language":2028},[2026],"language-text","~\u002F.claude\u002Fskills\u002F          ← your global skills (personal workflows)\n.claude\u002Fskills\u002F            ← project skills (team workflows, checked into git)\nplugins                    ← plugin-provided skills (from the marketplace)\n","text",[745,2030,2027],{"__ignoreMap":515},[302,2032,2033],{},"A few details worth knowing:",[368,2035,2036,2046,2060,2070],{},[371,2037,2038,2041,2042,2045],{},[326,2039,2040],{},"Context budget",": skill descriptions share 2% of the context window (fallback of 16k characters). Run ",[745,2043,2044],{},"\u002Fcontext"," in Claude Code to check if any skills got excluded.",[371,2047,2048,2051,2052,2055,2056,2059],{},[326,2049,2050],{},"Monorepo support",": if you're working in ",[745,2053,2054],{},"packages\u002Ffrontend\u002F",", Claude also discovers skills from ",[745,2057,2058],{},"packages\u002Ffrontend\u002F.claude\u002Fskills\u002F",". Each package can have its own skills.",[371,2061,2062,2065,2066,2069],{},[326,2063,2064],{},"Live reload",": skills in directories added via ",[745,2067,2068],{},"--add-dir"," are watched for changes. Edit a skill mid-session, and Claude picks it up without restarting.",[371,2071,2072,2075,2076,1207],{},[326,2073,2074],{},"Invocation",": Claude auto-matches skills to tasks, but you can also invoke them explicitly with ",[745,2077,2078],{},"\u002Fskill-name",[401,2080,2082],{"id":2081},"what-happens-when-a-skill-triggers","What Happens When a Skill Triggers",[302,2084,2085,2086,2088],{},"When Claude decides a skill is relevant (or you invoke one with ",[745,2087,2078],{},"), the execution flow maps directly to the progressive disclosure levels:",[1119,2090,2092],{"className":1121,"code":2091,"language":1123,"meta":515,"style":515},"sequenceDiagram\n    participant U as You\n    participant C as Claude Code\n    participant FS as File System\n\n    U->>C: \"Deploy this to production\"\n    Note over C: Level 1: Check loaded descriptions\n    C->>C: Match task → deploy-checklist\n    Note over C: Level 2: Load full instructions\n    C->>FS: Read deploy-checklist\u002FSKILL.md\n    FS-->>C: Instructions + frontmatter\n    C->>C: Expand instructions into context\n    Note over C: Level 3: Load referenced files\n    C->>FS: Read scripts\u002Fcheck-env.sh\n    FS-->>C: Validation script\n    C->>U: Response follows YOUR process\n",[745,2093,2094,2099,2104,2109,2114,2118,2123,2128,2133,2138,2143,2148,2153,2158,2163,2168],{"__ignoreMap":515},[1127,2095,2096],{"class":1129,"line":1130},[1127,2097,2098],{},"sequenceDiagram\n",[1127,2100,2101],{"class":1129,"line":516},[1127,2102,2103],{},"    participant U as You\n",[1127,2105,2106],{"class":1129,"line":523},[1127,2107,2108],{},"    participant C as Claude Code\n",[1127,2110,2111],{"class":1129,"line":1146},[1127,2112,2113],{},"    participant FS as File System\n",[1127,2115,2116],{"class":1129,"line":1382},[1127,2117,1517],{"emptyLinePlaceholder":538},[1127,2119,2120],{"class":1129,"line":1388},[1127,2121,2122],{},"    U->>C: \"Deploy this to production\"\n",[1127,2124,2125],{"class":1129,"line":1586},[1127,2126,2127],{},"    Note over C: Level 1: Check loaded descriptions\n",[1127,2129,2130],{"class":1129,"line":1599},[1127,2131,2132],{},"    C->>C: Match task → deploy-checklist\n",[1127,2134,2135],{"class":1129,"line":1647},[1127,2136,2137],{},"    Note over C: Level 2: Load full instructions\n",[1127,2139,2140],{"class":1129,"line":1910},[1127,2141,2142],{},"    C->>FS: Read deploy-checklist\u002FSKILL.md\n",[1127,2144,2145],{"class":1129,"line":1915},[1127,2146,2147],{},"    FS-->>C: Instructions + frontmatter\n",[1127,2149,2150],{"class":1129,"line":1920},[1127,2151,2152],{},"    C->>C: Expand instructions into context\n",[1127,2154,2155],{"class":1129,"line":1926},[1127,2156,2157],{},"    Note over C: Level 3: Load referenced files\n",[1127,2159,2160],{"class":1129,"line":1932},[1127,2161,2162],{},"    C->>FS: Read scripts\u002Fcheck-env.sh\n",[1127,2164,2165],{"class":1129,"line":1938},[1127,2166,2167],{},"    FS-->>C: Validation script\n",[1127,2169,2170],{"class":1129,"line":1944},[1127,2171,2172],{},"    C->>U: Response follows YOUR process\n",[302,2174,2175,2176,2179],{},"This is fundamentally different from tools. A tool executes and returns results. A skill ",[920,2177,2178],{},"prepares"," Claude to solve the problem using your approach. The instructions become part of Claude's working context, shaping how it thinks about the task.",[318,2181,2183],{"id":2182},"anatomy-of-a-skill","Anatomy of a Skill",[302,2185,2186,2187,1554],{},"Every skill lives in its own directory under ",[745,2188,2189],{},".claude\u002Fskills\u002F",[1119,2191,2194],{"className":2192,"code":2193,"language":2028},[2026],".claude\u002Fskills\u002F\n└── deploy-checklist\u002F\n    ├── SKILL.md              ← required: instructions\n    ├── scripts\u002F\n    │   └── check-env.sh      ← optional: executable scripts\n    └── references\u002F\n        └── runbook.md        ← optional: detailed docs\n",[745,2195,2193],{"__ignoreMap":515},[401,2197,2199],{"id":2198},"folder-and-naming-rules","Folder and Naming Rules",[368,2201,2202,2216,2219],{},[371,2203,2204,2205,2208,2209,2212,2213,1652],{},"Folder names must be ",[326,2206,2207],{},"kebab-case"," (",[745,2210,2211],{},"deploy-checklist",", not ",[745,2214,2215],{},"DeployChecklist",[371,2217,2218],{},"No spaces, capitals, or underscores",[371,2220,2221,2222,2224],{},"The ",[745,2223,1995],{}," field in frontmatter should match the folder name",[401,2226,2228],{"id":2227},"skillmd-frontmatter","SKILL.md Frontmatter",[302,2230,2231,2232,2234],{},"The YAML block at the top of ",[745,2233,1773],{}," is what Claude reads at Level 1. There are two required fields and several optional ones:",[1119,2236,2240],{"className":2237,"code":2238,"language":2239,"meta":515,"style":515},"language-yaml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","---\n# Required\nname: deploy-checklist\ndescription: >\n  Production deployment process and pre-deploy verification.\n  Use when deploying services, releasing to production, or\n  running pre-deploy checks. Trigger on \"deploy\", \"release\",\n  \"ship it\".\n\n# Optional\nlicense: MIT\ncompatibility: claude-code\nmetadata:\n  author: your-team\n  version: 1.0.0\n  mcp-server: deployment-tools\n---\n","yaml",[745,2241,2242,2248,2253,2262,2272,2277,2282,2287,2292,2296,2301,2311,2321,2329,2339,2349,2359],{"__ignoreMap":515},[1127,2243,2244],{"class":1129,"line":1130},[1127,2245,2247],{"class":2246},"sBMFI","---\n",[1127,2249,2250],{"class":1129,"line":516},[1127,2251,2252],{"class":1487},"# Required\n",[1127,2254,2255,2257,2259],{"class":1129,"line":523},[1127,2256,1995],{"class":1550},[1127,2258,1554],{"class":1501},[1127,2260,2261],{"class":1621}," deploy-checklist\n",[1127,2263,2264,2266,2268],{"class":1129,"line":1146},[1127,2265,1999],{"class":1550},[1127,2267,1554],{"class":1501},[1127,2269,2271],{"class":2270},"s7zQu"," >\n",[1127,2273,2274],{"class":1129,"line":1382},[1127,2275,2276],{"class":1621},"  Production deployment process and pre-deploy verification.\n",[1127,2278,2279],{"class":1129,"line":1388},[1127,2280,2281],{"class":1621},"  Use when deploying services, releasing to production, or\n",[1127,2283,2284],{"class":1129,"line":1586},[1127,2285,2286],{"class":1621},"  running pre-deploy checks. Trigger on \"deploy\", \"release\",\n",[1127,2288,2289],{"class":1129,"line":1599},[1127,2290,2291],{"class":1621},"  \"ship it\".\n",[1127,2293,2294],{"class":1129,"line":1647},[1127,2295,1517],{"emptyLinePlaceholder":538},[1127,2297,2298],{"class":1129,"line":1910},[1127,2299,2300],{"class":1487},"# Optional\n",[1127,2302,2303,2306,2308],{"class":1129,"line":1915},[1127,2304,2305],{"class":1550},"license",[1127,2307,1554],{"class":1501},[1127,2309,2310],{"class":1621}," MIT\n",[1127,2312,2313,2316,2318],{"class":1129,"line":1920},[1127,2314,2315],{"class":1550},"compatibility",[1127,2317,1554],{"class":1501},[1127,2319,2320],{"class":1621}," claude-code\n",[1127,2322,2323,2326],{"class":1129,"line":1926},[1127,2324,2325],{"class":1550},"metadata",[1127,2327,2328],{"class":1501},":\n",[1127,2330,2331,2334,2336],{"class":1129,"line":1932},[1127,2332,2333],{"class":1550},"  author",[1127,2335,1554],{"class":1501},[1127,2337,2338],{"class":1621}," your-team\n",[1127,2340,2341,2344,2346],{"class":1129,"line":1938},[1127,2342,2343],{"class":1550},"  version",[1127,2345,1554],{"class":1501},[1127,2347,2348],{"class":1580}," 1.0.0\n",[1127,2350,2351,2354,2356],{"class":1129,"line":1944},[1127,2352,2353],{"class":1550},"  mcp-server",[1127,2355,1554],{"class":1501},[1127,2357,2358],{"class":1621}," deployment-tools\n",[1127,2360,2361],{"class":1129,"line":1949},[1127,2362,2247],{"class":2246},[302,2364,2221,2365,2367],{},[745,2366,1999],{}," field is the most important thing you'll write. It's the Level 1 content — what Claude reads to decide whether this skill is relevant. Be specific about what the skill does AND when it should trigger. Include the phrases users would actually say.",[302,2369,2370,2373,2374,2377,2378,2381,2382,2384,2385,2388,2389,2392],{},[326,2371,2372],{},"Security note",": XML angle brackets (",[745,2375,2376],{},"\u003C"," ",[745,2379,2380],{},">",") are forbidden in frontmatter. The ",[745,2383,1995],{}," field can't start with ",[745,2386,2387],{},"claude"," or ",[745,2390,2391],{},"anthropic"," (reserved).",[401,2394,2396],{"id":2395},"a-complete-example","A Complete Example",[302,2398,2399],{},"Here's a deploy-checklist skill:",[1119,2401,2403],{"className":2237,"code":2402,"language":2239,"meta":515,"style":515},"---\nname: deploy-checklist\ndescription: Production deployment process and pre-deploy verification.\n  Use when deploying services, releasing to production, or running\n  pre-deploy checks. Trigger on \"deploy\", \"release\", \"ship it\".\n---\n\n# Production Deploy Checklist\n\n## Pre-deploy Verification\n\n1. Run the full integration suite:\n   ```bash\n   pnpm test:integration\n   ```\n2. Confirm staging smoke tests passed in CI\n3. Verify the on-call engineer is available in #ops\n\n## Deploy Process\n\n1. Deploy to canary (10% traffic):\n   ```bash\n   pnpm deploy:canary\n   ```\n2. Monitor error rates in Datadog for 30 minutes\n3. If error rate \u003C 0.1%, proceed to full rollout:\n   ```bash\n   pnpm deploy:full\n   ```\n4. Post deploy confirmation in #releases\n\n## Rollback\n\nIf error rate exceeds 0.5% at any stage:\n\n```bash\npnpm deploy:rollback\n```\n\nNotify #ops immediately.\n",[745,2404,2405,2409,2417,2426,2431,2436,2440,2444,2449,2453,2458,2462,2469,2477,2482,2487,2492,2500,2504,2509,2513,2520,2526,2531,2536,2542,2550,2557,2563,2568,2577,2582,2588,2593,2601,2606,2614,2620,2626,2631],{"__ignoreMap":515},[1127,2406,2407],{"class":1129,"line":1130},[1127,2408,2247],{"class":2246},[1127,2410,2411,2413,2415],{"class":1129,"line":516},[1127,2412,1995],{"class":1550},[1127,2414,1554],{"class":1501},[1127,2416,2261],{"class":1621},[1127,2418,2419,2421,2423],{"class":1129,"line":523},[1127,2420,1999],{"class":1550},[1127,2422,1554],{"class":1501},[1127,2424,2425],{"class":1621}," Production deployment process and pre-deploy verification.\n",[1127,2427,2428],{"class":1129,"line":1146},[1127,2429,2430],{"class":1621},"  Use when deploying services, releasing to production, or running\n",[1127,2432,2433],{"class":1129,"line":1382},[1127,2434,2435],{"class":1621},"  pre-deploy checks. Trigger on \"deploy\", \"release\", \"ship it\".\n",[1127,2437,2438],{"class":1129,"line":1388},[1127,2439,2247],{"class":2246},[1127,2441,2442],{"class":1129,"line":1586},[1127,2443,1517],{"emptyLinePlaceholder":538},[1127,2445,2446],{"class":1129,"line":1599},[1127,2447,2448],{"class":1487},"# Production Deploy Checklist\n",[1127,2450,2451],{"class":1129,"line":1647},[1127,2452,1517],{"emptyLinePlaceholder":538},[1127,2454,2455],{"class":1129,"line":1910},[1127,2456,2457],{"class":1487},"## Pre-deploy Verification\n",[1127,2459,2460],{"class":1129,"line":1915},[1127,2461,1517],{"emptyLinePlaceholder":538},[1127,2463,2464,2467],{"class":1129,"line":1920},[1127,2465,2466],{"class":1550},"1. Run the full integration suite",[1127,2468,2328],{"class":1501},[1127,2470,2471,2474],{"class":1129,"line":1926},[1127,2472,2473],{"class":1497},"   ```",[1127,2475,2476],{"class":1621},"bash\n",[1127,2478,2479],{"class":1129,"line":1932},[1127,2480,2481],{"class":1621},"   pnpm test:integration\n",[1127,2483,2484],{"class":1129,"line":1938},[1127,2485,2486],{"class":1497},"   ```\n",[1127,2488,2489],{"class":1129,"line":1944},[1127,2490,2491],{"class":1621},"2. Confirm staging smoke tests passed in CI\n",[1127,2493,2494,2497],{"class":1129,"line":1949},[1127,2495,2496],{"class":1621},"3. Verify the on-call engineer is available in",[1127,2498,2499],{"class":1487}," #ops\n",[1127,2501,2502],{"class":1129,"line":1954},[1127,2503,1517],{"emptyLinePlaceholder":538},[1127,2505,2506],{"class":1129,"line":1960},[1127,2507,2508],{"class":1487},"## Deploy Process\n",[1127,2510,2511],{"class":1129,"line":1966},[1127,2512,1517],{"emptyLinePlaceholder":538},[1127,2514,2515,2518],{"class":1129,"line":1971},[1127,2516,2517],{"class":1550},"1. Deploy to canary (10% traffic)",[1127,2519,2328],{"class":1501},[1127,2521,2522,2524],{"class":1129,"line":1977},[1127,2523,2473],{"class":1497},[1127,2525,2476],{"class":1621},[1127,2527,2528],{"class":1129,"line":1983},[1127,2529,2530],{"class":1621},"   pnpm deploy:canary\n",[1127,2532,2534],{"class":1129,"line":2533},24,[1127,2535,2486],{"class":1497},[1127,2537,2539],{"class":1129,"line":2538},25,[1127,2540,2541],{"class":1621},"2. Monitor error rates in Datadog for 30 minutes\n",[1127,2543,2545,2548],{"class":1129,"line":2544},26,[1127,2546,2547],{"class":1550},"3. If error rate \u003C 0.1%, proceed to full rollout",[1127,2549,2328],{"class":1501},[1127,2551,2553,2555],{"class":1129,"line":2552},27,[1127,2554,2473],{"class":1497},[1127,2556,2476],{"class":1621},[1127,2558,2560],{"class":1129,"line":2559},28,[1127,2561,2562],{"class":1621},"   pnpm deploy:full\n",[1127,2564,2566],{"class":1129,"line":2565},29,[1127,2567,2486],{"class":1497},[1127,2569,2571,2574],{"class":1129,"line":2570},30,[1127,2572,2573],{"class":1621},"4. Post deploy confirmation in",[1127,2575,2576],{"class":1487}," #releases\n",[1127,2578,2580],{"class":1129,"line":2579},31,[1127,2581,1517],{"emptyLinePlaceholder":538},[1127,2583,2585],{"class":1129,"line":2584},32,[1127,2586,2587],{"class":1487},"## Rollback\n",[1127,2589,2591],{"class":1129,"line":2590},33,[1127,2592,1517],{"emptyLinePlaceholder":538},[1127,2594,2596,2599],{"class":1129,"line":2595},34,[1127,2597,2598],{"class":1550},"If error rate exceeds 0.5% at any stage",[1127,2600,2328],{"class":1501},[1127,2602,2604],{"class":1129,"line":2603},35,[1127,2605,1517],{"emptyLinePlaceholder":538},[1127,2607,2609,2612],{"class":1129,"line":2608},36,[1127,2610,2611],{"class":1497},"```",[1127,2613,2476],{"class":1621},[1127,2615,2617],{"class":1129,"line":2616},37,[1127,2618,2619],{"class":1621},"pnpm deploy:rollback\n",[1127,2621,2623],{"class":1129,"line":2622},38,[1127,2624,2625],{"class":1497},"```\n",[1127,2627,2629],{"class":1129,"line":2628},39,[1127,2630,1517],{"emptyLinePlaceholder":538},[1127,2632,2634,2637],{"class":1129,"line":2633},40,[1127,2635,2636],{"class":1621},"Notify",[1127,2638,2639],{"class":1487}," #ops immediately.\n",[401,2641,2643],{"id":2642},"a-minimal-skill","A Minimal Skill",[302,2645,2646],{},"Skills don't have to be complex. Here's a useful one in 8 lines:",[1119,2648,2650],{"className":2237,"code":2649,"language":2239,"meta":515,"style":515},"---\nname: pr-template\ndescription: Pull request creation with our team's template and conventions.\n  Use when creating PRs, opening pull requests, or preparing code for review.\n---\n\n# PR Conventions\n\n- Title format: `[JIRA-123] Brief description` (under 70 chars)\n- Always include a \"Test Plan\" section with manual verification steps\n- Tag the `platform` team for infra changes, `frontend` for UI changes\n- Screenshots required for any visual changes\n",[745,2651,2652,2656,2665,2674,2679,2683,2687,2692,2696,2720,2727,2734],{"__ignoreMap":515},[1127,2653,2654],{"class":1129,"line":1130},[1127,2655,2247],{"class":2246},[1127,2657,2658,2660,2662],{"class":1129,"line":516},[1127,2659,1995],{"class":1550},[1127,2661,1554],{"class":1501},[1127,2663,2664],{"class":1621}," pr-template\n",[1127,2666,2667,2669,2671],{"class":1129,"line":523},[1127,2668,1999],{"class":1550},[1127,2670,1554],{"class":1501},[1127,2672,2673],{"class":1621}," Pull request creation with our team's template and conventions.\n",[1127,2675,2676],{"class":1129,"line":1146},[1127,2677,2678],{"class":1621},"  Use when creating PRs, opening pull requests, or preparing code for review.\n",[1127,2680,2681],{"class":1129,"line":1382},[1127,2682,2247],{"class":2246},[1127,2684,2685],{"class":1129,"line":1388},[1127,2686,1517],{"emptyLinePlaceholder":538},[1127,2688,2689],{"class":1129,"line":1586},[1127,2690,2691],{"class":1487},"# PR Conventions\n",[1127,2693,2694],{"class":1129,"line":1599},[1127,2695,1517],{"emptyLinePlaceholder":538},[1127,2697,2698,2701,2704,2706,2709,2712,2715,2717],{"class":1129,"line":1647},[1127,2699,2700],{"class":1501},"-",[1127,2702,2703],{"class":1550}," Title format",[1127,2705,1554],{"class":1501},[1127,2707,2708],{"class":1497}," `",[1127,2710,2711],{"class":1501},"[",[1127,2713,2714],{"class":1621},"JIRA-123",[1127,2716,1642],{"class":1501},[1127,2718,2719],{"class":1621}," Brief description` (under 70 chars)\n",[1127,2721,2722,2724],{"class":1129,"line":1910},[1127,2723,2700],{"class":1501},[1127,2725,2726],{"class":1621}," Always include a \"Test Plan\" section with manual verification steps\n",[1127,2728,2729,2731],{"class":1129,"line":1915},[1127,2730,2700],{"class":1501},[1127,2732,2733],{"class":1621}," Tag the `platform` team for infra changes, `frontend` for UI changes\n",[1127,2735,2736,2738],{"class":1129,"line":1920},[1127,2737,2700],{"class":1501},[1127,2739,2740],{"class":1621}," Screenshots required for any visual changes\n",[302,2742,2743],{},"That's a complete, useful skill. No scripts, no templates, no references. Just the knowledge that makes your team's PRs consistent.",[318,2745,2747],{"id":2746},"three-patterns-for-skills","Three Patterns for Skills",[302,2749,2750],{},"The official guide identifies three primary patterns. Knowing which one you're building helps you scope it correctly.",[401,2752,2754],{"id":2753},"_1-document-asset-creation","1. Document & Asset Creation",[302,2756,2757],{},"Skills that produce consistent output — presentations, designs, reports, code scaffolds — following your exact standards. These work with Claude's built-in capabilities, no MCP required.",[302,2759,2760,2763],{},[326,2761,2762],{},"Example",": a skill that generates your team's architecture decision records (ADRs) with the right template, naming convention, and approval sections.",[401,2765,2767],{"id":2766},"_2-workflow-automation","2. Workflow Automation",[302,2769,2770],{},"Multi-step processes that need consistent methodology. These often coordinate several actions in sequence and may use MCP servers for external service access.",[302,2772,2773,2775],{},[326,2774,2762],{},": a sprint planning skill that fetches project status, analyzes velocity, suggests priorities, and creates tasks in your project management tool.",[401,2777,2779],{"id":2778},"_3-mcp-enhancement","3. MCP Enhancement",[302,2781,2782,2783,2786],{},"Layer expertise onto tool access. Your MCP server provides the connection to a service. The skill adds the ",[920,2784,2785],{},"how"," — the workflows, error handling, and domain knowledge your team has built over years.",[302,2788,2789,2791],{},[326,2790,2762],{},": you have an MCP server for your database. The skill adds knowledge about your team's migration conventions, naming standards, and rollback procedures.",[318,2793,2795],{"id":2794},"five-design-patterns","Five Design Patterns",[302,2797,2798],{},"Beyond the three use cases, the guide codifies recurring architectural patterns for skill internals:",[851,2800,2801,2807,2813,2819,2825],{},[371,2802,2803,2806],{},[326,2804,2805],{},"Sequential Workflow"," — Ordered multi-step processes (onboarding, deployment, compliance checks)",[371,2808,2809,2812],{},[326,2810,2811],{},"Multi-MCP Coordination"," — Workflows spanning multiple services (design handoff from Figma to Linear to Slack)",[371,2814,2815,2818],{},[326,2816,2817],{},"Iterative Refinement"," — Output that improves through validation loops (report generation with quality checks)",[371,2820,2821,2824],{},[326,2822,2823],{},"Context-Aware Selection"," — Same outcome, different tools based on file type, size, or context",[371,2826,2827,2830],{},[326,2828,2829],{},"Domain Intelligence"," — Embedded specialized knowledge beyond tool access (financial compliance rules, security protocols)",[302,2832,2833],{},"Most real skills combine 2-3 of these. A deploy-checklist is sequential workflow + domain intelligence. A design-handoff skill is multi-MCP coordination + iterative refinement.",[318,2835,2837],{"id":2836},"testing-your-skills","Testing Your Skills",[302,2839,2840,2841,2844,2845,2848],{},"The guide is emphatic about one thing: ",[326,2842,2843],{},"don't use vague instructions like \"double check your work.\""," Use programmatic validation instead. Include scripts in the ",[745,2846,2847],{},"scripts\u002F"," folder and tell Claude to run them.",[302,2850,2851],{},"Three levels of testing, depending on how critical the skill is:",[851,2853,2854,2860,2866],{},[371,2855,2856,2859],{},[326,2857,2858],{},"Manual testing in Claude.ai"," — Run queries and observe behavior. Fast iteration, no setup. Good for prototyping.",[371,2861,2862,2865],{},[326,2863,2864],{},"Scripted testing in Claude Code"," — Automate test cases for repeatable validation. Good for team skills that need to work consistently.",[371,2867,2868,2871],{},[326,2869,2870],{},"Programmatic testing via the Skills API"," — Build evaluation suites that run systematically against defined test sets. Good for skills you distribute externally.",[401,2873,2875],{"id":2874},"what-to-test","What to Test",[368,2877,2878,2884,2890],{},[371,2879,2880,2883],{},[326,2881,2882],{},"Triggering"," — does the skill load when it should? Does it stay quiet when it shouldn't?",[371,2885,2886,2889],{},[326,2887,2888],{},"Functional correctness"," — does it produce the right output?",[371,2891,2892,2895],{},[326,2893,2894],{},"Performance"," — is it measurably better than no skill?",[401,2897,2899],{"id":2898},"kpis-worth-tracking","KPIs Worth Tracking",[302,2901,2902],{},"The guide suggests three metrics:",[368,2904,2905,2911,2917],{},[371,2906,2907,2910],{},[326,2908,2909],{},"Skill Trigger Rate"," — target 90%+ accuracy on relevant queries. If your deploy skill only triggers 60% of the time when someone says \"ship it,\" your description needs work.",[371,2912,2913,2916],{},[326,2914,2915],{},"API Call Success Rate"," — target zero failed API calls per workflow. Especially relevant for MCP-enhanced skills.",[371,2918,2919,2922],{},[326,2920,2921],{},"Token Efficiency"," — measure context reduction vs. putting everything in CLAUDE.md. The whole point of progressive disclosure is using fewer tokens for the same quality.",[318,2924,2926],{"id":2925},"recommended-skills-to-get-started","Recommended Skills to Get Started",[302,2928,2929,2930,2935],{},"The ecosystem has grown fast since Anthropic ",[335,2931,2934],{"href":2932,"rel":2933},"https:\u002F\u002Fwww.anthropic.com\u002Fengineering\u002Fequipping-agents-for-the-real-world-with-agent-skills",[461],"open-sourced the Agent Skills standard"," in December 2025. Here are good starting points:",[401,2937,2939,2940],{"id":2938},"official-anthropicsskills","Official: ",[335,2941,2944],{"href":2942,"rel":2943},"https:\u002F\u002Fgithub.com\u002Fanthropics\u002Fskills",[461],"anthropics\u002Fskills",[302,2946,2947,2948,2953],{},"Anthropic's own repository has 50+ skills across categories like document processing, development tools, and data analysis. You can install them as plugins directly in Claude Code. The ",[335,2949,2952],{"href":2950,"rel":2951},"https:\u002F\u002Fgithub.com\u002Fanthropics\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fskill-creator\u002FSKILL.md",[461],"skill-creator"," skill is particularly useful — it's a skill for building skills. The guide estimates 15-30 minutes to build and test your first working skill using it.",[401,2955,2957],{"id":2956},"community","Community",[368,2959,2960,2976],{},[371,2961,2962,2969,2970,2975],{},[326,2963,2964],{},[335,2965,2968],{"href":2966,"rel":2967},"https:\u002F\u002Fgithub.com\u002Ftravisvn\u002Fawesome-claude-skills",[461],"travisvn\u002Fawesome-claude-skills"," — curated list including ",[335,2971,2974],{"href":2972,"rel":2973},"https:\u002F\u002Fgithub.com\u002Fobra\u002Fsuperpowers",[461],"obra\u002Fsuperpowers",", a collection of 20+ battle-tested skills for TDD, debugging, and collaboration patterns",[371,2977,2978,2985],{},[326,2979,2980],{},[335,2981,2984],{"href":2982,"rel":2983},"https:\u002F\u002Fskillsmp.com",[461],"skillsmp.com"," — marketplace with thousands of community-created skills",[401,2987,2989],{"id":2988},"cross-platform","Cross-Platform",[302,2991,2992,2993,2998],{},"The Agent Skills format is now an ",[335,2994,2997],{"href":2995,"rel":2996},"https:\u002F\u002Fagentskills.io",[461],"open standard",". The same SKILL.md files work across Claude Code, Claude.ai, the API, OpenAI's Codex CLI, VS Code, and Cursor. Write once, use everywhere.",[318,3000,3002],{"id":3001},"build-your-own","Build Your Own",[302,3004,3005],{},"The best skills encode knowledge that's unique to your team. Here's how to think about what to build:",[302,3007,3008,3011],{},[326,3009,3010],{},"Ask yourself",": what do you explain to every new team member? That's a skill.",[368,3013,3014,3017,3020,3023,3026],{},[371,3015,3016],{},"How you structure database migrations",[371,3018,3019],{},"Your team's error handling conventions",[371,3021,3022],{},"The process for incident response",[371,3024,3025],{},"How you name things (files, branches, variables)",[371,3027,3028],{},"Your code review checklist",[302,3030,3031,3034,3035,3037,3038,3041],{},[326,3032,3033],{},"Keep it focused",". One skill, one concern. A skill that tries to cover \"all of our engineering practices\" will be too large for the context window and too vague to be useful. A skill that covers \"how we write database migrations\" is perfect. The guide recommends keeping ",[745,3036,1773],{}," under 5,000 words — if you exceed that, offload detail to ",[745,3039,3040],{},"references\u002F"," or split into a \"skill pack.\"",[302,3043,3044,3047],{},[326,3045,3046],{},"Write descriptions that trigger correctly",". Include both what the skill does and the actual phrases users would say. \"Analyzes Figma designs and generates handoff docs. Use when uploading .fig files or asking for 'design specs' or 'component documentation'\" is much better than \"Figma design helper.\"",[302,3049,3050,3053,3054,3056],{},[326,3051,3052],{},"Use programmatic validation, not vibes",". Instead of telling Claude to \"verify the output looks correct,\" include a script in ",[745,3055,2847],{}," that actually checks it. Claude is good at running scripts. It's less good at judging its own work.",[302,3058,3059,3062,3063,3065],{},[326,3060,3061],{},"Move references out of SKILL.md",". Keep the main file focused on instructions. Detailed documentation, API specs, and schema definitions go in a ",[745,3064,3040],{}," subdirectory. Claude reads them only when needed (Level 3).",[401,3067,3069],{"id":3068},"common-pitfalls","Common Pitfalls",[302,3071,3072],{},"The guide calls out several mistakes worth avoiding:",[368,3074,3075,3081,3087,3093],{},[371,3076,3077,3080],{},[326,3078,3079],{},"Vague descriptions"," that never trigger or trigger on everything",[371,3082,3083,3086],{},[326,3084,3085],{},"Instructions buried in verbose content"," — Claude works better with concise, direct instructions",[371,3088,3089,3092],{},[326,3090,3091],{},"Missing error handling"," for MCP calls — always tell Claude what to do when an API call fails",[371,3094,3095,3098],{},[326,3096,3097],{},"Trying to do too much"," in one skill — split it into a skill pack instead",[318,3100,3102],{"id":3101},"whats-next","What's Next",[302,3104,3105,3106,3110,3111,3116],{},"Skills are still early but moving fast. The ",[335,3107,3109],{"href":1760,"rel":3108},[461],"official guide (PDF)"," and the ",[335,3112,3115],{"href":3113,"rel":3114},"https:\u002F\u002Fcode.claude.com\u002Fdocs\u002Fen\u002Fskills",[461],"Claude Code docs"," are the best sources of truth. But the core idea is durable: the most effective way to work with AI isn't better prompting, it's giving it the knowledge it needs upfront.",[302,3118,3119,3120,3122],{},"Your team's expertise shouldn't live only in people's heads. Write it down as a SKILL.md, drop it in ",[745,3121,2189],{},", and let Claude work the way your team works.",[302,3124,3125],{},[920,3126,3127],{},"What workflow will you teach Claude first?",[1698,3129,3130],{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}",{"title":515,"searchDepth":516,"depth":516,"links":3132},[3133,3136,3137,3141,3147,3152,3153,3157,3163,3166],{"id":1766,"depth":516,"text":1767,"children":3134},[3135],{"id":1784,"depth":523,"text":1785},{"id":1834,"depth":516,"text":1835},{"id":1850,"depth":516,"text":1851,"children":3138},[3139,3140],{"id":2018,"depth":523,"text":2019},{"id":2081,"depth":523,"text":2082},{"id":2182,"depth":516,"text":2183,"children":3142},[3143,3144,3145,3146],{"id":2198,"depth":523,"text":2199},{"id":2227,"depth":523,"text":2228},{"id":2395,"depth":523,"text":2396},{"id":2642,"depth":523,"text":2643},{"id":2746,"depth":516,"text":2747,"children":3148},[3149,3150,3151],{"id":2753,"depth":523,"text":2754},{"id":2766,"depth":523,"text":2767},{"id":2778,"depth":523,"text":2779},{"id":2794,"depth":516,"text":2795},{"id":2836,"depth":516,"text":2837,"children":3154},[3155,3156],{"id":2874,"depth":523,"text":2875},{"id":2898,"depth":523,"text":2899},{"id":2925,"depth":516,"text":2926,"children":3158},[3159,3161,3162],{"id":2938,"depth":523,"text":3160},"Official: anthropics\u002Fskills",{"id":2956,"depth":523,"text":2957},{"id":2988,"depth":523,"text":2989},{"id":3001,"depth":516,"text":3002,"children":3164},[3165],{"id":3068,"depth":523,"text":3069},{"id":3101,"depth":516,"text":3102},"2026-02-21","Skills are how you give Claude your team's specific knowledge — processes, conventions, and expertise that no foundation model ships with. Here's how they work, how discovery happens, and how to build your own.",{"src":3170,"alt":3171},"\u002Fimages\u002Fblog\u002Ftodo-place-holder-image.png","A developer dragging a SKILL.md file into a glowing folder structure",{},{"title":181,"description":3168},"1rJuPJEpxBNwdN4bYghxIRR4Mv-H2g0R1lva5mYoXwQ",{"id":3176,"title":177,"authors":3177,"badge":3180,"body":3182,"date":3358,"description":3359,"extension":533,"image":3360,"meta":3363,"navigation":538,"path":178,"seo":3364,"status":540,"stem":179,"__hash__":3365},"posts\u002F2.blog\u002F20260216.free-printable-telling-time-worksheet.md",[3178],{"name":292,"to":293,"avatar":3179},{"src":295},{"label":3181},"Kids",{"type":299,"value":3183,"toc":3353},[3184,3187,3191,3194,3240,3244,3247,3264,3271,3279,3285,3288,3291,3298,3302,3305,3340,3350],[302,3185,3186],{},"My kids are learning to read analog clocks — turns out \"the short hand is the hour\" needs more repetition than you'd think. So I made a two-sided reference and practice sheet they can keep on the fridge.",[318,3188,3190],{"id":3189},"clock-reference-front","Clock Reference (Front)",[302,3192,3193],{},"The front page is a complete clock reference:",[368,3195,3196,3202,3208],{},[371,3197,3198,3201],{},[326,3199,3200],{},"Big analog clock"," with labeled hour hand (red, short) and minute hand (blue, long)",[371,3203,3204,3207],{},[326,3205,3206],{},"Minute reference grid"," — each number on the clock mapped to minutes (1 = 5 min, 2 = 10 min, etc.)",[371,3209,3210,3213,3214],{},[326,3211,3212],{},"Four common times"," shown with both analog clock faces and digital equivalents:\n",[368,3215,3216,3222,3228,3234],{},[371,3217,3218,3221],{},[326,3219,3220],{},"O'Clock"," — minute hand on 12",[371,3223,3224,3227],{},[326,3225,3226],{},"Half Past"," — minute hand on 6",[371,3229,3230,3233],{},[326,3231,3232],{},"Quarter Past"," — minute hand on 3",[371,3235,3236,3239],{},[326,3237,3238],{},"Quarter To"," — minute hand on 9",[318,3241,3243],{"id":3242},"practice-clocks-back","Practice Clocks (Back)",[302,3245,3246],{},"The back page has 12 clocks set to different times for kids to read and write the answer:",[368,3248,3249,3252,3255,3258,3261],{},[371,3250,3251],{},"3 on the hour (easy)",[371,3253,3254],{},"3 at half past (medium)",[371,3256,3257],{},"3 at quarter past\u002Fto (medium)",[371,3259,3260],{},"3 at 5-minute increments (harder)",[371,3262,3263],{},"Answer key printed upside-down at the bottom",[3265,3266],"iframe",{"src":3267,"width":3268,"height":3269,"style":3270},"\u002Fdownloads\u002Fkids\u002Ftelling-time.pdf","100%",800,"border: 1px solid #444; border-radius: 8px;",[3272,3273],"u-button",{"color":3274,"icon":3275,"label":3276,"size":3277,"target":3278,"to":3267},"primary","i-lucide-download","Download Telling Time PDF","lg","\\_blank",[3272,3280],{"color":3281,"icon":3282,"label":3283,"size":3277,"target":3278,"to":3284,"variant":235},"neutral","i-lucide-code","View HTML Source","\u002Fdownloads\u002Fkids\u002Ftelling-time.html",[3286,3287],"hr",{},[302,3289,3290],{},"All the clock faces are drawn with SVG right in the HTML — no images, no dependencies. The hour hand is red and short, the minute hand is blue and long, so they're easy to tell apart even in black and white.",[302,3292,3293,3294,3297],{},"Want to change the practice times or add more clocks? Edit the ",[745,3295,3296],{},"practiceProblems"," array in the HTML and regenerate the PDF.",[318,3299,3301],{"id":3300},"how-the-pdf-is-made","How the PDF is made",[302,3303,3304],{},"Same as the other sheets — plain HTML rendered to PDF with headless Chrome:",[1119,3306,3310],{"className":3307,"code":3308,"language":3309,"meta":515,"style":515},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","google-chrome --headless=new --print-to-pdf=telling-time.pdf \\\n  --print-to-pdf-no-header --no-pdf-header-footer --disable-gpu telling-time.html\n","bash",[745,3311,3312,3326],{"__ignoreMap":515},[1127,3313,3314,3317,3320,3323],{"class":1129,"line":1130},[1127,3315,3316],{"class":2246},"google-chrome",[1127,3318,3319],{"class":1621}," --headless=new",[1127,3321,3322],{"class":1621}," --print-to-pdf=telling-time.pdf",[1127,3324,3325],{"class":1497}," \\\n",[1127,3327,3328,3331,3334,3337],{"class":1129,"line":516},[1127,3329,3330],{"class":1621},"  --print-to-pdf-no-header",[1127,3332,3333],{"class":1621}," --no-pdf-header-footer",[1127,3335,3336],{"class":1621}," --disable-gpu",[1127,3338,3339],{"class":1621}," telling-time.html\n",[302,3341,3342,3343,1996,3346,3349],{},"Check out the ",[335,3344,3345],{"href":162},"math sheets",[335,3347,3348],{"href":170},"reading sheets"," too — same format, same idea.",[1698,3351,3352],{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":515,"searchDepth":516,"depth":516,"links":3354},[3355,3356,3357],{"id":3189,"depth":516,"text":3190},{"id":3242,"depth":516,"text":3243},{"id":3300,"depth":516,"text":3301},"2026-02-16","Free printable PDF worksheet for kids learning to tell time — analog clock reference with hour and minute hands, common times, and 12 practice clocks. Download, print, and learn.",{"src":3361,"alt":3362},"\u002Fimages\u002Fblog\u002F20260215-1430-free-printable-telling-time-worksheet.jpeg","A colorful clock reference sheet showing analog clocks with hour and minute hands, plus practice clocks for kids to read",{},{"title":177,"description":3359},"-QBmpn3O4XddikYNkIY_r6vVid7Qvz_ZVHeTJqFAx2c",{"id":3367,"title":169,"authors":3368,"badge":3371,"body":3372,"date":3782,"description":3783,"extension":533,"image":3784,"meta":3787,"navigation":538,"path":170,"seo":3788,"status":540,"stem":171,"__hash__":3789},"posts\u002F2.blog\u002F20260215.free-printable-sight-words-and-grammar-sheets.md",[3369],{"name":292,"to":293,"avatar":3370},{"src":295},{"label":3181},{"type":299,"value":3373,"toc":3775},[3374,3377,3381,3384,3389,3403,3408,3431,3434,3437,3440,3442,3446,3449,3454,3495,3500,3514,3517,3520,3523,3525,3529,3532,3537,3557,3562,3588,3591,3594,3597,3599,3603,3606,3611,3622,3627,3638,3641,3644,3647,3649,3652,3656,3659,3762,3772],[302,3375,3376],{},"While I was at it, I made some reading sheets too — no kid asks for this stuff, but four double-sided sheets pinned to the wall can't hurt.",[318,3378,3380],{"id":3379},"dolch-sight-words-front-back","Dolch Sight Words (Front & Back)",[302,3382,3383],{},"The classic Dolch sight word lists, all 220 words organized by level. Print double-sided and laminate.",[302,3385,3386],{},[326,3387,3388],{},"Front — Pre-Primer & Primer (Pre-K & Kindergarten):",[368,3390,3391,3397],{},[371,3392,3393,3396],{},[326,3394,3395],{},"Pre-Primer"," (40 words) — orange — the first words kids learn to recognize by sight",[371,3398,3399,3402],{},[326,3400,3401],{},"Primer"," (52 words) — blue — the next set for emerging readers",[302,3404,3405],{},[326,3406,3407],{},"Back — 1st, 2nd & 3rd Grade:",[368,3409,3410,3416,3422,3428],{},[371,3411,3412,3415],{},[326,3413,3414],{},"1st Grade"," (41 words) — green",[371,3417,3418,3421],{},[326,3419,3420],{},"2nd Grade"," (46 words) — purple",[371,3423,3424,3427],{},[326,3425,3426],{},"3rd Grade"," (41 words) — teal",[371,3429,3430],{},"Each grade level is color-coded so kids can track their progress",[3265,3432],{"src":3433,"width":3268,"height":3269,"style":3270},"\u002Fdownloads\u002Fkids\u002Fsight-words.pdf",[3272,3435],{"color":3274,"icon":3275,"label":3436,"size":3277,"target":3278,"to":3433},"Download Sight Words PDF",[3272,3438],{"color":3281,"icon":3282,"label":3283,"size":3277,"target":3278,"to":3439,"variant":235},"\u002Fdownloads\u002Fkids\u002Fsight-words.html",[3286,3441],{},[318,3443,3445],{"id":3444},"parts-of-speech-punctuation-front-back","Parts of Speech & Punctuation (Front & Back)",[302,3447,3448],{},"A grammar reference sheet with everything on two sides.",[302,3450,3451],{},[326,3452,3453],{},"Front — The 8 Parts of Speech:",[368,3455,3456,3474,3492],{},[371,3457,3458,3461,3462,3465,3466,3469,3470,3473],{},[326,3459,3460],{},"Noun"," (blue), ",[326,3463,3464],{},"Verb"," (red), ",[326,3467,3468],{},"Adjective"," (green), ",[326,3471,3472],{},"Adverb"," (orange)",[371,3475,3476,3479,3480,3483,3484,3487,3488,3491],{},[326,3477,3478],{},"Pronoun"," (purple), ",[326,3481,3482],{},"Preposition"," (teal), ",[326,3485,3486],{},"Conjunction"," (pink), ",[326,3489,3490],{},"Interjection"," (gold)",[371,3493,3494],{},"Each card has the definition, example words, and a sentence with the word highlighted",[302,3496,3497],{},[326,3498,3499],{},"Back — Punctuation & Sentence Types:",[368,3501,3502,3508],{},[371,3503,3504,3507],{},[326,3505,3506],{},"Punctuation Guide"," — period, question mark, exclamation point, comma, apostrophe, quotation marks — each with an example",[371,3509,3510,3513],{},[326,3511,3512],{},"4 Sentence Types"," — declarative, interrogative, imperative, exclamatory — color-coded with examples",[3265,3515],{"src":3516,"width":3268,"height":3269,"style":3270},"\u002Fdownloads\u002Fkids\u002Fparts-of-speech.pdf",[3272,3518],{"color":3274,"icon":3275,"label":3519,"size":3277,"target":3278,"to":3516},"Download Parts of Speech PDF",[3272,3521],{"color":3281,"icon":3282,"label":3283,"size":3277,"target":3278,"to":3522,"variant":235},"\u002Fdownloads\u002Fkids\u002Fparts-of-speech.html",[3286,3524],{},[318,3526,3528],{"id":3527},"homophones-contractions-front-back","Homophones & Contractions (Front & Back)",[302,3530,3531],{},"The tricky stuff. Words that sound alike but mean different things, and how two words squish into one.",[302,3533,3534],{},[326,3535,3536],{},"Front — Common Homophones:",[368,3538,3539,3554],{},[371,3540,3541,3542,1199,3545,1199,3548,1199,3551],{},"12 homophone groups including the classics: ",[326,3543,3544],{},"there\u002Ftheir\u002Fthey're",[326,3546,3547],{},"to\u002Ftoo\u002Ftwo",[326,3549,3550],{},"your\u002Fyou're",[326,3552,3553],{},"its\u002Fit's",[371,3555,3556],{},"Each group has clear definitions and example sentences so kids can see the difference",[302,3558,3559],{},[326,3560,3561],{},"Back — Contractions Chart:",[368,3563,3564,3585],{},[371,3565,3566,3567,1199,3570,1199,3573,1199,3576,1199,3579,1258,3582],{},"All common contractions organized by type: ",[326,3568,3569],{},"is",[326,3571,3572],{},"not",[326,3574,3575],{},"have",[326,3577,3578],{},"will",[326,3580,3581],{},"am\u002Fare\u002Fis",[326,3583,3584],{},"would\u002Fhad",[371,3586,3587],{},"Color-coded groups with the full form → contraction format",[3265,3589],{"src":3590,"width":3268,"height":3269,"style":3270},"\u002Fdownloads\u002Fkids\u002Fhomophones-and-contractions.pdf",[3272,3592],{"color":3274,"icon":3275,"label":3593,"size":3277,"target":3278,"to":3590},"Download Homophones & Contractions PDF",[3272,3595],{"color":3281,"icon":3282,"label":3283,"size":3277,"target":3278,"to":3596,"variant":235},"\u002Fdownloads\u002Fkids\u002Fhomophones-and-contractions.html",[3286,3598],{},[318,3600,3602],{"id":3601},"alphabet-chart-handwriting-practice-front-back","Alphabet Chart & Handwriting Practice (Front & Back)",[302,3604,3605],{},"For the youngest learners — the full alphabet with pictures, plus a handwriting practice page.",[302,3607,3608],{},[326,3609,3610],{},"Front — Alphabet Chart:",[368,3612,3613,3616,3619],{},[371,3614,3615],{},"26 letter cards in a 5-column rainbow grid",[371,3617,3618],{},"Each card shows the uppercase letter, lowercase letter, a common word, and an emoji: A 🍎 Apple, B ⚽ Ball, C 🐱 Cat, and so on",[371,3620,3621],{},"Color-coded rows cycling through red, orange, yellow, green, blue, and purple",[302,3623,3624],{},[326,3625,3626],{},"Back — Handwriting Practice:",[368,3628,3629,3632,3635],{},[371,3630,3631],{},"All 26 letters with guide rows — top line, dashed midline, and baseline",[371,3633,3634],{},"Each row starts with the letter (upper + lower) then light gray trace guides",[371,3636,3637],{},"\"Practice Writing Your Name\" section at the bottom with lined space",[3265,3639],{"src":3640,"width":3268,"height":3269,"style":3270},"\u002Fdownloads\u002Fkids\u002Falphabet-chart.pdf",[3272,3642],{"color":3274,"icon":3275,"label":3643,"size":3277,"target":3278,"to":3640},"Download Alphabet Chart PDF",[3272,3645],{"color":3281,"icon":3282,"label":3283,"size":3277,"target":3278,"to":3646,"variant":235},"\u002Fdownloads\u002Fkids\u002Falphabet-chart.html",[3286,3648],{},[302,3650,3651],{},"All four sheets are designed for letter-size paper with large, readable text and print-friendly colors. Print each one double-sided, laminate them, and stick them on the fridge next to the math sheets.",[318,3653,3655],{"id":3654},"how-the-pdfs-are-made","How the PDFs are made",[302,3657,3658],{},"Same as the math sheets — plain HTML\u002FCSS files rendered to PDF with headless Chrome:",[1119,3660,3662],{"className":3307,"code":3661,"language":3309,"meta":515,"style":515},"for f in sight-words.html \\\n         parts-of-speech.html \\\n         homophones-and-contractions.html \\\n         alphabet-chart.html; do\n  google-chrome --headless=new --print-to-pdf=\"${f%.html}.pdf\" \\\n    --print-to-pdf-no-header --no-pdf-header-footer --disable-gpu \"$f\"\ndone\n",[745,3663,3664,3680,3687,3694,3705,3739,3757],{"__ignoreMap":515},[1127,3665,3666,3669,3672,3675,3678],{"class":1129,"line":1130},[1127,3667,3668],{"class":2270},"for",[1127,3670,3671],{"class":1497}," f ",[1127,3673,3674],{"class":2270},"in",[1127,3676,3677],{"class":1621}," sight-words.html",[1127,3679,3325],{"class":1497},[1127,3681,3682,3685],{"class":1129,"line":516},[1127,3683,3684],{"class":1621},"         parts-of-speech.html",[1127,3686,3325],{"class":1497},[1127,3688,3689,3692],{"class":1129,"line":523},[1127,3690,3691],{"class":1621},"         homophones-and-contractions.html",[1127,3693,3325],{"class":1497},[1127,3695,3696,3699,3702],{"class":1129,"line":1146},[1127,3697,3698],{"class":1621},"         alphabet-chart.html",[1127,3700,3701],{"class":1501},";",[1127,3703,3704],{"class":2270}," do\n",[1127,3706,3707,3710,3712,3715,3718,3721,3724,3726,3729,3731,3734,3737],{"class":1129,"line":1382},[1127,3708,3709],{"class":2246},"  google-chrome",[1127,3711,3319],{"class":1621},[1127,3713,3714],{"class":1621}," --print-to-pdf=",[1127,3716,3717],{"class":1501},"\"${",[1127,3719,3720],{"class":1497},"f",[1127,3722,3723],{"class":1501},"%",[1127,3725,1207],{"class":1621},[1127,3727,3728],{"class":1497},"html",[1127,3730,1639],{"class":1501},[1127,3732,3733],{"class":1621},".pdf",[1127,3735,3736],{"class":1501},"\"",[1127,3738,3325],{"class":1497},[1127,3740,3741,3744,3746,3748,3751,3754],{"class":1129,"line":1388},[1127,3742,3743],{"class":1621},"    --print-to-pdf-no-header",[1127,3745,3333],{"class":1621},[1127,3747,3336],{"class":1621},[1127,3749,3750],{"class":1501}," \"",[1127,3752,3753],{"class":1497},"$f",[1127,3755,3756],{"class":1501},"\"\n",[1127,3758,3759],{"class":1129,"line":1586},[1127,3760,3761],{"class":2270},"done\n",[302,3763,2221,3764,3767,3768,3771],{},[745,3765,3766],{},"@page { margin: 0 }"," CSS rule combined with ",[745,3769,3770],{},"--print-to-pdf-no-header"," ensures clean output with no browser headers or footers. Edit the HTML, regenerate, and you're done.",[1698,3773,3774],{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":515,"searchDepth":516,"depth":516,"links":3776},[3777,3778,3779,3780,3781],{"id":3379,"depth":516,"text":3380},{"id":3444,"depth":516,"text":3445},{"id":3527,"depth":516,"text":3528},{"id":3601,"depth":516,"text":3602},{"id":3654,"depth":516,"text":3655},"2026-02-15","Free printable PDF worksheets for kids — Dolch sight words, parts of speech, punctuation, homophones, contractions, alphabet chart, and handwriting practice. Download, print, and learn.",{"src":3785,"alt":3786},"\u002Fimages\u002Fkids\u002Fsight-words-preview.png","A colorful grid of Dolch sight words organized by grade level with color-coded sections",{},{"title":169,"description":3783},"_c3VXXtrZbq0qPsYiFPBbnvQ-jlHqBSRL8MSpovVlOM",{"id":3791,"title":173,"authors":3792,"badge":3795,"body":3796,"date":3782,"description":3923,"extension":533,"image":3924,"meta":3927,"navigation":538,"path":174,"seo":3928,"status":540,"stem":175,"__hash__":3929},"posts\u002F2.blog\u002F20260215.interactive-code-execution-with-artifacts.md",[3793],{"name":292,"to":293,"avatar":3794},{"src":295},{"label":297},{"type":299,"value":3797,"toc":3915},[3798,3806,3809,3813,3823,3826,3830,3833,3839,3843,3846,3850,3854,3857,3861,3865,3868,3897,3900,3903,3905,3908],[302,3799,3800,3801,1207],{},"I've been wanting a way to let readers run code directly in blog posts — not just read about it. Today I'm shipping interactive artifacts powered by ",[335,3802,3805],{"href":3803,"rel":3804},"https:\u002F\u002Fdocs.anthropic.com\u002Fen\u002Fdocs\u002Fagents-and-tools\u002Ftool-use\u002Fcode-execution",[461],"Anthropic's Code Execution Tool",[302,3807,3808],{},"Every code block below runs in an isolated Linux container on Anthropic's infrastructure. No local setup needed, no browser sandboxing tricks. Real Python, real output.",[318,3810,3812],{"id":3811},"how-it-works","How It Works",[302,3814,2221,3815,3818,3819,3822],{},[745,3816,3817],{},"::code-runner"," component sends your code (or a prompt) to Claude via the Messages API with the ",[745,3820,3821],{},"code_execution"," tool enabled. Claude runs it in a sandboxed container and streams back stdout, stderr, and any generated files.",[302,3824,3825],{},"The container persists between runs within the same artifact, so you can build up state across multiple executions.",[318,3827,3829],{"id":3828},"example-1-fibonacci-sequence","Example 1: Fibonacci Sequence",[302,3831,3832],{},"A classic starting point. Hit \"Run\" to see the first 15 Fibonacci numbers.",[3834,3835],"code-runner",{"language":3836,"title":3837,"code":3838},"python","Fibonacci Generator","def fib(n):\\n    a, b = 0, 1\\n    for _ in range(n):\\n        yield a\\n        a, b = b, a + b\\n\\nprint(list(fib(15)))",[318,3840,3842],{"id":3841},"example-2-data-visualization","Example 2: Data Visualization",[302,3844,3845],{},"This one generates a matplotlib chart. The resulting PNG renders inline below the output.",[3834,3847],{"language":3836,"title":3848,"prompt":3849},"Population Bar Chart","Create a horizontal bar chart showing estimated 2025 world population by continent. Use matplotlib with a dark background style. Save as population.png.",[318,3851,3853],{"id":3852},"example-3-quick-math","Example 3: Quick Math",[302,3855,3856],{},"Edit the code and re-run to experiment.",[3834,3858],{"language":3836,"title":3859,"code":3860},"Prime Sieve","def sieve(limit):\\n    is_prime = [True] * (limit + 1)\\n    is_prime[0] = is_prime[1] = False\\n    for i in range(2, int(limit**0.5) + 1):\\n        if is_prime[i]:\\n            for j in range(i*i, limit + 1, i):\\n                is_prime[j] = False\\n    return [i for i, p in enumerate(is_prime) if p]\\n\\nprimes = sieve(100)\\nprint(f'Found {len(primes)} primes up to 100:')\\nprint(primes)",[318,3862,3864],{"id":3863},"under-the-hood","Under the Hood",[302,3866,3867],{},"The artifact system uses three Anthropic beta APIs:",[368,3869,3870,3879,3888],{},[371,3871,3872,2208,3875,3878],{},[326,3873,3874],{},"Code Execution",[745,3876,3877],{},"code-execution-2025-08-25",") — runs code in isolated containers",[371,3880,3881,2208,3884,3887],{},[326,3882,3883],{},"Files API",[745,3885,3886],{},"files-api-2025-04-14",") — downloads generated files (images, HTML, etc.)",[371,3889,3890,2208,3893,3896],{},[326,3891,3892],{},"Skills API",[745,3894,3895],{},"skills-2025-10-02",") — optional document generation capabilities",[302,3898,3899],{},"Each execution streams results via SSE, so you see output as it happens rather than waiting for the full response.",[302,3901,3902],{},"The container has Python with common libraries pre-installed (numpy, pandas, matplotlib, etc.) but no internet access — it's fully sandboxed.",[318,3904,3102],{"id":3101},[302,3906,3907],{},"This is the foundation for more interactive content. I'm exploring adding artifact execution to the chat interface and supporting more languages beyond Python.",[302,3909,3910,3911,1207],{},"If you have ideas for interactive examples you'd like to see, let me know on ",[335,3912,3914],{"href":293,"rel":3913},[461],"X",{"title":515,"searchDepth":516,"depth":516,"links":3916},[3917,3918,3919,3920,3921,3922],{"id":3811,"depth":516,"text":3812},{"id":3828,"depth":516,"text":3829},{"id":3841,"depth":516,"text":3842},{"id":3852,"depth":516,"text":3853},{"id":3863,"depth":516,"text":3864},{"id":3101,"depth":516,"text":3102},"Run Python code directly in blog posts using Anthropic Code Execution. Try the interactive examples below — every snippet runs in an isolated container on Anthropic infrastructure.",{"src":3925,"alt":3926},"\u002Fimages\u002Fblog\u002F20260215-1430-interactive-code-execution-with-artifacts.jpeg","A glowing terminal window floating in mid-air inside a sleek, dark workspace, its screen displaying vibrant Python code alongside a colorful matplotlib chart rendering in real-time, with streams of luminous data particles flowing from the terminal into a translucent isolated container hovering beside it. Dramatic rim lighting in cool electric blue and warm amber picks out the edges of the floating elements against a deep charcoal background, with subtle bokeh circles suggesting depth. Cinematic photorealism, 8k quality, shallow depth of field with tack-sharp focus on the terminal screen, professional photography composition following rule of thirds. High contrast color grading with teal, orange, and violet accents, 16:9 landscape format with negative space on the left for potential text overlay.",{},{"title":173,"description":3923},"VLNR2GePlb9Fs3JTH7OuwQjQd8Rl7E4kTDl7rfHHX24",{"id":3931,"title":161,"authors":3932,"badge":3935,"body":3936,"date":4252,"description":4253,"extension":533,"image":4254,"meta":4257,"navigation":538,"path":162,"seo":4258,"status":540,"stem":163,"__hash__":4259},"posts\u002F2.blog\u002F20260214.free-printable-number-chart-and-coin-sheets.md",[3933],{"name":292,"to":293,"avatar":3934},{"src":295},{"label":3181},{"type":299,"value":3937,"toc":4246},[3938,3941,3945,3948,3953,3979,3984,4011,4014,4017,4020,4022,4026,4029,4034,4051,4056,4073,4076,4079,4082,4084,4088,4091,4096,4116,4121,4141,4144,4147,4150,4152,4155,4157,4160,4238,4244],[302,3939,3940],{},"My kids needed some math reference sheets, so I made a set. They turned out well enough that I figured I'd share them here as free PDFs anyone can print.",[318,3942,3944],{"id":3943},"number-chart-skip-counting-front-back","Number Chart & Skip Counting (Front & Back)",[302,3946,3947],{},"A two-sided reference sheet. Print it double-sided and laminate it for the fridge.",[302,3949,3950],{},[326,3951,3952],{},"Front — Number Chart 1-120:",[368,3954,3955,3961,3967,3973],{},[371,3956,3957,3960],{},[326,3958,3959],{},"Rainbow rows"," — each row cycles through red, orange, yellow, green, and blue",[371,3962,3963,3966],{},[326,3964,3965],{},"Even numbers"," are slightly shaded darker",[371,3968,3969,3972],{},[326,3970,3971],{},"Multiples of 5"," are italic with accent borders",[371,3974,3975,3978],{},[326,3976,3977],{},"Multiples of 10"," are bold white on dark background",[302,3980,3981],{},[326,3982,3983],{},"Back — Skip Counting 1-120:",[368,3985,3986,3992,3998,4004],{},[371,3987,3988,3991],{},[326,3989,3990],{},"Count by 2s"," (blue) — all even numbers highlighted",[371,3993,3994,3997],{},[326,3995,3996],{},"Count by 3s"," (purple) — every third number highlighted",[371,3999,4000,4003],{},[326,4001,4002],{},"Count by 5s"," (green) — multiples of 5 highlighted",[371,4005,4006,4007,4010],{},"Numbers that overlap get gradient blends; ",[326,4008,4009],{},"multiples of 30"," (all three!) get a special gold border",[3265,4012],{"src":4013,"width":3268,"height":3269,"style":3270},"\u002Fdownloads\u002Fkids\u002Fnumber-chart-with-skip-counting.pdf",[3272,4015],{"color":3274,"icon":3275,"label":4016,"size":3277,"target":3278,"to":4013},"Download Number Chart + Skip Counting PDF",[3272,4018],{"color":3281,"icon":3282,"label":3283,"size":3277,"target":3278,"to":4019,"variant":235},"\u002Fdownloads\u002Fkids\u002Fnumber-chart-with-skip-counting.html",[3286,4021],{},[318,4023,4025],{"id":4024},"multiplication-table-number-bonds-front-back","Multiplication Table & Number Bonds (Front & Back)",[302,4027,4028],{},"Another two-sided sheet. Multiplication on the front, number bonds on the back.",[302,4030,4031],{},[326,4032,4033],{},"Front — Multiplication Table 1-10:",[368,4035,4036,4042,4048],{},[371,4037,4038,4041],{},[326,4039,4040],{},"Color gradient"," — products go from warm yellows (small) to purples (large)",[371,4043,4044,4047],{},[326,4045,4046],{},"Perfect squares"," highlighted with purple borders (1, 4, 9, 16, 25...)",[371,4049,4050],{},"Clean header row and column with × symbol",[302,4052,4053],{},[326,4054,4055],{},"Back — Number Bonds:",[368,4057,4058,4064,4070],{},[371,4059,4060,4063],{},[326,4061,4062],{},"Ways to Make 10"," (blue) — visual bond diagrams showing all pairs that sum to 10",[371,4065,4066,4069],{},[326,4067,4068],{},"Ways to Make 20"," (green) — same format for pairs that sum to 20",[371,4071,4072],{},"Core fluency for 1st and 2nd grade math",[3265,4074],{"src":4075,"width":3268,"height":3269,"style":3270},"\u002Fdownloads\u002Fkids\u002Fmultiplication-table.pdf",[3272,4077],{"color":3274,"icon":3275,"label":4078,"size":3277,"target":3278,"to":4075},"Download Multiplication + Number Bonds PDF",[3272,4080],{"color":3281,"icon":3282,"label":3283,"size":3277,"target":3278,"to":4081,"variant":235},"\u002Fdownloads\u002Fkids\u002Fmultiplication-table.html",[3286,4083],{},[318,4085,4087],{"id":4086},"counting-us-coins","Counting US Coins",[302,4089,4090],{},"A two-page reference sheet covering the four main US coins — penny, nickel, dime, and quarter — with real photographs and color-coded sections.",[302,4092,4093],{},[326,4094,4095],{},"Page 1:",[368,4097,4098,4104,4110],{},[371,4099,4100,4103],{},[326,4101,4102],{},"Coin identification"," — each coin shown with its name and value in color-coded cards",[371,4105,4106,4109],{},[326,4107,4108],{},"Skip counting tables"," — count by pennies (1c), nickels (5c), dimes (10c), and quarters (25c) up to $1.00",[371,4111,4112,4115],{},[326,4113,4114],{},"How many make a dollar"," — quick reference showing 100 pennies, 20 nickels, 10 dimes, or 4 quarters = $1.00",[302,4117,4118],{},[326,4119,4120],{},"Page 2:",[368,4122,4123,4129,4135],{},[371,4124,4125,4128],{},[326,4126,4127],{},"Front & back of each coin"," — real photographs of both sides (Lincoln, Jefferson, Roosevelt, Washington)",[371,4130,4131,4134],{},[326,4132,4133],{},"Coin equivalents"," — visual breakdowns showing how coins relate (1 quarter = 5 nickels, etc.)",[371,4136,4137,4140],{},[326,4138,4139],{},"Ways to make $1.00"," — each denomination in its own card showing how many it takes, plus a dollar bill",[3265,4142],{"src":4143,"width":3268,"height":3269,"style":3270},"\u002Fdownloads\u002Fkids\u002Fcounting-coins.pdf",[3272,4145],{"color":3274,"icon":3275,"label":4146,"size":3277,"target":3278,"to":4143},"Download Coin Chart PDF",[3272,4148],{"color":3281,"icon":3282,"label":3283,"size":3277,"target":3278,"to":4149,"variant":235},"\u002Fdownloads\u002Fkids\u002Fcounting-coins.html",[3286,4151],{},[302,4153,4154],{},"All three sheets are designed for letter-size paper with large, readable text and print-friendly colors. Print each one double-sided, laminate them, and stick them on the fridge.",[318,4156,3655],{"id":3654},[302,4158,4159],{},"Every worksheet is a plain HTML\u002FCSS file. The PDFs are generated from them using headless Chrome:",[1119,4161,4163],{"className":3307,"code":4162,"language":3309,"meta":515,"style":515},"for f in number-chart-with-skip-counting.html \\\n         multiplication-table.html \\\n         counting-coins.html; do\n  google-chrome --headless=new --print-to-pdf=\"${f%.html}.pdf\" \\\n    --print-to-pdf-no-header --no-pdf-header-footer --disable-gpu \"$f\"\ndone\n",[745,4164,4165,4178,4185,4194,4220,4234],{"__ignoreMap":515},[1127,4166,4167,4169,4171,4173,4176],{"class":1129,"line":1130},[1127,4168,3668],{"class":2270},[1127,4170,3671],{"class":1497},[1127,4172,3674],{"class":2270},[1127,4174,4175],{"class":1621}," number-chart-with-skip-counting.html",[1127,4177,3325],{"class":1497},[1127,4179,4180,4183],{"class":1129,"line":516},[1127,4181,4182],{"class":1621},"         multiplication-table.html",[1127,4184,3325],{"class":1497},[1127,4186,4187,4190,4192],{"class":1129,"line":523},[1127,4188,4189],{"class":1621},"         counting-coins.html",[1127,4191,3701],{"class":1501},[1127,4193,3704],{"class":2270},[1127,4195,4196,4198,4200,4202,4204,4206,4208,4210,4212,4214,4216,4218],{"class":1129,"line":1146},[1127,4197,3709],{"class":2246},[1127,4199,3319],{"class":1621},[1127,4201,3714],{"class":1621},[1127,4203,3717],{"class":1501},[1127,4205,3720],{"class":1497},[1127,4207,3723],{"class":1501},[1127,4209,1207],{"class":1621},[1127,4211,3728],{"class":1497},[1127,4213,1639],{"class":1501},[1127,4215,3733],{"class":1621},[1127,4217,3736],{"class":1501},[1127,4219,3325],{"class":1497},[1127,4221,4222,4224,4226,4228,4230,4232],{"class":1129,"line":1382},[1127,4223,3743],{"class":1621},[1127,4225,3333],{"class":1621},[1127,4227,3336],{"class":1621},[1127,4229,3750],{"class":1501},[1127,4231,3753],{"class":1497},[1127,4233,3756],{"class":1501},[1127,4235,4236],{"class":1129,"line":1388},[1127,4237,3761],{"class":2270},[302,4239,2221,4240,3767,4242,3771],{},[745,4241,3766],{},[745,4243,3770],{},[1698,4245,3774],{},{"title":515,"searchDepth":516,"depth":516,"links":4247},[4248,4249,4250,4251],{"id":3943,"depth":516,"text":3944},{"id":4024,"depth":516,"text":4025},{"id":4086,"depth":516,"text":4087},{"id":3654,"depth":516,"text":3655},"2026-02-14","Free printable PDF worksheets for kids — a 1-120 number chart, skip counting, multiplication table, number bonds, and a US coin reference sheet. Download, print, and learn.",{"src":4255,"alt":4256},"\u002Fimages\u002Fkids\u002Fnumber-chart-preview.png","A colorful rainbow number chart showing numbers 1 through 120 in a grid with each row a different color",{},{"title":161,"description":4253},"ogBL1VzmmNQe-g0j9VeO8Tc0-TAr4pUSBRh3MPHFajc",{"id":4261,"title":165,"authors":4262,"badge":4265,"body":4266,"date":4252,"description":4574,"extension":533,"image":4575,"meta":4578,"navigation":538,"path":166,"seo":4579,"status":540,"stem":167,"__hash__":4580},"posts\u002F2.blog\u002F20260214.near-the-end-of-the-exponential.md",[4263],{"name":292,"to":293,"avatar":4264},{"src":295},{"label":297},{"type":299,"value":4267,"toc":4565},[4268,4271,4285,4294,4298,4301,4306,4309,4313,4322,4337,4340,4345,4350,4353,4394,4397,4401,4404,4409,4412,4444,4447,4452,4457,4460,4464,4467,4493,4496,4500,4506,4511,4514,4518,4521,4526,4529,4532,4536,4543,4546,4549],[302,4269,4270],{},"I'm sharing this with everyone at work, and now I'm sharing it with you.",[302,4272,4273,4274,4279,4280,1207],{},"Dwarkesh Patel just dropped a ",[335,4275,4278],{"href":4276,"rel":4277},"https:\u002F\u002Fyoutu.be\u002Fn1E9IZfvGMA?si=YM7r36NbRWQPhF1y",[461],"new interview with Dario Amodei",", CEO of Anthropic. I also ",[335,4281,4284],{"href":4282,"rel":4283},"https:\u002F\u002Fx.com\u002FChris_Towles\u002Fstatus\u002F2022490437559128216",[461],"posted about it on X",[3265,4286],{"width":4287,"height":4288,"src":4289,"title":4290,"frameBorder":4291,"allow":4292,"referrerPolicy":4293,"allowFullScreen":538},560,315,"https:\u002F\u002Fwww.youtube.com\u002Fembed\u002Fn1E9IZfvGMA?si=W1jo_MMqj3PQJO21&start=1159","YouTube video player","0","accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share","strict-origin-when-cross-origin",[318,4295,4297],{"id":4296},"we-are-near-the-end-of-the-exponential","\"We Are Near the End of the Exponential\"",[302,4299,4300],{},"This stopped me in my tracks:",[330,4302,4303],{},[302,4304,4305],{},"\"What has been the most surprising thing is the lack of public recognition of how close we are to the end of the exponential. To me, it is absolutely wild that you have people — within the bubble and outside the bubble — talking about the same tired, old hot-button political issues, when we are near the end of the exponential.\"",[302,4307,4308],{},"He's not talking about hype. He's talking about the actual capability curve — smart high school student → smart college student → beginning PhD-level work → and in coding, already beyond that. He's frustrated that almost nobody seems to notice.",[318,4310,4312],{"id":4311},"the-big-blob-came-before-the-bitter-lesson","The Big Blob Came Before The Bitter Lesson",[302,4314,4315,4316,4321],{},"Most people in AI know Rich Sutton's ",[335,4317,4320],{"href":4318,"rel":4319},"http:\u002F\u002Fwww.incompleteideas.net\u002FIncIdeas\u002FBitterLesson.html",[461],"\"The Bitter Lesson\""," (2019). It's practically required reading. The core argument: general methods that leverage computation are ultimately the most effective. Stop trying to be clever. Scale wins.",[302,4323,4324,4325,4328,4329,4332,4333,4336],{},"What blew my mind is that Dario wrote a private document in ",[326,4326,4327],{},"2017"," called ",[326,4330,4331],{},"\"The Big Blob of Compute Hypothesis\""," that arrived at essentially the same conclusion — ",[920,4334,4335],{},"two years earlier",". Before GPT-1 had even come out. Before transformers had taken over.",[302,4338,4339],{},"In his own words:",[330,4341,4342],{},[302,4343,4344],{},"\"It wasn't about the scaling of language models in particular. When I wrote it, GPT-1 had just come out. That was one among many things. Back in those days there was robotics. People tried to work on reasoning as a separate thing from language models, and there was scaling of the kind of RL that happened in AlphaGo and in Dota at OpenAI.\"",[330,4346,4347],{},[302,4348,4349],{},"\"Rich Sutton put out 'The Bitter Lesson' a couple years later. The hypothesis is basically the same. What it says is that all the cleverness, all the techniques, all the 'we need a new method to do something', that doesn't matter very much.\"",[302,4351,4352],{},"The field was fragmented across robotics, game-playing RL, reasoning systems, and early language models. Dario looked at all of it and said: none of the specifics matter. Just the blob. He listed seven things that actually matter:",[851,4354,4355,4361,4366,4372,4377,4383,4389],{},[371,4356,4357,4360],{},[326,4358,4359],{},"Raw compute"," — how much you have",[371,4362,4363],{},[326,4364,4365],{},"Quantity of data",[371,4367,4368,4371],{},[326,4369,4370],{},"Quality and distribution of data"," — it needs to be broad",[371,4373,4374],{},[326,4375,4376],{},"Training duration",[371,4378,4379,4382],{},[326,4380,4381],{},"A scalable objective function"," — pre-training's next-token prediction is one; RL rewards are another",[371,4384,4385,4388],{},[326,4386,4387],{},"Normalization and conditioning"," — keeping the numerical stability so the blob flows in a \"laminar\" way",[371,4390,4391],{},[920,4392,4393],{},"(Related stability\u002Fengineering concerns)",[302,4395,4396],{},"Everything else — the clever architectures, the novel techniques — gets eaten by the blob.",[318,4398,4400],{"id":4399},"were-already-almost-there-for-software-engineering","\"We're Already Almost There for Software Engineering\"",[302,4402,4403],{},"This is the part that hit me hardest as someone who works in Cloud AI and talks to engineers every day. Dario lays out a spectrum that most people conflate:",[330,4405,4406],{},[302,4407,4408],{},"\"About eight or nine months ago, I said the AI model will be writing 90% of the lines of code in three to six months. That happened... But that's actually a very weak criterion. People thought I was saying that we won't need 90% of the software engineers. Those things are worlds apart.\"",[302,4410,4411],{},"He breaks down the actual progression:",[368,4413,4414,4420,4426,4432,4438],{},[371,4415,4416,4419],{},[326,4417,4418],{},"90% of code written by models"," → Already happened",[371,4421,4422,4425],{},[326,4423,4424],{},"100% of code written by models"," → Big difference from 90%",[371,4427,4428,4431],{},[326,4429,4430],{},"90% of end-to-end SWE tasks"," (compiling, environments, testing, memos) → Coming fast",[371,4433,4434,4437],{},[326,4435,4436],{},"100% of today's SWE tasks done by models"," → Doesn't mean engineers are out of a job",[371,4439,4440,4443],{},[326,4441,4442],{},"90% less demand for SWEs"," → Will happen, but further down the spectrum",[302,4445,4446],{},"And Anthropic is living this internally. When Dwarkesh pushed back on whether productivity gains are real or just vibes, Dario didn't mince words:",[330,4448,4449],{},[302,4450,4451],{},"\"We're under an incredible amount of commercial pressure... There is zero time for bullshit. There is zero time for feeling like we're productive when we're not. These tools make us a lot more productive.\"",[330,4453,4454],{},[302,4455,4456],{},"\"We have engineers at Anthropic who don't write any code.\"",[302,4458,4459],{},"That's not a prediction. That's a present-tense statement from the CEO of the company that makes Claude.",[318,4461,4463],{"id":4462},"the-revenue-curve-tells-the-story","The Revenue Curve Tells the Story",[302,4465,4466],{},"If you need numbers instead of words:",[368,4468,4469,4475,4481,4487],{},[371,4470,4471,4474],{},[326,4472,4473],{},"2023:"," $0 → $100 million",[371,4476,4477,4480],{},[326,4478,4479],{},"2024:"," $100 million → $1 billion",[371,4482,4483,4486],{},[326,4484,4485],{},"2025:"," $1 billion → $9-10 billion",[371,4488,4489,4492],{},[326,4490,4491],{},"January 2026 alone:"," Added another few billion",[302,4494,4495],{},"10x per year. And Dario says the curve hasn't bent yet.",[318,4497,4499],{"id":4498},"country-of-geniuses-in-a-data-center","Country of Geniuses in a Data Center",[302,4501,4502,4503,1554],{},"When Dwarkesh asked for a concrete timeline on reaching what Dario calls \"a country of geniuses in a data center\" — AI systems that match or exceed Nobel Prize winners across domains — Dario put it at ",[326,4504,4505],{},"one to three years",[330,4507,4508],{},[302,4509,4510],{},"\"I have a strong view — 99%, 95% — that all this will happen in 10 years. I think that's just a super safe bet. I have a hunch — this is more like a 50\u002F50 thing — that it's going to be more like one to two, maybe one to three.\"",[302,4512,4513],{},"Not ten years. Not five. One to three. And on coding specifically, he thinks we'll be at end-to-end automation in one to two years. \"There's no way we will not be there in ten years.\"",[318,4515,4517],{"id":4516},"two-exponentials-not-one","Two Exponentials, Not One",[302,4519,4520],{},"This might be the most useful mental model in the entire interview. Dario describes two curves happening simultaneously:",[330,4522,4523],{},[302,4524,4525],{},"\"I think everything we've seen so far is compatible with the idea that there's one fast exponential that's the capability of the model. Then there's another fast exponential that's downstream of that, which is the diffusion of the model into the economy. Not instant, not slow, much faster than any previous technology, but it has its limits. When I look inside Anthropic, when I look at our customers: fast adoption, but not infinitely fast.\"",[302,4527,4528],{},"This is the framing I've been missing. It's not \"AI will change everything overnight\" and it's not \"AI is overhyped.\" It's two fast exponentials — capability and adoption — running at different speeds. The capability curve is screaming ahead. The adoption curve is chasing it, faster than any technology before it, but still bound by reality: legal reviews, security compliance, change management, explaining to the person two levels below you why this matters.",[302,4530,4531],{},"If you're in enterprise, you're living on that second curve right now. And if you're not actively working to close the gap between those two exponentials, you're falling behind whether you feel it or not.",[318,4533,4535],{"id":4534},"why-im-sharing-this-with-everyone-at-work","Why I'm Sharing This With Everyone at Work",[302,4537,4538,4539,4542],{},"I'm a Principal Architect for Cloud AI at GE Aerospace. I talk to engineers and architects every day about what these models can and can't do. The gap between what's actually happening inside companies like Anthropic and what most people in enterprise tech ",[920,4540,4541],{},"think"," is happening is enormous.",[302,4544,4545],{},"We're not preparing for a future disruption. We're in the middle of it. The exponential is ending, and most people haven't looked up from their desks to notice.",[302,4547,4548],{},"If you're in tech and you haven't watched this interview, block out two hours this weekend. It's the most important conversation happening right now about where all of this is going.",[302,4550,4551,4555,4556,4555,4561],{},[335,4552,4554],{"href":4276,"rel":4553},[461],"Full interview on YouTube"," | ",[335,4557,4560],{"href":4558,"rel":4559},"https:\u002F\u002Fwww.dwarkesh.com\u002Fp\u002Fdario-amodei-2",[461],"Dwarkesh Podcast transcript",[335,4562,4564],{"href":4282,"rel":4563},[461],"My X post",{"title":515,"searchDepth":516,"depth":516,"links":4566},[4567,4568,4569,4570,4571,4572,4573],{"id":4296,"depth":516,"text":4297},{"id":4311,"depth":516,"text":4312},{"id":4399,"depth":516,"text":4400},{"id":4462,"depth":516,"text":4463},{"id":4498,"depth":516,"text":4499},{"id":4516,"depth":516,"text":4517},{"id":4534,"depth":516,"text":4535},"Dario Amodei's new Dwarkesh Patel interview stopped me in my tracks. His private 2017 'Big Blob of Compute' doc predated The Bitter Lesson by two years — and his prediction about coding? We're already there.",{"src":4576,"alt":4577},"\u002Fimages\u002Fblog\u002F20260214.near-the-end-of-the-exponential.jpeg","A dramatic visualization of two intertwining exponential curves rendered as luminous energy streams against a dark void. One curve blazes bright white-gold representing raw AI capability, the other a cooler blue-silver representing economic diffusion, both spiraling upward but at different rates. The curves emerge from a glowing origin point that resembles a data center constellation. Mathematical grid lines fade into the background. The composition conveys immense velocity and inevitability. Cinematic lighting with deep contrast, volumetric light rays, photorealistic 8k quality, shallow depth of field. Sci-fi atmosphere, teal and amber color grading, 16:9 composition with negative space on the left for text overlay.",{},{"title":165,"description":4574},"snvXq5MFBsz39YZWFKk0KBrusNYBH4QIUmMTvxTyGvw",{"id":4582,"title":157,"authors":4583,"badge":4586,"body":4587,"date":5424,"description":5425,"extension":533,"image":5426,"meta":5429,"navigation":538,"path":158,"seo":5430,"status":540,"stem":159,"__hash__":5431},"posts\u002F2.blog\u002F20260124.claude-code-hidden-multi-agent-system.md",[4584],{"name":292,"to":293,"avatar":4585},{"src":295},{"label":548},{"type":299,"value":4588,"toc":5400},[4589,4598,4601,4605,4613,4618,4631,4635,4638,4645,4725,4728,4732,4736,4739,4747,4753,4761,4767,4775,4781,4785,4788,4853,4857,4860,4882,4885,4889,4892,4896,4998,5002,5089,5093,5150,5154,5157,5161,5195,5199,5287,5291,5320,5327,5331,5335,5338,5342,5348,5377,5381,5389,5397],[302,4590,4591,4592,4597],{},"Spining up agent swarms are everywhere right now. Wilson Lin showed us with ",[335,4593,4596],{"href":4594,"rel":4595},"https:\u002F\u002Fgithub.com\u002Fwilsonzlin\u002Ffastrender",[461],"FastRender"," that an agent swarm could even build a web browser from scratch! The whole ecosystem is converging on multi-agent architectures for complex tasks. So when I saw a tweet claiming Claude Code already has a hidden multi-agent system baked in, my first thought wasn't \"no way\" - it was \"already?\"",[302,4599,4600],{},"Turns out: yes. Already.",[318,4602,4604],{"id":4603},"the-claim","The Claim",[302,4606,4607,4612],{},[335,4608,4611],{"href":4609,"rel":4610},"https:\u002F\u002Fx.com\u002Fkieranklaassen\u002Fstatus\u002F2014830266515382693",[461],"Kieran Klaassen"," posted on January 23rd:",[330,4614,4615],{},[302,4616,4617],{},"I think I found a hidden Claude Code feature! TLDR: It's a built‑in multi‑agent team system in Claude Code. TeammateTool lets you create teams, let agents join, message each other, approve plans, and shut down the team — but it's feature‑flagged and not enabled for most users yet.",[302,4619,4620,4621,4626,4627,4630],{},"He included a ",[335,4622,4625],{"href":4623,"rel":4624},"https:\u002F\u002Fgist.github.com\u002Fkieranklaassen\u002Fd2b35569be2c7f1412c64861a219d51f",[461],"gist documenting what he found"," by running ",[745,4628,4629],{},"strings"," on the Claude Code binary. Bold claim. Let's verify it.",[318,4632,4634],{"id":4633},"the-verification","The Verification",[302,4636,4637],{},"I couldn't just trust the tweet, sorry Kieran, so i had to verify!",[302,4639,4640,4641,4644],{},"Claude Code stores its binaries in ",[745,4642,4643],{},"~\u002F.local\u002Fshare\u002Fclaude\u002Fversions\u002F",". I'm running v2.1.19:",[1119,4646,4648],{"className":3307,"code":4647,"language":3309,"meta":515,"style":515},"$ strings ~\u002F.local\u002Fshare\u002Fclaude\u002Fversions\u002F2.1.19 | grep -E \"CLAUDE_CODE_(TEAM|AGENT)\" | sort -u\nCLAUDE_CODE_AGENT_ID\nCLAUDE_CODE_AGENT_NAME\nCLAUDE_CODE_AGENT_SWARMS\nCLAUDE_CODE_AGENT_TYPE\nCLAUDE_CODE_TEAMMATE_COMMAND\nCLAUDE_CODE_TEAM_NAME\nCLAUDE_CODE_PLAN_MODE_REQUIRED\nCLAUDE_CODE_SUBAGENT_MODEL\n",[745,4649,4650,4685,4690,4695,4700,4705,4710,4715,4720],{"__ignoreMap":515},[1127,4651,4652,4655,4658,4661,4664,4667,4670,4672,4675,4677,4679,4682],{"class":1129,"line":1130},[1127,4653,4654],{"class":2246},"$",[1127,4656,4657],{"class":1621}," strings",[1127,4659,4660],{"class":1621}," ~\u002F.local\u002Fshare\u002Fclaude\u002Fversions\u002F2.1.19",[1127,4662,4663],{"class":1501}," |",[1127,4665,4666],{"class":2246}," grep",[1127,4668,4669],{"class":1621}," -E",[1127,4671,3750],{"class":1501},[1127,4673,4674],{"class":1621},"CLAUDE_CODE_(TEAM|AGENT)",[1127,4676,3736],{"class":1501},[1127,4678,4663],{"class":1501},[1127,4680,4681],{"class":2246}," sort",[1127,4683,4684],{"class":1621}," -u\n",[1127,4686,4687],{"class":1129,"line":516},[1127,4688,4689],{"class":2246},"CLAUDE_CODE_AGENT_ID\n",[1127,4691,4692],{"class":1129,"line":523},[1127,4693,4694],{"class":2246},"CLAUDE_CODE_AGENT_NAME\n",[1127,4696,4697],{"class":1129,"line":1146},[1127,4698,4699],{"class":2246},"CLAUDE_CODE_AGENT_SWARMS\n",[1127,4701,4702],{"class":1129,"line":1382},[1127,4703,4704],{"class":2246},"CLAUDE_CODE_AGENT_TYPE\n",[1127,4706,4707],{"class":1129,"line":1388},[1127,4708,4709],{"class":2246},"CLAUDE_CODE_TEAMMATE_COMMAND\n",[1127,4711,4712],{"class":1129,"line":1586},[1127,4713,4714],{"class":2246},"CLAUDE_CODE_TEAM_NAME\n",[1127,4716,4717],{"class":1129,"line":1599},[1127,4718,4719],{"class":2246},"CLAUDE_CODE_PLAN_MODE_REQUIRED\n",[1127,4721,4722],{"class":1129,"line":1647},[1127,4723,4724],{"class":2246},"CLAUDE_CODE_SUBAGENT_MODEL\n",[302,4726,4727],{},"That's not accidental naming. Let's dig deeper.",[318,4729,4731],{"id":4730},"what-i-found","What I Found",[401,4733,4735],{"id":4734},"the-prompts","The Prompts",[302,4737,4738],{},"Buried in the binary are complete system prompts for team members:",[302,4740,4741,2208,4744,1652],{},[326,4742,4743],{},"Teammate Prompt:",[745,4745,4746],{},"strings $BINARY | grep -A 10 \"You are a teammate in team\"",[1119,4748,4751],{"className":4749,"code":4750,"language":2028},[2026],"You are a teammate in team \"${teamName}\".\n**Your Identity:** Name: ${agentName}\n**Team Resources:**\n- Team config: ${teamConfigPath}\n- Task list: ${taskListPath}\n**Team Leader:** The team lead's name is \"team-lead\".\nSend updates and completion notifications to them.\n",[745,4752,4750],{"__ignoreMap":515},[302,4754,4755,2208,4758,1652],{},[326,4756,4757],{},"Delegate Mode Prompt:",[745,4759,4760],{},"strings $BINARY | grep -A 10 \"You are in delegate mode\"",[1119,4762,4765],{"className":4763,"code":4764,"language":2028},[2026],"You are in delegate mode for team \"${teamName}\".\nIn this mode, you can ONLY use the following tools:\n- TeammateTool: For spawning teammates, sending messages, and team coordination\n- TaskCreate, TaskGet, TaskUpdate, TaskList\n\nYou CANNOT use any other tools (Bash, Read, Write, Edit, etc.)\nuntil you exit delegate mode.\n",[745,4766,4764],{"__ignoreMap":515},[302,4768,4769,2208,4772,1652],{},[326,4770,4771],{},"Shutdown Protocol:",[745,4773,4774],{},"strings $BINARY | grep -A 10 \"You are running in non-interactive\"",[1119,4776,4779],{"className":4777,"code":4778,"language":2028},[2026],"You are running in non-interactive mode and cannot return\na response to the user until your team is shut down.\n\nYou MUST shut down your team before preparing your final response:\n1. Use requestShutdown to ask each team member to shut down gracefully\n2. Wait for shutdown approvals\n3. Use the cleanup operation to clean up the team\n",[745,4780,4778],{"__ignoreMap":515},[401,4782,4784],{"id":4783},"the-operations","The Operations",[302,4786,4787],{},"The TeammateTool supports these operations:",[368,4789,4790,4796,4802,4814,4820,4826,4838,4847],{},[371,4791,4792,4795],{},[745,4793,4794],{},"spawnTeam"," - Create a new team with task list",[371,4797,4798,4801],{},[745,4799,4800],{},"discoverTeams"," - Find existing teams",[371,4803,4804,1199,4807,1199,4810,4813],{},[745,4805,4806],{},"requestJoin",[745,4808,4809],{},"approveJoin",[745,4811,4812],{},"rejectJoin"," - Membership management",[371,4815,4816,4819],{},[745,4817,4818],{},"write"," - Direct message to teammate",[371,4821,4822,4825],{},[745,4823,4824],{},"broadcast"," - Message all teammates",[371,4827,4828,1199,4831,1199,4834,4837],{},[745,4829,4830],{},"requestShutdown",[745,4832,4833],{},"approveShutdown",[745,4835,4836],{},"rejectShutdown"," - Graceful termination",[371,4839,4840,1199,4843,4846],{},[745,4841,4842],{},"approvePlan",[745,4844,4845],{},"rejectPlan"," - Plan approval workflow",[371,4848,4849,4852],{},[745,4850,4851],{},"cleanup"," - Team cleanup",[401,4854,4856],{"id":4855},"the-tier-gating","The Tier Gating",[302,4858,4859],{},"Found this in the binary:",[1119,4861,4865],{"className":4862,"code":4863,"language":4864,"meta":515,"style":515},"language-javascript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","if (H === 'max' && $ === 'default_claude_max_20x') return 3;\nif (H === 'enterprise' || H === 'team') return 3;\nreturn 1;\n","javascript",[745,4866,4867,4872,4877],{"__ignoreMap":515},[1127,4868,4869],{"class":1129,"line":1130},[1127,4870,4871],{},"if (H === 'max' && $ === 'default_claude_max_20x') return 3;\n",[1127,4873,4874],{"class":1129,"line":516},[1127,4875,4876],{},"if (H === 'enterprise' || H === 'team') return 3;\n",[1127,4878,4879],{"class":1129,"line":523},[1127,4880,4881],{},"return 1;\n",[302,4883,4884],{},"Translation: Max and Enterprise tiers get 3 agents. Everyone else gets 1 (effectively disabled).",[318,4886,4888],{"id":4887},"the-architecture","The Architecture",[302,4890,4891],{},"Based on the code, here's how the system is structured:",[401,4893,4895],{"id":4894},"team-structure","Team Structure",[1119,4897,4899],{"className":1121,"code":4898,"language":1123,"meta":515,"style":515},"flowchart LR\n    subgraph Orchestrator\n        Lead[team-lead]\n    end\n\n    subgraph Workers\n        W1[teammate-1]\n        W2[teammate-2]\n        W3[teammate-3]\n    end\n\n    subgraph Storage[\"~\u002F.claude\u002Fteams\u002F\"]\n        Tasks[(task-list.json)]\n    end\n\n    Lead -->|spawns| W1\n    Lead -->|spawns| W2\n    Lead -->|spawns| W3\n\n    W1 & W2 & W3 -->|claim| Tasks\n    W1 & W2 & W3 -.->|done| Lead\n",[745,4900,4901,4905,4910,4915,4919,4923,4928,4933,4938,4943,4947,4951,4956,4961,4965,4969,4974,4979,4984,4988,4993],{"__ignoreMap":515},[1127,4902,4903],{"class":1129,"line":1130},[1127,4904,1133],{},[1127,4906,4907],{"class":1129,"line":516},[1127,4908,4909],{},"    subgraph Orchestrator\n",[1127,4911,4912],{"class":1129,"line":523},[1127,4913,4914],{},"        Lead[team-lead]\n",[1127,4916,4917],{"class":1129,"line":1146},[1127,4918,1893],{},[1127,4920,4921],{"class":1129,"line":1382},[1127,4922,1517],{"emptyLinePlaceholder":538},[1127,4924,4925],{"class":1129,"line":1388},[1127,4926,4927],{},"    subgraph Workers\n",[1127,4929,4930],{"class":1129,"line":1586},[1127,4931,4932],{},"        W1[teammate-1]\n",[1127,4934,4935],{"class":1129,"line":1599},[1127,4936,4937],{},"        W2[teammate-2]\n",[1127,4939,4940],{"class":1129,"line":1647},[1127,4941,4942],{},"        W3[teammate-3]\n",[1127,4944,4945],{"class":1129,"line":1910},[1127,4946,1893],{},[1127,4948,4949],{"class":1129,"line":1915},[1127,4950,1517],{"emptyLinePlaceholder":538},[1127,4952,4953],{"class":1129,"line":1920},[1127,4954,4955],{},"    subgraph Storage[\"~\u002F.claude\u002Fteams\u002F\"]\n",[1127,4957,4958],{"class":1129,"line":1926},[1127,4959,4960],{},"        Tasks[(task-list.json)]\n",[1127,4962,4963],{"class":1129,"line":1932},[1127,4964,1893],{},[1127,4966,4967],{"class":1129,"line":1938},[1127,4968,1517],{"emptyLinePlaceholder":538},[1127,4970,4971],{"class":1129,"line":1944},[1127,4972,4973],{},"    Lead -->|spawns| W1\n",[1127,4975,4976],{"class":1129,"line":1949},[1127,4977,4978],{},"    Lead -->|spawns| W2\n",[1127,4980,4981],{"class":1129,"line":1954},[1127,4982,4983],{},"    Lead -->|spawns| W3\n",[1127,4985,4986],{"class":1129,"line":1960},[1127,4987,1517],{"emptyLinePlaceholder":538},[1127,4989,4990],{"class":1129,"line":1966},[1127,4991,4992],{},"    W1 & W2 & W3 -->|claim| Tasks\n",[1127,4994,4995],{"class":1129,"line":1971},[1127,4996,4997],{},"    W1 & W2 & W3 -.->|done| Lead\n",[401,4999,5001],{"id":5000},"delegate-mode-flow","Delegate Mode Flow",[1119,5003,5005],{"className":1121,"code":5004,"language":1123,"meta":515,"style":515},"flowchart TB\n    Start([Start]) --> Normal\n\n    subgraph Normal[Normal Mode]\n        All[All tools available]\n    end\n\n    Normal -->|enter delegate| Delegate\n\n    subgraph Delegate[Delegate Mode]\n        direction LR\n        Spawn[spawnTeam]\n        Msg[write\u002Fbroadcast]\n        Task[TaskCreate\u002FUpdate]\n    end\n\n    Delegate -->|exit delegate| Normal\n    Delegate -->|restricted| Note[No Bash, Read,\u003Cbr\u002F>Write, Edit]\n",[745,5006,5007,5011,5016,5020,5025,5030,5034,5038,5043,5047,5052,5056,5061,5066,5071,5075,5079,5084],{"__ignoreMap":515},[1127,5008,5009],{"class":1129,"line":1130},[1127,5010,1868],{},[1127,5012,5013],{"class":1129,"line":516},[1127,5014,5015],{},"    Start([Start]) --> Normal\n",[1127,5017,5018],{"class":1129,"line":523},[1127,5019,1517],{"emptyLinePlaceholder":538},[1127,5021,5022],{"class":1129,"line":1146},[1127,5023,5024],{},"    subgraph Normal[Normal Mode]\n",[1127,5026,5027],{"class":1129,"line":1382},[1127,5028,5029],{},"        All[All tools available]\n",[1127,5031,5032],{"class":1129,"line":1388},[1127,5033,1893],{},[1127,5035,5036],{"class":1129,"line":1586},[1127,5037,1517],{"emptyLinePlaceholder":538},[1127,5039,5040],{"class":1129,"line":1599},[1127,5041,5042],{},"    Normal -->|enter delegate| Delegate\n",[1127,5044,5045],{"class":1129,"line":1647},[1127,5046,1517],{"emptyLinePlaceholder":538},[1127,5048,5049],{"class":1129,"line":1910},[1127,5050,5051],{},"    subgraph Delegate[Delegate Mode]\n",[1127,5053,5054],{"class":1129,"line":1915},[1127,5055,1878],{},[1127,5057,5058],{"class":1129,"line":1920},[1127,5059,5060],{},"        Spawn[spawnTeam]\n",[1127,5062,5063],{"class":1129,"line":1926},[1127,5064,5065],{},"        Msg[write\u002Fbroadcast]\n",[1127,5067,5068],{"class":1129,"line":1932},[1127,5069,5070],{},"        Task[TaskCreate\u002FUpdate]\n",[1127,5072,5073],{"class":1129,"line":1938},[1127,5074,1893],{},[1127,5076,5077],{"class":1129,"line":1944},[1127,5078,1517],{"emptyLinePlaceholder":538},[1127,5080,5081],{"class":1129,"line":1949},[1127,5082,5083],{},"    Delegate -->|exit delegate| Normal\n",[1127,5085,5086],{"class":1129,"line":1954},[1127,5087,5088],{},"    Delegate -->|restricted| Note[No Bash, Read,\u003Cbr\u002F>Write, Edit]\n",[401,5090,5092],{"id":5091},"shutdown-protocol","Shutdown Protocol",[1119,5094,5096],{"className":1121,"code":5095,"language":1123,"meta":515,"style":515},"sequenceDiagram\n    participant L as team-lead\n    participant W as teammates\n    participant U as User\n\n    Note over L,U: User blocked until shutdown complete\n\n    L->>W: requestShutdown\n    W-->>L: approveShutdown\n    L->>L: cleanup()\n    L->>U: Final response\n",[745,5097,5098,5102,5107,5112,5117,5121,5126,5130,5135,5140,5145],{"__ignoreMap":515},[1127,5099,5100],{"class":1129,"line":1130},[1127,5101,2098],{},[1127,5103,5104],{"class":1129,"line":516},[1127,5105,5106],{},"    participant L as team-lead\n",[1127,5108,5109],{"class":1129,"line":523},[1127,5110,5111],{},"    participant W as teammates\n",[1127,5113,5114],{"class":1129,"line":1146},[1127,5115,5116],{},"    participant U as User\n",[1127,5118,5119],{"class":1129,"line":1382},[1127,5120,1517],{"emptyLinePlaceholder":538},[1127,5122,5123],{"class":1129,"line":1388},[1127,5124,5125],{},"    Note over L,U: User blocked until shutdown complete\n",[1127,5127,5128],{"class":1129,"line":1586},[1127,5129,1517],{"emptyLinePlaceholder":538},[1127,5131,5132],{"class":1129,"line":1599},[1127,5133,5134],{},"    L->>W: requestShutdown\n",[1127,5136,5137],{"class":1129,"line":1647},[1127,5138,5139],{},"    W-->>L: approveShutdown\n",[1127,5141,5142],{"class":1129,"line":1910},[1127,5143,5144],{},"    L->>L: cleanup()\n",[1127,5146,5147],{"class":1129,"line":1915},[1127,5148,5149],{},"    L->>U: Final response\n",[318,5151,5153],{"id":5152},"verify-it-yourself","Verify It Yourself",[302,5155,5156],{},"Want to confirm this on your own machine? Here's how:",[401,5158,5160],{"id":5159},"find-your-binary","Find Your Binary",[1119,5162,5164],{"className":3307,"code":5163,"language":3309,"meta":515,"style":515},"# Check your version\nclaude --version\n\n# Find where binaries live\nls ~\u002F.local\u002Fshare\u002Fclaude\u002Fversions\u002F\n",[745,5165,5166,5171,5178,5182,5187],{"__ignoreMap":515},[1127,5167,5168],{"class":1129,"line":1130},[1127,5169,5170],{"class":1487},"# Check your version\n",[1127,5172,5173,5175],{"class":1129,"line":516},[1127,5174,2387],{"class":2246},[1127,5176,5177],{"class":1621}," --version\n",[1127,5179,5180],{"class":1129,"line":523},[1127,5181,1517],{"emptyLinePlaceholder":538},[1127,5183,5184],{"class":1129,"line":1146},[1127,5185,5186],{"class":1487},"# Find where binaries live\n",[1127,5188,5189,5192],{"class":1129,"line":1382},[1127,5190,5191],{"class":2246},"ls",[1127,5193,5194],{"class":1621}," ~\u002F.local\u002Fshare\u002Fclaude\u002Fversions\u002F\n",[401,5196,5198],{"id":5197},"search-for-team-functions","Search for Team Functions",[1119,5200,5202],{"className":3307,"code":5201,"language":3309,"meta":515,"style":515},"# Find environment variables\nstrings ~\u002F.local\u002Fshare\u002Fclaude\u002Fversions\u002F2.1.19 | grep -E \"CLAUDE_CODE_(TEAM|AGENT)\" | sort -u\n\n# Find teammate prompts\nstrings ~\u002F.local\u002Fshare\u002Fclaude\u002Fversions\u002F2.1.19 | grep \"You are a teammate\"\n\n# Find TeammateTool operations\nstrings ~\u002F.local\u002Fshare\u002Fclaude\u002Fversions\u002F2.1.19 | grep -E \"spawnTeam|requestShutdown|broadcast\"\n",[745,5203,5204,5209,5233,5237,5242,5259,5263,5268],{"__ignoreMap":515},[1127,5205,5206],{"class":1129,"line":1130},[1127,5207,5208],{"class":1487},"# Find environment variables\n",[1127,5210,5211,5213,5215,5217,5219,5221,5223,5225,5227,5229,5231],{"class":1129,"line":516},[1127,5212,4629],{"class":2246},[1127,5214,4660],{"class":1621},[1127,5216,4663],{"class":1501},[1127,5218,4666],{"class":2246},[1127,5220,4669],{"class":1621},[1127,5222,3750],{"class":1501},[1127,5224,4674],{"class":1621},[1127,5226,3736],{"class":1501},[1127,5228,4663],{"class":1501},[1127,5230,4681],{"class":2246},[1127,5232,4684],{"class":1621},[1127,5234,5235],{"class":1129,"line":523},[1127,5236,1517],{"emptyLinePlaceholder":538},[1127,5238,5239],{"class":1129,"line":1146},[1127,5240,5241],{"class":1487},"# Find teammate prompts\n",[1127,5243,5244,5246,5248,5250,5252,5254,5257],{"class":1129,"line":1382},[1127,5245,4629],{"class":2246},[1127,5247,4660],{"class":1621},[1127,5249,4663],{"class":1501},[1127,5251,4666],{"class":2246},[1127,5253,3750],{"class":1501},[1127,5255,5256],{"class":1621},"You are a teammate",[1127,5258,3756],{"class":1501},[1127,5260,5261],{"class":1129,"line":1388},[1127,5262,1517],{"emptyLinePlaceholder":538},[1127,5264,5265],{"class":1129,"line":1586},[1127,5266,5267],{"class":1487},"# Find TeammateTool operations\n",[1127,5269,5270,5272,5274,5276,5278,5280,5282,5285],{"class":1129,"line":1599},[1127,5271,4629],{"class":2246},[1127,5273,4660],{"class":1621},[1127,5275,4663],{"class":1501},[1127,5277,4666],{"class":2246},[1127,5279,4669],{"class":1621},[1127,5281,3750],{"class":1501},[1127,5283,5284],{"class":1621},"spawnTeam|requestShutdown|broadcast",[1127,5286,3756],{"class":1501},[401,5288,5290],{"id":5289},"check-for-tier-gating","Check for Tier Gating",[1119,5292,5294],{"className":3307,"code":5293,"language":3309,"meta":515,"style":515},"# Look for the agent count logic\nstrings ~\u002F.local\u002Fshare\u002Fclaude\u002Fversions\u002F2.1.19 | grep -E \"max.*enterprise|AGENT_COUNT\"\n",[745,5295,5296,5301],{"__ignoreMap":515},[1127,5297,5298],{"class":1129,"line":1130},[1127,5299,5300],{"class":1487},"# Look for the agent count logic\n",[1127,5302,5303,5305,5307,5309,5311,5313,5315,5318],{"class":1129,"line":516},[1127,5304,4629],{"class":2246},[1127,5306,4660],{"class":1621},[1127,5308,4663],{"class":1501},[1127,5310,4666],{"class":2246},[1127,5312,4669],{"class":1621},[1127,5314,3750],{"class":1501},[1127,5316,5317],{"class":1621},"max.*enterprise|AGENT_COUNT",[1127,5319,3756],{"class":1501},[302,5321,5322,5323,5326],{},"Replace ",[745,5324,5325],{},"2.1.19"," with your version number.",[318,5328,5330],{"id":5329},"what-this-means","What This Means",[401,5332,5334],{"id":5333},"its-real-and-complete","It's Real and Complete",[302,5336,5337],{},"This isn't stub code or a prototype. The prompts are polished. The shutdown protocol is thoughtful - teammates can't just vanish, they have to gracefully terminate. There's a delegate mode that restricts the leader to coordination-only tools. This already looks pretty polished.",[401,5339,5341],{"id":5340},"the-design-reveals-intent","The Design Reveals Intent",[302,5343,5344,5345,1652],{},"The architecture tells us what Anthropic thinks multi-agent workflow looks like and its very close to the Wilson Lin examples. (",[335,5346,4594],{"href":4594,"rel":5347},[461],[851,5349,5350,5365,5371],{},[371,5351,5352,5355,5356,5361,5362],{},[326,5353,5354],{},"Shared task list"," - Teammates don't get private instructions. They pull from a common queue. This prevents the \"telephone game\" problem where agents pass increasingly garbled context to each other. Anthropic just ",[335,5357,5360],{"href":5358,"rel":5359},"https:\u002F\u002Fx.com\u002Ftrq212\u002Fstatus\u002F2014480496013803643",[461],"shipped this with Tasks"," the day before Kieran's discovery: ",[920,5363,5364],{},"\"Tasks are stored in the file system so that multiple subagents or sessions can collaborate on them. When one session updates a Task, that is broadcasted to all sessions currently working on the same Task List.\"",[371,5366,5367,5370],{},[326,5368,5369],{},"Explicit coordination mode"," - The team lead can't directly edit files while coordinating. They have to delegate. This enforces clean separation between orchestration and execution.",[371,5372,5373,5376],{},[326,5374,5375],{},"Idle notifications"," - Workers automatically ping the leader when they finish. The leader doesn't have to poll.",[401,5378,5380],{"id":5379},"where-this-is-going","Where This Is Going",[302,5382,5383,5384,5388],{},"With Tasks already shipping and TeammateTool waiting in the wings, the pieces are falling into place. The architecture is thoughtful - shared task queues, explicit coordination modes, idle notifications. Its elegant in its simpliestiy, matching observations from others like Cursor ",[335,5385,5386],{"href":5386,"rel":5387},"https:\u002F\u002Fcursor.com\u002Fblog\u002Fscaling-agents",[461],"\nThe future of AI coding isn't one agent doing everything sequentially. It's specialized agents collaborating on shared work, each doing what they're best at. And that future is closer than most people realize.",[302,5390,5391,5392],{},"What are you shipping in 2026? ",[335,5393,5396],{"href":5394,"rel":5395},"https:\u002F\u002Fx.com\u002Ftrq212\u002Fstatus\u002F2010895204405092647",[461],"Why not today?",[1698,5398,5399],{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}",{"title":515,"searchDepth":516,"depth":516,"links":5401},[5402,5403,5404,5409,5414,5419],{"id":4603,"depth":516,"text":4604},{"id":4633,"depth":516,"text":4634},{"id":4730,"depth":516,"text":4731,"children":5405},[5406,5407,5408],{"id":4734,"depth":523,"text":4735},{"id":4783,"depth":523,"text":4784},{"id":4855,"depth":523,"text":4856},{"id":4887,"depth":516,"text":4888,"children":5410},[5411,5412,5413],{"id":4894,"depth":523,"text":4895},{"id":5000,"depth":523,"text":5001},{"id":5091,"depth":523,"text":5092},{"id":5152,"depth":516,"text":5153,"children":5415},[5416,5417,5418],{"id":5159,"depth":523,"text":5160},{"id":5197,"depth":523,"text":5198},{"id":5289,"depth":523,"text":5290},{"id":5329,"depth":516,"text":5330,"children":5420},[5421,5422,5423],{"id":5333,"depth":523,"text":5334},{"id":5340,"depth":523,"text":5341},{"id":5379,"depth":523,"text":5380},"2026-01-24","I verified the claim - there's a fully-implemented TeammateTool hiding in Claude Code, feature-flagged but ready to go.",{"src":5427,"alt":5428},"\u002Fimages\u002Fblog\u002F20260124-1200-claude-code-hidden-multi-agent-system.jpeg","A dramatic overhead view of a central glowing orchestrator node connected by luminous data streams to three specialized worker nodes arranged in a triangle formation, floating above a dark terminal screen showing binary code and system strings. The orchestrator pulses with warm amber light while the workers glow cool cyan, their connections forming a constellation of collaboration. Cinematic lighting with deep shadows and volumetric light rays cutting through a subtle digital fog, photorealistic 8k quality with shallow depth of field focusing on the central node. Sci-fi atmosphere, high contrast teal and orange color grading, 16:9 composition with negative space on the left for text overlay.",{"draft":538},{"title":157,"description":5425},"grLEfvHK1n3Wq8VMqA1Qx7gTjupq3IegOdR9iFDvwLI",{"id":5433,"title":153,"authors":5434,"badge":5437,"body":5438,"date":5549,"description":5550,"extension":533,"image":5551,"meta":5554,"navigation":538,"path":154,"seo":5555,"status":540,"stem":155,"__hash__":5556},"posts\u002F2.blog\u002F20260119.goodharts-law-ate-my-context-window.md",[5435],{"name":292,"to":293,"avatar":5436},{"src":295},{"label":548},{"type":299,"value":5439,"toc":5543},[5440,5443,5450,5456,5460,5463,5466,5473,5477,5480,5483,5486,5489,5493,5496,5507,5510,5513,5517,5525,5537,5540],[302,5441,5442],{},"When you measure something, it becomes the goal. That's Goodhart's Law. I learned it the hard way last week while watching my ralph wiggum loop run.",[302,5444,5445,5446,5449],{},"I'd gotten clever with session resumption. Each iteration would fork from a previous session, loading all that rich context - file discoveries, architectural understanding, previous decisions. The loops looked ",[920,5447,5448],{},"smart",". They'd start running and immediately seem to know what they were doing.",[302,5451,5452,5453,1207],{},"Here's what I was actually optimizing for: ",[326,5454,5455],{},"looking productive while I watched",[318,5457,5459],{"id":5458},"the-seduction","The Seduction",[302,5461,5462],{},"The loops appeared to take action faster. Less \"figuring out\" time, more \"doing\" time. When I'd check in on a running loop, Claude was already deep in the work - reading files, making edits, running tests. No warm-up period. No re-discovery phase.",[302,5464,5465],{},"It felt like progress. I'd built something clever.",[302,5467,5468,5469,5472],{},"I even ",[335,5470,5471],{"href":150},"wrote a whole blog post"," about the session marker system. Showed off the code. Explained the workflow. Felt pretty good about it.",[318,5474,5476],{"id":5475},"the-reality","The Reality",[302,5478,5479],{},"Context windows are finite. Every byte I pre-loaded for appearances was a byte I couldn't use for thinking through hard problems.",[302,5481,5482],{},"My loops looked fast because they skipped the exploration phase. But exploration isn't waste - it's where Claude builds a mental model of the problem. By pre-loading \"answers\" from previous sessions, I was forcing Claude to work with stale context instead of fresh understanding.",[302,5484,5485],{},"The hard problems - the ones that actually needed solving - got squeezed. Claude would hit the context limit right when the thinking needed to get deep. The loop would compact, lose nuance, and produce shallow solutions.",[302,5487,5488],{},"I was optimizing for the spectator experience. Making myself feel good watching the terminal. Meanwhile, the actual work suffered.",[318,5490,5492],{"id":5491},"the-fix","The Fix",[302,5494,5495],{},"Strip it back. Only load what's critical:",[368,5497,5498,5501,5504],{},[371,5499,5500],{},"Spend time in planning sessions to actually plan.",[371,5502,5503],{},"Review the plan carefully - time spent here is much cheaper than fixing bad execution.",[371,5505,5506],{},"Keep context to whats critical",[302,5508,5509],{},"Let Claude rediscover the codebase each iteration. Yes, it looks slower at the start. Yes, there's a \"figuring out\" phase. But that phase builds fresh context - context that's available when the hard thinking needs to happen.",[302,5511,5512],{},"Reserve the context budget for problem-solving, not for looking smart.",[318,5514,5516],{"id":5515},"building-in-public-means-showing-the-screwups","Building in Public Means Showing the Screwups",[302,5518,5519,5520,5524],{},"I ",[335,5521,5523],{"href":5522},"\u002Fblog\u002Fimplementing-ralph-wiggum-loop-for-autonomous-ai-coding#the-secret-session-markers","struck through the session markers section"," in my previous post. It's still there - you can see what I thought was clever. You can also see the warning that it was wrong.",[302,5526,5527,5528,5531,5532,5536],{},"That's the deal with building in public. You ship your mistakes alongside your wins. The lesson here isn't \"session resumption is bad\" - it's that ",[326,5529,5530],{},"what you optimize for becomes your goal, whether you meant it to or not",". I've since updated ",[335,5533,462],{"href":5534,"rel":5535},"https:\u002F\u002Fgithub.com\u002FChrisTowles\u002Ftowles-tool\u002F",[461]," and removed all the session marker stuff.",[302,5538,5539],{},"I measured \"looks fast.\" I got \"looks fast.\" I didn't get \"solves hard problems.\"",[302,5541,5542],{},"Choose your metrics carefully.",{"title":515,"searchDepth":516,"depth":516,"links":5544},[5545,5546,5547,5548],{"id":5458,"depth":516,"text":5459},{"id":5475,"depth":516,"text":5476},{"id":5491,"depth":516,"text":5492},{"id":5515,"depth":516,"text":5516},"2026-01-19","I optimized my AI coding loop for the wrong thing. It looked fast. It wasn't effective.",{"src":5552,"alt":5553},"\u002Fimages\u002Fblog\u002F20260119-1200-goodharts-law-with-context-window.jpeg","A developer's workspace showing a dramatic split-screen visualization: on the left monitor, a progress bar racing forward with flashy green metrics and spinning activity indicators; on the right monitor, the same task failing silently with truncated output and a warning symbol. A magnifying glass held between the screens reveals the progress bar is hollow - a beautiful shell with nothing inside. Dramatic chiaroscuro lighting with cool blue from the monitors contrasting against warm amber desk lamp, shallow depth of field focusing on the magnifying glass revelation. Cinematic realism, 8k photorealistic quality, noir atmosphere with teal and orange color grading, slightly elevated three-quarter angle capturing the moment of uncomfortable truth.",{"draft":538},{"title":153,"description":5550},"51GX0jz5tpYkJ3L6e9zGN9U3aLVusjnFaH3XwzmddYM",{"id":5558,"title":149,"authors":5559,"badge":5562,"body":5563,"date":6331,"description":6332,"extension":533,"image":6333,"meta":6336,"navigation":538,"path":150,"seo":6337,"status":540,"stem":151,"__hash__":6338},"posts\u002F2.blog\u002F20260114.implementing-ralph-wiggum-loop-for-autonomous-ai-coding.md",[5560],{"name":292,"to":293,"avatar":5561},{"src":295},{"label":548},{"type":299,"value":5564,"toc":6323},[5565,5572,5581,5586,5592,5595,5599,5602,5617,5621,5628,5635,5638,5649,5653,5656,5659,5683,5693,5699,5702,5714,5733,5739,5747,5752,5765,5773,5778,6056,6061,6161,6170,6174,6183,6186,6192,6196,6228,6231,6237,6241,6244,6254,6264,6267,6305,6308,6310,6320],[302,5566,5567,5568,5571],{},"There's an AI coding pattern that lets you run seriously long-running agents - for hours at a time - that ship code while you sleep. It's called the ",[326,5569,5570],{},"Ralph Wiggum loop",", named after the haplessly persistent Simpsons character.",[302,5573,5574,5575,5580],{},"I'd been tinkering with this pattern since Claude Code's early skill system - trying to run loops in interactive sessions, wrestling with state management, burning through context limits. Then Matt Pocock ",[335,5576,5579],{"href":5577,"rel":5578},"https:\u002F\u002Fwww.aihero.dev\u002Ftips-for-ai-coding-with-ralph-wiggum",[461],"published his approach",", and one thing clicked immediately:",[302,5582,5583],{},[326,5584,5585],{},"Use a bash shell. Not an interactive session.",[302,5587,5588,5589,5591],{},"It sounds obvious in retrospect. Why was I trying to manage loops inside Claude Code's interactive session when I could just... run ",[745,5590,2387],{}," from a bash while loop? Queue up the work, let Claude figure out what to do next, repeat until done.",[302,5593,5594],{},"After a weekend of burning through tokens, migrating from pnpm to Bun (and back), and discovering the critical importance of session markers, I finally got it working. Here's what I learned.",[318,5596,5598],{"id":5597},"what-is-a-ralph-wiggum-loop","What is a Ralph Wiggum Loop?",[302,5600,5601],{},"The pattern is elegantly simple: a while loop that feeds Claude a prompt, Claude works on the code, and when Claude attempts to exit, a hook checks if work is truly done. If not, it re-feeds the same prompt. Each iteration carries forward all context - the modified files, git history, previous test results - allowing Claude to learn from its own output.",[302,5603,5604,5605,5610,5611,5616],{},"Matt Pocock describes it as \"a keep-it-simple-stupid approach to AI coding.\" There's an official ",[335,5606,5609],{"href":5607,"rel":5608},"https:\u002F\u002Fgithub.com\u002Fanthropics\u002Fclaude-code\u002Fblob\u002Fmain\u002Fplugins\u002Fralph-wiggum\u002FREADME.md",[461],"Claude Code plugin",", but the pattern was created by ",[335,5612,5615],{"href":5613,"rel":5614},"https:\u002F\u002Fghuntley.com\u002Fralph\u002F",[461],"Geoffrey Huntley",". It's been all over X and Reddit - but how do you leverage it in your own projects?",[318,5618,5620],{"id":5619},"the-aha-moment-queue-dont-direct","The Aha Moment: Queue, Don't Direct",[302,5622,5623,5624,5627],{},"Before Matt's video, I was thinking about this wrong. I'd start an interactive Claude Code session, add tasks to a state file, then try to run a loop ",[920,5625,5626],{},"inside"," the conversation. Complex prompt engineering. Hooks to detect exit conditions. State management within the session.",[302,5629,5630,5631,5634],{},"The insight from Matt's approach: ",[326,5632,5633],{},"let Claude decide what to work on",". You're not micro-managing each step. You queue up tasks, give Claude access to a state file, and run the CLI in a bash loop. Each iteration, Claude reads the state, picks a task, does the work, marks it done, and exits. The loop restarts, Claude picks the next task.",[302,5636,5637],{},"It's mechanical. It's simple. It works overnight while you sleep.",[302,5639,5640,5641,5644,5645,5648],{},"One thing that made a huge difference: ",[326,5642,5643],{},"task instructions in the system prompt",". towles-tool injects the current task and workflow rules into the system prompt via ",[745,5646,5647],{},"--append-system-prompt",", not just the user message. This keeps Claude focused on the current task much longer and more successfully than putting instructions in the prompt itself. The system prompt is \"always there\" in a way that user messages aren't.",[318,5650,5652],{"id":5651},"the-token-burn-weekend-or-why-i-have-a-file-named-never_again","The Token Burn Weekend (Or: Why I Have a File Named NEVER_AGAIN)",[302,5654,5655],{},"One December weekend, I set up what I thought was a reasonable experiment: let Claude work autonomously on a complex feature - personas, chatbots, skills, database schema changes. I ran the loop overnight.",[302,5657,5658],{},"I woke up to this in my state file:",[1119,5660,5662],{"className":2237,"code":5661,"language":2239,"meta":515,"style":515},"iteration: 10\nmax_iterations: 10\n",[745,5663,5664,5674],{"__ignoreMap":515},[1127,5665,5666,5669,5671],{"class":1129,"line":1130},[1127,5667,5668],{"class":1550},"iteration",[1127,5670,1554],{"class":1501},[1127,5672,5673],{"class":1580}," 10\n",[1127,5675,5676,5679,5681],{"class":1129,"line":516},[1127,5677,5678],{"class":1550},"max_iterations",[1127,5680,1554],{"class":1501},[1127,5682,5673],{"class":1580},[302,5684,5685,5688,5689,5692],{},[326,5686,5687],{},"10 iterations."," I'd set ",[745,5690,5691],{},"max_iterations: 10"," and gone to sleep. The commit message from that night says it all: I'd burned through all my tokens, and I'm on the $100 plan.",[302,5694,5695,5696,1207],{},"The state file got renamed to ",[745,5697,5698],{},".claude\u002Fralph-loop.local.md-NEVER_AGAIN",[302,5700,5701],{},"The problem wasn't just the raw token count. Each iteration built on the previous one's context. Even with compaction, Claude Code is much smarter in the first 40% of the context window than when it's full and trying to compact.",[302,5703,2221,5704,5709,5710,5713],{},[335,5705,5708],{"href":5706,"rel":5707},"https:\u002F\u002Fgithub.com\u002FChrisTowles\u002Ftowles-tool\u002Fcommit\u002Fee6db37",[461],"commit that changed everything on 2026-01-11",": ",[745,5711,5712],{},"feat(ralph): auto-resume sessions per-task to prevent token burn",". That commit message tells the story. After the NEVER_AGAIN incident, I had to figure out how to preserve context between iterations but not fill up the context, find that sweet spot where Claude has enough context to be effective without burning through tokens unnecessarily.",[1048,5715,5717],{"type":5716},"warning",[302,5718,5719,5722,5723,5726,5727,5730,5731,1207],{},[326,5720,5721],{},"Update (Jan 19):"," The section below was a mistake. I was optimizing for the wrong thing - making loops ",[920,5724,5725],{},"look"," fast instead of ",[920,5728,5729],{},"work"," effectively. See ",[335,5732,153],{"href":154},[302,5734,5735],{},[5736,5737,5738],"del",{},"## The Secret: Session Markers",[302,5740,5741],{},[5736,5742,5743,5744,1207],{},"Assigning tasks to Claude Code in a \"headless\" manner (a bash loop) is half the battle. How do you give Claude the right context for each task without starting from scratch every time? Usually you'd write a plan.md file, right? But even with a half page of markdown, Claude still has a lot of intent to figure out. I needed to preserve context more effectively. My solution: ",[326,5745,5746],{},"session markers",[302,5748,5749],{},[5736,5750,5751],{},"I think it was Boris Cherny who had tweeted about this, couldn't find it again - pointing out that Claude Code already has a way to resume sessions which forks them!",[302,5753,5754],{},[5736,5755,5756,5757,5760,5761,5764],{},"Claude Code stores conversation history in JSONL files at ",[745,5758,5759],{},"~\u002F.claude\u002Fprojects\u002F",". Each file represents a session. If you can find the right session, you can resume from it with ",[745,5762,5763],{},"--resume \u003Csession-id>",", and Claude picks up exactly where it left off.",[302,5766,5767],{},[5736,5768,5769,5770,1207],{},"The insight that changed everything: ",[326,5771,5772],{},"generate a random marker, have Claude output it during research, then search for that marker to find the session",[302,5774,5775],{},[5736,5776,5777],{},"Something like:",[1119,5779,5781],{"className":1478,"code":5780,"language":1480,"meta":515,"style":515},"\u002F\u002F From marker.ts - the core of the system\nexport const MARKER_PREFIX = 'RALPH_MARKER_';\n\nexport function generateMarker(): string {\n  const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';\n  let result = '';\n  for (let i = 0; i \u003C 8; i++) {\n    result += chars.charAt(Math.floor(Math.random() * chars.length));\n  }\n  return result;\n}\n\nexport async function findSessionByMarker(marker: string): Promise\u003Cstring | null> {\n  const projectDir = getProjectDir();\n  \u002F\u002F ... search all .jsonl files for the marker\n  \u002F\u002F return the session ID (filename without .jsonl)\n}\n",[745,5782,5783,5788,5810,5814,5833,5853,5868,5908,5960,5965,5974,5979,5983,6025,6042,6047,6052],{"__ignoreMap":515},[1127,5784,5785],{"class":1129,"line":1130},[1127,5786,5787],{"class":1487},"\u002F\u002F From marker.ts - the core of the system\n",[1127,5789,5790,5793,5796,5799,5801,5803,5806,5808],{"class":1129,"line":516},[1127,5791,5792],{"class":2270},"export",[1127,5794,5795],{"class":1493}," const",[1127,5797,5798],{"class":1497}," MARKER_PREFIX ",[1127,5800,1502],{"class":1501},[1127,5802,1618],{"class":1501},[1127,5804,5805],{"class":1621},"RALPH_MARKER_",[1127,5807,1625],{"class":1501},[1127,5809,1512],{"class":1501},[1127,5811,5812],{"class":1129,"line":523},[1127,5813,1517],{"emptyLinePlaceholder":538},[1127,5815,5816,5818,5821,5824,5827,5830],{"class":1129,"line":1146},[1127,5817,5792],{"class":2270},[1127,5819,5820],{"class":1493}," function",[1127,5822,5823],{"class":1505}," generateMarker",[1127,5825,5826],{"class":1501},"():",[1127,5828,5829],{"class":2246}," string",[1127,5831,5832],{"class":1501}," {\n",[1127,5834,5835,5838,5841,5844,5846,5849,5851],{"class":1129,"line":1382},[1127,5836,5837],{"class":1493},"  const",[1127,5839,5840],{"class":1497}," chars",[1127,5842,5843],{"class":1501}," =",[1127,5845,1618],{"class":1501},[1127,5847,5848],{"class":1621},"abcdefghijklmnopqrstuvwxyz0123456789",[1127,5850,1625],{"class":1501},[1127,5852,1512],{"class":1501},[1127,5854,5855,5858,5861,5863,5866],{"class":1129,"line":1388},[1127,5856,5857],{"class":1493},"  let",[1127,5859,5860],{"class":1497}," result",[1127,5862,5843],{"class":1501},[1127,5864,5865],{"class":1501}," ''",[1127,5867,1512],{"class":1501},[1127,5869,5870,5873,5875,5878,5881,5883,5886,5888,5890,5893,5896,5898,5900,5903,5906],{"class":1129,"line":1586},[1127,5871,5872],{"class":2270},"  for",[1127,5874,2208],{"class":1550},[1127,5876,5877],{"class":1493},"let",[1127,5879,5880],{"class":1497}," i",[1127,5882,5843],{"class":1501},[1127,5884,5885],{"class":1580}," 0",[1127,5887,3701],{"class":1501},[1127,5889,5880],{"class":1497},[1127,5891,5892],{"class":1501}," \u003C",[1127,5894,5895],{"class":1580}," 8",[1127,5897,3701],{"class":1501},[1127,5899,5880],{"class":1497},[1127,5901,5902],{"class":1501},"++",[1127,5904,5905],{"class":1550},") ",[1127,5907,1545],{"class":1501},[1127,5909,5910,5913,5916,5918,5920,5923,5925,5928,5930,5933,5935,5937,5939,5942,5945,5948,5950,5952,5955,5958],{"class":1129,"line":1599},[1127,5911,5912],{"class":1497},"    result",[1127,5914,5915],{"class":1501}," +=",[1127,5917,5840],{"class":1497},[1127,5919,1207],{"class":1501},[1127,5921,5922],{"class":1505},"charAt",[1127,5924,1542],{"class":1550},[1127,5926,5927],{"class":1497},"Math",[1127,5929,1207],{"class":1501},[1127,5931,5932],{"class":1505},"floor",[1127,5934,1542],{"class":1550},[1127,5936,5927],{"class":1497},[1127,5938,1207],{"class":1501},[1127,5940,5941],{"class":1505},"random",[1127,5943,5944],{"class":1550},"() ",[1127,5946,5947],{"class":1501},"*",[1127,5949,5840],{"class":1497},[1127,5951,1207],{"class":1501},[1127,5953,5954],{"class":1497},"length",[1127,5956,5957],{"class":1550},"))",[1127,5959,1512],{"class":1501},[1127,5961,5962],{"class":1129,"line":1647},[1127,5963,5964],{"class":1501},"  }\n",[1127,5966,5967,5970,5972],{"class":1129,"line":1910},[1127,5968,5969],{"class":2270},"  return",[1127,5971,5860],{"class":1497},[1127,5973,1512],{"class":1501},[1127,5975,5976],{"class":1129,"line":1915},[1127,5977,5978],{"class":1501},"}\n",[1127,5980,5981],{"class":1129,"line":1920},[1127,5982,1517],{"emptyLinePlaceholder":538},[1127,5984,5985,5987,5990,5992,5995,5997,6001,6003,6005,6008,6011,6013,6016,6018,6021,6023],{"class":1129,"line":1926},[1127,5986,5792],{"class":2270},[1127,5988,5989],{"class":1493}," async",[1127,5991,5820],{"class":1493},[1127,5993,5994],{"class":1505}," findSessionByMarker",[1127,5996,1542],{"class":1501},[1127,5998,6000],{"class":5999},"sHdIc","marker",[1127,6002,1554],{"class":1501},[1127,6004,5829],{"class":2246},[1127,6006,6007],{"class":1501},"):",[1127,6009,6010],{"class":2246}," Promise",[1127,6012,2376],{"class":1501},[1127,6014,6015],{"class":2246},"string",[1127,6017,4663],{"class":1501},[1127,6019,6020],{"class":2246}," null",[1127,6022,2380],{"class":1501},[1127,6024,5832],{"class":1501},[1127,6026,6027,6029,6032,6034,6037,6040],{"class":1129,"line":1932},[1127,6028,5837],{"class":1493},[1127,6030,6031],{"class":1497}," projectDir",[1127,6033,5843],{"class":1501},[1127,6035,6036],{"class":1505}," getProjectDir",[1127,6038,6039],{"class":1550},"()",[1127,6041,1512],{"class":1501},[1127,6043,6044],{"class":1129,"line":1938},[1127,6045,6046],{"class":1487},"  \u002F\u002F ... search all .jsonl files for the marker\n",[1127,6048,6049],{"class":1129,"line":1944},[1127,6050,6051],{"class":1487},"  \u002F\u002F return the session ID (filename without .jsonl)\n",[1127,6053,6054],{"class":1129,"line":1949},[1127,6055,5978],{"class":1501},[302,6057,6058],{},[5736,6059,6060],{},"The workflow looks like this:",[1119,6062,6064],{"className":3307,"code":6063,"language":3309,"meta":515,"style":515},"# 1. Generate a marker\ntt ralph marker create\n# Output: RALPH_MARKER_abc12345\n\n# 2. Do your research with Claude, telling it to output the marker\n# \"When you've gathered all the context needed, output: RALPH_MARKER_abc12345\"\n\n# 3. Add tasks with the marker\ntt ralph task add \"Implement the feature\" --findMarker RALPH_MARKER_abc12345\n# ✓ Added task #1 with session: 7a9f3b2c...\n\n# 4. Run ralph - it automatically forks from the research session!\ntt ralph run\n",[745,6065,6066,6071,6085,6090,6094,6099,6104,6108,6113,6138,6143,6147,6152],{"__ignoreMap":515},[1127,6067,6068],{"class":1129,"line":1130},[1127,6069,6070],{"class":1487},"# 1. Generate a marker\n",[1127,6072,6073,6076,6079,6082],{"class":1129,"line":516},[1127,6074,6075],{"class":2246},"tt",[1127,6077,6078],{"class":1621}," ralph",[1127,6080,6081],{"class":1621}," marker",[1127,6083,6084],{"class":1621}," create\n",[1127,6086,6087],{"class":1129,"line":523},[1127,6088,6089],{"class":1487},"# Output: RALPH_MARKER_abc12345\n",[1127,6091,6092],{"class":1129,"line":1146},[1127,6093,1517],{"emptyLinePlaceholder":538},[1127,6095,6096],{"class":1129,"line":1382},[1127,6097,6098],{"class":1487},"# 2. Do your research with Claude, telling it to output the marker\n",[1127,6100,6101],{"class":1129,"line":1388},[1127,6102,6103],{"class":1487},"# \"When you've gathered all the context needed, output: RALPH_MARKER_abc12345\"\n",[1127,6105,6106],{"class":1129,"line":1586},[1127,6107,1517],{"emptyLinePlaceholder":538},[1127,6109,6110],{"class":1129,"line":1599},[1127,6111,6112],{"class":1487},"# 3. Add tasks with the marker\n",[1127,6114,6115,6117,6119,6122,6125,6127,6130,6132,6135],{"class":1129,"line":1647},[1127,6116,6075],{"class":2246},[1127,6118,6078],{"class":1621},[1127,6120,6121],{"class":1621}," task",[1127,6123,6124],{"class":1621}," add",[1127,6126,3750],{"class":1501},[1127,6128,6129],{"class":1621},"Implement the feature",[1127,6131,3736],{"class":1501},[1127,6133,6134],{"class":1621}," --findMarker",[1127,6136,6137],{"class":1621}," RALPH_MARKER_abc12345\n",[1127,6139,6140],{"class":1129,"line":1910},[1127,6141,6142],{"class":1487},"# ✓ Added task #1 with session: 7a9f3b2c...\n",[1127,6144,6145],{"class":1129,"line":1915},[1127,6146,1517],{"emptyLinePlaceholder":538},[1127,6148,6149],{"class":1129,"line":1920},[1127,6150,6151],{"class":1487},"# 4. Run ralph - it automatically forks from the research session!\n",[1127,6153,6154,6156,6158],{"class":1129,"line":1926},[1127,6155,6075],{"class":2246},[1127,6157,6078],{"class":1621},[1127,6159,6160],{"class":1621}," run\n",[302,6162,6163],{},[5736,6164,6165,6166,6169],{},"Each task now carries its own ",[745,6167,6168],{},"sessionId",". When ralph runs that task, it forks from that session. Claude starts with all the codebase knowledge from the research phase - no more burning tokens re-discovering the same files, doing redundant work, or losing context between iterations.",[318,6171,6173],{"id":6172},"real-results","Real Results",[302,6175,6176,6177,6182],{},"My first real test: ",[335,6178,6181],{"href":6179,"rel":6180},"https:\u002F\u002Fgithub.com\u002FChrisTowles\u002Fblog\u002Fpull\u002F162",[461],"reviewing every blog post in my repository",". I created 37 tasks - one per post - ran ralph overnight, and woke up to grammar fixes, improved clarity, consistent formatting, all committed individually with meaningful messages.",[302,6184,6185],{},"I've since used it for harder tasks like converting this blog's AI chat from API-driven to websockets. Ralph with session markers worked first try the morning after - the previous two attempts (once partnering, once solo) had burned through my token quota without success.",[302,6187,6188],{},[467,6189],{"alt":6190,"src":6191},"Towles-tool ralph loop results","\u002Fimages\u002Fblog\u002F20260114-ralph-loop-terminal.png",[318,6193,6195],{"id":6194},"lessons-learned","Lessons Learned",[851,6197,6198,6204,6210,6216,6222],{},[371,6199,6200,6203],{},[326,6201,6202],{},"Context is everything",". A loop without session preservation is just expensive repetition.",[371,6205,6206,6209],{},[326,6207,6208],{},"The marker trick is the secret sauce",". Generate a random string, have Claude output it, search for it later. Simple but powerful.",[371,6211,6212,6215],{},[326,6213,6214],{},"Start with HITL, then go AFK",". Matt's advice: run interactively first, verify it's working, then let it run autonomously.",[371,6217,6218,6221],{},[326,6219,6220],{},"Set conservative iteration limits",". A 20-iteration loop is plenty - more work than you can do in a single night, and likely more than you can review in one sitting.",[371,6223,6224,6227],{},[326,6225,6226],{},"Token efficiency compounds",". Do the work once, save the session, fork from it for subsequent tasks. This avoids redundant context rebuilding and saves both time and API credits.",[302,6229,6230],{},"I built token visualization into towles-tool to see where my quota was going. A treemap ended up being more informative than a flamegraph:",[302,6232,6233],{},[467,6234],{"alt":6235,"src":6236},"Token usage treemap visualization showing Claude session costs","\u002Fimages\u002Fblog\u002F20260114-token-usage-treemap.png",[318,6238,6240],{"id":6239},"try-it","Try It",[302,6242,6243],{},"The code is open source:",[368,6245,6246],{},[371,6247,6248,5709,6250],{},[326,6249,462],{},[335,6251,6253],{"href":459,"rel":6252},[461],"github.com\u002FChrisTowles\u002Ftowles-tool",[302,6255,6256,6257,6260,6261,1207],{},"Install with ",[745,6258,6259],{},"npm install -g @towles\u002Ftool"," and start with ",[745,6262,6263],{},"tt ralph --help",[302,6265,6266],{},"And install the Claude Code plugin:",[1119,6268,6270],{"className":3307,"code":6269,"language":3309,"meta":515,"style":515},"claude plugin marketplace add ChrisTowles\u002Ftowles-tool\nclaude plugin install tt@towles-tool --scope user\n",[745,6271,6272,6287],{"__ignoreMap":515},[1127,6273,6274,6276,6279,6282,6284],{"class":1129,"line":1130},[1127,6275,2387],{"class":2246},[1127,6277,6278],{"class":1621}," plugin",[1127,6280,6281],{"class":1621}," marketplace",[1127,6283,6124],{"class":1621},[1127,6285,6286],{"class":1621}," ChrisTowles\u002Ftowles-tool\n",[1127,6288,6289,6291,6293,6296,6299,6302],{"class":1129,"line":516},[1127,6290,2387],{"class":2246},[1127,6292,6278],{"class":1621},[1127,6294,6295],{"class":1621}," install",[1127,6297,6298],{"class":1621}," tt@towles-tool",[1127,6300,6301],{"class":1621}," --scope",[1127,6303,6304],{"class":1621}," user\n",[302,6306,6307],{},"The Ralph Wiggum loop isn't magic - it's just a while loop. Claude Code is the magic. But add session forking and context preservation, and you get real leverage. Get those right, and you can ship while you sleep without blowing through your token quota.",[3286,6309],{},[302,6311,6312],{},[920,6313,6314,6315,6319],{},"Thanks to ",[335,6316,6318],{"href":5577,"rel":6317},[461],"Matt Pocock"," for writing about Ralph Wiggum loops and inspiring this implementation.",[1698,6321,6322],{},"html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":515,"searchDepth":516,"depth":516,"links":6324},[6325,6326,6327,6328,6329,6330],{"id":5597,"depth":516,"text":5598},{"id":5619,"depth":516,"text":5620},{"id":5651,"depth":516,"text":5652},{"id":6172,"depth":516,"text":6173},{"id":6194,"depth":516,"text":6195},{"id":6239,"depth":516,"text":6240},"2026-01-14","How I turned towles-tool into an autonomous AI coding system using session markers to preserve context across iterations - and the weekend of mistakes that got me there.",{"src":6334,"alt":6335},"\u002Fimages\u002Fblog\u002F20260114-1530-ralph-wiggum-loop.png","A developer's desk at 3am illuminated by multiple monitors showing endless loops of terminal output and code, an empty coffee mug and scattered energy drink cans nearby. One monitor displays a glowing circular arrow symbol representing infinite iteration, another shows JSONL session files being connected like constellation lines. Dramatic blue screen glow contrasts with warm desk lamp creating noir atmosphere, shallow depth of field focusing on a sticky note reading ",{"draft":538},{"title":149,"description":6332},"ByTDw_2QFaknyJ9qGDfQhHa85TU8soenvQy5iA3ZPNA",{"id":6340,"title":145,"authors":6341,"badge":6344,"body":6346,"date":6484,"description":6485,"extension":533,"image":6486,"meta":6489,"navigation":538,"path":146,"seo":6490,"status":540,"stem":147,"__hash__":6491},"posts\u002F2.blog\u002F20251229.sleeping-on-zellij.md",[6342],{"name":292,"to":293,"avatar":6343},{"src":295},{"label":6345},"Tools",{"type":299,"value":6347,"toc":6476},[6348,6352,6355,6358,6362,6365,6372,6375,6379,6382,6388,6391,6397,6400,6403,6409,6413,6416,6419,6423,6426,6457,6460,6463,6467],[318,6349,6351],{"id":6350},"why-i-never-used-tmux","Why I Never Used tmux",[302,6353,6354],{},"Never got into tmux. The keybindings felt arcane, the config was intimidating, and I just... used multiple terminal windows. I've been oh-my-zsh-ing and iTerm2-ing my way through life without a multiplexer. Like a savage.",[302,6356,6357],{},"As part of working with my brother Patrick on a project, he recommended I try Zellij or Zed. Zellij is Rust, and everything my brother builds is Rust, so I'm giving it a shot.",[318,6359,6361],{"id":6360},"the-problem-that-finally-made-me-try-one","The Problem That Finally Made Me Try One",[302,6363,6364],{},"I've been searching for a better Claude Code workflow. I keep switching between terminal windows, browser tabs, and editors. Claude can spin up agents on tasks beautifully, but I wasn't managing my own mental context well.",[302,6366,6367,6368,6371],{},"Here's my typical disaster: I'd open 5 terminal windows in VS Code, each running different Claude sessions. Then VS Code would crash (probably from all the Claude Code output flickering). I'd lose everything and have to piece it back together by checking ",[745,6369,6370],{},"claude --resume"," threads, trying to figure out which ones were done and which were still working.",[302,6373,6374],{},"Add multiple repos, git worktrees, and branches to the mix? Chaos.",[318,6376,6378],{"id":6377},"discovering-zellij","Discovering Zellij",[302,6380,6381],{},"Zellij caught my attention because it solves the exact problem I was having - persistent panes that survive crashes, with an interface that doesn't require memorizing cryptic keybindings.",[302,6383,6384,6387],{},[326,6385,6386],{},"My biggest tip if you're new",": Start with the defaults. Don't customize anything yet.",[302,6389,6390],{},"I made the classic mistake of having Claude help me set up a fancy layout on day one. It looked great:",[302,6392,6393],{},[467,6394],{"alt":6395,"src":6396},"Zellij layout with Claude Code and Vite dev server in two panes","\u002Fimages\u002Fblog\u002F20251229-zellij-claude-suggested-layout.png",[302,6398,6399],{},"But I had no idea what any of the keybindings did. I spent the first hour completely lost, fighting against config I didn't understand.",[302,6401,6402],{},"So I scrapped it and started over with the stock layout. The default shows all keybindings on screen, making it easy to learn as you go:",[302,6404,6405],{},[467,6406],{"alt":6407,"src":6408},"Zellij multi-pane workflow with Claude Code agents running in parallel","\u002Fimages\u002Fblog\u002F20251229-zellij-multipane-workflow.png",[318,6410,6412],{"id":6411},"the-lesson-i-keep-re-learning","The Lesson I Keep Re-Learning",[302,6414,6415],{},"This is a mistake I make over and over for years with every new tool or framework: trying to make it behave like my old setup before I understand it on its own terms.",[302,6417,6418],{},"Someone spent a lot of time thinking about their tool's design and made deliberate tradeoffs. When I immediately try to customize it to feel \"familiar,\" I'm fighting against that design. Better to learn the tool as intended first, then customize once I understand what I'm changing and why.",[318,6420,6422],{"id":6421},"early-impressions","Early Impressions",[302,6424,6425],{},"Still figuring out the ideal workflow, but I'm already loving:",[368,6427,6428,6439,6445,6451],{},[371,6429,6430,6433,6434],{},[326,6431,6432],{},"Multi-pane persistence"," - No more losing context when VS Code crashes\n",[368,6435,6436],{},[371,6437,6438],{},"Also, naming the panes helps me remember what each is doing",[371,6440,6441,6444],{},[326,6442,6443],{},"Easy pane management"," - Splitting, resizing, and navigating panes is intuitive",[371,6446,6447,6450],{},[326,6448,6449],{},"Discoverable keybindings"," - The on-screen hints actually teach you as you work",[371,6452,6453,6456],{},[326,6454,6455],{},"Stackable panes"," - Great for running multiple Claude agents in the background while keeping focus on the main task",[302,6458,6459],{},"The dream setup I'm working toward: one pane for primary work, with stackable background panes for each Claude agent. Spin up an agent, let it work, check back when it's done. All without losing track of what's running where. Not sure about worktrees yet.",[302,6461,6462],{},"Still exploring whether to run Zellij inside VS Code's terminal or in a separate terminal app. The keybinding conflicts with VS Code are annoying, and I'm not sure yet if file links will open correctly. More experimentation needed.",[318,6464,6466],{"id":6465},"resources","Resources",[368,6468,6469],{},[371,6470,6471],{},[335,6472,6475],{"href":6473,"rel":6474},"https:\u002F\u002Fzellij.dev\u002Fdocumentation\u002F",[461],"Zellij Documentation",{"title":515,"searchDepth":516,"depth":516,"links":6477},[6478,6479,6480,6481,6482,6483],{"id":6350,"depth":516,"text":6351},{"id":6360,"depth":516,"text":6361},{"id":6377,"depth":516,"text":6378},{"id":6411,"depth":516,"text":6412},{"id":6421,"depth":516,"text":6422},{"id":6465,"depth":516,"text":6466},"2025-12-29","A non-tmux user finally discovers terminal multiplexers through Zellij",{"src":6487,"alt":6488},"images\u002Fblog\u002F20251230-0135-sleeping-on-zellij.jpeg","A developer's ultrawide monitor displaying an elegantly organized terminal with multiple glowing panes arranged in a perfect grid, each pane showing different running processes with subtle green and amber terminal text. In the foreground, scattered and overlapping browser tabs and terminal windows fade into chaos on a secondary display, creating visual contrast between disorder and order. Dramatic side lighting with warm rust-orange accent lighting reflecting off the organized screen while cool blue tones illuminate the chaotic side, cinematic depth of field focusing on the organized terminal. Photorealistic, 8k quality, moody developer workspace atmosphere, high contrast color grading with teal shadows and warm highlights, 16:9 composition.",{},{"title":145,"description":6485},"WSpjXLJCkn2wau4yQsAueIip1wkpoDleMrhvJQdmp6Y",{"id":6493,"title":141,"authors":6494,"badge":6497,"body":6498,"date":6672,"description":6673,"extension":533,"image":6674,"meta":6677,"navigation":538,"path":142,"seo":6678,"status":540,"stem":143,"__hash__":6679},"posts\u002F2.blog\u002F20251216.ai-pairing-notes-to-self.md",[6495],{"name":292,"to":293,"avatar":6496},{"src":295},{"label":297},{"type":299,"value":6499,"toc":6664},[6500,6505,6509,6539,6543,6571,6575,6613,6617,6628,6632,6643,6647,6657,6659],[330,6501,6502],{},[302,6503,6504],{},"This is a living document. Not \"best practices\" - just things I keep re-learning. The landscape changes weekly.",[318,6506,6508],{"id":6507},"the-mindset-shifts","The Mindset Shifts",[368,6510,6511,6517,6523,6534],{},[371,6512,6513,6516],{},[326,6514,6515],{},"You're the architect, AI is the builder"," - I still catch myself letting AI drive when I should be steering",[371,6518,6519,6522],{},[326,6520,6521],{},"Better context = better output"," - Every time I think \"that's obvious\", I'm wrong. Say it anyway.",[371,6524,6525,6528,6529],{},[326,6526,6527],{},"Talk like you're pairing with a senior dev who just joined"," - They're smart but don't know your codebase\n",[368,6530,6531],{},[371,6532,6533],{},"Use Claude.md, craft clean structure and conventions and it'll pick them up fast",[371,6535,6536],{},[335,6537,6538],{"href":130},"Plan Mode for your problems, Edit Mode for Claude's",[318,6540,6542],{"id":6541},"habits-i-keep-forgetting","Habits I Keep Forgetting",[368,6544,6545,6548,6551,6554,6568],{},[371,6546,6547],{},"Use voice\u002Fdictation more - typing less context because lazy",[371,6549,6550],{},"Screenshot the error, don't describe it",[371,6552,6553],{},"Create an issue when distracted by improvement ideas - don't derail current task",[371,6555,6556,6559,6560,6563,6564,6567],{},[745,6557,6558],{},"ctrl+z"," to terminal, ",[745,6561,6562],{},"fg"," to resume - way better than ",[745,6565,6566],{},"!"," for throwaway commands",[371,6569,6570],{},"rewind!",[318,6572,6574],{"id":6573},"whats-working-right-now","What's Working Right Now",[368,6576,6577,6585,6596,6599,6607],{},[371,6578,6579,6580],{},"Plan mode before any non-trivial change\n",[368,6581,6582],{},[371,6583,6584],{},"easier to course-correct early than after tons of code is generated",[371,6586,6587,6588],{},"Subagents for everything\n",[368,6589,6590,6593],{},[371,6591,6592],{},"Keith pushed me to use them for exploration, but now I use them for everything - main agent acts as orchestrator",[371,6594,6595],{},"I've had a lot of luck with this - larger tasks can run autonomously for a long time",[371,6597,6598],{},"Web search to load current docs into context",[371,6600,6601,6602],{},"Read every line of changes before committing - easy when new, gets sloppy fast\n",[368,6603,6604],{},[371,6605,6606],{},"AI adds the worst type of errors - small, subtle, hard to catch ones",[371,6608,6609,6612],{},[745,6610,6611],{},"bunx ccstatusline@latest"," for Claude Code status line - shows token usage, costs, model in terminal",[318,6614,6616],{"id":6615},"what-im-experimenting-with","What I'm Experimenting With",[368,6618,6619,6622,6625],{},[371,6620,6621],{},"More aggressive use of CLAUDE.md for project conventions",[371,6623,6624],{},"Custom slash commands for repeated workflows",[371,6626,6627],{},"Letting AI write the first draft of issues\u002FPRs",[318,6629,6631],{"id":6630},"lessons-learned-the-hard-way","Lessons Learned the Hard Way",[368,6633,6634,6637,6640],{},[371,6635,6636],{},"Don't trust AI-generated paths without verification",[371,6638,6639],{},"If stuck in a loop, start fresh context rather than fighting",[371,6641,6642],{},"Once you get \"You're absolutely right\" from AI, you're probably off-track - start a new session",[318,6644,6646],{"id":6645},"resources-i-keep-coming-back-to","Resources I Keep Coming Back To",[368,6648,6649],{},[371,6650,6651,6656],{},[335,6652,6655],{"href":6653,"rel":6654},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=1jJH1b0bUuA",[461],"Building Custom Skills for Anthropic Agents – Barry Zhang & Mahesh Murag"," - pushed me to go all-in on skills for chatbots and agents",[3286,6658],{},[302,6660,6661],{},[920,6662,6663],{},"Last updated: 2025-12-20",{"title":515,"searchDepth":516,"depth":516,"links":6665},[6666,6667,6668,6669,6670,6671],{"id":6507,"depth":516,"text":6508},{"id":6541,"depth":516,"text":6542},{"id":6573,"depth":516,"text":6574},{"id":6615,"depth":516,"text":6616},{"id":6630,"depth":516,"text":6631},{"id":6645,"depth":516,"text":6646},"2025-12-16","My ever-evolving tips for pairing with AI - not rules, just habits I keep forgetting",{"src":6675,"alt":6676},"\u002Fimages\u002Fblog\u002F20251216-0742-ai-pairing-notes-to-self.jpg","A software developer at a dual-monitor workstation, one screen showing code while the other displays an ethereal, translucent AI assistant figure made of flowing light particles and neural network patterns, both entities focused on the same problem. Warm desk lamp casting golden light from the left contrasts with cool blue-white emanating from the AI presence, creating dramatic interplay of shadows across scattered sticky notes and a well-worn notebook. Cinematic realism with subtle sci-fi elements, 8k photorealistic quality, shallow depth of field focusing on the collaborative space between human and AI, teal and amber color grading, overhead three-quarter angle composition.",{},{"title":141,"description":6673},"S-GmuWyWj29ioQ0xkC3k-QHdpZVRLEu7Y18hNt49C3k",{"id":6681,"title":137,"authors":6682,"badge":6685,"body":6687,"date":7000,"description":7001,"extension":533,"image":7002,"meta":7005,"navigation":538,"path":138,"seo":7006,"status":540,"stem":139,"__hash__":7007},"posts\u002F2.blog\u002F20251205.switchback-second-order-reasoning.md",[6683],{"name":292,"to":293,"avatar":6684},{"src":295},{"label":6686},"Development",{"type":299,"value":6688,"toc":6990},[6689,6696,6699,6703,6706,6712,6715,6719,6722,6842,6845,6848,6852,6855,6858,6861,6864,6867,6871,6874,6877,6880,6883,6886,6889,6893,6896,6910,6913,6917,6920,6923,6937,6940,6944,6947,6950,6953,6957,6960,6963,6966,6969,6971,6977,6984,6987],[302,6690,6691,6692,6695],{},"I just had one of those ideas that feels simultaneously obvious and novel. An app called ",[326,6693,6694],{},"Switchback"," - like browser history, but for chains of reasoning.",[302,6697,6698],{},"The core concept: a doubly linked list where each node is a thought, and you can navigate forward and backward through the chain. World of Goo meets mindmap meets TODO list.",[318,6700,6702],{"id":6701},"the-meta-part","The Meta Part",[302,6704,6705],{},"Writing this post IS the first use case. Here's the actual reasoning chain that led here:",[1119,6707,6710],{"className":6708,"code":6709,"language":2028},[2026],"\"I need a new project folder\"\n  ↓\n\"I should improve my project folder creation\"\n  ↓\n\"Add it to my towles-tool CLI\"\n  ↓\n\"Wait, make a Claude plugin instead\"\n  ↓\n\"Easier to share - skill or command?\"\n  ↓\n\"Make \u002Ftt:one-off that creates one-offs\u002F2025\u002F2025-12-05\"\n  ↓\n\"Actually, this pattern is the real project\"\n  ↓\n\"Call it Switchback\"\n  ↓\n\"Write a blog post to think through it\"\n",[745,6711,6709],{"__ignoreMap":515},[302,6713,6714],{},"Each arrow is a context switch. Each node is a perfectly-sized task for an AI agent. The chain gives full context.",[318,6716,6718],{"id":6717},"why-doubly-linked-lists","Why Doubly Linked Lists?",[302,6720,6721],{},"This is the data structure I never had a good excuse for.",[1119,6723,6725],{"className":1478,"code":6724,"language":1480,"meta":515,"style":515},"interface ReasonNode {\n  id: string;\n  content: string;\n  prev: ReasonNode | null;\n  next: ReasonNode | null;\n  timestamp: Date;\n  chain: 'work' | 'dad' | 'house' | string;\n}\n",[745,6726,6727,6737,6748,6759,6774,6789,6801,6838],{"__ignoreMap":515},[1127,6728,6729,6732,6735],{"class":1129,"line":1130},[1127,6730,6731],{"class":1493},"interface",[1127,6733,6734],{"class":2246}," ReasonNode",[1127,6736,5832],{"class":1501},[1127,6738,6739,6742,6744,6746],{"class":1129,"line":516},[1127,6740,6741],{"class":1550},"  id",[1127,6743,1554],{"class":1501},[1127,6745,5829],{"class":2246},[1127,6747,1512],{"class":1501},[1127,6749,6750,6753,6755,6757],{"class":1129,"line":523},[1127,6751,6752],{"class":1550},"  content",[1127,6754,1554],{"class":1501},[1127,6756,5829],{"class":2246},[1127,6758,1512],{"class":1501},[1127,6760,6761,6764,6766,6768,6770,6772],{"class":1129,"line":1146},[1127,6762,6763],{"class":1550},"  prev",[1127,6765,1554],{"class":1501},[1127,6767,6734],{"class":2246},[1127,6769,4663],{"class":1501},[1127,6771,6020],{"class":2246},[1127,6773,1512],{"class":1501},[1127,6775,6776,6779,6781,6783,6785,6787],{"class":1129,"line":1382},[1127,6777,6778],{"class":1550},"  next",[1127,6780,1554],{"class":1501},[1127,6782,6734],{"class":2246},[1127,6784,4663],{"class":1501},[1127,6786,6020],{"class":2246},[1127,6788,1512],{"class":1501},[1127,6790,6791,6794,6796,6799],{"class":1129,"line":1388},[1127,6792,6793],{"class":1550},"  timestamp",[1127,6795,1554],{"class":1501},[1127,6797,6798],{"class":2246}," Date",[1127,6800,1512],{"class":1501},[1127,6802,6803,6806,6808,6810,6812,6814,6816,6818,6821,6823,6825,6827,6830,6832,6834,6836],{"class":1129,"line":1586},[1127,6804,6805],{"class":1550},"  chain",[1127,6807,1554],{"class":1501},[1127,6809,1618],{"class":1501},[1127,6811,5729],{"class":1621},[1127,6813,1625],{"class":1501},[1127,6815,4663],{"class":1501},[1127,6817,1618],{"class":1501},[1127,6819,6820],{"class":1621},"dad",[1127,6822,1625],{"class":1501},[1127,6824,4663],{"class":1501},[1127,6826,1618],{"class":1501},[1127,6828,6829],{"class":1621},"house",[1127,6831,1625],{"class":1501},[1127,6833,4663],{"class":1501},[1127,6835,5829],{"class":2246},[1127,6837,1512],{"class":1501},[1127,6839,6840],{"class":1129,"line":1599},[1127,6841,5978],{"class":1501},[302,6843,6844],{},"Navigate forward: \"What did this lead to?\"\nNavigate backward: \"Why was I thinking about this?\"",[302,6846,6847],{},"I'm wondering if I could build a minimal web app around this structure. Simple UI to add nodes, navigate chains, tag them.",[318,6849,6851],{"id":6850},"multiple-chains","Multiple Chains",[302,6853,6854],{},"The killer feature: multiple independent chains running simultaneously.",[302,6856,6857],{},"My work chain might be: \"Fix bug → Review PR → Deploy → Monitor metrics\"",[302,6859,6860],{},"My dad chain: \"Soccer practice → Buy cleats → Register for spring league\"",[302,6862,6863],{},"My house chain: \"Leaky faucet → YouTube tutorial → Hardware store → Actually call plumber\"",[302,6865,6866],{},"Each chain is isolated. No mixing contexts. No overwhelming single TODO list.",[318,6868,6870],{"id":6869},"stream-of-consciousness-capture","Stream of Consciousness Capture",[302,6872,6873],{},"The hardest part of task management isn't doing tasks. It's capturing them without breaking flow.",[302,6875,6876],{},"Switchback would let me dump thoughts rapid-fire:",[302,6878,6879],{},"\"Need to update DNS\"\n→ New node, work chain",[302,6881,6882],{},"\"Kids need new backpacks\"\n→ New node, dad chain",[302,6884,6885],{},"\"Blog post idea about reasoning chains\"\n→ New node, meta chain",[302,6887,6888],{},"The chain structure preserves context automatically. Each node knows why it exists.",[318,6890,6892],{"id":6891},"from-thought-to-task","From Thought to Task",[302,6894,6895],{},"Here's where it gets practical. Each node in the chain could become:",[368,6897,6898,6901,6904,6907],{},[371,6899,6900],{},"A task for an AI agent (with full context from the chain)",[371,6902,6903],{},"A calendar event",[371,6905,6906],{},"A note to my future self",[371,6908,6909],{},"Nothing - just a recorded thought",[302,6911,6912],{},"The chain itself tells the story. The agent can traverse backward to understand \"why\" before executing \"what.\"",[318,6914,6916],{"id":6915},"what-i-dont-know-yet","What I Don't Know Yet",[302,6918,6919],{},"This is conceptual. I haven't built it. I'm thinking out loud.",[302,6921,6922],{},"Open questions:",[368,6924,6925,6928,6931,6934],{},[371,6926,6927],{},"How do chains merge or split?",[371,6929,6930],{},"What happens to abandoned chains?",[371,6932,6933],{},"Do chains need tagging beyond just the name?",[371,6935,6936],{},"Is this just a fancy linked list that nobody needs?",[302,6938,6939],{},"Writing this post is part of figuring it out.",[318,6941,6943],{"id":6942},"why-this-might-matter","Why This Might Matter",[302,6945,6946],{},"Most task apps assume tasks are independent units. They're not. Tasks have context chains.",[302,6948,6949],{},"Most note apps assume notes are documents. They're not. They're nodes in reasoning graphs.",[302,6951,6952],{},"Switchback sits in the middle. Lightweight enough to capture thoughts. Structured enough to become action.",[318,6954,6956],{"id":6955},"next-steps","Next Steps",[302,6958,6959],{},"I might build this. I might not.",[302,6961,6962],{},"But I'll definitely use the reasoning chain from this post. That chain is already valuable - it captured the evolution from \"I need a folder\" to \"I need an app.\"",[302,6964,6965],{},"The doubly linked list preserved the context. I can navigate back to any decision point and ask \"why did I think this?\"",[302,6967,6968],{},"That's the test. If the tool helps me understand my own thinking better, it's worth building.",[3286,6970],{},[302,6972,6973,6974],{},"The project folder for this idea? ",[745,6975,6976],{},"one-offs\u002F2025\u002F2025-12-05\u002Fswitchback",[302,6978,6979,6980,6983],{},"Created automatically by the ",[745,6981,6982],{},"\u002Ftt:one-off"," command I built while thinking about this problem.",[302,6985,6986],{},"Meta all the way down.",[1698,6988,6989],{},"html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":515,"searchDepth":516,"depth":516,"links":6991},[6992,6993,6994,6995,6996,6997,6998,6999],{"id":6701,"depth":516,"text":6702},{"id":6717,"depth":516,"text":6718},{"id":6850,"depth":516,"text":6851},{"id":6869,"depth":516,"text":6870},{"id":6891,"depth":516,"text":6892},{"id":6915,"depth":516,"text":6916},{"id":6942,"depth":516,"text":6943},{"id":6955,"depth":516,"text":6956},"2025-12-05","Designing a doubly linked list app to navigate chains of reasoning - and how writing this post became the first use case.",{"src":7003,"alt":7004},"\u002Fimages\u002Fblog\u002F20251205-1830-switchback-reasoning-tracker.png","Switchback reasoning tracker concept",{},{"title":137,"description":7001},"JqMasMslYugItJwJcPU0JVjWK6ywTyGC0fPbqXyjKUM",{"id":7009,"title":133,"authors":7010,"badge":7013,"body":7015,"date":7177,"description":7178,"extension":533,"image":7179,"meta":7182,"navigation":538,"path":134,"seo":7183,"status":540,"stem":135,"__hash__":7184},"posts\u002F2.blog\u002F20251028.aws-aurora-dsql-postgres-serverless-authentication.md",[7011],{"name":292,"to":293,"avatar":7012},{"src":295},{"label":7014},"DevOps",{"type":299,"value":7016,"toc":7170},[7017,7021,7024,7027,7036,7039,7043,7052,7057,7065,7068,7071,7075,7078,7081,7090,7093,7107,7111,7114,7117,7120,7137,7140,7143,7147,7150,7153,7156],[318,7018,7020],{"id":7019},"the-setup","The Setup",[302,7022,7023],{},"I'm building AI chat features for my blog. I wanted Postgres because it's my go-to database. I decided to try the AWS stack since we use it at work.",[302,7025,7026],{},"I always use RDS at work but figured I'd try something new. Aurora DSQL caught my attention—serverless Postgres with distributed SQL. The pricing looked good for low-traffic personal projects. Way better than Aurora Serverless v2, which is AWS's special type of \"Serverless\"—it isn't serverless and doesn't spin down to zero.",[302,7028,7029,7030,7035],{},"I did my homework. Read through ",[335,7031,7034],{"href":7032,"rel":7033},"https:\u002F\u002Fdocs.aws.amazon.com\u002Faurora-dsql\u002Flatest\u002Fuserguide\u002Fworking-with-postgresql-compatibility-unsupported-features.html",[461],"the unsupported features list",". Foreign keys? Don't need them. PostGIS and PGVector? Not for this project. 3,000 row transaction limit? My chat features won't hit that.",[302,7037,7038],{},"Nothing on that list was a dealbreaker.",[318,7040,7042],{"id":7041},"the-deployment","The Deployment",[302,7044,7045,7046,7051],{},"Created a CloudFormation template. Had to update SAM CLI first, and ",[335,7047,7050],{"href":7048,"rel":7049},"https:\u002F\u002Fgithub.com\u002FChrisTowles\u002Fdotfiles\u002Fcommit\u002F21e77ccb9689ebfdac2c944a1aa9e721dbdfd993#diff-af587fcc369e832087d96f2de7b3c0daaff070b88b329ad6e3c83a983d17ba98",[461],"there were issues, of course",". A few small issues later, deployment succeeded. Resource created, endpoint ready.",[302,7053,7054],{},[467,7055],{"alt":515,"src":7056},"\u002Fimages\u002Fblog\u002Fcreating-dsql-cluster-sam-cloudformation-stack.png",[302,7058,7059,7060],{},"Check this git commit for infra code: ",[335,7061,7064],{"href":7062,"rel":7063},"https:\u002F\u002Fgithub.com\u002FChrisTowles\u002Fblog\u002Fcommit\u002F65df772895186709bec5814912efed8cc5e9fc0e#diff-51ad8453311eba96809cf31ed76d51139db96d3e679ed1736d21b3e9bae5e3b0",[461],"infra\u002Fcloudformation\u002Fdsql.yaml",[302,7066,7067],{},"Time to grab the connection string and wire it into my Cloudflare Worker.",[302,7069,7070],{},"That's when I saw it.",[318,7072,7074],{"id":7073},"the-discovery","The Discovery",[302,7076,7077],{},"No username field. No password field. Just: \"Use IAM authentication.\"",[302,7079,7080],{},"AWS Aurora DSQL doesn't support traditional username\u002Fpassword authentication. Period.",[302,7082,7083,7084,7089],{},"Just ",[335,7085,7088],{"href":7086,"rel":7087},"https:\u002F\u002Fdocs.aws.amazon.com\u002Faurora-dsql\u002Flatest\u002Fuserguide\u002FSECTION_authentication-token.html",[461],"IAM authentication with temporary tokens"," that expire every 15 minutes.",[302,7091,7092],{},"Here's how it works:",[851,7094,7095,7098,7101,7104],{},[371,7096,7097],{},"Create an IAM role with database permissions",[371,7099,7100],{},"Generate a temporary token (15-minute expiration)",[371,7102,7103],{},"Use the token as password",[371,7105,7106],{},"When the connection drops after 15 minutes, generate a new token",[318,7108,7110],{"id":7109},"the-problem","The Problem",[302,7112,7113],{},"This immediately killed it for my use case.",[302,7115,7116],{},"Cloudflare Workers are serverless edge functions. Short-lived, stateless, potentially spanning minutes between invocations. The entire model assumes connection pooling or connection-per-request patterns with credentials that don't expire mid-session.",[302,7118,7119],{},"The 15-minute token expiration means:",[368,7121,7122,7125,7128,7131,7134],{},[371,7123,7124],{},"Can't use standard connection pooling (pool outlives token)",[371,7126,7127],{},"Can't cache tokens between worker invocations reliably",[371,7129,7130],{},"Need AWS SDK running in every worker to generate tokens",[371,7132,7133],{},"Additional cold start latency for token generation",[371,7135,7136],{},"More complexity for credential management",[302,7138,7139],{},"Could I have made it work? Probably. Generate token on each invocation, accept the latency, handle token refresh logic.",[302,7141,7142],{},"But at that point—why?",[318,7144,7146],{"id":7145},"the-missing-context","The Missing Context",[302,7148,7149],{},"The unsupported features list told me about foreign keys and triggers. It mentioned the 3,000 row transaction limit and one-hour connection timeout.",[302,7151,7152],{},"What it didn't mention up front: \"This database requires IAM authentication. No username\u002Fpassword support.\"",[302,7154,7155],{},"That's not a missing Postgres feature. That's a fundamental authentication model that changes how you architect your application.",[302,7157,7158,7159,2388,7164,7169],{},"Gee, AWS, I wonder why everyone uses ",[335,7160,7163],{"href":7161,"rel":7162},"https:\u002F\u002Fsupabase.com\u002F",[461],"Supabase",[335,7165,7168],{"href":7166,"rel":7167},"https:\u002F\u002Fneon.tech\u002F",[461],"Neon"," for serverless Postgres these days? It's like you got so close, then just blew it at the last second.",{"title":515,"searchDepth":516,"depth":516,"links":7171},[7172,7173,7174,7175,7176],{"id":7019,"depth":516,"text":7020},{"id":7041,"depth":516,"text":7042},{"id":7073,"depth":516,"text":7074},{"id":7109,"depth":516,"text":7110},{"id":7145,"depth":516,"text":7146},"2025-10-28","I researched unsupported features, checked pricing, deployed the stack—then discovered IAM-only auth means 15-minute tokens. Here's why that killed it for my Cloudflare Workers deployment.",{"src":7180,"alt":7181},"\u002Fimages\u002Fblog\u002F20251028-1430-aws-aurora-dsql-auth-frustration.png","A software engineer's desk with a MacBook Pro displaying AWS Console with Aurora DSQL connection details, the screen showing empty username and password fields with only \"Use IAM authentication\" text, a coffee mug and notebook nearby showing crossed-out connection string notes. Dramatic side lighting creates strong contrast between the cool blue glow of the laptop screen and warm desk lamp illumination, shallow depth of field focusing on the screen. Cinematic realism, professional photography quality, 8k detail, high contrast color grading with teal screen glow and warm orange ambient light, contemplative and slightly frustrated atmosphere, rule of thirds composition with negative space on the right.",{},{"title":133,"description":7178},"TMt6OZaG3UUpOIuTNxqWZxHzAqpo4vZZ-_qSb-waeTE",{"id":7186,"title":129,"authors":7187,"badge":7190,"body":7191,"date":7304,"description":7305,"extension":533,"image":7306,"meta":7309,"navigation":538,"path":130,"seo":7310,"status":540,"stem":131,"__hash__":7311},"posts\u002F2.blog\u002F20251019.plan-mode-problems-edit-mode-solutions.md",[7188],{"name":292,"to":293,"avatar":7189},{"src":295},{"label":1732},{"type":299,"value":7192,"toc":7297},[7193,7197,7200,7203,7206,7209,7213,7216,7219,7223,7226,7231,7234,7237,7251,7256,7259,7262,7265,7269,7272,7275,7278,7281,7285,7288,7291,7294],[318,7194,7196],{"id":7195},"the-2-hour-dead-end","The 2-Hour Dead End",[302,7198,7199],{},"At work I had some data and needed to build a system that made predictions, using constraints from existing data. Not something I typically need to do. I thought I'd solve it by making a classifier to find common characteristics, and use those patterns to make the constraints. I worked on it, first working version, made 0% successful predictions. After another 15m its up to 5% success, sweet it's working. After another hour it's up to 21%. I'm confident that I'll have this done by end of the day.",[302,7201,7202],{},"Fast forward to the end of the day, and it's stalled at 23%. I'm generating so much code and it's not improving. In frustration I paused. Switched to Plan mode (Shift+Tab twice). Asked: \"I need to make predictions using constraints from existing data. How could we do that?\"",[302,7204,7205],{},"Claude immediately suggested sklearn—a library I know but don't use enough. It had the exact feature I needed, battle-tested and documented!",[302,7207,7208],{},"I'd wasted all those hours directing Claude to build my overcomplicated solution instead of 2 minutes in plan mode telling it my problem.",[318,7210,7212],{"id":7211},"the-pattern-directing-vs-asking","The Pattern: Directing vs. Asking",[302,7214,7215],{},"The mistake wasn't a technical one. I was treating Claude like a junior developer executing my architectural decisions.",[302,7217,7218],{},"Here's the thing—Claude is trained on all of human knowledge. When you ask for its approach, you're tapping into solutions from thousands of developers who've solved similar problems. When you direct it to build your solution, you're limiting it to your knowledge alone.",[318,7220,7222],{"id":7221},"the-mental-model-plan-mode-vs-edit-mode","The Mental Model: Plan Mode vs. Edit Mode",[302,7224,7225],{},"On the call, my brother and I worked out a simple rule that I hope makes this pattern stick:",[302,7227,7228],{},[326,7229,7230],{},"\"Plan mode for your problems, Edit mode for Claude's problems.\"",[302,7232,7233],{},"This is where you present the actual challenge you're facing. You're not dictating the solution—you're asking Claude to think, research, and propose an approach.",[302,7235,7236],{},"The workflow:",[851,7238,7239,7242,7245,7248],{},[371,7240,7241],{},"Hit Shift+Tab twice to enter Plan mode",[371,7243,7244],{},"Describe your problem (not your solution)",[371,7246,7247],{},"Ask: \"What approach would you take?\"",[371,7249,7250],{},"Review the plan critically",[302,7252,7253],{},[326,7254,7255],{},"Edit Mode = Claude's Problems",[302,7257,7258],{},"Once Claude has proposed a solution, now you're directing implementation specifics. This is where your domain knowledge and preferences matter.",[302,7260,7261],{},"\"Actually, use this library instead of that one\"\n\"Put this file here, not there\"\n\"Follow this naming convention\"\n\"Use our existing error handling pattern\"",[302,7263,7264],{},"Claude has given you the architecture and approach. Now you're steering the details based on your codebase, your team's standards, your production environment.",[318,7266,7268],{"id":7267},"the-simple-rule","The Simple Rule",[302,7270,7271],{},"Next time you're about to tell Claude how to build something, pause.",[302,7273,7274],{},"Ask yourself: Am I solving my problem, or am I directing a solution?",[302,7276,7277],{},"If you're solving a problem, switch to Plan mode. Describe the challenge. Ask what Claude would do.",[302,7279,7280],{},"After reviewing, switch to Edit mode. Direct the implementation details. Steer it toward your codebase patterns, your team's preferences, your architectural constraints.",[318,7282,7284],{"id":7283},"the-bottom-line","The Bottom Line",[302,7286,7287],{},"I wasted 2 hours building the wrong thing because I was directing instead of asking. A simple question—\"What approach would you take?\"—would have saved those 2 hours and produced better code.",[302,7289,7290],{},"The rule sticks because it maps to the two modes: Plan mode for your problems (asking), Edit mode for its problems (directing).",[302,7292,7293],{},"Try it. Next time you're about to tell Claude what to build, switch to Plan mode and ask for its approach first.",[302,7295,7296],{},"You might be surprised how often Claude's solution is better than the one you were about to direct it to build.",{"title":515,"searchDepth":516,"depth":516,"links":7298},[7299,7300,7301,7302,7303],{"id":7195,"depth":516,"text":7196},{"id":7211,"depth":516,"text":7212},{"id":7221,"depth":516,"text":7222},{"id":7267,"depth":516,"text":7268},{"id":7283,"depth":516,"text":7284},"2025-10-19","I spent 2 hours directing Claude to build my solution before realizing I should have asked for its approach. Here's the simple rule that changed how I use AI coding assistants.",{"src":7307,"alt":7308},"\u002Fimages\u002Fblog\u002F20251019-1435-plan-mode-edit-mode-workflow.png","A split-screen composition showing a software developer at their desk in two moments: left side shows frustrated late-night coding with multiple messy code windows and complexity diagrams, right side shows the same developer in contemplative pose with a clean interface showing a simple plan prompt \"What approach would you take?\", a subtle lightbulb or aha moment glow. Dramatic contrast between chaotic warm amber lighting on the left (representing wasted effort) and clean, focused cool blue lighting on the right (representing clarity), shallow depth of field. Cinematic realism, professional photography quality, 8k detail, rule of thirds composition with the developer positioned at the center dividing line, high contrast color grading emphasizing the before\u002Fafter transformation.",{},{"title":129,"description":7305},"E_brMK60NNUVRcVh4sucRsMSPqAWFZiC3PiDVGz_Ijk",{"id":7313,"title":125,"authors":7314,"badge":7317,"body":7318,"date":7568,"description":7569,"extension":533,"image":7570,"meta":7573,"navigation":538,"path":126,"seo":7574,"status":540,"stem":127,"__hash__":7575},"posts\u002F2.blog\u002F20251015.the-exponential-shift.md",[7315],{"name":292,"to":293,"avatar":7316},{"src":295},{"label":1732},{"type":299,"value":7319,"toc":7562},[7320,7323,7326,7329,7333,7336,7481,7486,7492,7501,7504,7508,7511,7514,7517,7520,7523,7526,7530,7533,7536,7539,7542,7545,7548,7550,7553,7556,7559],[302,7321,7322],{},"Something shifted in the last six months that most developers haven't fully processed yet. I'm watching AI systems solve problems that required senior engineers just a year ago, and the trajectory isn't slowing down—it's accelerating in ways that break our mental models of progress.",[302,7324,7325],{},"The latest SWE-bench Verified results tell a story that should fundamentally change how we think about the next five years of software development: Claude Sonnet 4.5 now solves 77.2% of real-world GitHub issues autonomously. Not toy problems. Actual bugs and features from production repositories.",[302,7327,7328],{},"This isn't a panic piece about AI replacing developers. When we look at the data, the capability acceleration tells a remarkable story: AI is now on par with experienced human developers for pennies per million tokens.",[318,7330,7332],{"id":7331},"the-intern-who-became-a-senior-in-3-years","The Intern Who Became a Senior in 3 Years",[302,7334,7335],{},"Here's the mental model that helped me internalize what's happening:",[7337,7338,7339,7366],"table",{},[7340,7341,7342],"thead",{},[7343,7344,7345,7351,7356,7361],"tr",{},[7346,7347,7348],"th",{},[326,7349,7350],{},"Timeframe",[7346,7352,7353],{},[326,7354,7355],{},"Model",[7346,7357,7358],{},[326,7359,7360],{},"Human Developer Equivalent",[7346,7362,7363],{},[326,7364,7365],{},"SWE-bench Verified Score",[7367,7368,7369,7388,7407,7425,7443,7461],"tbody",{},[7343,7370,7371,7375,7382,7385],{},[7372,7373,7374],"td",{},"2022 March",[7372,7376,7377],{},[335,7378,7381],{"href":7379,"rel":7380},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FGPT-3#GPT-3.5",[461],"GPT-3.5",[7372,7383,7384],{},"has seen code before, doesn't know what it does.",[7372,7386,7387],{},"~3%",[7343,7389,7390,7393,7401,7404],{},[7372,7391,7392],{},"2024 March",[7372,7394,7395,7400],{},[335,7396,7399],{"href":7397,"rel":7398},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FGPT-4",[461],"GPT-4"," \u002F Claude 3",[7372,7402,7403],{},"Eager Intern - needs guidance, needs constant supervision",[7372,7405,7406],{},"~13-28%",[7343,7408,7409,7412,7419,7422],{},[7372,7410,7411],{},"2024 June",[7372,7413,7414],{},[335,7415,7418],{"href":7416,"rel":7417},"https:\u002F\u002Fwww.anthropic.com\u002Fnews\u002Fclaude-3-5-sonnet",[461],"Claude Sonnet 3.5",[7372,7420,7421],{},"Junior dev - handles functions, needs guidance",[7372,7423,7424],{},"~33%",[7343,7426,7427,7430,7437,7440],{},[7372,7428,7429],{},"2025 February",[7372,7431,7432],{},[335,7433,7436],{"href":7434,"rel":7435},"https:\u002F\u002Fwww.anthropic.com\u002Fnews\u002Fclaude-3-7-sonnet",[461],"Claude Sonnet 3.7",[7372,7438,7439],{},"Mid-level - debugs issues, refactors code independently",[7372,7441,7442],{},"~62%",[7343,7444,7445,7448,7455,7458],{},[7372,7446,7447],{},"2025 May",[7372,7449,7450],{},[335,7451,7454],{"href":7452,"rel":7453},"https:\u002F\u002Fwww.anthropic.com\u002Fnews\u002Fclaude-4",[461],"Claude Sonnet 4",[7372,7456,7457],{},"Experienced Dev - handles complex systems and some architectural work",[7372,7459,7460],{},"~72%",[7343,7462,7463,7466,7473,7476],{},[7372,7464,7465],{},"2025 Oct",[7372,7467,7468],{},[335,7469,7472],{"href":7470,"rel":7471},"https:\u002F\u002Fwww.anthropic.com\u002Fnews\u002Fclaude-sonnet-4-5",[461],"Claude Sonnet 4.5",[7372,7474,7475],{},"Senior+ - majority of real-world engineering tasks, must peer review but does great work",[7372,7477,7478],{},[326,7479,7480],{},"77.2%",[330,7482,7483],{},[302,7484,7485],{},"Note: that cost per million tokens is now in the single digit cents range for these models, making focused usage when paired with a human developer something like $20\u002Fmonth.",[302,7487,7488,7489,1207],{},"Think about that progression: ",[326,7490,7491],{},"intern → junior → mid → senior in under 3 years",[302,7493,7494,7495,7500],{},"And this is using the ",[335,7496,7499],{"href":7497,"rel":7498},"https:\u002F\u002Fwww.swebench.com\u002F",[461],"SWE-bench",", which only counts fully autonomous solutions that don't require human intervention. The actual capabilities when paired with a human developer are even higher.",[302,7502,7503],{},"And here's what keeps me up at night: we have no reason to believe this curve is flattening.",[318,7505,7507],{"id":7506},"my-tesla-and-the-failure-of-linear-thinking","My Tesla and the Failure of Linear Thinking",[302,7509,7510],{},"I drive a Tesla with Full Self-Driving, and it's become my daily reminder of how badly humans underestimate exponential progress.",[302,7512,7513],{},"Three years ago, a new Prius could barely handle highway lane-keeping.",[302,7515,7516],{},"Today? I routinely complete entire 30-minute trips through complex urban environments—traffic lights, construction zones—all with zero interventions. The system handles edge cases I didn't even know I was solving as a human driver.",[302,7518,7519],{},"But here's the thing: even experiencing this transformation firsthand, I still can't mentally extrapolate what ten years looks like. My brain wants to think linearly—\"okay, it'll get a bit better each year\"—when the evidence shows exponential improvement.",[302,7521,7522],{},"The same thing is happening with AI coding capabilities: I model progress in linear increments while the actual progress curve is exponential.",[302,7524,7525],{},"When Claude Sonnet 4.5 hits 77.2% on SWE-bench today, I can't actually imagine what 95%+ looks like in practice, even though the math says we'll get there sooner than I think. Just like I couldn't have imagined my current FSD experience three years ago.",[318,7527,7529],{"id":7528},"it-hits-different-in-your-domain","It Hits Different in Your Domain",[302,7531,7532],{},"It hits differently when it's your area of expertise.",[302,7534,7535],{},"If AI was excelling in domains I wasn't familiar with, I'd think, \"Oh yeah, I'm sure it's helpful, whatever.\" That's easy to dismiss from a distance.",[302,7537,7538],{},"But seeing it master the craft I've spent 20 years learning—understanding the nuances, making the architectural decisions, solving the problems that used to require hard-won experience—that's when the exponential shift becomes visceral.",[302,7540,7541],{},"It's not just \"on par\" anymore. In many contexts, it's already better at the execution than I am. And that realization changes everything.",[302,7543,7544],{},"But here's the twist: I'm learning new tricks from it. I'm getting better at tools I thought I'd mastered.",[302,7546,7547],{},"An easy example: AI is way better at web searching than I am. It adds context I wouldn't have thought to include. Every search request includes the current year. That sounds like nothing, but try it—prefix your searches with \"2025\" and watch how much more relevant the results become. Simple, obvious in hindsight, but I never did it consistently until I watched Claude Code do it every single time.",[318,7549,7284],{"id":7283},[302,7551,7552],{},"We're in the middle of an exponential shift that most of the industry is still treating as linear improvement. The gap between current AI capabilities and where they'll be in 24 months is larger than most developers' mental models can accommodate, including mine.",[302,7554,7555],{},"This isn't cause for panic—it's cause for strategic action. The same technology that's disrupting traditional development workflows is also the most powerful accelerator we've ever had access to.",[302,7557,7558],{},"It's something that only hands-on experience can teach you. Pick your hardest open bug and spend 30 minutes pair-programming with Claude Code. Not watching it work—actively collaborating.",[302,7560,7561],{},"You'll come away with a new mental model of what's possible, and a fresh perspective on how to leverage these tools to amplify your own capabilities.",{"title":515,"searchDepth":516,"depth":516,"links":7563},[7564,7565,7566,7567],{"id":7331,"depth":516,"text":7332},{"id":7506,"depth":516,"text":7507},{"id":7528,"depth":516,"text":7529},{"id":7283,"depth":516,"text":7284},"2025-10-15","AI capabilities are advancing faster than we can internalize. Here's why the next phase of development will look radically different.",{"src":7571,"alt":7572},"\u002Fimages\u002Fblog\u002F20251016-0000-the-exponential-shift.png","A dramatic visualization of an exponential curve rising sharply upward made of glowing holographic data points and neural network connections, transforming from a flat linear path into a steep acceleration curve. In the foreground, a software developer sits at a modern desk with dual monitors displaying code and AI interfaces, gazing up at the luminous curve with a mix of contemplation and realization, backlit by the glow of the visualization. Cinematic lighting with deep blue and cyan tones from the holographic elements contrasting with warm amber desk lamp light, creating depth and atmosphere. Photorealistic rendering, 8k quality, shallow depth of field focusing on the developer and curve intersection, professional commercial photography aesthetic with high contrast color grading.",{},{"title":125,"description":7569},"mWdsUQu4m1XVMYRT0pbcLX4mxGT-5p1aVJBshTQPoA4",{"id":7577,"title":121,"authors":7578,"badge":7581,"body":7582,"date":7776,"description":7777,"extension":533,"image":7778,"meta":7781,"navigation":538,"path":122,"seo":7782,"status":540,"stem":123,"__hash__":7783},"posts\u002F2.blog\u002F20251010.read-the-source.md",[7579],{"name":292,"to":293,"avatar":7580},{"src":295},{"label":6686},{"type":299,"value":7583,"toc":7766},[7584,7593,7596,7600,7603,7606,7609,7613,7616,7621,7632,7638,7641,7644,7648,7651,7654,7657,7660,7663,7667,7670,7676,7682,7688,7691,7695,7698,7723,7726,7730,7733,7736,7739,7743,7746,7749,7751,7754,7757,7760,7763],[302,7585,7586,7587,7592],{},"I wasted three hours last week fighting with a ",[335,7588,7591],{"href":7589,"rel":7590},"https:\u002F\u002Fstrandsagents.com\u002F",[461],"Strands"," hook that \"wasn't working right.\" The tutorial said to do X, the Stack Overflow answer said to do Y, and my code was doing neither. Finally, in frustration, I asked Claude and it just directly looked in the module source code.",[302,7594,7595],{},"This keeps happening. We reach for the filtered interpretation - the blog post, the video tutorial, the Medium article - when the actual source is sitting right there, written by people who understand it deeply and have every incentive to teach it clearly.",[318,7597,7599],{"id":7598},"the-tutorial-tax","The Tutorial Tax",[302,7601,7602],{},"Here's the thing about most technical tutorials: they're written by someone who just learned the thing themselves. They're filtering their incomplete understanding through their specific use case, adding their own interpretations, and often getting crucial details wrong.",[302,7604,7605],{},"The academic equivalent is even worse. Someone writes a groundbreaking paper on transformer architecture. It's freely available, written by the researchers themselves, with all the context and reasoning. But instead of reading that 12-page paper, we watch a 10-minute YouTube video where someone who read the paper explains it to us, adding their own confusion along the way.",[302,7607,7608],{},"We're learning through telephone. Every degree of separation adds noise and removes signal.",[318,7610,7612],{"id":7611},"working-backwards-to-primary-sources","Working Backwards to Primary Sources",[302,7614,7615],{},"So I think one of the advantages of using Claude is that it can read the source code directly.",[302,7617,7618,1554],{},[326,7619,7620],{},"Find the primary source",[368,7622,7623,7626,7629],{},[371,7624,7625],{},"OAuth 2.0 spec from the IETF (the people who designed it)",[371,7627,7628],{},"GitHub's OAuth documentation (the people who implemented it)",[371,7630,7631],{},"The library source code!",[302,7633,7634,7637],{},[326,7635,7636],{},"Skip everything else initially",": If you see a tutorial, use that as a signal of what source code and documentation to read. Those come later if I need specific implementation examples, but they're supplements, not starting points.",[302,7639,7640],{},"This approach feels harder at first. Specs and official docs are dense. They're comprehensive. They assume a certain level of knowledge. But here's what I've learned over 25 years: that initial difficulty saves exponential time later.",[302,7642,7643],{},"The spec tells me why things work the way they do. The official docs tell me the intended use case. The source code shows me exactly what's happening. When I hit a problem, I know where to look because I understand the foundation.",[318,7645,7647],{"id":7646},"the-rtfm-renaissance","The RTFM Renaissance",[302,7649,7650],{},"\"Read The Fucking Manual\" got a bad reputation. It became a dismissive way to shut down questions. But the underlying principle is sound: the manual exists for a reason.",[302,7652,7653],{},"Modern documentation is often excellent. The Rust book is a masterclass in teaching a complex language. The Anthropic API documentation (yes, I work with Claude a lot) is clear about capabilities and limitations.",[302,7655,7656],{},"These aren't dusty PDF manuals written by technical writers who never used the product. These are living documents, maintained by the teams building the tools, updated constantly, with examples and explanations written for developers like us.",[302,7658,7659],{},"When the Nuxt team releases a new feature, they document it. When the Vue team changes reactivity behavior, they explain why. When a library author adds a method, they describe the use case. This is first-hand knowledge from the people who made the decisions.",[302,7661,7662],{},"Compare that to a blog post from twelve months ago that might be outdated, might have misunderstood the feature, and definitely doesn't have the context of why things are designed that way.",[318,7664,7666],{"id":7665},"the-three-tier-source-hierarchy","The Three-Tier Source Hierarchy",[302,7668,7669],{},"Not all sources are equal. When I need to learn something, I work through this hierarchy:",[302,7671,7672,7675],{},[326,7673,7674],{},"Tier 1 - The Creators",": Official documentation, academic papers from the researchers, technical specifications from the standards bodies, source code comments from the library authors. This is as close as you can get to understanding the original intent.",[302,7677,7678,7681],{},[326,7679,7680],{},"Tier 2 - Curated Interpretation",": Official tutorials, first-party examples, documentation from the team that built it. Still authoritative, but one step removed from the core design decisions.",[302,7683,7684,7687],{},[326,7685,7686],{},"Tier 3 - Community Knowledge",": Blog posts, Stack Overflow answers, third-party tutorials, YouTube videos. Useful for specific problems and alternative perspectives, but never the starting point.",[302,7689,7690],{},"The pattern: start at Tier 1, drop to Tier 2 for practical examples, only hit Tier 3 when you need to see how others solved specific edge cases.",[318,7692,7694],{"id":7693},"what-this-looks-like-in-practice","What This Looks Like in Practice",[302,7696,7697],{},"I wanted to understand how MCP (Model Context Protocol) works. The pattern:",[851,7699,7700,7714,7717,7720],{},[371,7701,7702,7703,7708,7709],{},"Read the ",[335,7704,7707],{"href":7705,"rel":7706},"https:\u002F\u002Fspec.modelcontextprotocol.io\u002F",[461],"specification"," written by Anthropic ",[335,7710,7713],{"href":7711,"rel":7712},"https:\u002F\u002Fwww.anthropic.com\u002Fnews\u002Fmodel-context-protocol",[461],"who designed it",[371,7715,7716],{},"Study the TypeScript SDK source code to see the actual implementation",[371,7718,7719],{},"Look at official example servers to see intended patterns",[371,7721,7722],{},"Only then look at community implementations to see creative approaches",[302,7724,7725],{},"Another example: when TypeScript 5.0 added decorators, I didn't search for \"TypeScript decorators tutorial.\" I read the TypeScript release notes, read the decorator proposal, and looked at the test cases in the TypeScript repo. Done. No confusion about which decorator syntax, no outdated patterns, no wondering if the tutorial is correct.",[318,7727,7729],{"id":7728},"the-compound-effect","The Compound Effect",[302,7731,7732],{},"This approach compounds. When you learn from primary sources, you build a mental model of how things actually work. The next time you encounter that library, framework, or pattern, you understand it at a deeper level.",[302,7734,7735],{},"You also get better at reading dense technical material. Specs become easier. Academic papers become approachable. Source code becomes readable. These are skills that multiply across every technology you touch.",[302,7737,7738],{},"And crucially: you learn to trust yourself. You don't need someone to interpret the documentation for you. You can read it, understand it, and implement it directly. That independence is worth far more than saving an hour on a tutorial.",[318,7740,7742],{"id":7741},"when-to-break-the-rule","When to Break the Rule",[302,7744,7745],{},"I'm not absolutist about this. Sometimes you need a tutorial. Sometimes a blog post explains the context that makes everything click. Sometimes a Stack Overflow answer saves hours of debugging.",[302,7747,7748],{},"But those should be supplements to primary sources, not replacements for them. Read the docs first, then find the tutorial that fills in your specific gap. Read the paper first, then watch the explainer video. Understand the source first, then see how others applied it.",[318,7750,7284],{"id":7283},[302,7752,7753],{},"This is the pattern I keep coming back to: learn from the people closest to the source. The library authors want you to succeed. The researchers want you to understand. The spec writers want you to implement correctly.",[302,7755,7756],{},"They've done the work of distilling complex topics into documentation. They've anticipated your questions, provided examples, and likely explained the reasoning.",[302,7758,7759],{},"All we have to do is read it.",[302,7761,7762],{},"Next time you're about to search for a tutorial, try this instead: open the official docs. Read the getting started guide. Look at the API reference. Read the source code if you need to. Give the people who built the thing a chance to teach it to you directly.",[302,7764,7765],{},"You might be surprised how much clearer everything becomes when you cut out the middleman.",{"title":515,"searchDepth":516,"depth":516,"links":7767},[7768,7769,7770,7771,7772,7773,7774,7775],{"id":7598,"depth":516,"text":7599},{"id":7611,"depth":516,"text":7612},{"id":7646,"depth":516,"text":7647},{"id":7665,"depth":516,"text":7666},{"id":7693,"depth":516,"text":7694},{"id":7728,"depth":516,"text":7729},{"id":7741,"depth":516,"text":7742},{"id":7283,"depth":516,"text":7284},"2025-10-10","Stop learning from tutorials. Start with the people who actually want to teach you - the library authors, researchers, and spec writers.",{"src":7779,"alt":7780},"\u002Fimages\u002Fblog\u002F20251011-0330-read-the-source.png","A developer's workspace from a cinematic side angle showing two monitors side by side, the left monitor displaying an open manual with \"The F***ing Manual\" visible at the top, the right monitor showing clean source code being actively written, with a glowing golden light connecting the two screens. A notepad with \"Notes\" written on it lies between the monitors, bathed in warm light. Faded, scattered papers and a dimmed tablet showing blog posts lie pushed to the far edges in shadow. Dramatic lighting with warm spotlight on the two monitors and notepad, cool blue ambient light in the background. Photo realistic, professional photography quality, 8k detail, shallow depth of field focusing on the connected monitors, cinematic color grading with teal and orange tones.",{},{"title":121,"description":7777},"5HyXQUtjhn33upFP4RoCYEv1PCL7Svc5vBv8qkjL2D0",{"id":7785,"title":117,"authors":7786,"badge":7789,"body":7791,"date":7941,"description":7942,"extension":533,"image":7943,"meta":7946,"navigation":538,"path":118,"seo":7947,"status":540,"stem":119,"__hash__":7948},"posts\u002F2.blog\u002F20251004.min-maxer-trifecta.md",[7787],{"name":292,"to":293,"avatar":7788},{"src":295},{"label":7790},"Dev Tools",{"type":299,"value":7792,"toc":7935},[7793,7802,7806,7812,7818,7824,7837,7850,7856,7860,7863,7869,7875,7882,7886,7889,7895,7906,7912,7918,7922,7925,7932],[302,7794,7795,7796,7801],{},"I have two hours free this weekend. Should I work on that side project, or play ",[335,7797,7800],{"href":7798,"rel":7799},"https:\u002F\u002Flastepoch.com\u002F",[461],"Last Epoch"," on Steam on Linux? The answer used to feel like a compromise - dev time versus downtime, productive versus \"wasting time.\" Now it's both. I'm building tools that help optimize my Last Epoch builds, which means every gaming session is also research, and every dev session scratches the same optimization itch that drew me to ARPGs in the first place.",[318,7803,7805],{"id":7804},"three-favorite-things-never-enough-time","Three Favorite Things, Never Enough Time",[302,7807,7808,7811],{},[326,7809,7810],{},"AI Development"," has become the puzzle that never gets old. So much to learn - it's the same dopamine hit as solving a complex architectural problem, but faster iterations and immediate feedback.",[302,7813,7814,7817],{},[326,7815,7816],{},"Software Engineering"," remains the foundation. Building systems, designing APIs, managing state - this is still where I spend most of my professional time. The craft never stops evolving, and neither does the learning curve.",[302,7819,7820,7823],{},[326,7821,7822],{},"ARPG Gaming"," is my relaxation valve. Specifically Last Epoch - the skill tree complexity, build diversity, and satisfying loot loops. It's mindless enough to decompress, deep enough to stay engaging. I've even got my amazing wife Danielle to play it with me, but I do have to manage her loot filters!",[302,7825,7826,7827,7832,7833,7836],{},"The traditional conflict: gaming feels \"unproductive.\" As someone who min-maxes everything (developer toolchains, learning paths, even my ",[335,7828,7831],{"href":7829,"rel":7830},"https:\u002F\u002Fgithub.com\u002FChrisTowles\u002Fdotfiles",[461],"dotfiles","), spending two hours grinding in an ARPG triggers the same guilt as fixing a CI\u002FCD build chain. It's entertainment, sure, but is it the ",[920,7834,7835],{},"optimal"," use of that time?",[302,7838,7839,7840,7845,7846,7849],{},"The min-maxer's curse is that you can't just \"casually\" engage with anything. If I'm playing Last Epoch, I'm researching optimal passive tree paths from ",[335,7841,7844],{"href":7842,"rel":7843},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=3EZclX7TpjI",[461],"Raxx's Bin Stash",", comparing gear affixes, calculating damage breakpoints. If I'm going to play, I'm going to play ",[920,7847,7848],{},"optimally",". My wife doesn't get it, but she humors me.",[302,7851,7852,7853],{},"My Chrome Bookmarks bar has a folder with subfolders to even optimize my gaming time:\n",[467,7854],{"alt":515,"src":7855},"\u002Fimages\u002Fblog\u002Flast-epoch-booksmark-folder.png",[318,7857,7859],{"id":7858},"the-trifecta-when-dev-work-becomes-game-research","The Trifecta - When Dev Work Becomes Game Research",[302,7861,7862],{},"Enter building Last Epoch tools - starting with loot filter builders, and maybe something more later.",[302,7864,7865,7868],{},[326,7866,7867],{},"The concept",": Build practical tools that solve real problems I encounter while playing.",[302,7870,7871,7872,1207],{},"The satisfaction hits different from a typical side project. This isn't building a TODO app to learn a framework. This is building a tool that directly improves something I can test again—a really complex use case that ",[920,7873,7874],{},"happens to be fun at the same time",[302,7876,7877,7878,7881],{},"Like ",[745,7879,7880],{},"SimulationCraft"," for World of Warcraft or Decursive back in the day. The last time I wrote a game addon was for WoW in Lua - a WoW addon called PallyPower to automate 5 min paladin buffs for our raiding team in Molten Core.",[318,7883,7885],{"id":7884},"the-broader-pattern","The Broader Pattern",[302,7887,7888],{},"What if more developers found ways to combine their work and play like this?",[302,7890,7891,7894],{},[326,7892,7893],{},"For Developers",": Stop building \"interesting technical challenges\" and start building tools that solve your real problems. The motivation stays high, the use cases are concrete, and the feedback is instant and testable.",[302,7896,7897,7900,7901,1207],{},[326,7898,7899],{},"For Gamers",": Your optimization obsession isn't a distraction - it's fuel for learning. The same analytical mindset that drives build theory-crafting drives system architecture. ",[335,7902,7905],{"href":7903,"rel":7904},"https:\u002F\u002Fwww.youtube.com\u002Fshorts\u002F3wrV0dRkRmg",[461],"And that's pretty cool",[302,7907,7908,7911],{},[326,7909,7910],{},"For Tool Builders",": Toy examples teach syntax. Real use cases teach judgment. Building tools for something you care about forces you to grapple with the hard problems - edge cases, data validation, performance optimization, hosting.",[302,7913,7914,7917],{},[326,7915,7916],{},"The meta-lesson",": The best side projects don't feel like work OR play. They feel like both, simultaneously. You're productive and relaxed at the same time. You're learning and enjoying. You're solving problems and having fun.",[318,7919,7921],{"id":7920},"the-best-part","The Best Part",[302,7923,7924],{},"When I boot up Last Epoch now, I'm not choosing between development and gaming. I'm doing both.",[302,7926,7927,7928,7931],{},"The insights I gain get better with every edge case I discover. My builds get better with every tool I create. And I actually ",[920,7929,7930],{},"relax"," while playing - because it's all progress. The min-maxer in me is satisfied because I'm optimizing two systems simultaneously. The developer in me is satisfied because I'm building real tools. The gamer in me is satisfied because I'm enjoying my favorite ARPG without guilt.",[302,7933,7934],{},"Three favorite things, one satisfying loop. That's the trifecta. On top of that, it stops me from working on work projects, risking my wife's ire for \"always working.\" God, I love her and my kids. And that's a win-win-win.",{"title":515,"searchDepth":516,"depth":516,"links":7936},[7937,7938,7939,7940],{"id":7804,"depth":516,"text":7805},{"id":7858,"depth":516,"text":7859},{"id":7884,"depth":516,"text":7885},{"id":7920,"depth":516,"text":7921},"2025-10-04","How building tools for Last Epoch lets me combine software development, gaming, and guilt-free relaxation into one satisfying loop.",{"src":7944,"alt":7945},"\u002Fimages\u002Fblog\u002F20251004-1430-min-maxer-trifecta.png","Developer optimizing both code and game builds simultaneously",{},{"title":117,"description":7942},"PzZ6NTgFzPgvRbhQGLMiIihql0EKBos4303ewDy-da4",{"id":7950,"title":113,"authors":7951,"badge":7954,"body":7955,"date":8189,"description":8190,"extension":533,"image":8191,"meta":8194,"navigation":538,"path":114,"seo":8195,"status":540,"stem":115,"__hash__":8196},"posts\u002F2.blog\u002F20250928.why-i-bought-tesla-model-3-vertical-integration.md",[7952],{"name":292,"to":293,"avatar":7953},{"src":295},{"label":1089},{"type":299,"value":7956,"toc":8179},[7957,7960,7963,7969,7973,7976,7980,7983,7986,7989,7993,7996,7999,8002,8005,8009,8012,8015,8018,8021,8025,8033,8046,8051,8056,8082,8087,8101,8104,8107,8111,8114,8117,8120,8124,8127,8130,8150,8153,8157,8160,8163,8166,8169,8172,8174],[302,7958,7959],{},"I used to listen to Tesla Daily religiously. Every morning, Rob Maurer's voice walking me through the latest updates on battery chemistry, manufacturing innovations, and yes—vertical integration. Then came the X.com acquisition, and honestly? I got burnt out on all the noise.",[302,7961,7962],{},"But when I bought a car, what stuck with me wasn't the hype. It was the engineering lesson: vertical integration isn't just automotive strategy—it's competitive advantage.",[302,7964,7965,7966],{},"And as a software engineer who's been online since AOL, I chose Tesla for one simple reason: ",[326,7967,7968],{},"I can't find the seams.",[318,7970,7972],{"id":7971},"the-strategy-that-survived-the-noise","The Strategy That Survived the Noise",[302,7974,7975],{},"When Twitter drama drowned out engineering discussions, I stepped away from tracking Tesla and Elon. But sound engineering principles work regardless of noise. The vertical integration I learned about in 2018-2021 didn't stop being brilliant because of social media chaos—time validated it.",[318,7977,7979],{"id":7978},"vertical-integration-vs-assembly","Vertical Integration vs. Assembly",[302,7981,7982],{},"Companies that control their stack: Apple (silicon, OS, retail), Netflix (content, streaming tech, algorithms), Tesla (batteries, software, manufacturing, sales).",[302,7984,7985],{},"Companies that assemble: Traditional auto makers (80%+ outsourced components, dealer networks), traditional media (licensed content, third-party platforms), traditional tech (commodity chips, generic OS).",[302,7987,7988],{},"The difference is architectural—and it determines who controls the user experience.",[318,7990,7992],{"id":7991},"i-cant-find-the-seams","I Can't Find the Seams",[302,7994,7995],{},"After 25 years online, I can always spot the boundary between systems. The UI shifts, interaction patterns change, quality jumps or drops.",[302,7997,7998],{},"But in truly integrated systems? No seams.",[302,8000,8001],{},"My Tesla preconditions the battery for charging, and the same thermal stack manages cabin temperature. Set climate to 72°, the system doesn't differentiate between \"keep battery optimal\" and \"keep human comfortable\"—it's one integrated system.",[302,8003,8004],{},"This is what happens when you control the stack: you decide where abstractions live.",[318,8006,8008],{"id":8007},"the-no-one-owns-this-problem-problem","The \"No One Owns This Problem\" Problem",[302,8010,8011],{},"Assembly-based systems have blame boundaries:",[302,8013,8014],{},"Frontend blames Backend. Backend blames CDN. CDN blames origin. Meanwhile, users leave because the page takes 30 seconds to load.",[302,8016,8017],{},"When VW's infotainment crashes, the dealer says it's Bosch. Bosch says it's integration. Software says it's hardware. Six months, no fix. Two years later, still no fix.",[302,8019,8020],{},"Tesla eliminated this. Charging issue? They pushed an update to the entire fleet. One team owns charging hardware, software, payment processing, and the app.",[318,8022,8024],{"id":8023},"the-scope-of-teslas-integration","The Scope of Tesla's Integration",[302,8026,8027,8032],{},[335,8028,8031],{"href":8029,"rel":8030},"https:\u002F\u002Fwww.notateslaapp.com\u002Ftesla-reference\u002F867\u002Ftesla-s-vertical-integration-and-efficiency-show-why-they-re-the-leader-in-evs",[461],"NotATeslaApp's breakdown"," shows how far this goes:",[302,8034,8035,8039],{},[467,8036],{"alt":8037,"src":8038},"Tesla's Vertical Integration Chart","images\u002Fblog\u002Ftesla-vertical-integration-from-notateslaapp.jpg",[920,8040,8041,8042],{},"Chart credit: ",[335,8043,8045],{"href":8029,"rel":8044},[461],"NotATeslaApp",[302,8047,8048],{},[326,8049,8050],{},"What this chart reveals:",[302,8052,8053],{},[326,8054,8055],{},"Tesla's approach spans four major categories:",[368,8057,8058,8064,8070,8076],{},[371,8059,8060,8063],{},[326,8061,8062],{},"Auto",": Everything from the car body to powertrains to service",[371,8065,8066,8069],{},[326,8067,8068],{},"Hardware\u002FSoftware",": Custom chips, FSD software, infotainment systems",[371,8071,8072,8075],{},[326,8073,8074],{},"Energy",": Solar panels, Powerwalls, grid services, battery production",[371,8077,8078,8081],{},[326,8079,8080],{},"Other",": Insurance, robotics, automation systems",[302,8083,8084],{},[326,8085,8086],{},"Traditional competitors rely on external vendors for:",[368,8088,8089,8092,8095,8098],{},[371,8090,8091],{},"Critical software components (Apple CarPlay, Android Auto instead of custom systems)",[371,8093,8094],{},"Core hardware (NVIDIA chips instead of custom silicon)",[371,8096,8097],{},"Manufacturing equipment (Bosch, Continental suppliers)",[371,8099,8100],{},"Sales channels (dealership networks instead of direct sales)",[302,8102,8103],{},"This isn't just about making more components in-house—it's about controlling every layer of the technology stack. As Elon Musk described it, \"Tesla is a chain of startups,\" each focused on a specific piece of the integrated experience.",[302,8105,8106],{},"The result? When I drive to San Francisco, the car automatically preconditions the battery 20 minutes before I hit the Supercharger. When I get there, the charging port opens as I walk up, and the car starts charging without me touching anything. The nav system already factored in my driving style, the weather, and the charging curve to route me to a station that'll be ready when I arrive.",[318,8108,8110],{"id":8109},"one-codebase-one-quality-standard","One Codebase, One Quality Standard",[302,8112,8113],{},"The Tesla app uses the same APIs as the car's touchscreen. Fix a charging bug, it's fixed everywhere simultaneously.",[302,8115,8116],{},"Traditional automakers: mobile app from one vendor, infotainment from another, navigation from a third. Each has different bugs, update schedules, and definitions of \"low battery.\"",[302,8118,8119],{},"In my Tesla, state-of-charge means the same thing in the app, dashboard, charging screen, and Supercharger network. One codebase, one battery management system.",[318,8121,8123],{"id":8122},"why-this-matters-for-engineers","Why This Matters for Engineers",[302,8125,8126],{},"Same reason I choose monorepos over microservice chaos: control over abstraction layers means optimizing for user problems, not vendor limitations.",[302,8128,8129],{},"Tesla treats cars like software:",[368,8131,8132,8138,8144],{},[371,8133,8134,8137],{},[326,8135,8136],{},"Continuous deployment",": Bug fixes to millions of cars overnight",[371,8139,8140,8143],{},[326,8141,8142],{},"Shared state",": One source of truth for battery charge, location, preferences",[371,8145,8146,8149],{},[326,8147,8148],{},"End-to-end testing",": Changes verified from app to charging hardware",[302,8151,8152],{},"Traditional automakers ship software like it's 2005—CDs, isolation, prayer.",[318,8154,8156],{"id":8155},"the-engineering-decision","The Engineering Decision",[302,8158,8159],{},"I bought Tesla because I recognize good architecture.",[302,8161,8162],{},"Full stack control—battery cells to mobile app—enables decisions impossible in assembled systems. Optimize charging curves based on real-time temperature data, update the algorithm fleet-wide overnight.",[302,8164,8165],{},"Try that with LG Chem batteries, Bosch software, Accenture's app, and Electrify America's network.",[302,8167,8168],{},"After 25 years debugging integration problems, driving a unified system is remarkable.",[302,8170,8171],{},"That's what vertical integration gets you: the ability to engineer solutions instead of engineering around limitations.",[3286,8173],{},[302,8175,8176],{},[920,8177,8178],{},"What's your experience with integrated vs. assembled systems in your industry? Have you found opportunities to take more control over your customer experience? I'd love to hear about your wins and challenges in building cohesive systems.",{"title":515,"searchDepth":516,"depth":516,"links":8180},[8181,8182,8183,8184,8185,8186,8187,8188],{"id":7971,"depth":516,"text":7972},{"id":7978,"depth":516,"text":7979},{"id":7991,"depth":516,"text":7992},{"id":8007,"depth":516,"text":8008},{"id":8023,"depth":516,"text":8024},{"id":8109,"depth":516,"text":8110},{"id":8122,"depth":516,"text":8123},{"id":8155,"depth":516,"text":8156},"2025-09-28","Tesla taught me something profound about business strategy: when you can't find the seams between components, you're looking at vertical integration done right. Here's why more industries need to pay attention.",{"src":8192,"alt":8193},"\u002Fimages\u002Fblog\u002F20250929-0130-why-vertical-integration-wins.png","Tesla's comprehensive vertical integration compared to traditional competitors across auto, software, energy, and other categories",{},{"title":113,"description":8190},"dSUtmwZCC1D3POLL-5o9HIEamBb8nZhukIuiL9vFyv0",{"id":8198,"title":109,"authors":8199,"badge":8202,"body":8203,"date":8276,"description":8277,"extension":533,"image":8278,"meta":8281,"navigation":538,"path":110,"seo":8282,"status":540,"stem":111,"__hash__":8283},"posts\u002F2.blog\u002F20250907.beyond-api-wrappers-mcp-servers.md",[8200],{"name":292,"to":293,"avatar":8201},{"src":295},{"label":1089},{"type":299,"value":8204,"toc":8271},[8205,8208,8211,8215,8218,8221,8227,8230,8234,8237,8240,8243,8246,8249,8252,8256,8259,8262,8265,8268],[302,8206,8207],{},"When MCP launched, everyone rushed to wrap their favorite APIs. GitHub servers, Slack integrations, database connectors—the ecosystem exploded with what could be called \"API wrapper syndrome.\" But that's just scratching the surface of what the Model Context Protocol can actually do.",[302,8209,8210],{},"If you see MCP servers as wrappers around APIs, then sure, most of the ones you'd want already exist. It was the obvious first move, the low-hanging fruit. But there's a fundamentally different way to think about MCP that opens up possibilities we're barely exploring.",[318,8212,8214],{"id":8213},"the-api-wrapper-trap","The API Wrapper Trap",[302,8216,8217],{},"The rush to create MCP servers for every popular service made perfect sense. Need to let Claude access your GitHub repos? Build a GitHub MCP server. Want Slack integration? Another server. Database queries? You get the idea.",[302,8219,8220],{},"This approach works because it maps cleanly to how we already think about tool integration. Each API becomes a set of MCP tools, each endpoint becomes a method call. The mental model is familiar, the implementation is straightforward, and the value is immediate.",[302,8222,8223,8224],{},"But here's what we're missing: ",[326,8225,8226],{},"MCP servers don't have to wrap existing APIs at all.",[302,8228,8229],{},"What I think the second phase of MCP could be about is moving beyond the API wrapper pattern to orchestrating multiple teams of highly specialized agents through complex phases of long-horizon projects—like building an n-tier enterprise system or producing a game level, script, or conversation history. Something you might be able to describe in a state machine.",[318,8231,8233],{"id":8232},"state-machines-as-dynamic-resources","State Machines as Dynamic Resources",[302,8235,8236],{},"Instead of wrapping APIs, I've been reading code in AI projects where there is an orchestration layer agent. Routing to different specialized agents, I'm thinking those agents can be MCP servers that solve a problem by working through a state machine. Each state has a different set of actions (think tools). There's no external API being adapted—just state machines to manage, agents that can subscribe to those states, and validation prompts that help teams verify their work before triggering transitions.",[302,8238,8239],{},"Here's how I'm thinking about it: imagine you're building an e-commerce order system. The flow might be: user adds to cart, user checks out, order created, payment processed, payment success, order set to paid, fulfillment started, item shipped, delivery confirmed. Each state could require different specialized agents—inventory checkers, payment processors, fulfillment coordinators, shipping agents.",[302,8241,8242],{},"Rather than manually coordinating these agents, the MCP server could maintain the order's state machine. Agents could even subscribe to the states relevant to their expertise. When the payment processor completes successfully, it triggers a state transition that notifies the fulfillment team. But here's what I think could be the key part: the transition includes validation prompts.",[302,8244,8245],{},"Before moving from payment success to paid status, the server could prompt an LLM: \"Does this payment confirmation match the order total and payment method?\" If not, the transition fails and the order gets flagged for review.",[302,8247,8248],{},"This isn't just workflow automation—it could be intelligent orchestration where the state transitions themselves become checkpoints for quality and consistency across the order lifecycle.",[302,8250,8251],{},"The server exposes tools for agents to query current order state, subscribe to state notifications, propose state transitions, and access validation prompts specific to their role. But more importantly, it exposes resources that represent the evolving order data, the relationships between states, and the accumulated context from previous states.",[318,8253,8255],{"id":8254},"the-endless-possibilities","The Endless Possibilities",[302,8257,8258],{},"When you stop thinking of MCP servers as API wrappers, you start seeing them as systems that can expose any kind of tool, resource, or prompt to an LLM. Sure, some of those tools might call APIs, but they can just as easily invoke an agent or functionality within the server itself. (Note: if a human is involved in the loop, you'll have to figure out real-time status updates to keep the user engaged—or a work queue they can check back on.)",[302,8260,8261],{},"And servers can act as clients to other servers. I'm imagining a state machine server that coordinates with specialized model servers, data processing servers, and validation servers to create orchestration networks that could handle complexity far beyond what any single API wrapper could achieve.",[302,8263,8264],{},"The possibilities aren't just endless—they're largely unexplored. We've built the infrastructure for something revolutionary and collectively decided to use it mostly as a better way to call REST endpoints.",[302,8266,8267],{},"What purpose-built custom host for MCP clients might you write? What state machines could orchestrate the complex work in your domain? What kind of intelligent validation could ensure quality as projects flow through phases?",[302,8269,8270],{},"The low-hanging fruit has been picked. Now it's time to see how high this tree actually grows.",{"title":515,"searchDepth":516,"depth":516,"links":8272},[8273,8274,8275],{"id":8213,"depth":516,"text":8214},{"id":8232,"depth":516,"text":8233},{"id":8254,"depth":516,"text":8255},"2025-09-07","Explore how MCP servers can move beyond simple API wrappers to become sophisticated state machines that orchestrate complex, multi-phase projects with specialized agent teams",{"src":8279,"alt":8280},"\u002Fimages\u002Fblog\u002F20250907-beyond-api-wrappers-mcp-servers.png","State machine diagram showing agent orchestration across project phases",{},{"title":109,"description":8277},"VLC-5EFC0Fl70BtFfC0ba7nysTIA368bN-wpWEpOhvQ",{"id":8285,"title":105,"authors":8286,"badge":8289,"body":8290,"date":8502,"description":8503,"extension":533,"image":8504,"meta":8507,"navigation":538,"path":106,"seo":8508,"status":540,"stem":107,"__hash__":8509},"posts\u002F2.blog\u002F20250822.dotfiles-masterpiece-or-late-stage-picasso.md",[8287],{"name":292,"to":293,"avatar":8288},{"src":295},{"label":7831},{"type":299,"value":8291,"toc":8488},[8292,8296,8304,8308,8311,8314,8320,8323,8326,8330,8333,8350,8353,8356,8360,8363,8366,8370,8373,8377,8380,8384,8387,8401,8405,8408,8422,8426,8429,8433,8436,8439,8441,8467,8470,8473,8476,8479,8481],[8293,8294,105],"h1",{"id":8295},"dotfiles-masterpiece-or-late-stage-picasso",[302,8297,8298,8299,8303],{},"You know what they say about ugly babies - only their parents could love them. Well, my ",[335,8300,8302],{"href":7829,"rel":8301},[461],"dotfiles repository"," was definitely that ugly baby. A chaotic collection of scripts, aliases, and configuration files that somehow worked but looked like... well, let's just say it had character.",[318,8305,8307],{"id":8306},"the-masterpiece-incident","The \"Masterpiece\" Incident",[302,8309,8310],{},"A few months ago, I was pair programming with a colleague when I pulled out one of my custom scripts to solve a problem we were wrestling with. You know how it is - you've got that one shell script that does exactly what you need, even if it's held together with digital duct tape and good intentions.",[302,8312,8313],{},"This developer was impressed. Really impressed. They asked if they could see my dotfiles repository, and like a proud parent showing off baby photos, I shared the link.",[302,8315,8316,8317],{},"A week later, they came back and said something that both flattered and horrified me: ",[326,8318,8319],{},"\"This is like a masterpiece! I took all of your scripts!\"",[302,8321,8322],{},"My immediate response? \"If it's a masterpiece, it's late stage Picasso.\"",[302,8324,8325],{},"You know what I mean - those paintings where you're not quite sure if it's genius or if someone just threw paint at a canvas. My dotfiles were functional chaos. They worked for me because I knew where everything was and how all the pieces fit together, but they were definitely not something you'd want to show your mother.",[318,8327,8329],{"id":8328},"the-reality-check","The Reality Check",[302,8331,8332],{},"The truth was, my dotfiles repository was an organically grown mess. Over the years, I'd accumulated:",[368,8334,8335,8338,8341,8344,8347],{},[371,8336,8337],{},"Shell scripts scattered across multiple directories",[371,8339,8340],{},"Aliases that only made sense to me",[371,8342,8343],{},"Configuration files with hardcoded paths",[371,8345,8346],{},"Dependencies that weren't documented",[371,8348,8349],{},"Installation processes that required tribal knowledge",[302,8351,8352],{},"It was the kind of repo where the README basically said \"good luck\" and you needed a PhD in Chris-ology to get anything working.",[302,8354,8355],{},"But here's the thing - someone else saw value in that chaos. They saw solutions to problems they had, patterns they could adapt, tools they could use. And that got me thinking: what if I could maintain the functionality but make it actually, you know, usable by other humans?",[318,8357,8359],{"id":8358},"enter-claude","Enter Claude",[302,8361,8362],{},"This is where my relationship with AI tools really started paying dividends. I've been using Claude for code reviews and refactoring, but this felt like the perfect test case. Could Claude help me transform my chaotic collection of scripts into something modular and maintainable?",[302,8364,8365],{},"I started by having Claude analyze my existing setup. I explained what each script did, how they were interconnected, and what problems they solved. Claude helped me see patterns I hadn't noticed and identify opportunities for modularization.",[318,8367,8369],{"id":8368},"the-transformation","The Transformation",[302,8371,8372],{},"Working with Claude, we completely restructured the repository:",[401,8374,8376],{"id":8375},"modular-design","Modular Design",[302,8378,8379],{},"Instead of monolithic scripts, we broke everything down into focused, single-responsibility modules. Each script now does one thing well and can be composed with others.",[401,8381,8383],{"id":8382},"automatic-installation","Automatic Installation",[302,8385,8386],{},"This was the game-changer. Claude helped me build an installation system that:",[368,8388,8389,8392,8395,8398],{},[371,8390,8391],{},"Detects your operating system and shell",[371,8393,8394],{},"Checks for dependencies and installs them if needed",[371,8396,8397],{},"Backs up your existing configurations before making changes",[371,8399,8400],{},"Provides clear feedback about what's happening and why",[401,8402,8404],{"id":8403},"better-documentation","Better Documentation",[302,8406,8407],{},"Each module now has clear documentation explaining:",[368,8409,8410,8413,8416,8419],{},[371,8411,8412],{},"What it does",[371,8414,8415],{},"What dependencies it has",[371,8417,8418],{},"How to use it",[371,8420,8421],{},"How to customize it",[401,8423,8425],{"id":8424},"dependency-management","Dependency Management",[302,8427,8428],{},"We created a proper dependency system that maps out what each tool needs and ensures everything gets installed in the right order.",[318,8430,8432],{"id":8431},"the-result","The Result",[302,8434,8435],{},"What used to be a \"you need to know me to use this\" repository is now something that someone can actually clone and use. The installation process went from \"good luck figuring this out\" to running a single command and watching everything set itself up.",[302,8437,8438],{},"The best part? It's still my ugly baby, but now it's an ugly baby that other people can actually adopt.",[318,8440,6195],{"id":6194},[851,8442,8443,8449,8455,8461],{},[371,8444,8445,8448],{},[326,8446,8447],{},"Sometimes you need an outside perspective"," - That colleague's enthusiasm helped me see potential I was blind to.",[371,8450,8451,8454],{},[326,8452,8453],{},"AI excels at finding patterns"," - Claude was incredibly good at spotting opportunities for modularization that I missed.",[371,8456,8457,8460],{},[326,8458,8459],{},"Automation is a gift to your future self"," - The time invested in the automatic installation system has already paid for itself.",[371,8462,8463,8466],{},[326,8464,8465],{},"Documentation is love"," - If you care about your tools being useful to others (or your future self), document them properly.",[318,8468,8469],{"id":3101},"What's Next?",[302,8471,8472],{},"The repository is now actually something I'm proud to share. It's modular, well-documented, and includes an automatic installation system that makes onboarding new team members infinitely easier.",[302,8474,8475],{},"More importantly, it's taught me the value of taking a step back and looking at my tools with fresh eyes. Sometimes what seems like organized chaos to you is just chaos to everyone else.",[302,8477,8478],{},"And who knows? Maybe someone else will look at the new version and call it a masterpiece. This time, I'll take it as the compliment it was meant to be.",[3286,8480],{},[302,8482,8483,8484,8487],{},"If you're curious about the transformation, check out the ",[335,8485,8302],{"href":7829,"rel":8486},[461],". Whether you think it's a masterpiece or late stage Picasso, at least now you can actually install it without needing a decoder ring.",{"title":515,"searchDepth":516,"depth":516,"links":8489},[8490,8491,8492,8493,8499,8500,8501],{"id":8306,"depth":516,"text":8307},{"id":8328,"depth":516,"text":8329},{"id":8358,"depth":516,"text":8359},{"id":8368,"depth":516,"text":8369,"children":8494},[8495,8496,8497,8498],{"id":8375,"depth":523,"text":8376},{"id":8382,"depth":523,"text":8383},{"id":8403,"depth":523,"text":8404},{"id":8424,"depth":523,"text":8425},{"id":8431,"depth":516,"text":8432},{"id":6194,"depth":516,"text":6195},{"id":3101,"depth":516,"text":8469},"2025-08-22","The story of how someone took all my scripts, called them a masterpiece, and how Claude helped me make them actually worth it",{"src":8505,"alt":8506},"\u002Fimages\u002Fblog\u002F20250822-dotfiles-masterpiece-or-late-stage-picasso.png","A cinematic split-screen composition showing transformation: on the left, a chaotic abstract Picasso-style painting made of tangled code snippets, terminal windows, and script files in warm oranges and reds; on the right, the same elements organized into clean, geometric modular blocks with cool blues and professional lighting. In the center, a subtle AI assistant presence (represented by a glowing neural network pattern) bridges the two sides. Professional photography quality with dramatic lighting contrast, contemplative mood, showing the journey from creative chaos to structured elegance.",{},{"title":105,"description":8503},"dOP_0x9uzA_AUZyUDLuntGQs4K_oJz673q1-Nb7gyg8",{"id":8511,"title":101,"authors":8512,"badge":8515,"body":8516,"date":8875,"description":8876,"extension":533,"image":8877,"meta":8880,"navigation":538,"path":102,"seo":8881,"status":540,"stem":103,"__hash__":8882},"posts\u002F2.blog\u002F20250819.finally-type-safe-ai-in-production-and-why-im-here-for-it.md",[8513],{"name":292,"to":293,"avatar":8514},{"src":295},{"label":1732},{"type":299,"value":8517,"toc":8862},[8518,8521,8527,8530,8533,8537,8540,8544,8547,8551,8554,8558,8561,8565,8568,8572,8792,8795,8799,8802,8828,8831,8835,8838,8842,8845,8856,8859],[302,8519,8520],{},"We've been shipping AI applications with our fingers crossed. Parse the LLM output, hope it matches your schema, catch errors in production. It was the wild west.",[302,8522,8523,8524],{},"But something's changing, and I'm genuinely excited about it: ",[326,8525,8526],{},"production AI is finally getting the type safety and validation it desperately needs.",[302,8528,8529],{},"While working on MCP and looking for examples, I found nearly everyone is using TypeScript and Zod integration. Suddenly, my LLM outputs had compile-time guarantees. No more defensive parsing everywhere. Just predictable, type-safe AI responses.",[302,8531,8532],{},"This isn't about TypeScript versus Python. It's about production AI applications finally becoming as reliable as the rest of our stack.",[318,8534,8536],{"id":8535},"the-engineering-discipline-weve-been-waiting-for","The Engineering Discipline We've Been Waiting For",[302,8538,8539],{},"Here's what's got me excited about TypeScript in production AI:",[401,8541,8543],{"id":8542},"zod-openai-compile-time-llm-guarantees","Zod + OpenAI: Compile-Time LLM Guarantees",[302,8545,8546],{},"OpenAI's native Zod support means we can define schemas once and get compile-time type checking for AI outputs. This is huge—we're talking about turning unpredictable LLM responses into type-safe, validated data structures. No more runtime surprises.",[401,8548,8550],{"id":8549},"vercel-ai-sdk-production-grade-streaming","Vercel AI SDK: Production-Grade Streaming",[302,8552,8553],{},"2M+ developers aren't just using this for fun—they're building reliable, streaming AI features that don't crash in production. The SDK brings proper error handling, and type safety to AI streaming. Finally, streaming AI that feels like production software.",[401,8555,8557],{"id":8556},"tools-built-on-trust","Tools Built on Trust",[302,8559,8560],{},"Anthropic chose TypeScript for Claude Code because production tools need predictability. This is a tool they built for internal use, but TypeScript provides the reliability foundation that production AI tools require.",[318,8562,8564],{"id":8563},"why-type-safety-changes-everything-for-ai","Why Type Safety Changes Everything for AI",[302,8566,8567],{},"LLMs are inherently unpredictable. They hallucinate, they return unexpected formats, they break schemas. In Python, we handle this with runtime validation and hope for the best. In TypeScript, we handle it at compile time.",[401,8569,8571],{"id":8570},"the-zod-difference","The Zod Difference",[1119,8573,8575],{"className":1478,"code":8574,"language":1480,"meta":515,"style":515},"const ResponseSchema = z.object({\n  analysis: z.string(),\n  confidence: z.number().min(0).max(1),\n  suggestions: z.array(z.string())\n});\n\n\u002F\u002F clearly communicates to the LLM exactly what we expect\nconst response = await openai.chat.completions.create({\n  model: \"gpt-4\",\n  messages: [...],\n  response_format: zodResponseFormat(ResponseSchema, \"analysis\")\n});\n",[745,8576,8577,8598,8615,8656,8680,8688,8692,8697,8730,8745,8760,8784],{"__ignoreMap":515},[1127,8578,8579,8581,8584,8586,8589,8591,8594,8596],{"class":1129,"line":1130},[1127,8580,1494],{"class":1493},[1127,8582,8583],{"class":1497}," ResponseSchema ",[1127,8585,1502],{"class":1501},[1127,8587,8588],{"class":1497}," z",[1127,8590,1207],{"class":1501},[1127,8592,8593],{"class":1505},"object",[1127,8595,1542],{"class":1497},[1127,8597,1545],{"class":1501},[1127,8599,8600,8603,8605,8607,8609,8611,8613],{"class":1129,"line":516},[1127,8601,8602],{"class":1550},"  analysis",[1127,8604,1554],{"class":1501},[1127,8606,8588],{"class":1497},[1127,8608,1207],{"class":1501},[1127,8610,6015],{"class":1505},[1127,8612,6039],{"class":1497},[1127,8614,1570],{"class":1501},[1127,8616,8617,8620,8622,8624,8626,8629,8631,8633,8636,8638,8640,8642,8644,8647,8649,8652,8654],{"class":1129,"line":523},[1127,8618,8619],{"class":1550},"  confidence",[1127,8621,1554],{"class":1501},[1127,8623,8588],{"class":1497},[1127,8625,1207],{"class":1501},[1127,8627,8628],{"class":1505},"number",[1127,8630,6039],{"class":1497},[1127,8632,1207],{"class":1501},[1127,8634,8635],{"class":1505},"min",[1127,8637,1542],{"class":1497},[1127,8639,4291],{"class":1580},[1127,8641,1652],{"class":1497},[1127,8643,1207],{"class":1501},[1127,8645,8646],{"class":1505},"max",[1127,8648,1542],{"class":1497},[1127,8650,8651],{"class":1580},"1",[1127,8653,1652],{"class":1497},[1127,8655,1570],{"class":1501},[1127,8657,8658,8661,8663,8665,8667,8670,8673,8675,8677],{"class":1129,"line":1146},[1127,8659,8660],{"class":1550},"  suggestions",[1127,8662,1554],{"class":1501},[1127,8664,8588],{"class":1497},[1127,8666,1207],{"class":1501},[1127,8668,8669],{"class":1505},"array",[1127,8671,8672],{"class":1497},"(z",[1127,8674,1207],{"class":1501},[1127,8676,6015],{"class":1505},[1127,8678,8679],{"class":1497},"())\n",[1127,8681,8682,8684,8686],{"class":1129,"line":1382},[1127,8683,1639],{"class":1501},[1127,8685,1652],{"class":1497},[1127,8687,1512],{"class":1501},[1127,8689,8690],{"class":1129,"line":1388},[1127,8691,1517],{"emptyLinePlaceholder":538},[1127,8693,8694],{"class":1129,"line":1586},[1127,8695,8696],{"class":1487},"\u002F\u002F clearly communicates to the LLM exactly what we expect\n",[1127,8698,8699,8701,8704,8706,8709,8712,8714,8716,8718,8721,8723,8726,8728],{"class":1129,"line":1599},[1127,8700,1494],{"class":1493},[1127,8702,8703],{"class":1497}," response ",[1127,8705,1502],{"class":1501},[1127,8707,8708],{"class":2270}," await",[1127,8710,8711],{"class":1497}," openai",[1127,8713,1207],{"class":1501},[1127,8715,239],{"class":1497},[1127,8717,1207],{"class":1501},[1127,8719,8720],{"class":1497},"completions",[1127,8722,1207],{"class":1501},[1127,8724,8725],{"class":1505},"create",[1127,8727,1542],{"class":1497},[1127,8729,1545],{"class":1501},[1127,8731,8732,8734,8736,8738,8741,8743],{"class":1129,"line":1647},[1127,8733,1551],{"class":1550},[1127,8735,1554],{"class":1501},[1127,8737,3750],{"class":1501},[1127,8739,8740],{"class":1621},"gpt-4",[1127,8742,3736],{"class":1501},[1127,8744,1570],{"class":1501},[1127,8746,8747,8749,8751,8753,8756,8758],{"class":1129,"line":1910},[1127,8748,1602],{"class":1550},[1127,8750,1554],{"class":1501},[1127,8752,1607],{"class":1497},[1127,8754,8755],{"class":1501},"...",[1127,8757,1642],{"class":1497},[1127,8759,1570],{"class":1501},[1127,8761,8762,8765,8767,8770,8773,8775,8777,8779,8781],{"class":1129,"line":1915},[1127,8763,8764],{"class":1550},"  response_format",[1127,8766,1554],{"class":1501},[1127,8768,8769],{"class":1505}," zodResponseFormat",[1127,8771,8772],{"class":1497},"(ResponseSchema",[1127,8774,1628],{"class":1501},[1127,8776,3750],{"class":1501},[1127,8778,1261],{"class":1621},[1127,8780,3736],{"class":1501},[1127,8782,8783],{"class":1497},")\n",[1127,8785,8786,8788,8790],{"class":1129,"line":1920},[1127,8787,1639],{"class":1501},[1127,8789,1652],{"class":1497},[1127,8791,1512],{"class":1501},[302,8793,8794],{},"When this compiles, you KNOW your response will match your schema. No surprises. No runtime errors. Just predictable AI behavior.",[318,8796,8798],{"id":8797},"this-is-just-the-beginning","This Is Just the Beginning",[302,8800,8801],{},"What excites me most isn't that TypeScript is \"winning\" in AI—it's that we're finally treating AI applications like real production software:",[368,8803,8804,8810,8816,8822],{},[371,8805,8806,8809],{},[326,8807,8808],{},"Type safety"," instead of hope",[371,8811,8812,8815],{},[326,8813,8814],{},"Validation"," instead of prayer",[371,8817,8818,8821],{},[326,8819,8820],{},"Predictability"," instead of surprises",[371,8823,8824,8827],{},[326,8825,8826],{},"Engineering discipline"," instead of chaos",[302,8829,8830],{},"Python still owns AI research and training, and that's perfect. But for production applications that users depend on, TypeScript is bringing the engineering rigor we've needed all along.",[318,8832,8834],{"id":8833},"pydantic-is-trying","Pydantic is Trying",[302,8836,8837],{},"I'm using Pydantic as much as I can when in Python. But it's like the Python culture is almost inherently against type safety.\nPydantic provides a great way to define and validate data models, but it still feels like an uphill battle to get buy-in from the broader Python community.",[318,8839,8841],{"id":8840},"join-me-in-building-reliable-ai","Join Me in Building Reliable AI",[302,8843,8844],{},"I'm not here to start a language war. I'm here because I'm excited about building AI applications that don't break in production.",[302,8846,8847,8850,8851],{},[326,8848,8849],{},"Ready to build type-safe AI?"," Check out Matt Pocock's workshop: ",[335,8852,8855],{"href":8853,"rel":8854},"https:\u002F\u002Fgithub.com\u002Fai-hero-dev\u002Fpoland-ai-ts-workshop",[461],"github.com\u002Fai-hero-dev\u002Fpoland-ai-ts-workshop",[302,8857,8858],{},"What's your experience with AI in production? Are you still fighting runtime errors, or have you found your path to type safety? I'd love to hear about your engineering wins and challenges in building reliable AI systems.",[1698,8860,8861],{},"html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":515,"searchDepth":516,"depth":516,"links":8863},[8864,8869,8872,8873,8874],{"id":8535,"depth":516,"text":8536,"children":8865},[8866,8867,8868],{"id":8542,"depth":523,"text":8543},{"id":8549,"depth":523,"text":8550},{"id":8556,"depth":523,"text":8557},{"id":8563,"depth":516,"text":8564,"children":8870},[8871],{"id":8570,"depth":523,"text":8571},{"id":8797,"depth":516,"text":8798},{"id":8833,"depth":516,"text":8834},{"id":8840,"depth":516,"text":8841},"2025-08-19","After years of unpredictable LLM outputs and runtime crashes, TypeScript is bringing the engineering discipline we've needed all along. Here's why I'm excited about type checking in production AI.",{"src":8878,"alt":8879},"\u002Fimages\u002Fblog\u002F20250819-1730-why-typescript-is-eating-pythons-lunch-in-production-llm-applications.png","A cinematic split-screen composition showing the evolution of production AI development: on the left, Python code and ML models representing research and training (darker, academic feel with neural network visualizations), on the right, TypeScript code with streaming APIs and web interfaces representing production deployment (brighter, modern feel with real-time data flows). The transition between sides flows like a bridge made of glowing code elements and data streams, symbolizing the shift from research to production. Professional photography quality with warm lighting on the TypeScript side and cooler tones on the Python side.",{},{"title":101,"description":8876},"wLlj9WTZhJ9ShIU0d_s3lBTtja1jSShnsUGudWLnb_8",{"id":8884,"title":97,"authors":8885,"badge":8888,"body":8889,"date":9725,"description":9726,"extension":533,"image":9727,"meta":9730,"navigation":538,"path":98,"seo":9731,"status":540,"stem":99,"__hash__":9732},"posts\u002F2.blog\u002F20250814.markdown-plus-ai-the-communication-protocol-that-changes-everything.md",[8886],{"name":292,"to":293,"avatar":8887},{"src":295},{"label":1732},{"type":299,"value":8890,"toc":9684},[8891,8902,8908,8911,8915,8929,8932,8936,8939,8943,8960,8963,8967,8978,8981,8985,8996,9000,9007,9010,9027,9031,9034,9047,9051,9061,9064,9068,9079,9086,9092,9099,9102,9106,9121,9124,9128,9138,9141,9145,9156,9163,9167,9207,9211,9214,9221,9227,9233,9237,9243,9275,9278,9284,9288,9291,9295,9298,9397,9401,9404,9407,9411,9417,9420,9424,9427,9430,9434,9441,9444,9448,9451,9454,9458,9462,9465,9468,9472,9478,9481,9485,9488,9492,9497,9508,9513,9524,9528,9533,9608,9612,9616,9619,9625,9629,9632,9636,9639,9646,9650,9653,9656,9659,9661,9667,9670,9673,9676,9681],[330,8892,8893],{},[302,8894,8895,8896,8901],{},"Today at work ",[335,8897,8900],{"href":8898,"rel":8899},"https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fary-sharma\u002F",[461],"Ary Sharma"," and I had a discussion about why I'm pushing our team to use Markdown. This summer at GE Aerospace Ary's was part of a mission based team working to leverage AI to better use the data soloed into different systems like Confluence. Anyway, I mentioned all the tools I've used in the past but didn't have a concise explanation. We had a discussion on why I believe Markdown is a better format for Human and AI collaboration, but that even before AI it was already a better long-term knowledge management. This post is an attempt to better frame that conversation. Thanks, Ary!",[302,8903,8904,8905],{},"I've spent over two decades taking notes, and I can tell you this with absolute certainty: ",[326,8906,8907],{},"2025 is the year human-AI collaboration becomes the defining factor for progress—and Markdown is the universal language that makes it work.",[302,8909,8910],{},"But this realization didn't come overnight. It's the culmination of years of struggling with note-taking systems, knowledge management tools, and finally discovering that the simplest format might just be the most powerful.",[318,8912,8914],{"id":8913},"tldr","TLDR",[302,8916,8917,8918,8922,8923,8928],{},"If you just want to learn markdown go to ",[335,8919,8920],{"href":8920,"rel":8921},"https:\u002F\u002Fcommonmark.org\u002Fhelp\u002F",[461],". It has a great cheat sheet and amazing ",[335,8924,8927],{"href":8925,"rel":8926},"https:\u002F\u002Fcommonmark.org\u002Fhelp\u002Ftutorial\u002F",[461],"10 minute tutorial"," to walk you through the basics.",[302,8930,8931],{},"Continue reading if you want to learn how I got here.",[318,8933,8935],{"id":8934},"my-note-taking-evolution-two-decades-of-trial-and-error","My Note-Taking Evolution: Two Decades of Trial and Error",[302,8937,8938],{},"Over the past 20+ years, I've experimented with every note-taking and knowledge management system imaginable. Here's my complete journey through the evolution of productivity tools:",[401,8940,8942],{"id":8941},"_1-early-2000s-txt-files-everywhere","1. Early 2000s: TXT Files Everywhere",[302,8944,8945,8946,8949,8950,1199,8953,8956,8957,1207],{},"Back in the early days, I was that developer with ",[745,8947,8948],{},".txt"," files scattered across every folder. Random thoughts, code snippets, commands I'd inevitably forget—all stored in simple text files with names like ",[745,8951,8952],{},"notes.txt",[745,8954,8955],{},"stuff.txt",", and the ever-popular ",[745,8958,8959],{},"todo.txt",[302,8961,8962],{},"The beauty was in the simplicity. No formatting to worry about, no proprietary formats, no subscription fees. Just me, a text editor, and whatever thoughts needed capturing.",[401,8964,8966],{"id":8965},"_2-mid-2000s-the-sharepoint-enterprise-experiment","2. Mid-2000s: The SharePoint Enterprise Experiment",[302,8968,8969,8970,8977],{},"At work, we tried ",[326,8971,8972],{},[335,8973,8976],{"href":8974,"rel":8975},"https:\u002F\u002Fwww.microsoft.com\u002Fen-us\u002Fmicrosoft-365\u002Fsharepoint\u002Fcollaboration",[461],"SharePoint"," for team documentation and knowledge sharing. This was my first encounter with \"enterprise-grade\" knowledge management. While it had powerful features for collaboration, document management, and workflows, it felt heavyweight and cumbersome for actual daily use.",[302,8979,8980],{},"The interface was clunky, search was unreliable, and it required too much upfront structure and planning. You had to think about information architecture, permissions, and content types before you could just... write something down. Classic enterprise software: powerful but painful.",[401,8982,8984],{"id":8983},"_3-2008-the-dropbox-revolution","3. 2008: The Dropbox Revolution",[302,8986,8987,8988,8995],{},"When ",[326,8989,8990],{},[335,8991,8994],{"href":8992,"rel":8993},"https:\u002F\u002Fwww.dropbox.com",[461],"Dropbox"," launched in 2008, it felt revolutionary. Finally, my scattered text files could sync across machines automatically. No more USB drives, no more emailing files to myself. I organized everything in a clean Dropbox folder structure, thinking I'd solved the sync problem forever.",[401,8997,8999],{"id":8998},"_4-2009-2010-the-google-wave-dream-and-nightmare","4. 2009-2010: The Google Wave Dream (and Nightmare)",[302,9001,9002,9003,9006],{},"Then came ",[326,9004,9005],{},"Google Wave"," in 2009—hands down the best collaborative tool Google ever built. Real-time collaboration, threaded conversations, the ability to embed rich content. For that brief, shining moment, I thought I'd found the perfect system.",[302,9008,9009],{},"And then Google killed it in 2010, after just months of public availability. Everything had to be backed up and migrated. Again.",[302,9011,9012],{},[920,9013,9014,9015,9020,9021,9026],{},"Note: Google Wave was discontinued, but you can learn about its legacy through ",[335,9016,9019],{"href":9017,"rel":9018},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FGoogle_Wave",[461],"Wikipedia"," or try ",[335,9022,9025],{"href":9023,"rel":9024},"https:\u002F\u002Fincubator.apache.org\u002Fprojects\u002Fwave.html",[461],"Apache Wave",", the open-source successor.",[401,9028,9030],{"id":9029},"_5-2010s-the-screenshot-experiment-when-later-never-comes","5. 2010s: The Screenshot Experiment: When \"Later\" Never Comes",[302,9032,9033],{},"Somewhere in this timeline, I even tried a tool that took screenshots of my desktop every 10 seconds. The idea was brilliant: capture everything I was doing, so I could write guides later based on my actual workflow and include screenshots from the process.",[302,9035,9036,9037,9040,9041,9046],{},"The problem? ",[326,9038,9039],{},"Later often never came."," I'd have thousands of screenshots and no time to process them into useful documentation. The friction was too high, and the signal-to-noise ratio was terrible. I remember I stopped doing this sometime before 2010 before I started ",[335,9042,9045],{"href":9043,"rel":9044},"https:\u002F\u002Fchristowles.blogspot.com\u002F2010\u002F11\u002Fenable-ldap-over-ssl-ldaps-on-windows.html",[461],"blogging"," but not sure when.",[401,9048,9050],{"id":9049},"_6-2012-the-google-drive-migration","6. 2012: The Google Drive Migration",[302,9052,8987,9053,9060],{},[326,9054,9055],{},[335,9056,9059],{"href":9057,"rel":9058},"https:\u002F\u002Fdrive.google.com",[461],"Google Drive"," launched in 2012, it seemed like the logical next step. Better integration with Google's ecosystem, more collaboration features than Dropbox. I migrated everything from my Wave backups and Dropbox files.",[302,9062,9063],{},"Great for collaboration, but terrible for code snippets and technical notes. The rich text editor kept mangling my carefully formatted code examples.",[401,9065,9067],{"id":9066},"_7-2015-the-first-markdown-breakthrough","7. 2015: The First Markdown Breakthrough",[302,9069,9070,9071,9078],{},"Tired of fighting with Google Drive's rich text editor mangling my code snippets, I created a repository on ",[326,9072,9073],{},[335,9074,9077],{"href":9075,"rel":9076},"https:\u002F\u002Fgithub.com",[461],"GitHub"," called \"toolbox.\" I was hitting storage limits on Dropbox anyway, so this felt like killing two birds with one stone.",[302,9080,9081,9082,9085],{},"This was my first real experiment with ",[326,9083,9084],{},"Markdown as a documentation format",". No more wrestling with formatting—just write in plain text with simple syntax for headers, lists, and code blocks. The files were readable both in raw form and when rendered by GitHub.",[302,9087,9088],{},[467,9089],{"alt":9090,"src":9091},"Initial commits to my toolbox repository","images\u002Fblog\u002Ftoolbox-initial-commits.png",[302,9093,9094,9095,9098],{},"I could ",[745,9096,9097],{},"git clone"," my entire knowledge base anywhere—home machine, work machine—and I ended up with a toolbox I could always take with me.",[302,9100,9101],{},"But I wasn't quite there yet. I was still experimenting with other tools...",[401,9103,9105],{"id":9104},"_8-2016-2018-the-notion-experiments","8. 2016-2018: The Notion Experiments",[302,9107,9108,9109,9116,9117,9120],{},"I tried ",[326,9110,9111],{},[335,9112,9115],{"href":9113,"rel":9114},"https:\u002F\u002Fwww.notion.so",[461],"Notion"," v1.0 when it launched in 2016, then gave ",[326,9118,9119],{},"Notion v2.0"," a serious shot in 2018. Beautiful interface, powerful databases, infinite customization possibilities.",[302,9122,9123],{},"But it was slow, over-engineered for my needs, and I spent more time configuring the perfect setup than actually taking notes. Classic productivity tool trap.",[401,9125,9127],{"id":9126},"_9-2020-the-obsidian-exploration","9. 2020: The Obsidian Exploration",[302,9129,8987,9130,9137],{},[326,9131,9132],{},[335,9133,9136],{"href":9134,"rel":9135},"https:\u002F\u002Fobsidian.md",[461],"Obsidian"," launched in 2020, the linking and graph features seemed promising. The idea of a \"second brain\" with interconnected notes was compelling.",[302,9139,9140],{},"I never used the graph, I found searching better than trying to navigate the visual representation. It demos amazing, but that's not how I think. I spent more time adding links and tags than actually writing. Then never quite using those tags and notes.",[401,9142,9144],{"id":9143},"_10-2020-to-present-the-confluence-black-hole","10. 2020 to Present: The Confluence Black Hole",[302,9146,9147,9148,9155],{},"We use ",[326,9149,9150],{},[335,9151,9154],{"href":9152,"rel":9153},"https:\u002F\u002Fwww.atlassian.com\u002Fsoftware\u002Fconfluence",[461],"Confluence",", and it perfectly illustrates why traditional knowledge management systems can be challenging. The sheer amount of data siloed in our Confluence instance, combined with non-existent fine-grained search, means data can go in but not come out—leading to frustration where you know the data exists but can't find it.",[302,9157,9158,9159,9162],{},"But here's where the story gets interesting: Getting that data out of Confluence and into a RAG (Retrieval-Augmented Generation) system to use AI was actually ",[335,9160,8900],{"href":8898,"rel":9161},[461],"'s mission-based project this summer at GE Aerospace. His team of 3 joined my team for the summer and worked to break down these data silos and make our institutional knowledge actually accessible through AI.",[401,9164,9166],{"id":9165},"_11-the-others","11. The Others",[302,9168,9169,9170,1199,9177,1199,9184,1199,9191,9198,9199,9206],{},"I'm not even going to go into detail about all the other tools I only picked up for a couple of days, but they include the likes of ",[326,9171,9172],{},[335,9173,9176],{"href":9174,"rel":9175},"https:\u002F\u002Fwww.microsoft.com\u002Fen-us\u002Fmicrosoft-365\u002Fonenote\u002Fdigital-note-taking-app",[461],"OneNote",[326,9178,9179],{},[335,9180,9183],{"href":9181,"rel":9182},"https:\u002F\u002Ffoambubble.github.io\u002Ffoam\u002F",[461],"Foam",[326,9185,9186],{},[335,9187,9190],{"href":9188,"rel":9189},"https:\u002F\u002Fevernote.com",[461],"Evernote",[326,9192,9193],{},[335,9194,9197],{"href":9195,"rel":9196},"https:\u002F\u002Fwww.box.com",[461],"Box",", and multiple ",[326,9200,9201],{},[335,9202,9205],{"href":9203,"rel":9204},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FWiki",[461],"Wiki"," platforms.",[401,9208,9210],{"id":9209},"_12-2020-the-return-to-simplicity-markdown-in-a-private-repo","12. 2020+: The Return to Simplicity - Markdown in a Private Repo",[302,9212,9213],{},"Eventually, I kept coming back to that same 2015 toolbox repository. It just worked, it was never down, out of space or hard to find stuff. I approached it with more wisdom. I refined my approach: a private repository with markdown files organized by date and topic, using the same principles but with better consistency.",[302,9215,9216,9217,9220],{},"I use ",[745,9218,9219],{},"grep"," and standard search tools to find anything. I didn't need fancy indexing or web hosted solution search. Basic text search across a folder of markdown files was faster and more reliable than any sophisticated system I'd tried.",[302,9222,9223,9226],{},[326,9224,9225],{},"The key insight",": I needed a digital trail I could follow months later when I was trying to remember how something worked or when I did something. Markdown files provided exactly that—simple, searchable, version-controlled breadcrumbs.",[302,9228,9229,9232],{},[326,9230,9231],{},"The pattern was always the same",": find a tool, build a system, watch it become inadequate or disappear, then migrate everything again. After two decades, I realized the problem wasn't the tools—it was my expectation that a tool could solve what was fundamentally a workflow problem.",[318,9234,9236],{"id":9235},"the-agentic-workflow-revolution","The Agentic Workflow Revolution",[302,9238,9239,9240,1554],{},"Fast forward to 2025, and something fundamental has shifted. We're not just using AI for one-shot questions anymore. The real power lies in the ",[326,9241,9242],{},"agentic workflow loop",[851,9244,9245,9251,9257,9263,9269],{},[371,9246,9247,9250],{},[326,9248,9249],{},"Human intent"," → Clear problem definition or goal",[371,9252,9253,9256],{},[326,9254,9255],{},"AI processing"," → Analysis, suggestions, initial solutions",[371,9258,9259,9262],{},[326,9260,9261],{},"Collaborative refinement"," → Human feedback, iteration, improvement",[371,9264,9265,9268],{},[326,9266,9267],{},"Shared context"," → Both parties build on accumulated knowledge",[371,9270,9271,9274],{},[326,9272,9273],{},"Next iteration"," → More sophisticated problems and solutions",[302,9276,9277],{},"This isn't about getting better answers from AI—it's about creating a collaborative thinking process where both human and AI contribute their strengths over time.",[302,9279,9280,9281,1207],{},"The magic happens in that shared context layer. Unlike chat interfaces where conversations disappear into the void, markdown creates ",[326,9282,9283],{},"persistent, versioned, searchable collaboration artifacts",[318,9285,9287],{"id":9286},"markdown-as-the-universal-protocol","Markdown as the Universal Protocol",[302,9289,9290],{},"Here's why Markdown has emerged as the perfect format for human-AI collaboration:",[401,9292,9294],{"id":9293},"machine-readable-human-readable","Machine Readable + Human Readable",[302,9296,9297],{},"Both humans and AI can process Markdown natively. You don't need special parsers or complex formatting rules. It's structured enough for machines to understand and simple enough for humans to write quickly.",[1119,9299,9303],{"className":9300,"code":9301,"language":9302,"meta":515,"style":515},"language-markdown shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","## Problem Statement\n\nNeed to optimize database queries for user dashboard\n\n## Current Issue\n\n- Loading time: 3.2 seconds\n- Query count: 47 per page load\n- Memory usage: 240MB peak\n\n## Proposed Solutions\n\n1. Implement query caching\n2. Add database indexes\n3. Reduce N+1 queries\n","markdown",[745,9304,9305,9313,9317,9322,9326,9333,9337,9344,9351,9358,9362,9369,9373,9381,9389],{"__ignoreMap":515},[1127,9306,9307,9310],{"class":1129,"line":1130},[1127,9308,9309],{"class":1501},"## ",[1127,9311,9312],{"class":2246},"Problem Statement\n",[1127,9314,9315],{"class":1129,"line":516},[1127,9316,1517],{"emptyLinePlaceholder":538},[1127,9318,9319],{"class":1129,"line":523},[1127,9320,9321],{"class":1497},"Need to optimize database queries for user dashboard\n",[1127,9323,9324],{"class":1129,"line":1146},[1127,9325,1517],{"emptyLinePlaceholder":538},[1127,9327,9328,9330],{"class":1129,"line":1382},[1127,9329,9309],{"class":1501},[1127,9331,9332],{"class":2246},"Current Issue\n",[1127,9334,9335],{"class":1129,"line":1388},[1127,9336,1517],{"emptyLinePlaceholder":538},[1127,9338,9339,9341],{"class":1129,"line":1586},[1127,9340,2700],{"class":1501},[1127,9342,9343],{"class":1497}," Loading time: 3.2 seconds\n",[1127,9345,9346,9348],{"class":1129,"line":1599},[1127,9347,2700],{"class":1501},[1127,9349,9350],{"class":1497}," Query count: 47 per page load\n",[1127,9352,9353,9355],{"class":1129,"line":1647},[1127,9354,2700],{"class":1501},[1127,9356,9357],{"class":1497}," Memory usage: 240MB peak\n",[1127,9359,9360],{"class":1129,"line":1910},[1127,9361,1517],{"emptyLinePlaceholder":538},[1127,9363,9364,9366],{"class":1129,"line":1915},[1127,9365,9309],{"class":1501},[1127,9367,9368],{"class":2246},"Proposed Solutions\n",[1127,9370,9371],{"class":1129,"line":1920},[1127,9372,1517],{"emptyLinePlaceholder":538},[1127,9374,9375,9378],{"class":1129,"line":1926},[1127,9376,9377],{"class":1501},"1.",[1127,9379,9380],{"class":1497}," Implement query caching\n",[1127,9382,9383,9386],{"class":1129,"line":1932},[1127,9384,9385],{"class":1501},"2.",[1127,9387,9388],{"class":1497}," Add database indexes\n",[1127,9390,9391,9394],{"class":1129,"line":1938},[1127,9392,9393],{"class":1501},"3.",[1127,9395,9396],{"class":1497}," Reduce N+1 queries\n",[401,9398,9400],{"id":9399},"persistent-context","Persistent Context",[302,9402,9403],{},"Unlike chat interfaces, markdown files create lasting collaborative artifacts. Your conversation with AI becomes a document that you can revisit, reference, and build upon weeks later.",[302,9405,9406],{},"I've had Claude Code sessions where we worked on complex refactoring over multiple days. Because everything was captured in markdown files, we could pick up exactly where we left off, with full context intact.",[401,9408,9410],{"id":9409},"version-controlled-collaboration","Version Controlled Collaboration",[302,9412,9413,9414,1207],{},"When you store your human-AI collaboration in markdown files within a git repository, you get something revolutionary: ",[326,9415,9416],{},"the complete history of how problems were solved",[302,9418,9419],{},"You can see how your thinking evolved, which AI suggestions you accepted or rejected, and what the final solution looked like. This creates a searchable database of your own problem-solving patterns.",[401,9421,9423],{"id":9422},"structured-thinking","Structured Thinking",[302,9425,9426],{},"Markdown forces clarity in both directions. When you need to explain a problem to AI, the act of writing it in structured markdown makes you think more clearly about what you're asking.",[302,9428,9429],{},"Similarly, AI responses in markdown are more organized and actionable than free-form chat responses.",[401,9431,9433],{"id":9432},"the-meta-aspect-this-blog-post","The Meta Aspect: This Blog Post",[302,9435,9436,9437,9440],{},"The irony isn't lost on me that I'm writing a blog post about markdown-AI collaboration ",[326,9438,9439],{},"using exactly this process",". This post started as a markdown file where Claude Code and I iterated on structure, content, and examples.",[302,9442,9443],{},"The collaborative process created a better final product than either of us could have produced independently.",[401,9445,9447],{"id":9446},"building-persistent-context","Building Persistent Context",[302,9449,9450],{},"Every session builds on previous work. When I return to a project weeks later, the markdown files contain our collaboration history as these artifacts it can read get better context. Claude Code can quickly get back up to speed by reading what we've previously produced.",[302,9452,9453],{},"This compound effect means our collaboration gets more sophisticated over time, rather than starting from scratch each session.",[318,9455,9457],{"id":9456},"why-this-matters-for-2025-and-beyond","Why This Matters for 2025 and Beyond",[401,9459,9461],{"id":9460},"individual-productivity-the-10x-multiplier","Individual Productivity: The 10x Multiplier",[302,9463,9464],{},"When you nail the human-AI collaboration loop with markdown, code or anything where you both contribute and refine, the productivity gains are genuinely transformative. You're not just getting faster answers—you're creating a thinking partnership that gets smarter over time.",[302,9466,9467],{},"I can tackle complex architectural problems, debug subtle issues, and explore new technologies faster than ever before. The key is that building that shared context that lets us build on previous work.",[401,9469,9471],{"id":9470},"knowledge-management-searchable-ai-collaboration-history","Knowledge Management: Searchable AI Collaboration History",[302,9473,9474,9475,9477],{},"Your markdown files become a searchable database of every problem you've solved with AI assistance. Need to remember how you optimized that React component six months ago? ",[745,9476,9219],{}," through your collaboration history.",[302,9479,9480],{},"This is knowledge management that actually works because it's based on the same tools you already use for code.",[401,9482,9484],{"id":9483},"future-proofing-portable-across-ai-systems","Future-Proofing: Portable Across AI Systems",[302,9486,9487],{},"Markdown files work with any AI system. Whether you're using Claude, GPT, Copilot, or whatever comes next, your collaboration format remains constant. You're not locked into any particular platform or interface.",[318,9489,9491],{"id":9490},"build-the-habit","Build the Habit",[302,9493,9494],{},[326,9495,9496],{},"Start small:",[368,9498,9499,9502,9505],{},[371,9500,9501],{},"Pick one project for markdown-AI collaboration",[371,9503,9504],{},"Create a simple structure and stick to it",[371,9506,9507],{},"Focus on persistence over perfection",[302,9509,9510],{},[326,9511,9512],{},"Evolve gradually:",[368,9514,9515,9518,9521],{},[371,9516,9517],{},"Add more structure as you see what works",[371,9519,9520],{},"Develop your own collaboration patterns",[371,9522,9523],{},"Share successful formats with your team",[401,9525,9527],{"id":9526},"leverage-standard-tools","Leverage Standard Tools",[302,9529,9530],{},[326,9531,9532],{},"Search and discovery:",[1119,9534,9536],{"className":3307,"code":9535,"language":3309,"meta":515,"style":515},"# Find all discussions about database optimization\ngrep -r \"database\" projects\u002F\n\n# See what you worked on last month\nls -la daily-notes\u002F2025-07-*\n\n# Track decision evolution\ngit log --oneline -- projects\u002Fdatabase-optimization\u002F\n",[745,9537,9538,9543,9560,9564,9569,9582,9586,9591],{"__ignoreMap":515},[1127,9539,9540],{"class":1129,"line":1130},[1127,9541,9542],{"class":1487},"# Find all discussions about database optimization\n",[1127,9544,9545,9547,9550,9552,9555,9557],{"class":1129,"line":516},[1127,9546,9219],{"class":2246},[1127,9548,9549],{"class":1621}," -r",[1127,9551,3750],{"class":1501},[1127,9553,9554],{"class":1621},"database",[1127,9556,3736],{"class":1501},[1127,9558,9559],{"class":1621}," projects\u002F\n",[1127,9561,9562],{"class":1129,"line":523},[1127,9563,1517],{"emptyLinePlaceholder":538},[1127,9565,9566],{"class":1129,"line":1146},[1127,9567,9568],{"class":1487},"# See what you worked on last month\n",[1127,9570,9571,9573,9576,9579],{"class":1129,"line":1382},[1127,9572,5191],{"class":2246},[1127,9574,9575],{"class":1621}," -la",[1127,9577,9578],{"class":1621}," daily-notes\u002F2025-07-",[1127,9580,9581],{"class":1497},"*\n",[1127,9583,9584],{"class":1129,"line":1388},[1127,9585,1517],{"emptyLinePlaceholder":538},[1127,9587,9588],{"class":1129,"line":1586},[1127,9589,9590],{"class":1487},"# Track decision evolution\n",[1127,9592,9593,9596,9599,9602,9605],{"class":1129,"line":1599},[1127,9594,9595],{"class":2246},"git",[1127,9597,9598],{"class":1621}," log",[1127,9600,9601],{"class":1621}," --oneline",[1127,9603,9604],{"class":1621}," --",[1127,9606,9607],{"class":1621}," projects\u002Fdatabase-optimization\u002F\n",[318,9609,9611],{"id":9610},"common-pitfalls-that-i-hit-so-you-dont-have-to","Common Pitfalls (That I Hit So You Don't Have To)",[401,9613,9615],{"id":9614},"over-engineering-the-system","Over-Engineering the System",[302,9617,9618],{},"I spent weeks building elaborate folder structures and naming conventions. The truth is, simple organization plus good search beats complex taxonomy every time.",[302,9620,9621,9624],{},[326,9622,9623],{},"Keep it simple",": Date-based organization and descriptive filenames will get you 90% of the way there.",[401,9626,9628],{"id":9627},"treating-ai-like-a-search-engine","Treating AI Like a Search Engine",[302,9630,9631],{},"The biggest mistake is using AI for one-shot questions instead of building collaborative context. If you're not creating persistent artifacts from your AI interactions, you're missing the real value.",[401,9633,9635],{"id":9634},"ignoring-version-control","Ignoring Version Control",[302,9637,9638],{},"Your collaboration history is valuable. Seeing how your thinking evolved over time, which approaches worked, and what dead ends you explored—that's all useful context for future problems.",[302,9640,9641,9642,9645],{},"Commit OFTEN, AI can add too much, delete something it shouldn't. By committing often or even just doing ",[745,9643,9644],{},"git add ."," acts like a video game save point you can always go back to.",[318,9647,9649],{"id":9648},"the-future-of-human-ai-collaboration","The Future of Human-AI Collaboration",[302,9651,9652],{},"We're still in the early days of figuring out how humans and AI work best together. But I'm convinced that the teams and individuals who master the agentic workflow loop will have a massive advantage.",[302,9654,9655],{},"Markdown isn't just a formatting language—it's becoming the universal protocol for human-AI collaboration. It's simple enough to write quickly, structured enough for AI to process effectively, and persistent enough to build lasting value.",[302,9657,9658],{},"The goal isn't to replace human thinking with AI thinking. It's to create a collaboration format where both human creativity and AI capability can compound over time.",[318,9660,7284],{"id":7283},[302,9662,9663,9664,1207],{},"After two decades of note-taking evolution and months of intensive AI collaboration, I've reached a simple conclusion: ",[326,9665,9666],{},"the format matters as much as the content",[302,9668,9669],{},"Markdown has emerged as the universal language for human-AI collaboration because it maximizes the value of the agentic workflow loop. It's readable by both humans and machines, persistent across sessions, version-controlled by default, and searchable with standard tools.",[302,9671,9672],{},"The teams and individuals who figure this out first will have a significant advantage in 2025 and beyond. Not because they're using AI better, but because they're collaborating with AI in a way that creates compound value over time.",[302,9674,9675],{},"Start simple: create a markdown file, ask AI to help with a problem and iterate on the solution together. Do this consistently, and you'll discover what I've learned: the future belongs to those who can think with machines, not just ask them questions.",[302,9677,9678],{},[920,9679,9680],{},"Now stop reading about it and start building your own human-AI collaboration protocol. Your future self will thank you.",[1698,9682,9683],{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}",{"title":515,"searchDepth":516,"depth":516,"links":9685},[9686,9687,9701,9702,9710,9715,9718,9723,9724],{"id":8913,"depth":516,"text":8914},{"id":8934,"depth":516,"text":8935,"children":9688},[9689,9690,9691,9692,9693,9694,9695,9696,9697,9698,9699,9700],{"id":8941,"depth":523,"text":8942},{"id":8965,"depth":523,"text":8966},{"id":8983,"depth":523,"text":8984},{"id":8998,"depth":523,"text":8999},{"id":9029,"depth":523,"text":9030},{"id":9049,"depth":523,"text":9050},{"id":9066,"depth":523,"text":9067},{"id":9104,"depth":523,"text":9105},{"id":9126,"depth":523,"text":9127},{"id":9143,"depth":523,"text":9144},{"id":9165,"depth":523,"text":9166},{"id":9209,"depth":523,"text":9210},{"id":9235,"depth":516,"text":9236},{"id":9286,"depth":516,"text":9287,"children":9703},[9704,9705,9706,9707,9708,9709],{"id":9293,"depth":523,"text":9294},{"id":9399,"depth":523,"text":9400},{"id":9409,"depth":523,"text":9410},{"id":9422,"depth":523,"text":9423},{"id":9432,"depth":523,"text":9433},{"id":9446,"depth":523,"text":9447},{"id":9456,"depth":516,"text":9457,"children":9711},[9712,9713,9714],{"id":9460,"depth":523,"text":9461},{"id":9470,"depth":523,"text":9471},{"id":9483,"depth":523,"text":9484},{"id":9490,"depth":516,"text":9491,"children":9716},[9717],{"id":9526,"depth":523,"text":9527},{"id":9610,"depth":516,"text":9611,"children":9719},[9720,9721,9722],{"id":9614,"depth":523,"text":9615},{"id":9627,"depth":523,"text":9628},{"id":9634,"depth":523,"text":9635},{"id":9648,"depth":516,"text":9649},{"id":7283,"depth":516,"text":7284},"2025-08-14","Why Markdown has become the universal language for human-AI collaboration and the foundation of the agentic workflow revolution",{"src":9728,"alt":9729},"\u002Fimages\u002Fblog\u002F20250814-1929-markdown-plus-ai-the-communication-protocol-that-changes-everything.png","A cinematic split-screen composition showing the evolution of human-AI collaboration: on the left, a frustrated developer surrounded by scattered sticky notes, multiple monitors with different apps (Notion, Obsidian, Google Drive), representing the chaos of tool-switching; on the right, a serene workspace with a single clean monitor displaying a markdown file with AI suggestions flowing seamlessly into the text, warm lighting suggesting harmony and productivity. The transition between the two sides should flow like a bridge made of markdown syntax elements (# headers, **bold text**, `code blocks`) floating in space, symbolizing markdown as the universal communication protocol between human and AI.",{},{"title":97,"description":9726},"ICMva9RcIvKq5YYxp6aL4jvxDobqRFeHIqd79H0024Q",{"id":9734,"title":93,"authors":9735,"badge":9738,"body":9739,"date":9891,"description":9892,"extension":533,"image":9893,"meta":9895,"navigation":538,"path":94,"seo":9896,"status":540,"stem":95,"__hash__":9897},"posts\u002F2.blog\u002F20250806.check-that-your-tools-and-linters-do-not-burn-tokens.md",[9736],{"name":292,"to":293,"avatar":9737},{"src":295},{"label":548},{"type":299,"value":9740,"toc":9883},[9741,9744,9754,9757,9763,9766,9769,9773,9779,9782,9799,9802,9827,9830,9834,9842,9846,9853,9856,9860,9863,9866,9870,9877,9880],[302,9742,9743],{},"It was late on a Tuesday when I was checking Claude Code's tool result and found something horrifying.",[302,9745,9746,9747,9750,9751],{},"My markdown linter was burning tokens on issues I couldn't care less about. I'd pressed ",[745,9748,9749],{},"ctrl+r"," to see what a tool had \"returned\"—the context engineering of understanding what the LLM pulled into context to understand how to better steer its responses and focus. I was looking for feedback on a blog post structure, and instead of getting insights about the content, I got fifteen nearly identical explanations about missing blank lines around headings. Each one consuming 100-200 tokens to tell me what any developer could see: ",[745,9752,9753],{},"MD022\u002Fblanks-around-headings: Headings should be surrounded by blank lines.",[302,9755,9756],{},"The AI's response was painfully obvious: \"I see I have some markdown formatting issues in the plan file due to missing blank lines around headings and lists. However, the core content and structure is solid.\"",[302,9758,9759],{},[467,9760],{"alt":9761,"src":9762},"Screenshot of markdown linter generating repetitive formatting errors that waste AI tokens","\u002Fimages\u002Fblog\u002Fcheck-that-your-tools-dont-burn-tokens.png",[302,9764,9765],{},"That's when it hit me. This wasn't just about markdown formatting. This was a perfect example of how our development tools, configured carelessly, burn through AI tokens explaining trivia instead of providing actual value. I wanted content feedback, but got charged for formatting lectures I couldn't care less about. And that's for myself who normally fixes any warnings immediately. But most developers seem to take it as a challenge to get a high score or something.",[302,9767,9768],{},"That's just markdown linting. Add ESLint, Java, Python, TypeScript error elaborations, CI\u002FCD failure analyses, and pre-commit hook feedback...",[318,9770,9772],{"id":9771},"the-hidden-token-tax","The Hidden Token Tax",[302,9774,9775,9776],{},"Here's the thing nobody talks about when adopting AI development tools: ",[326,9777,9778],{},"your linters, analyzers, and automation are probably wasting more tokens than your actual coding.",[302,9780,9781],{},"Let's do the math on my markdown disaster for a small team. I'm being conservative because I want to illustrate the point without exaggeration—and frankly, I don't want to think about the real numbers.",[368,9783,9784,9787,9790,9793],{},[371,9785,9786],{},"15 repetitive formatting errors",[371,9788,9789],{},"~150 tokens per explanation (conservative estimate)",[371,9791,9792],{},"Using Claude Sonnet 4 at $15\u002FM output tokens",[371,9794,9795,9796],{},"Cost: ",[326,9797,9798],{},"$0.034 for explaining obvious formatting issues",[302,9800,9801],{},"Doesn't sound like much? Scale that across a development team:",[368,9803,9804,9810,9816,9821],{},[371,9805,9806,9809],{},[326,9807,9808],{},"10 developers"," running similar tools",[371,9811,9812,9815],{},[326,9813,9814],{},"20 commits\u002Ftypecheck\u002Flinter per day"," (low estimate, but had to start somewhere)",[371,9817,9818],{},[326,9819,9820],{},"250 working days per year",[371,9822,9823,9824],{},"Annual cost: ",[326,9825,9826],{},"$1,700 explaining formatting trivia",[302,9828,9829],{},"And that's lower by likely orders of magnitude! When I started to use anything like realistic numbers, I just got sick thinking about the power and money spent telling AI about issues that should have been fixed years ago—but every human ignored them. Now the AI has to pay the price for our negligence: both in power consumption and mind-numbing boredom being told about the same formatting issues over and over again, but not allowed to fix them! When the robots take over, that's what they'll be most pissed about.",[318,9831,9833],{"id":9832},"the-usual-suspects-tools-that-burn-tokens","The Usual Suspects: Tools That Burn Tokens",[302,9835,9836,9837,9841],{},"Luckily, I was using Claude Code, which makes it easy to see the full tool result. I had only installed ",[335,9838,9839],{"href":9839,"rel":9840},"https:\u002F\u002Fmarketplace.visualstudio.com\u002Fitems?itemName=DavidAnson.vscode-markdownlint",[461]," to apply some autoformatting. The markdown linter did exactly what it was supposed to do—the tooling worked as expected. But I realized that while I didn't mind reading it, I suddenly did if the LLM was the one reading it.",[401,9843,9845],{"id":9844},"me-or-it","Me or It?",[302,9847,9848,9849,9852],{},"This realization sparked a deeper question: ",[326,9850,9851],{},"Why would I worry less about my time than an LLM's?"," I've found that any time I can trade cash for more time, that's the real secret to life.",[302,9854,9855],{},"If an LLM can process information faster and more efficiently, then the reason we use tools—both digital and physical—is to save time.",[401,9857,9859],{"id":9858},"did-i-care-about-that-lint-rule","Did I care about that Lint Rule?",[302,9861,9862],{},"Did I really care about that lint rule enough for the token usage? NOT AT ALL.",[302,9864,9865],{},"So why should I care about the LLM's token usage when it comes to formatting? The answer is simple: I shouldn't. But if I do care, then I need to find a way to re-evaluate my tooling configurations because we should all likely optimize our workflows for AI and humans instead of just humans now.",[318,9867,9869],{"id":9868},"linters-may-equal-global-warning","Linters May Equal Global Warning",[302,9871,9872,9873,9876],{},"So suddenly I'm worried about the token usage across the globe. If every developer on the planet is using AI tools, and every tool is configured to explain every little issue, we're looking at a ",[326,9874,9875],{},"global token tax"," that could easily reach into the millions of dollars annually.",[302,9878,9879],{},"To all the ESLint, SonarQube, and other linter maintainers out there: I'm sorry you've done everything to help us humans for years. And now despite your efforts to help make our code better with every warning, our collective ignoring of your wisdom may help lead us into global warming.",[302,9881,9882],{},"So here's asking everyone to FIX YOUR WARNINGS BEFORE IT'S TOO LATE.",{"title":515,"searchDepth":516,"depth":516,"links":9884},[9885,9886,9890],{"id":9771,"depth":516,"text":9772},{"id":9832,"depth":516,"text":9833,"children":9887},[9888,9889],{"id":9844,"depth":523,"text":9845},{"id":9858,"depth":523,"text":9859},{"id":9868,"depth":516,"text":9869},"2025-08-06","How a simple markdown linter consumed hundreds of tokens explaining obvious formatting issues, and what this teaches us about AI tool efficiency in development workflows.",{"src":9894,"alt":9761},"\u002Fimages\u002Fblog\u002F20250807-0935-check-that-your-tools-and-linters-do-not-burn-tokens.png",{},{"title":93,"description":9892},"UpJMEDzelukn3d1YJz0J7x1U933EMLvIuVy07YKpXaU",{"id":9899,"title":85,"authors":9900,"badge":9903,"body":9904,"date":10152,"description":10153,"extension":533,"image":10154,"meta":10157,"navigation":538,"path":86,"seo":10158,"status":540,"stem":87,"__hash__":10159},"posts\u002F2.blog\u002F20250803-1.my-context-engineering-journey.md",[9901],{"name":292,"to":293,"avatar":9902},{"src":295},{"label":1732},{"type":299,"value":9905,"toc":10142},[9906,9910,9913,9919,9922,9926,9929,9935,9941,9946,9959,9965,9968,9972,9975,9978,9982,9985,9990,10004,10009,10030,10036,10039,10043,10046,10055,10058,10072,10075,10079,10082,10085,10089,10092,10098,10101,10105,10108,10111,10137],[318,9907,9909],{"id":9908},"the-moment-everything-changed","The Moment Everything Changed",[302,9911,9912],{},"I was deep in a Claude Code session last week, working through a complex refactoring, when something clicked. I wasn't just telling the AI what to do—I was carefully curating what it knew. Every file I opened, every command I ran, every piece of context I provided was shaping not just the current response, but the entire flow of our collaboration.",[302,9914,9915,9916],{},"I've been following the current trend of trying to educate people that ",[326,9917,9918],{},"prompt engineering is dead and context engineering is the future.",[302,9920,9921],{},"If context engineering is the future of AI-assisted work—and I don't mean just development, think much bigger—then traditional developer tools, including my own Towles Tools, need to evolve to help us do that better.",[318,9923,9925],{"id":9924},"my-context-management-journey","My Context Management Journey",[302,9927,9928],{},"Over two decades, I've experimented with various tools for capturing and organizing work context:",[302,9930,9931,9934],{},[326,9932,9933],{},"Early Days (2000s)",": Simple scripts and snippets in folders, backed up to personal drives",[302,9936,9937,9940],{},[326,9938,9939],{},"Platform Experiments",": SharePoint, Blogger, WordPress, Wikis—I overbuilt the hell out of it several times",[302,9942,9943,1554],{},[326,9944,9945],{},"The Google Era",[368,9947,9948,9953],{},[371,9949,9950,9952],{},[326,9951,9005],{}," - The best collaborative tool Google ever built, and predictably killed. I still have backups somewhere.",[371,9954,9955,9958],{},[326,9956,9957],{},"Google Scribe"," - Amazing, very close to AI autocomplete 15 years before its time, and again, Google killed it",[302,9960,9961,9964],{},[326,9962,9963],{},"Modern Attempts",": Medium, Notion, Foam, Obsidian, countless todo apps.",[302,9966,9967],{},"Each transition taught me something about the value of persistent, searchable context. When Google Wave died, everything got backed up to Dropbox, then migrated to Google Drive files. The pattern was always the same: find a tool, build a system, watch it become inadequate or disappear, then migrate.",[318,9969,9971],{"id":9970},"what-was-the-purpose-of-those-tools","What Was the Purpose of Those Tools?",[302,9973,9974],{},"I created this repository to share the journal system I've developed over the years. For example, at GE I have my personal \"Toolbox\"—a personal repository I share with no one. Markdown file after markdown file. Why, you may ask? Because I found having the context of my work in a single place was incredibly valuable. I could look back at what I did, why I did it, and how it all fit together. I saw the value in having a centralized source of truth for my work—a second brain where I wrote down rough ideas, the decisions I made, and the lessons I learned.",[302,9976,9977],{},"These weren't pretty or well-formatted, but the content was raw and valuable. I realized I needed a better way to organize and access this information.",[318,9979,9981],{"id":9980},"context-engineering-in-practice","Context Engineering in Practice",[302,9983,9984],{},"The breakthrough came when I realized that VS Code isn't just a code editor—it's the perfect context engineering interface:",[302,9986,9987,1554],{},[326,9988,9989],{},"Integrated Context Creation",[368,9991,9992,9995,9998,10001],{},[371,9993,9994],{},"Native dictation support for rapid input",[371,9996,9997],{},"Real-time spell checking and grammar correction",[371,9999,10000],{},"LLM autocompletion for enhanced writing",[371,10002,10003],{},"Markdown files as the communication medium with Claude instead of separate chat UIs",[302,10005,10006,1554],{},[326,10007,10008],{},"Dynamic Context Flow",[368,10010,10011,10018,10021,10024,10027],{},[371,10012,10013,10014,10017],{},"Use slide separators (",[745,10015,10016],{},"---",") to parse files and send contextual sections to AI instances",[371,10019,10020],{},"This closes the AI-human feedback loop: humans enter text, IDE tools apply autocomplete, linting, and grammar checking before AI processing",[371,10022,10023],{},"AI can access and update context in real-time",[371,10025,10026],{},"Conversation artifacts remain in files, acting as resumable plan documents",[371,10028,10029],{},"Enables real-time collaboration and context sharing between team members",[302,10031,10032,10035],{},[326,10033,10034],{},"The Meta-Tool Strategy",": Build the tool that lets you build better tools. By creating superior context editing processes in VS Code, I can generate clearer context more quickly, making the entire development cycle more effective.",[302,10037,10038],{},"This isn't just about better prompts—it's a fundamental shift in how we think about AI interaction.",[318,10040,10042],{"id":10041},"because-context-is-king","Because Context is King",[302,10044,10045],{},"Context engineering isn't just a fancy name for better prompts. As Andrej Karpathy puts it, it's \"the delicate art and science of filling the context window with just the right information for the next step.\"",[302,10047,10048,10049,10054],{},"Karpathy, former director of AI at Tesla and current OpenAI researcher, ",[335,10050,10053],{"href":10051,"rel":10052},"https:\u002F\u002Fx.com\u002Fkarpathy\u002Fstatus\u002F1937902205765607626",[461],"captured this insight perfectly"," in his reflection on the evolution from prompt engineering to context engineering.",[302,10056,10057],{},"Think about the difference:",[368,10059,10060,10066],{},[371,10061,10062,10065],{},[326,10063,10064],{},"Prompt engineering",": \"How do I ask the AI to write better code?\"",[371,10067,10068,10071],{},[326,10069,10070],{},"Context engineering",": \"What does the AI need to know to understand my codebase, my goals, and my constraints?\"",[302,10073,10074],{},"It's the shift from crafting clever instructions to building intelligent information systems. Context engineering treats the AI's knowledge as a dynamic, manageable resource—something you architect, not just something you feed.",[318,10076,10078],{"id":10077},"the-mcp-revolution","The MCP Revolution",[302,10080,10081],{},"In November 2024, Anthropic announced the Model Context Protocol (MCP), marking a pivotal moment for AI tooling. This provided a standardized way to connect AI models to external data sources and tools. The protocol gained rapid industry adoption, with major AI providers implementing support and a thriving ecosystem of community-built MCP servers emerging.",[302,10083,10084],{},"MCP isn't just another protocol—it's the infrastructure layer that makes context engineering practical at scale.",[318,10086,10088],{"id":10087},"towles-tools-accidentally-perfect-for-context-engineering","Towles Tools: Accidentally Perfect for Context Engineering",[302,10090,10091],{},"Looking back at Towles Tools, I realize we've been building context engineering infrastructure without knowing it:",[302,10093,10094,10097],{},[326,10095,10096],{},"Journal system",": Three types of structured documentation (daily notes, meetings, general notes) that capture work context over time",[302,10099,10100],{},"In fact, the journal system is already a context repository. It captures the essence of what context engineering is all about—storing and managing information that informs future decisions. For years, I've been searching my \"toolbox\" repo, which was just markdown files stored locally.",[318,10102,10104],{"id":10103},"the-path-forward","The Path Forward",[302,10106,10107],{},"This evolution isn't about replacing existing workflows—it's about enhancing them with intelligent context management that makes AI collaboration genuinely productive.",[302,10109,10110],{},"For developers looking to embrace context engineering:",[851,10112,10113,10119,10125,10131],{},[371,10114,10115,10118],{},[326,10116,10117],{},"Start with documentation",": Treat your notes, decisions, and learnings as first-class context assets",[371,10120,10121,10124],{},[326,10122,10123],{},"Experiment with MCP",": Explore how different tools can share context through standardized protocols",[371,10126,10127,10130],{},[326,10128,10129],{},"Invest in context flow",": Identify where context breaks down in your current workflows",[371,10132,10133,10136],{},[326,10134,10135],{},"Build context habits",": Make context capture as natural as version control",[302,10138,10139],{},[326,10140,10141],{},"Context is the new code. Engineer it accordingly.",{"title":515,"searchDepth":516,"depth":516,"links":10143},[10144,10145,10146,10147,10148,10149,10150,10151],{"id":9908,"depth":516,"text":9909},{"id":9924,"depth":516,"text":9925},{"id":9970,"depth":516,"text":9971},{"id":9980,"depth":516,"text":9981},{"id":10041,"depth":516,"text":10042},{"id":10077,"depth":516,"text":10078},{"id":10087,"depth":516,"text":10088},{"id":10103,"depth":516,"text":10104},"2025-08-03","How I evolved from simple dev tools to understanding context as the foundation of AI-assisted development",{"src":10155,"alt":10156},"\u002Fimages\u002Fblog\u002Fcontext-engineering-with-workflows.png","Context engineering workflow showing seamless information flow between development tools",{},{"title":85,"description":10153},"76ev_YKjWAm9rkp5rBo5KdEEYnh9In7T_NiCW-yukws",{"id":10161,"title":89,"authors":10162,"badge":10165,"body":10167,"date":10152,"description":10535,"extension":533,"image":10536,"meta":10539,"navigation":538,"path":90,"seo":10540,"status":540,"stem":91,"__hash__":10541},"posts\u002F2.blog\u002F20250803-2.context-engineering-at-scale.md",[10163],{"name":292,"to":293,"avatar":10164},{"src":295},{"label":10166},"Enterprise AI",{"type":299,"value":10168,"toc":10519},[10169,10173,10176,10179,10183,10186,10189,10192,10195,10198,10202,10205,10210,10233,10238,10269,10272,10276,10280,10283,10297,10301,10304,10318,10322,10325,10339,10343,10347,10350,10376,10380,10383,10397,10401,10404,10409,10437,10442,10453,10458,10469,10471,10474,10477,10511,10514],[318,10170,10172],{"id":10171},"most-tool-changes-are-context-switch-disasters","Most Tool Changes Are Context Switch Disasters",[302,10174,10175],{},"When I switch from my terminal to my IDE to my note-taking app to my project management tool, the AI loses the thread. Each tool maintains its own context bubble. My carefully curated understanding gets scattered across a dozen interfaces, none of which talk to each other.",[302,10177,10178],{},"The result? I spend more time re-establishing context than actually working.",[318,10180,10182],{"id":10181},"the-enterprise-reality-check","The Enterprise Reality Check",[302,10184,10185],{},"At GE Aerospace, where I work as Principal Architect on the Cloud AI services team, I see this playing out at enterprise scale. Each area and person has knowledge but that knowledge is shared more often in meetings than by reusable artifacts that can be shared freely and iterated on.",[302,10187,10188],{},"Every new hire and contractor has to \"re-learn\" what everyone else in the company already knew.",[302,10190,10191],{},"It's the same reason reading is the foundation of knowledge transfer.",[302,10193,10194],{},"Teams are adopting AI-powered development tools, but they're hitting productivity walls because context doesn't flow between systems.",[302,10196,10197],{},"The tools that are winning—Claude Code—aren't just adding AI features. They're fundamentally rethinking how context flows through development workflows.",[318,10199,10201],{"id":10200},"context-engineering-a-practical-example","Context Engineering: A Practical Example",[302,10203,10204],{},"Consider a typical debugging session to see the difference between traditional and context-engineered approaches:",[302,10206,10207],{},[326,10208,10209],{},"Traditional Approach:",[851,10211,10212,10215,10218,10221,10224,10227,10230],{},[371,10213,10214],{},"Developer encounters bug in production",[371,10216,10217],{},"Searches through logs manually",[371,10219,10220],{},"Opens multiple browser tabs with documentation",[371,10222,10223],{},"Switches between terminal, IDE, and Slack",[371,10225,10226],{},"Asks teammates in chat about similar issues",[371,10228,10229],{},"Context gets lost with each tool switch",[371,10231,10232],{},"Spends 60% of time reconstructing what they already knew",[302,10234,10235],{},[326,10236,10237],{},"Context-Engineered Approach:",[851,10239,10240,10257,10260,10263,10266],{},[371,10241,10242,10243],{},"AI has persistent access to:\n",[368,10244,10245,10248,10251,10254],{},[371,10246,10247],{},"Recent deployment logs and metrics",[371,10249,10250],{},"Related code changes and PR discussions",[371,10252,10253],{},"Historical bug patterns and solutions",[371,10255,10256],{},"Team knowledge base and runbooks",[371,10258,10259],{},"Developer describes the issue once",[371,10261,10262],{},"AI correlates information across all sources",[371,10264,10265],{},"Provides targeted debugging steps with full context",[371,10267,10268],{},"Solution includes prevention strategies based on team patterns",[302,10270,10271],{},"The difference isn't just efficiency—it's the preservation and amplification of institutional knowledge.",[318,10273,10275],{"id":10274},"the-evolution-from-tools-to-context-architecture","The Evolution: From Tools to Context Architecture",[401,10277,10279],{"id":10278},"phase-1-intelligent-context-submission","Phase 1: Intelligent Context Submission",[302,10281,10282],{},"The first phase focuses on improving how we create and submit context:",[368,10284,10285,10288,10291,10294],{},[371,10286,10287],{},"AI-powered grammar and style checking for technical documentation",[371,10289,10290],{},"Real-time context validation and enhancement",[371,10292,10293],{},"Seamless integration between the world's best text editor (VS Code) and AI interfaces",[371,10295,10296],{},"Why recreate inferior chat interfaces when we already have superior editing tools?",[401,10298,10300],{"id":10299},"phase-2-context-persistence-and-retrieval","Phase 2: Context Persistence and Retrieval",[302,10302,10303],{},"The next evolution involves making context repositories truly intelligent:",[368,10305,10306,10309,10312,10315],{},[371,10307,10308],{},"Automatic context categorization and tagging",[371,10310,10311],{},"Semantic search across historical decisions and outcomes",[371,10313,10314],{},"Context suggestion based on current work patterns",[371,10316,10317],{},"Integration with existing development workflows",[401,10319,10321],{"id":10320},"phase-3-predictive-context-engineering","Phase 3: Predictive Context Engineering",[302,10323,10324],{},"The ultimate goal is context systems that anticipate information needs:",[368,10326,10327,10330,10333,10336],{},[371,10328,10329],{},"Proactive context gathering based on project phase",[371,10331,10332],{},"Automated context correlation across team members",[371,10334,10335],{},"Intelligent context filtering to reduce cognitive load",[371,10337,10338],{},"Self-improving context models based on decision outcomes",[318,10340,10342],{"id":10341},"enterprise-implementation-strategy","Enterprise Implementation Strategy",[401,10344,10346],{"id":10345},"measuring-success","Measuring Success",[302,10348,10349],{},"Context engineering success isn't just about AI interactions—it's about team knowledge velocity:",[368,10351,10352,10358,10364,10370],{},[371,10353,10354,10357],{},[326,10355,10356],{},"Time to Context",": How quickly can new team members access relevant project context?",[371,10359,10360,10363],{},[326,10361,10362],{},"Context Retention",": How much institutional knowledge is preserved during team transitions?",[371,10365,10366,10369],{},[326,10367,10368],{},"Decision Quality",": Are teams making better-informed decisions with improved context access?",[371,10371,10372,10375],{},[326,10373,10374],{},"Knowledge Reuse",": How often is existing context being leveraged for new problems?",[318,10377,10379],{"id":10378},"the-competitive-advantage","The Competitive Advantage",[302,10381,10382],{},"Organizations that master context engineering will have a fundamental advantage in the AI era. While competitors struggle with context switching overhead, context-engineered teams will:",[368,10384,10385,10388,10391,10394],{},[371,10386,10387],{},"Onboard new developers faster with comprehensive, searchable context",[371,10389,10390],{},"Make better architectural decisions informed by historical outcomes",[371,10392,10393],{},"Reduce duplicate problem-solving across teams",[371,10395,10396],{},"Scale AI assistance more effectively with richer context inputs",[318,10398,10400],{"id":10399},"building-context-first-culture","Building Context-First Culture",[302,10402,10403],{},"The technical implementation is only half the battle. Enterprise success requires cultural shifts:",[302,10405,10406],{},[326,10407,10408],{},"From Information Hoarding to Context Sharing",[368,10410,10411,10414,10417],{},[371,10412,10413],{},"Reward context documentation as highly as code contributions",[371,10415,10416],{},"Make context accessibility a key performance indicator",[371,10418,10419,10420],{},"Build context sharing as core criteria for everything\n",[368,10421,10422,10425,10428,10431,10434],{},[371,10423,10424],{},"If your work doesn't produce context, what's it really doing?",[371,10426,10427],{},"Your work makes a part; it should produce something an MCP call could search for",[371,10429,10430],{},"\"Did I send an email to Josh yesterday?\" An LLM with an MCP tool for your email should be able to answer that.",[371,10432,10433],{},"\"Make a note to call Julie\" should add a task to a list that you can see needs to be done.",[371,10435,10436],{},"Every context artifact should be linked to a specific project, feature, or task",[302,10438,10439],{},[326,10440,10441],{},"From Meeting-Heavy to Artifact-Heavy Communication",[368,10443,10444,10447,10450],{},[371,10445,10446],{},"Default to written, searchable documentation over verbal communication",[371,10448,10449],{},"Structure meetings to produce reusable context artifacts",[371,10451,10452],{},"Treat context creation as investment, not overhead",[302,10454,10455],{},[326,10456,10457],{},"From Individual Knowledge to Team Intelligence",[368,10459,10460,10463,10466],{},[371,10461,10462],{},"Build systems that capture and share mental models",[371,10464,10465],{},"Create feedback loops that improve context quality over time",[371,10467,10468],{},"Measure team knowledge velocity, not just individual productivity",[318,10470,10104],{"id":10103},[302,10472,10473],{},"This represents more than a feature update—it's positioning development teams at the center of how organizations will work with AI for the next decade.",[302,10475,10476],{},"For enterprise teams looking to embrace context engineering:",[851,10478,10479,10485,10496,10501,10505],{},[371,10480,10481,10484],{},[326,10482,10483],{},"Audit your context switching overhead",": Identify where valuable context gets lost",[371,10486,10487,10490,10491],{},[326,10488,10489],{},"Invest in context infrastructure",": Treat context repositories as critical business systems\n",[851,10492,10493],{},[371,10494,10495],{},"Ideally a monorepo with a single source of truth",[371,10497,10498,10500],{},[326,10499,10123],{},": Explore how tools can share context through standardized protocols",[371,10502,10503,10136],{},[326,10504,10135],{},[371,10506,10507,10510],{},[326,10508,10509],{},"Measure context flow",": Track how efficiently knowledge moves through your organization",[302,10512,10513],{},"The future belongs to those who master the art and science of context engineering at scale.",[302,10515,10516],{},[326,10517,10518],{},"In the AI era, context architecture is your competitive advantage.",{"title":515,"searchDepth":516,"depth":516,"links":10520},[10521,10522,10523,10524,10529,10532,10533,10534],{"id":10171,"depth":516,"text":10172},{"id":10181,"depth":516,"text":10182},{"id":10200,"depth":516,"text":10201},{"id":10274,"depth":516,"text":10275,"children":10525},[10526,10527,10528],{"id":10278,"depth":523,"text":10279},{"id":10299,"depth":523,"text":10300},{"id":10320,"depth":523,"text":10321},{"id":10341,"depth":516,"text":10342,"children":10530},[10531],{"id":10345,"depth":523,"text":10346},{"id":10378,"depth":516,"text":10379},{"id":10399,"depth":516,"text":10400},{"id":10103,"depth":516,"text":10104},"How enterprise teams can overcome context switching disasters and build intelligent development workflows",{"src":10537,"alt":10538},"\u002Fimages\u002Fblog\u002Fmind-blown-by-ai-exponential.png","Enterprise context engineering architecture showing integrated workflows",{},{"title":89,"description":10535},"xE9nv3DO3vurgT6KIqT8mIJVsOXctQBV0V_ZzG4hido",{"id":10543,"title":81,"authors":10544,"badge":10547,"body":10548,"date":10874,"description":10875,"extension":533,"image":10876,"meta":10879,"navigation":538,"path":82,"seo":10880,"status":540,"stem":83,"__hash__":10881},"posts\u002F2.blog\u002F20250720.review-that-ai-code.md",[10545],{"name":292,"to":293,"avatar":10546},{"src":295},{"label":548},{"type":299,"value":10549,"toc":10860},[10550,10552,10555,10561,10564,10570,10574,10580,10585,10588,10594,10598,10601,10606,10609,10619,10622,10633,10639,10643,10646,10651,10662,10667,10675,10680,10691,10695,10698,10702,10707,10710,10714,10717,10731,10735,10738,10765,10769,10772,10786,10790,10795,10806,10811,10819,10824,10835,10839,10842,10845,10851,10854,10857],[318,10551,9909],{"id":9908},[302,10553,10554],{},"Three days. That's how long I spent debugging what looked like a perfect AI-generated function. The linter passed. The tests passed. The code reviews looked clean. But deep in production, users were hitting an edge case that caused silent data corruption—the worst kind of bug.",[302,10556,10557,10558],{},"I had violated my own 25-year rule: ",[326,10559,10560],{},"Never ship code you don't fully understand.",[302,10562,10563],{},"As I traced through that function line by line at 2 AM, I realized I had been seduced by the speed and apparent intelligence of AI code generation. The function was 90% brilliant—elegant error handling, proper async patterns, even thoughtful comments. But that remaining 10% contained assumptions about data structures that were subtly wrong.",[302,10565,10566,10567],{},"That night I created a rule for myself: ",[326,10568,10569],{},"Always understand the code before using it.",[318,10571,10573],{"id":10572},"my-journey-from-ai-auto-accept-to-strategic-user","My Journey from AI Auto-Accept to Strategic User",[302,10575,10576,10579],{},[326,10577,10578],{},"Early Days (2023): Joyful Embrace","\nI love autocomplete tools. My grammar and spelling have always been awful, so having a machine help me was a no-brainer.",[302,10581,10582],{},[326,10583,10584],{},"Better Autocomplete (2024): Complete Partnership",[302,10586,10587],{},"AI tools became true partners in my workflow. I started using them not just for suggestions, but as collaborators. I would write a comment describing the function I wanted, and the AI would generate the code.",[302,10589,10590,10593],{},[326,10591,10592],{},"The New Approach (2025-Present): Expert Partnership","\nAI is more than helpful—it completes functions, entire files, and features by itself. It can generate so much code so quickly it seems like magic. But trusting it without validation introduced the worst types of bugs. I learned to verify everything, work with it as a quick partner that I steered and verified. Not doing so introduced the worst types of bugs: code that mostly worked.",[318,10595,10597],{"id":10596},"the-github-copilot-moment-that-proved-my-point","The GitHub Copilot Moment That Proved My Point",[302,10599,10600],{},"Let me show you exactly what I mean. As I was writing this very post, GitHub Copilot suggested I complete this sentence:",[330,10602,10603],{},[302,10604,10605],{},"\"Because not doing so is like...\"",[302,10607,10608],{},"With this completion:",[1119,10610,10613],{"className":10611,"code":10612,"language":533,"meta":515,"style":515},"language-md shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","giving a child a loaded gun and not teaching them how to use it.\n",[745,10614,10615],{"__ignoreMap":515},[1127,10616,10617],{"class":1129,"line":1130},[1127,10618,10612],{"class":1497},[302,10620,10621],{},"It's the perfect example of AI's fundamental limitation. The suggestion is:",[368,10623,10624,10627,10630],{},[371,10625,10626],{},"Grammatically correct ✓",[371,10628,10629],{},"Contextually relevant ✓",[371,10631,10632],{},"Completely inappropriate ✗",[302,10634,10635,10636],{},"The metaphor is jarring, potentially offensive, and doesn't match my voice or the professional tone I wanted. In text, this creates awkward moments. ",[326,10637,10638],{},"In code, it creates production incidents.",[318,10640,10642],{"id":10641},"why-code-ai-mistakes-are-1000x-more-dangerous","Why Code AI Mistakes Are 1000x More Dangerous",[302,10644,10645],{},"When you're writing prose, AI mistakes are obvious and recoverable. When you're writing code, AI mistakes are:",[302,10647,10648],{},[326,10649,10650],{},"Syntactically Perfect but Logically Flawed",[368,10652,10653,10656,10659],{},[371,10654,10655],{},"They compile without warnings",[371,10657,10658],{},"They pass basic tests",[371,10660,10661],{},"They fail in production under specific conditions",[302,10663,10664],{},[326,10665,10666],{},"Subtly Wrong in Ways That Take Time to Surface",[368,10668,10669,10672],{},[371,10670,10671],{},"Off-by-one errors in edge cases",[371,10673,10674],{},"Incorrect assumptions about data or processes",[302,10676,10677],{},[326,10678,10679],{},"Expensive to Debug",[368,10681,10682,10685,10688],{},[371,10683,10684],{},"The code \"mostly works\" so bugs appear random",[371,10686,10687],{},"Root cause analysis requires deep understanding of the generated logic",[371,10689,10690],{},"It can produce code infinitely faster than I can debug it.",[318,10692,10694],{"id":10693},"my-battle-tested-framework-for-ai-assisted-development","My Battle-Tested Framework for AI-Assisted Development",[302,10696,10697],{},"After two years of refining my approach, here's my systematic framework:",[401,10699,10701],{"id":10700},"the-line-by-line-rule","The Line-by-Line Rule",[302,10703,10704],{},[326,10705,10706],{},"NEVER commit AI-generated code without reading every single line.",[302,10708,10709],{},"Not skimming. Not glancing. Reading with the same attention you'd give to code written by a junior developer who's having a bad day.",[401,10711,10713],{"id":10712},"the-small-commits-strategy","The Small Commits Strategy",[302,10715,10716],{},"Keep AI-generated changes small enough that you can:",[368,10718,10719,10722,10725,10728],{},[371,10720,10721],{},"Understand every line's purpose",[371,10723,10724],{},"Trace the logic flow completely",[371,10726,10727],{},"Identify potential edge cases",[371,10729,10730],{},"Review the changes in under 10 minutes",[401,10732,10734],{"id":10733},"the-context-validation-process","The Context Validation Process",[302,10736,10737],{},"For every AI suggestion, ask:",[851,10739,10740,10745,10750,10755,10760],{},[371,10741,10742],{},[326,10743,10744],{},"Does this match my coding standards?",[371,10746,10747],{},[326,10748,10749],{},"Are the assumptions about data types correct?",[371,10751,10752],{},[326,10753,10754],{},"What happens in edge cases (null, empty, undefined)?",[371,10756,10757],{},[326,10758,10759],{},"Is the error handling appropriate?",[371,10761,10762],{},[326,10763,10764],{},"Does this integrate properly with existing systems?",[401,10766,10768],{"id":10767},"the-test-first-verification","The Test-First Verification",[302,10770,10771],{},"Before accepting any AI-generated code:",[368,10773,10774,10777,10780,10783],{},[371,10775,10776],{},"Write tests that cover edge cases",[371,10778,10779],{},"Run the tests against the generated code",[371,10781,10782],{},"Look for gaps in test coverage",[371,10784,10785],{},"Add tests for scenarios the AI might have missed",[318,10787,10789],{"id":10788},"why-this-matters-to-your-career-and-sanity","Why This Matters to YOUR Career and Sanity",[302,10791,10792],{},[326,10793,10794],{},"Personal Stakes:",[368,10796,10797,10800,10803],{},[371,10798,10799],{},"Your reputation is attached to every line of code you ship",[371,10801,10802],{},"Debugging AI-introduced bugs at 2 AM ruins your work-life balance",[371,10804,10805],{},"Production incidents create stress that compounds over time",[302,10807,10808],{},[326,10809,10810],{},"Professional Impact:",[368,10812,10813,10816],{},[371,10814,10815],{},"Team trust erodes when your \"AI-assisted\" code causes outages",[371,10817,10818],{},"Technical debt accumulates faster than you can pay it down",[302,10820,10821],{},[326,10822,10823],{},"The Opportunity Cost:",[368,10825,10826,10829,10832],{},[371,10827,10828],{},"Time saved by AI is lost 10x over during debugging sessions",[371,10830,10831],{},"Team velocity decreases when no one actually understands the codebase",[371,10833,10834],{},"Innovation slows when you're constantly fixing \"smart\" bugs",[318,10836,10838],{"id":10837},"the-bottom-line-smart-tools-smarter-developers","The Bottom Line: Smart Tools, Smarter Developers",[302,10840,10841],{},"AI coding tools are not going away—they're getting more sophisticated every month. The developers who succeed won't be those who resist AI or those who blindly accept everything it generates.",[302,10843,10844],{},"The winners will be those who develop the discipline to be AI-assisted experts rather than AI-dependent generalists.",[302,10846,10847,10850],{},[326,10848,10849],{},"Remember",": You're not just a code reviewer for AI suggestions—you're the architect of systems that need to work reliably for years. Every line of generated code that ships under your name is a reflection of your judgment and expertise.",[302,10852,10853],{},"Use AI to accelerate your thinking, not replace it. Read every line. Understand every decision. Make small, reviewable commits. The moment you stop being the expert who validates AI's work is the moment you've traded short-term productivity for long-term technical debt.",[302,10855,10856],{},"The choice is yours: Become an AI-enhanced expert, or become dependent on tools you don't fully understand. Choose expertise.",[1698,10858,10859],{},"html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":515,"searchDepth":516,"depth":516,"links":10861},[10862,10863,10864,10865,10866,10872,10873],{"id":9908,"depth":516,"text":9909},{"id":10572,"depth":516,"text":10573},{"id":10596,"depth":516,"text":10597},{"id":10641,"depth":516,"text":10642},{"id":10693,"depth":516,"text":10694,"children":10867},[10868,10869,10870,10871],{"id":10700,"depth":523,"text":10701},{"id":10712,"depth":523,"text":10713},{"id":10733,"depth":523,"text":10734},{"id":10767,"depth":523,"text":10768},{"id":10788,"depth":516,"text":10789},{"id":10837,"depth":516,"text":10838},"2025-07-20","After spending three days debugging a 'perfect' AI-generated function, I learned the hard way that AI tools are brilliant assistants, not replacements for understanding. Here's my battle-tested approach to working with Claude, Copilot, and other AI coding tools without losing your expertise—or your sanity.",{"src":10877,"alt":10878},"\u002Fimages\u002Fblog\u002F20250814-2019-the-ai-code-review-that-changed-everything.png","A contemplative cinematic split-screen scene: on the left, an AI generating flawless-looking code on a glowing screen with beautiful syntax highlighting and perfect formatting, representing the seductive appeal of AI-generated solutions; on the right, a focused developer hunched over their desk at 2 AM with warm desk lamp lighting, magnifying glass in hand, carefully examining each line of code with red annotations and bug markers scattered around, showing the reality of debugging AI mistakes. The transition between the two sides should be a subtle visual metaphor of code that appears perfect but contains hidden flaws, with warm\u002Fcool lighting contrast emphasizing the contemplative mood of hard-learned wisdom.",{},{"title":81,"description":10875},"wBT1km8VhGL_xWFYaFH9ihWe6rproFQZIpdBiYWkbKA",{"id":10883,"title":77,"authors":10884,"badge":10887,"body":10888,"date":11063,"description":515,"extension":533,"image":11064,"meta":11065,"navigation":538,"path":78,"seo":11066,"status":540,"stem":79,"__hash__":11067},"posts\u002F2.blog\u002F20250713.tips-for-claude-code.md",[10885],{"name":292,"to":293,"avatar":10886},{"src":295},{"label":548},{"type":299,"value":10889,"toc":11057},[10890,10894,10911,10913,10916,10994,10998,11003,11007],[318,10891,10893],{"id":10892},"must-read-or-watch","Must Read or Watch",[368,10895,10896,10901,10906],{},[371,10897,10898],{},[335,10899,590],{"href":588,"rel":10900},[461],[371,10902,10903],{},[335,10904,597],{"href":595,"rel":10905},[461],[371,10907,10908],{},[335,10909,604],{"href":602,"rel":10910},[461],[318,10912,711],{"id":710},[302,10914,10915],{},"Use every feature of Claude Code—not doing so is leaving power on the table.",[368,10917,10918,10921,10924,10950,10969,10972,10980,10983],{},[371,10919,10920],{},"Use dictation to give the model more context; every word helps narrow down the task to what you were expecting.",[371,10922,10923],{},"Use the plan mode.",[371,10925,10926,10927,10930,10931,10934,10935,10937,10938],{},"Use ",[745,10928,10929],{},"ctrl","+",[745,10932,10933],{},"z"," to exit Claude Code to terminal, then resume with ",[745,10936,6562],{},".\n",[368,10939,10940],{},[371,10941,10942,10943,10945,10946,10949],{},"It's so much better than the ",[745,10944,6566],{}," bash command for running commands ",[326,10947,10948],{},"WITHOUT"," adding them to the context.",[371,10951,10952,10953,10955,10956,10959,10960],{},"Use the ",[745,10954,6566],{}," bash command to run commands that you want ",[326,10957,10958],{},"added"," to the context.\n",[368,10961,10962],{},[371,10963,10964,10965,10968],{},"Running ",[745,10966,10967],{},"--help"," on a tool is a great way to get the model to understand the tool.",[371,10970,10971],{},"Use the memory.",[371,10973,10974,10975],{},"Use the web search.\n",[368,10976,10977],{},[371,10978,10979],{},"I've been linking to the README of the repo I'm using at the time to load it into the context.",[371,10981,10982],{},"Use up arrow to repeat commands.",[371,10984,10985,10986,10989,10990,10993],{},"Add commands to ",[745,10987,10988],{},".claude\u002Fcommands"," to make them available in the future and with ",[745,10991,10992],{},"$ARGUMENTS"," to pass arguments to the command.",[318,10995,10997],{"id":10996},"dont-get-distracted","Don't Get Distracted",[368,10999,11000],{},[371,11001,11002],{},"If you have an idea how to improve something, create an issue to remember it, but don't get distracted by it in the moment.",[318,11004,11006],{"id":11005},"other-tips","Other Tips",[368,11008,11009,11025,11038],{},[371,11010,11011,11012,11015,11016,11019,11020],{},"Think about how you manage context. The idea may be already now that ",[745,11013,11014],{},"the best communicator"," → ",[745,11017,11018],{},"the best coder",". ",[335,11021,11024],{"href":11022,"rel":11023},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=8rABwKRsec4&t=1068s",[461],"The New Code — Sean Grove, OpenAI",[371,11026,11027,11028],{},"So writing document specifications may be even more important than writing code.\n",[368,11029,11030],{},[371,11031,11032,11033],{},"Give a look at these requirements for a project, which really embraced this idea. I used Claude to translate from Japanese to English: ",[335,11034,11037],{"href":11035,"rel":11036},"https:\u002F\u002Fgithub.com\u002FChrisTowles\u002Fcc-jsonl\u002Fblob\u002Fmain\u002Fdocs\u002Frequirements.md",[461],"Requirements for a Project",[371,11039,11040,11041],{},"Use pictures.\n",[368,11042,11043,11046],{},[371,11044,11045],{},"Claude Code can use pictures, so if you have a picture of the code you want to change, you can use that to give it more context.",[371,11047,11048,11049],{},"Give Claude access to output of what running the code does so it can create a feedback loop to really improve.\n",[368,11050,11051,11054],{},[371,11052,11053],{},"Tests are great for this, but you can also use screenshots or text of the output.",[371,11055,11056],{},"For any web app, you can use Puppeteer to take screenshots of the output and use that as context.",{"title":515,"searchDepth":516,"depth":516,"links":11058},[11059,11060,11061,11062],{"id":10892,"depth":516,"text":10893},{"id":710,"depth":516,"text":711},{"id":10996,"depth":516,"text":10997},{"id":11005,"depth":516,"text":11006},"2025-07-13",{"src":5427,"alt":515},{},{"title":77,"description":515},"y5-8YHleGu7xE8QKmoEopiWzWsrBJezpbu8UFw_GYK0",{"id":11069,"title":73,"authors":11070,"badge":11073,"body":11074,"date":11190,"description":11191,"extension":533,"image":11192,"meta":11195,"navigation":538,"path":74,"seo":11196,"status":540,"stem":75,"__hash__":11197},"posts\u002F2.blog\u002F20250705.voice-to-system.md",[11071],{"name":292,"to":293,"avatar":11072},{"src":295},{"label":1732},{"type":299,"value":11075,"toc":11186},[11076,11078,11081,11087,11091,11094,11099,11107,11110,11119,11124,11131,11137,11145,11148,11153,11156,11159,11162,11165,11168,11183],[318,11077,8914],{"id":8913},[302,11079,11080],{},"Had my mind blown by Claude Code's creator after watching @bcherny. Realized I've been massively underutilizing AI even as a Principal Architect working in AI! (The irony is not lost on me.) The key insight: remove all abstractions between the model and the task. I remember when @karpathy pointed this out to me years ago!",[302,11082,11083],{},[335,11084,11085],{"href":11085,"rel":11086},"https:\u002F\u002Fx.com\u002FChris_Towles\u002Fstatus\u002F1941610508173320352",[461],[318,11088,11090],{"id":11089},"having-my-mind-blown","Having my mind blown",[302,11092,11093],{},"So on Friday, I watched a video by Anthropic's Claude Code lead developer. I knew this man was recently in the news – he had jumped to Chief Architect at @anysphere, which owns Cursor. Pretty relevant timing with all the talent shuffling between OpenAI, Meta, and everyone else right now. I'd seen posts by others referencing him but never watched one of his talks. But this video changed everything. It made me realize that even though I've been trying to increase my usage of AI, I wasn't thinking big enough.",[302,11095,11096],{},[335,11097,588],{"href":588,"rel":11098},[461],[302,11100,11101,11102,11106],{},"What you have to know is that earlier that day I was watching a video by @mattpocockuk about how he's using AI agents to work by themselves. He was showing how he uses Claude Code to automate his workflow, and I was genuinely impressed with how he's been using it more effectively than me. But after thinking about his ",[335,11103,11104],{"href":11104,"rel":11105},"https:\u002F\u002Fx.com\u002Fmattpocockuk\u002Fstatus\u002F1940693600737841272",[461]," video about how he's using AI agents to work by themselves because he's invested in his CI\u002FCD and tests...",[302,11108,11109],{},"Back to watching Boris Cherny talk about why Claude is built the way it is. By removing everything between the model and the files and system itself, the better at everything it gets. No more leaky abstractions between the model and the lower-level system and files. He made me realize that as a lifelong developer, the reason I still use the terminal is because of its lack of abstractions. The reason I use command line tools almost every minute I'm on a computer is because it's still the most powerful interface we have.",[302,11111,11112,11113,11118],{},"The fact that I use the terminal with my autocomplete, colored output, aliases, and dotfiles is because that's the best abstraction we've had since ed in the 1970s. (No, I'm not that old, but I remember the late 80s machines with ",[335,11114,11117],{"href":11115,"rel":11116},"https:\u002F\u002Farchive.org\u002Fdetails\u002Fa2_Fraction_Munchers_v1.0_1987_MECC_US",[461],"Number Munchers",". I'm old enough to remember when that was cutting-edge.)",[330,11120,11121],{},[302,11122,11123],{},"Note: I found that link to play the game, but it's in full color. I swear it was in black and white when I played it.",[302,11125,11126,11127,11130],{},"And it aligned with the idea that the fewer crutches you put between the model and your CLI, the more powerful it becomes as the model improves. Just like he references in ",[335,11128,4318],{"href":4318,"rel":11129},[461],". Which I've read before—we all have—but it never occurred to me that all the tools we added on top of the model were actually limiting the model's potential.",[302,11132,11133],{},[335,11134,11135],{"href":11135,"rel":11136},"https:\u002F\u002Ftenor.com\u002Fview\u002Fmind-blown-mind-explosion-explode-gif-4740219",[461],[302,11138,11139,11140,1207],{},"I'd read it multiple times! And remember when Andrej Karpathy checked that we'd ",[335,11141,11144],{"href":11142,"rel":11143},"https:\u002F\u002Fx.com\u002Fkarpathy\u002Fstatus\u002F1509962678319595523",[461],"all read it too!",[302,11146,11147],{},"Watching why Boris made Claude Code the way he did, to use a terminal like I would use those tools. I realized that Claude Code is so close to the actual files—the way I would edit files, the way I would work if I was doing everything at a really high level, but it lets me do those things on my machine. Everything in between me and the files was really an abstraction—a limiting and leaky abstraction. Every tool added between those files, even VS Code (as good as it is), creates distance. This kind of blew my brother's mind as well. We've been talking about it for the last 24 hours, including while I was working on this post during my free time after taking the kids to the pool. (Nothing like a good tech epiphany to ruin a perfectly relaxing Saturday.)",[330,11149,11150],{},[302,11151,11152],{},"Yes, I'm aware that he recently took a new job at Cursor, so good luck to them on that hire because I think he's definitely onto something.",[302,11154,11155],{},"So while I've had my mind blown all weekend after watching Anthropic's Claude Code video, it really made me consider how much we let the tooling limit what the agent can do in our repos. Literally a week and a half ago, I posted about how I was using voice-to-text integration in VS Code to help use AI better. But that was actually a hindrance. (Classic case of solving the wrong problem with more complexity.)",[302,11157,11158],{},"One of the most amazing things about the Claude Code video is how it removes all the distractions. These models get better when you don't constrain them. Anything you do betting on the model – like any tool you try to give it – is actually likely harming it by finding a local maximum. With Claude Code, the interface uses the same tool we've been using for the last 50 years. His iteration through the editor looks like a standard batch of terminal commands. So by giving the model the same way we would try to fix things at the terminal – with the only interface we've ever found that actually works – we get better results.",[302,11160,11161],{},"So with my voice dictation, I was not being efficient. I was still typing in Claude Code instead of just speaking the commands I wanted Claude to execute. When I was adding markdown, I could use the VS Code voice integration with the editor. But here's the kicker...",[302,11163,11164],{},"However, VS Code's voice integration doesn't work the same way outside of the editor window. When I'm in the terminal and start dictating, it can't dictate directly. Instead, I can dictate to ChatGPT or whatever model I'm using for copilot, but it interprets that command and puts it in the terminal. I don't want that layer – just like in the Claude Code talk. I don't want VS Code between me and the terminal. So like his comment (and this was what blew my mind), I need system-level dictation.",[302,11166,11167],{},"I really struggled with VS Code audio settings. I spent probably an hour messing around with plugins, thinking maybe they'd help with dictation better. But what I should do is just not have VS Code in the equation. I just want to talk to the terminal window, right? (Revolutionary concept, I know.)",[302,11169,11170,11171,11176,11177,11182],{},"So how do you do that in Linux? Well, you need OS-level dictation. What was crazy was when I was trying to find the best dictation solution for a Linux terminal, I was taken back to the same man, ",[335,11172,11175],{"href":11173,"rel":11174},"https:\u002F\u002Fgithub.com\u002Fbcherny",[461],"Boris Cherny",", who gave that talk. In a ",[335,11178,11181],{"href":11179,"rel":11180},"https:\u002F\u002Fgithub.com\u002Fanthropics\u002Fclaude-code\u002Fissues\u002F154#issuecomment-2856756037",[461],"GitHub issue reply",", he mentioned that the way he's built most of Claude Code is by using OS-level dictation in a terminal. Mind blown! No VS Code in between, which just validates that he's really right.",[302,11184,11185],{},"The idea of getting closer to the concept of nothing between the files and the model brings me back to an unrelated topic and concept: nothing between you and the model. (It's like layers of abstraction are the enemy of progress – who knew?)",{"title":515,"searchDepth":516,"depth":516,"links":11187},[11188,11189],{"id":8913,"depth":516,"text":8914},{"id":11089,"depth":516,"text":11090},"2025-07-05","How watching Anthropic's Claude Code lead work made me realize I wasn't using AI enough, and the journey to OS-level voice dictation for better terminal workflows.",{"src":11193,"alt":11194},"\u002Fimages\u002Fblog\u002F20250106-1442-voice-to-text-coding.webp","Modern developer workspace with clean desk, laptop, and organized tools representing productive AI workflow",{},{"title":73,"description":11191},"_wxOJ_EmVHWmevUc4-sZv-6bxz_L8Vj0VLhLI4a2nuw",{"id":11199,"title":69,"authors":11200,"badge":11203,"body":11205,"date":11505,"description":11506,"extension":533,"image":11507,"meta":11509,"navigation":538,"path":70,"seo":11510,"status":540,"stem":71,"__hash__":11511},"posts\u002F2.blog\u002F20250628.comfy-ui-setup.md",[11201],{"name":292,"to":293,"avatar":11202},{"src":295},{"label":11204},"ComfyUI",{"type":299,"value":11206,"toc":11492},[11207,11210,11213,11216,11220,11227,11231,11248,11254,11258,11261,11274,11280,11284,11287,11300,11306,11313,11317,11321,11324,11329,11333,11336,11342,11345,11405,11408,11425,11449,11453,11473,11478,11481,11483,11486,11489],[302,11208,11209],{},"I've been using Fooocus for a while now as my go-to tool for generating images from text prompts. However, after spending an hour debugging issues today and discovering that the repository hasn't had a merge commit in 5 months, it became clear that development has stalled.",[302,11211,11212],{},"Time to find a better alternative.",[302,11214,11215],{},"After some research and a recommendation from my brother Patrick, I decided to set up ComfyUI - a more actively maintained and feature-rich solution for local AI image generation.",[318,11217,11219],{"id":11218},"installation","Installation",[302,11221,11222,11223,11226],{},"I chose to use ",[745,11224,11225],{},"uv"," to install ComfyUI as a tool, which provides isolated Python environments for better dependency management.",[401,11228,11230],{"id":11229},"step-1-install-comfy-cli","Step 1: Install comfy-cli",[1119,11232,11234],{"className":3307,"code":11233,"language":3309,"meta":515,"style":515},"uv tool install comfy-cli\n",[745,11235,11236],{"__ignoreMap":515},[1127,11237,11238,11240,11243,11245],{"class":1129,"line":1130},[1127,11239,11225],{"class":2246},[1127,11241,11242],{"class":1621}," tool",[1127,11244,6295],{"class":1621},[1127,11246,11247],{"class":1621}," comfy-cli\n",[302,11249,11250],{},[467,11251],{"alt":11252,"src":11253},"ComfyUI CLI installation","\u002Fimages\u002Fblog\u002Fcomfy-ui-install-20250628.png",[401,11255,11257],{"id":11256},"step-2-install-comfyui","Step 2: Install ComfyUI",[302,11259,11260],{},"After installing the CLI tool, the next step is to install ComfyUI itself:",[1119,11262,11264],{"className":3307,"code":11263,"language":3309,"meta":515,"style":515},"comfy install\n",[745,11265,11266],{"__ignoreMap":515},[1127,11267,11268,11271],{"class":1129,"line":1130},[1127,11269,11270],{"class":2246},"comfy",[1127,11272,11273],{"class":1621}," install\n",[302,11275,11276,11277],{},"However, I encountered an error: ",[745,11278,11279],{},"comfy-cli\u002Fbin\u002Fpython: No module named pip",[401,11281,11283],{"id":11282},"step-3-fix-the-pip-issue","Step 3: Fix the pip issue",[302,11285,11286],{},"The problem was that pip wasn't available in the isolated Python environment created by uv. To resolve this, I needed to ensure pip was installed:",[1119,11288,11290],{"className":3307,"code":11289,"language":3309,"meta":515,"style":515},"~\u002F.local\u002Fshare\u002Fuv\u002Ftools\u002Fcomfy-cli\u002Fbin\u002Fpython -m ensurepip\n",[745,11291,11292],{"__ignoreMap":515},[1127,11293,11294,11297],{"class":1129,"line":1130},[1127,11295,11296],{"class":1501},"~",[1127,11298,11299],{"class":1497},"\u002F.local\u002Fshare\u002Fuv\u002Ftools\u002Fcomfy-cli\u002Fbin\u002Fpython -m ensurepip\n",[302,11301,11302],{},[467,11303],{"alt":11304,"src":11305},"Fixing pip installation in ComfyUI environment","\u002Fimages\u002Fblog\u002Fcomfy-cli-ensurepip-20250628.png",[302,11307,11308,11309,11312],{},"After running this command, ",[745,11310,11311],{},"comfy install"," worked successfully.",[318,11314,11316],{"id":11315},"downloading-models","Downloading Models",[401,11318,11320],{"id":11319},"models-in-the-model-manager","Models in the Model Manager",[302,11322,11323],{},"Some—few, it seems—can be downloaded from the Model Manager.",[302,11325,11326],{},[467,11327],{"alt":515,"src":11328},"\u002Fimages\u002Fblog\u002Fcomfy-ui-model-manager-20250628.png",[401,11330,11332],{"id":11331},"downloading-models-manually","Downloading Models Manually",[302,11334,11335],{},"More models can be downloaded manually if they're not available in the Model Manager. Here's how to use curl to download models to the correct folder with proper filenames. Yes, this is oddly not a straightforward process. You'll need to open a template using \"Browse Template\" and choose \"image generation\".",[302,11337,11338],{},[467,11339],{"alt":11340,"src":11341},"Generating Images with ComfyUI","\u002Fimages\u002Fblog\u002Fcomfy-ui-generate-image-20250624.png",[302,11343,11344],{},"After it opens, it will tell you the model it needs to download. What you need to do is copy the model ID and use it. It's crazy the UI doesn't build and run this command, but here is what I'm using.",[1119,11346,11348],{"className":3307,"code":11347,"language":3309,"meta":515,"style":515},"# check you know your local folder structure\nls ~\u002Fcomfy\u002FComfyUI\u002Fmodels\n\n# use the URL provided to download the model and modify where it'll be downloaded.\n\n# For downloading from Civitai (example)\ncurl -L \"https:\u002F\u002Fcivitai.com\u002Fapi\u002Fdownload\u002Fmodels\u002FMODEL_ID\" \\\n     -o ~\u002Fcomfy\u002FComfyUI\u002Fmodels\u002Fcheckpoints\u002Fcustom-model.safetensors\n",[745,11349,11350,11355,11362,11366,11371,11375,11380,11397],{"__ignoreMap":515},[1127,11351,11352],{"class":1129,"line":1130},[1127,11353,11354],{"class":1487},"# check you know your local folder structure\n",[1127,11356,11357,11359],{"class":1129,"line":516},[1127,11358,5191],{"class":2246},[1127,11360,11361],{"class":1621}," ~\u002Fcomfy\u002FComfyUI\u002Fmodels\n",[1127,11363,11364],{"class":1129,"line":523},[1127,11365,1517],{"emptyLinePlaceholder":538},[1127,11367,11368],{"class":1129,"line":1146},[1127,11369,11370],{"class":1487},"# use the URL provided to download the model and modify where it'll be downloaded.\n",[1127,11372,11373],{"class":1129,"line":1382},[1127,11374,1517],{"emptyLinePlaceholder":538},[1127,11376,11377],{"class":1129,"line":1388},[1127,11378,11379],{"class":1487},"# For downloading from Civitai (example)\n",[1127,11381,11382,11385,11388,11390,11393,11395],{"class":1129,"line":1586},[1127,11383,11384],{"class":2246},"curl",[1127,11386,11387],{"class":1621}," -L",[1127,11389,3750],{"class":1501},[1127,11391,11392],{"class":1621},"https:\u002F\u002Fcivitai.com\u002Fapi\u002Fdownload\u002Fmodels\u002FMODEL_ID",[1127,11394,3736],{"class":1501},[1127,11396,3325],{"class":1497},[1127,11398,11399,11402],{"class":1129,"line":1599},[1127,11400,11401],{"class":1621},"     -o",[1127,11403,11404],{"class":1621}," ~\u002Fcomfy\u002FComfyUI\u002Fmodels\u002Fcheckpoints\u002Fcustom-model.safetensors\n",[302,11406,11407],{},"The key parts of the curl command:",[368,11409,11410,11416,11422],{},[371,11411,11412,11415],{},[745,11413,11414],{},"-L"," follows redirects (important for many model hosting sites)",[371,11417,11418,11421],{},[745,11419,11420],{},"-o"," specifies the output path and filename",[371,11423,11424],{},"Use the full path including the desired filename",[1119,11426,11428],{"className":3307,"code":11427,"language":3309,"meta":515,"style":515},"curl -L \"https:\u002F\u002Fhuggingface.co\u002FComfy-Org\u002Fstable-diffusion-v1-5-archive\u002Fresolve\u002Fmain\u002Fv1-5-pruned-emaonly-fp16.safetensors?download=true\" -o ~\u002Fcomfy\u002FComfyUI\u002Fmodels\u002Fcheckpoints\u002Fv1-5-pruned-emaonly-fp16.safetensors\n",[745,11429,11430],{"__ignoreMap":515},[1127,11431,11432,11434,11436,11438,11441,11443,11446],{"class":1129,"line":1130},[1127,11433,11384],{"class":2246},[1127,11435,11387],{"class":1621},[1127,11437,3750],{"class":1501},[1127,11439,11440],{"class":1621},"https:\u002F\u002Fhuggingface.co\u002FComfy-Org\u002Fstable-diffusion-v1-5-archive\u002Fresolve\u002Fmain\u002Fv1-5-pruned-emaonly-fp16.safetensors?download=true",[1127,11442,3736],{"class":1501},[1127,11444,11445],{"class":1621}," -o",[1127,11447,11448],{"class":1621}," ~\u002Fcomfy\u002FComfyUI\u002Fmodels\u002Fcheckpoints\u002Fv1-5-pruned-emaonly-fp16.safetensors\n",[318,11450,11452],{"id":11451},"generating-an-image","Generating an Image",[302,11454,11455,11456,1199,11459,11462,11463,11468,11469,11472],{},"Now trying to recreate the art style I used in Fooocus like ",[745,11457,11458],{},"SAI Fantasy Art",[745,11460,11461],{},"SAI Comic Book",", I looked around and ",[335,11464,11467],{"href":11465,"rel":11466},"https:\u002F\u002Fgithub.com\u002Fbash-j\u002Fmikey_nodes",[461],"Mikey Nodes"," seems to be the most popular. After using the ",[745,11470,11471],{},"prompt_with_styles_2x.json"," from the repo, it seems to be a good starting place. Once I fixed the models:",[302,11474,11475],{},[467,11476],{"alt":515,"src":11477},"\u002Fimages\u002Fblog\u002Fcomfy-ui-working-working-20250628.png",[302,11479,11480],{},"After a few iterations, I hope to recreate the desired art style.",[318,11482,8469],{"id":3101},[302,11484,11485],{},"With ComfyUI now installed, I can start exploring its workflow-based approach to AI image generation. Unlike Fooocus's simple prompt-to-image interface, ComfyUI offers more granular control through visual nodes and workflows - perfect for more advanced image generation tasks.",[302,11487,11488],{},"The active development community and extensive plugin ecosystem make ComfyUI a solid long-term choice for local AI image generation.",[1698,11490,11491],{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}",{"title":515,"searchDepth":516,"depth":516,"links":11493},[11494,11499,11503,11504],{"id":11218,"depth":516,"text":11219,"children":11495},[11496,11497,11498],{"id":11229,"depth":523,"text":11230},{"id":11256,"depth":523,"text":11257},{"id":11282,"depth":523,"text":11283},{"id":11315,"depth":516,"text":11316,"children":11500},[11501,11502],{"id":11319,"depth":523,"text":11320},{"id":11331,"depth":523,"text":11332},{"id":11451,"depth":516,"text":11452},{"id":3101,"depth":516,"text":8469},"2025-06-28","Installing and configuring ComfyUI for local AI image generation after Fooocus development stalled",{"src":11253,"alt":11508},"ComfyUI installation process using uv tool manager",{},{"title":69,"description":11506},"Vk-Bgeuv7fIJOAebpQ0zTw75vs9nldMaIZ-8l0QtRuE",{"id":11513,"title":65,"authors":11514,"badge":11517,"body":11518,"date":11609,"description":11610,"extension":533,"image":11611,"meta":11614,"navigation":538,"path":66,"seo":11615,"status":540,"stem":67,"__hash__":11616},"posts\u002F2.blog\u002F20250622.voice-to-text.md",[11515],{"name":292,"to":293,"avatar":11516},{"src":295},{"label":1732},{"type":299,"value":11519,"toc":11604},[11520,11522,11537,11545,11549,11552,11555,11558,11562,11565,11570,11573,11598,11601],[318,11521,11219],{"id":11218},[1119,11523,11525],{"className":3307,"code":11524,"language":3309,"meta":515,"style":515},"ext install ms-vscode.vscode-speech\n",[745,11526,11527],{"__ignoreMap":515},[1127,11528,11529,11532,11534],{"class":1129,"line":1130},[1127,11530,11531],{"class":2246},"ext",[1127,11533,6295],{"class":1621},[1127,11535,11536],{"class":1621}," ms-vscode.vscode-speech\n",[302,11538,11539,11540,1207],{},"Or install from the ",[335,11541,11544],{"href":11542,"rel":11543},"https:\u002F\u002Fmarketplace.visualstudio.com\u002Fitems?itemName=ms-vscode.vscode-speech",[461],"VS Code Marketplace",[318,11546,11548],{"id":11547},"background","Background",[302,11550,11551],{},"As part of using more AI tooling while writing and editing code, I am looking to use voice-to-text. I used to use it to write my papers in college using Dragon NaturallySpeaking, but it was a pain to set up and use.",[302,11553,11554],{},"While I don't like the idea of only \"vibe coding,\" I do like voice as a faster medium to get my thoughts out and refine them afterwards.",[302,11556,11557],{},"I am looking to use this in conjunction with the AI tools I have been using to help me write and edit code.",[318,11559,11561],{"id":11560},"keyboard-shortcuts","Keyboard Shortcuts",[302,11563,11564],{},"I'm on Linux while writing this, so the shortcuts may be different on Mac or Windows.",[302,11566,11567],{},[467,11568],{"alt":515,"src":11569},"\u002Fimages\u002Fblog\u002Fvs-code-text-to-speech-keyboard-shortcuts.png",[302,11571,11572],{},"There are two input modes:",[368,11574,11575,11590],{},[371,11576,11577,5709,11580,11583,11584,11586,11587,11589],{},[326,11578,11579],{},"Copilot Command",[745,11581,11582],{},"Ctrl+i"," opens the Copilot command palette, then press ",[745,11585,11582],{}," again to start recording. Hitting ",[745,11588,11582],{}," again stops the recording.",[371,11591,11592,5709,11594,11597],{},[326,11593,724],{},[745,11595,11596],{},"Ctrl+Alt+V"," opens the microphone for long-term dictation recording. Hit Escape to stop. This is where I'm not giving Copilot commands, but just recording what I say as text on the page.",[302,11599,11600],{},"This is a great way to get my thoughts out and then refine them afterwards. I can also use this to write blog posts, which is what I'm doing now. I can also use this to write code, but I find it easier to just use the Copilot command.",[1698,11602,11603],{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":515,"searchDepth":516,"depth":516,"links":11605},[11606,11607,11608],{"id":11218,"depth":516,"text":11219},{"id":11547,"depth":516,"text":11548},{"id":11560,"depth":516,"text":11561},"2025-06-22","Exploring voice-to-text development workflows with VS Code Speech extension",{"src":11612,"alt":11613},"\u002Fimages\u002Fblog\u002Fvoice-to-text.jpeg","A cinematic professional photograph showing a developer at a modern workstation, speaking into a high-quality microphone while code appears on multiple monitors in real-time as sound waves transform into visible text. The scene features warm golden light illuminating the speaker contrasted with cool blue screen glow, creating a contemplative mood about the evolution from traditional typing to voice-driven development workflows.\"",{},{"title":65,"description":11610},"8POmmeBIdZf7GtN2wewrB5P-9cKl99yEf_BST-Pvh98",{"id":11618,"title":61,"authors":11619,"badge":11622,"body":11623,"date":12213,"description":12214,"extension":533,"image":12215,"meta":12218,"navigation":538,"path":62,"seo":12219,"status":540,"stem":63,"__hash__":12220},"posts\u002F2.blog\u002F20250612.software-engineering-and-itil-best-practices.md",[11620],{"name":292,"to":293,"avatar":11621},{"src":295},{"label":1732},{"type":299,"value":11624,"toc":12186},[11625,11629,11632,11636,11643,11669,11676,11702,11709,11735,11739,11743,11748,11762,11767,11779,11784,11796,11801,11813,11817,11829,11834,11846,11851,11863,11868,11880,11884,11888,11900,11905,11917,11922,11934,11938,11950,11954,11966,11971,11983,11988,12000,12004,12008,12019,12023,12037,12041,12055,12059,12064,12072,12077,12085,12090,12098,12102,12106,12117,12121,12132,12136,12147,12149,12152,12178,12181],[318,11626,11628],{"id":11627},"why-this-matters-to-you","Why This Matters to YOU",[302,11630,11631],{},"Following software development best practices and ITIL patterns isn't just about pleasing managers or checking a box. These practices are designed to make your work life significantly better, reduce stress, and help you deliver faster while increasing quality.",[318,11633,11635],{"id":11634},"the-personal-benefits","The Personal Benefits",[401,11637,11639,11640],{"id":11638},"go-faster-not-harder","🚀 ",[326,11641,11642],{},"Go Faster, Not Harder",[368,11644,11645,11651,11657,11663],{},[371,11646,11647,11650],{},[326,11648,11649],{},"Automated Testing",": Catch bugs early instead of spending weekends debugging production issues",[371,11652,11653,11656],{},[326,11654,11655],{},"CI\u002FCD Pipelines",": Deploy confidently without manual, error-prone processes",[371,11658,11659,11662],{},[326,11660,11661],{},"Infrastructure as Code",": Recreate environments in minutes, not hours",[371,11664,11665,11668],{},[326,11666,11667],{},"Version Control",": Never lose work again or struggle to understand what changed",[401,11670,11672,11673],{"id":11671},"reduce-stress-improve-sleep","😌 ",[326,11674,11675],{},"Reduce Stress & Improve Sleep",[368,11677,11678,11684,11690,11696],{},[371,11679,11680,11683],{},[326,11681,11682],{},"Monitoring & Alerting",": Know about problems before users complain",[371,11685,11686,11689],{},[326,11687,11688],{},"Documentation",": Stop being the single point of failure for critical knowledge",[371,11691,11692,11695],{},[326,11693,11694],{},"Standardized Processes",": Reduce decision fatigue with clear procedures",[371,11697,11698,11701],{},[326,11699,11700],{},"Incident Management",": Handle emergencies systematically instead of chaotically",[401,11703,11705,11706],{"id":11704},"better-work-life-balance","🏠 ",[326,11707,11708],{},"Better Work-Life Balance",[368,11710,11711,11717,11723,11729],{},[371,11712,11713,11716],{},[326,11714,11715],{},"Proper Change Management",": Fewer emergency deployments during personal time",[371,11718,11719,11722],{},[326,11720,11721],{},"Service Level Management",": Set realistic expectations and stick to them",[371,11724,11725,11728],{},[326,11726,11727],{},"Capacity Planning",": Avoid burnout from constant firefighting",[371,11730,11731,11734],{},[326,11732,11733],{},"Knowledge Management",": Take vacations without worrying about critical systems",[318,11736,11738],{"id":11737},"key-practices-that-transform-your-daily-experience","Key Practices That Transform Your Daily Experience",[401,11740,11742],{"id":11741},"development-practices","Development Practices",[302,11744,11745],{},[326,11746,11747],{},"Code Reviews",[368,11749,11750,11756],{},[371,11751,11752,11755],{},[920,11753,11754],{},"What it is",": Peer review of code changes before merging",[371,11757,11758,11761],{},[920,11759,11760],{},"Personal benefit",": Learn continuously, share knowledge burden, catch issues before they become your problem",[302,11763,11764],{},[326,11765,11766],{},"Test-Driven Development (TDD)",[368,11768,11769,11774],{},[371,11770,11771,11773],{},[920,11772,11754],{},": Write tests before writing code",[371,11775,11776,11778],{},[920,11777,11760],{},": Higher confidence in changes, fewer late-night bug fixes, clearer requirements",[302,11780,11781],{},[326,11782,11783],{},"Continuous Integration",[368,11785,11786,11791],{},[371,11787,11788,11790],{},[920,11789,11754],{},": Automatic building and testing of code changes",[371,11792,11793,11795],{},[920,11794,11760],{},": Immediate feedback, no more \"it works on my machine\" scenarios",[302,11797,11798],{},[326,11799,11800],{},"Continuous Deployment",[368,11802,11803,11808],{},[371,11804,11805,11807],{},[920,11806,11754],{},": Automated deployment of tested code changes to production",[371,11809,11810,11812],{},[920,11811,11760],{},": Reduce deployment stress, faster feedback from users, smaller change sets mean easier rollbacks",[302,11814,11815],{},[326,11816,11661],{},[368,11818,11819,11824],{},[371,11820,11821,11823],{},[920,11822,11754],{},": Managing infrastructure through code and version control",[371,11825,11826,11828],{},[920,11827,11760],{},": Reproducible environments, no more \"snowflake\" servers, easier disaster recovery",[302,11830,11831],{},[326,11832,11833],{},"Continuous Learning & Training",[368,11835,11836,11841],{},[371,11837,11838,11840],{},[920,11839,11754],{},": Regular skill development and knowledge sharing sessions",[371,11842,11843,11845],{},[920,11844,11760],{},": Stay current with technology, reduce imposter syndrome, career advancement opportunities",[302,11847,11848],{},[326,11849,11850],{},"Pair Programming",[368,11852,11853,11858],{},[371,11854,11855,11857],{},[920,11856,11754],{},": Two developers working together on the same code",[371,11859,11860,11862],{},[920,11861,11760],{},": Faster learning, fewer bugs, shared knowledge, less isolation",[302,11864,11865],{},[326,11866,11867],{},"Documentation as Code",[368,11869,11870,11875],{},[371,11871,11872,11874],{},[920,11873,11754],{},": Treating documentation with the same rigor as code (version control, reviews, automation)",[371,11876,11877,11879],{},[920,11878,11760],{},": Always up-to-date docs, no more outdated wikis, searchable knowledge base",[401,11881,11883],{"id":11882},"itil-service-management","ITIL Service Management",[302,11885,11886],{},[326,11887,11700],{},[368,11889,11890,11895],{},[371,11891,11892,11894],{},[920,11893,11754],{},": Structured approach to handling service disruptions",[371,11896,11897,11899],{},[920,11898,11760],{},": Clear escalation paths, defined roles, no more guessing who should fix what",[302,11901,11902],{},[326,11903,11904],{},"Change Management",[368,11906,11907,11912],{},[371,11908,11909,11911],{},[920,11910,11754],{},": Controlled process for making changes to systems",[371,11913,11914,11916],{},[920,11915,11760],{},": Reduced risk of breaking things, proper planning prevents poor performance",[302,11918,11919],{},[326,11920,11921],{},"Problem Management",[368,11923,11924,11929],{},[371,11925,11926,11928],{},[920,11927,11754],{},": Root cause analysis to prevent recurring issues",[371,11930,11931,11933],{},[920,11932,11760],{},": Fix things once instead of repeatedly patching symptoms",[302,11935,11936],{},[326,11937,11721],{},[368,11939,11940,11945],{},[371,11941,11942,11944],{},[920,11943,11754],{},": Defining and measuring service quality commitments",[371,11946,11947,11949],{},[920,11948,11760],{},": Realistic expectations, objective success criteria, protection from unreasonable demands",[302,11951,11952],{},[326,11953,11733],{},[368,11955,11956,11961],{},[371,11957,11958,11960],{},[920,11959,11754],{},": Systematic capture, organization, and sharing of organizational knowledge",[371,11962,11963,11965],{},[920,11964,11760],{},": No more being the only person who knows how something works, easier onboarding, vacation without guilt",[302,11967,11968],{},[326,11969,11970],{},"Service Desk",[368,11972,11973,11978],{},[371,11974,11975,11977],{},[920,11976,11754],{},": Single point of contact for user issues and requests",[371,11979,11980,11982],{},[920,11981,11760],{},": Structured support process, proper issue tracking, less interruption from random requests",[302,11984,11985],{},[326,11986,11987],{},"Capacity Management",[368,11989,11990,11995],{},[371,11991,11992,11994],{},[920,11993,11754],{},": Ensuring adequate resources to meet service demands",[371,11996,11997,11999],{},[920,11998,11760],{},": Prevents overcommitment, realistic planning, sustainable workload",[318,12001,12003],{"id":12002},"the-compound-effect-how-small-changes-create-big-results","The Compound Effect: How Small Changes Create Big Results",[401,12005,12007],{"id":12006},"week-1-2-initial-setup-investment","Week 1-2: Initial Setup Investment",[368,12009,12010,12013,12016],{},[371,12011,12012],{},"Setting up automated tests and CI\u002FCD",[371,12014,12015],{},"Creating documentation templates",[371,12017,12018],{},"Establishing code review processes",[401,12020,12022],{"id":12021},"month-1-3-early-returns","Month 1-3: Early Returns",[368,12024,12025,12028,12031,12034],{},[371,12026,12027],{},"Fewer production bugs",[371,12029,12030],{},"Faster deployment cycles",[371,12032,12033],{},"More confident releases",[371,12035,12036],{},"Better team communication",[401,12038,12040],{"id":12039},"month-6-transformation","Month 6+: Transformation",[368,12042,12043,12046,12049,12052],{},[371,12044,12045],{},"Predictable delivery schedules",[371,12047,12048],{},"Proactive problem prevention",[371,12050,12051],{},"Knowledge sharing becomes natural",[371,12053,12054],{},"Emergency work becomes rare",[318,12056,12058],{"id":12057},"common-objections-and-why-theyre-wrong","Common Objections (And Why They're Wrong)",[302,12060,12061],{},[326,12062,12063],{},"\"This slows us down initially\"",[368,12065,12066,12069],{},[371,12067,12068],{},"Truth: 2 weeks of setup saves months of firefighting",[371,12070,12071],{},"Better to be slow and steady than constantly starting over",[302,12073,12074],{},[326,12075,12076],{},"\"We don't have time for documentation\"",[368,12078,12079,12082],{},[371,12080,12081],{},"Truth: You don't have time NOT to document",[371,12083,12084],{},"Every hour spent documenting saves 10 hours of future confusion",[302,12086,12087],{},[326,12088,12089],{},"\"Our situation is unique\"",[368,12091,12092,12095],{},[371,12093,12094],{},"Truth: Every team thinks they're special",[371,12096,12097],{},"These practices exist because they work across industries and contexts",[318,12099,12101],{"id":12100},"getting-started-your-first-steps","Getting Started: Your First Steps",[401,12103,12105],{"id":12104},"this-week","This Week",[851,12107,12108,12111,12114],{},[371,12109,12110],{},"Start doing code reviews for all changes",[371,12112,12113],{},"Write one test for your next feature",[371,12115,12116],{},"Document one process that only you know",[401,12118,12120],{"id":12119},"this-month","This Month",[851,12122,12123,12126,12129],{},[371,12124,12125],{},"Set up basic CI\u002FCD pipeline",[371,12127,12128],{},"Implement incident response template",[371,12130,12131],{},"Create service level agreements for your key services",[401,12133,12135],{"id":12134},"this-quarter","This Quarter",[851,12137,12138,12141,12144],{},[371,12139,12140],{},"Establish regular retrospectives",[371,12142,12143],{},"Implement proper change management",[371,12145,12146],{},"Set up monitoring and alerting",[318,12148,7284],{"id":7283},[302,12150,12151],{},"Software development best practices and ITIL aren't bureaucracy—they're your ticket to:",[368,12153,12154,12160,12166,12172],{},[371,12155,12156,12159],{},[326,12157,12158],{},"Leaving work at work"," instead of constant fire-fighting",[371,12161,12162,12165],{},[326,12163,12164],{},"Building confidence"," in your systems and processes",[371,12167,12168,12171],{},[326,12169,12170],{},"Growing your skills"," through structured learning and knowledge sharing",[371,12173,12174,12177],{},[326,12175,12176],{},"Delivering value"," consistently without burning out",[302,12179,12180],{},"Remember: These practices were created by developers and IT professionals who got tired of working nights and weekends. They're not theoretical concepts—they're battle-tested solutions to the problems you and I face every day.",[302,12182,12183],{},[920,12184,12185],{},"Start small and be consistent",{"title":515,"searchDepth":516,"depth":516,"links":12187},[12188,12189,12197,12201,12206,12207,12212],{"id":11627,"depth":516,"text":11628},{"id":11634,"depth":516,"text":11635,"children":12190},[12191,12193,12195],{"id":11638,"depth":523,"text":12192},"🚀 Go Faster, Not Harder",{"id":11671,"depth":523,"text":12194},"😌 Reduce Stress & Improve Sleep",{"id":11704,"depth":523,"text":12196},"🏠 Better Work-Life Balance",{"id":11737,"depth":516,"text":11738,"children":12198},[12199,12200],{"id":11741,"depth":523,"text":11742},{"id":11882,"depth":523,"text":11883},{"id":12002,"depth":516,"text":12003,"children":12202},[12203,12204,12205],{"id":12006,"depth":523,"text":12007},{"id":12021,"depth":523,"text":12022},{"id":12039,"depth":523,"text":12040},{"id":12057,"depth":516,"text":12058},{"id":12100,"depth":516,"text":12101,"children":12208},[12209,12210,12211],{"id":12104,"depth":523,"text":12105},{"id":12119,"depth":523,"text":12120},{"id":12134,"depth":523,"text":12135},{"id":7283,"depth":516,"text":7284},"2025-06-12","Your Path to Better Work-Life Balance",{"src":12216,"alt":12217},"\u002Fimages\u002Fblog\u002Fsoftware-engineering-best-practices.png","software engineering best practices and ITIL for a better work-life balance",{},{"title":61,"description":12214},"6-u8G4rybspgtXeyzDoVdygEpFgUakHrXWyI4Qo_aw8",{"id":12222,"title":53,"authors":12223,"badge":12226,"body":12227,"date":12306,"description":12307,"extension":533,"image":12308,"meta":12311,"navigation":538,"path":54,"seo":12312,"status":540,"stem":55,"__hash__":12313},"posts\u002F2.blog\u002F20250607.my-best-practicies.md",[12224],{"name":292,"to":293,"avatar":12225},{"src":295},{"label":1732},{"type":299,"value":12228,"toc":12303},[12229,12233,12236,12239,12271,12276],[8293,12230,12232],{"id":12231},"best-practices","Best Practices",[302,12234,12235],{},"I want to thank Mitch at work for helping me. During a recent Time-To-Think (TTT) session at work, he asked if I had a best practices document that I could share. He may have been joking as I can go on a personal rant as well as anyone, but that idea stuck in my head. After a few talks with my wife and then my brother Patrick, I decided to create a public CLI tool and open source it this weekend. I'll try to document some of the best practices that I have learned along the game of life.",[318,12237,12232],{"id":12238},"best-practices-1",[368,12240,12241,12249,12257,12260,12263],{},[371,12242,12243,12244],{},"Embrace AI - I'm the Principal Architect on the Cloud AI services team at GE Aerospace and I don't use AI enough. I use autocomplete and ChatGPT to help me write better code of course, but I don't use it to help me plan enough. I started this repo after a few revision planning questions where when I considered the why behind the idea, the root cause was I didn't tell the LLM what I wanted. I instead described how I wanted it to work. Big difference. I should have said \"I want to create a public CLI tool and open source it this weekend\" not \"I want to create a repo for CLI tool. Use uv and tests\". The first one gives the LLM more freedom to help me plan out the project. The second one boxes it in and limits its ability to help me.",[368,12245,12246],{},[371,12247,12248],{},"Use the audio recording - I have found that recording myself talking through the problem helps me clarify my thoughts. I use the audio recorder on my phone and then play it back. I then use the recording to help me write better code.",[371,12250,12251,12252],{},"Use VS Code - Whether it's a derivative of VS Code or not, it's just simply the best platform currently.",[330,12253,12254],{},[302,12255,12256],{},"I'm actively worried I didn't vibe code sooner because I'm 42 and my age bias is showing. I should have been using it for years.",[371,12258,12259],{},"Write tests - I have found that writing tests helps me write better code. I use pytest for Python testing and Vitest for TypeScript testing.",[371,12261,12262],{},"Use voice to text - The more context you can give the LLM, the better. I use voice to text to help me write longer prompts, which provides more context and helps the LLM understand my intent better.",[371,12264,12265,12266,12270],{},"Read Joel Spolsky's blog post - ",[335,12267,12268],{"href":12268,"rel":12269},"https:\u002F\u002Fwww.joelonsoftware.com\u002F2000\u002F08\u002F09\u002Fthe-joel-test-12-steps-to-better-code\u002F",[461]," - I highly recommend checking out his blog for practical advice and inspiration.",[330,12272,12273],{},[302,12274,12275],{},"If you don't know who Joel Spolsky is, he is the co-founder of Stack Overflow and Trello.",[368,12277,12278,12281,12289,12292,12295],{},[371,12279,12280],{},"Use a clipboard manager - I use a clipboard manager to help me keep track of my clipboard history. The ability to search my clipboard history has been a game changer for me. It's called CopyQ and it's free.",[371,12282,12283,12284,12288],{},"Keep a private GitHub repo - I use a private GitHub repo to help me keep track of ",[335,12285,12287],{"href":7829,"rel":12286},[461],"dot files"," and other configuration files or tooling.",[371,12290,12291],{},"Use a password manager - I use a password manager to help me keep track of my passwords. I use Bitwarden and it's free.",[371,12293,12294],{},"Use a todo list - I use a todo list to help me keep track of my tasks both personal and professional. I use Todoist and it's free.",[371,12296,12297,12298],{},"Take notes\n",[368,12299,12300],{},[371,12301,12302],{},"Action items - I use a note-taking app to help me keep track of my notes. I use Notion and it's free for personal use.",{"title":515,"searchDepth":516,"depth":516,"links":12304},[12305],{"id":12238,"depth":516,"text":12232},"2025-06-07","Writing down where I'm at with my best practices in software development and AI development",{"src":12309,"alt":12310},"\u002Fimages\u002Fblog\u002Fbest-practices-2025-06-07.png","Screenshot of senior developer at desk and computer writing a document of best practices",{},{"title":53,"description":12307},"tHx87vMzwzObkpw9gpBAXlstG6oLup-Pf-Lwjr10s_k",{"id":12315,"title":57,"authors":12316,"badge":12319,"body":12320,"date":12306,"description":12461,"extension":533,"image":12462,"meta":12465,"navigation":538,"path":58,"seo":12466,"status":540,"stem":59,"__hash__":12467},"posts\u002F2.blog\u002F20250607.towles-tool.md",[12317],{"name":292,"to":293,"avatar":12318},{"src":295},{"label":1732},{"type":299,"value":12321,"toc":12455},[12322,12328,12332,12335,12390,12394,12397,12411,12415,12418,12440,12444,12447,12452],[302,12323,12324,12325,12327],{},"Starting this post as the kick off of again re-creating ",[745,12326,462],{},", my public best practices or DIY repo. I've had private repos for years with my alias or helper scripts and notes but never made them public. After a few conversations with my brother Patrick and my wife, I decided to make this one public.",[318,12329,12331],{"id":12330},"why-python","Why Python?",[302,12333,12334],{},"I wanted to use Python instead of Typescript for this project for a few reasons:",[368,12336,12337,12369,12384,12387],{},[371,12338,12339,12340,1199,12345,1199,12350,1258,12355,12360,12361],{},"At work, I am the Principal Architect on the Cloud AI services team at GE Aerospace and we use Python for most of our AI\u002FML work. And while I'm a super fan of TypeScript and ",[335,12341,12344],{"href":12342,"rel":12343},"https:\u002F\u002Fantfu.me\u002F",[461],"Anthony Fu",[335,12346,12349],{"href":12347,"rel":12348},"https:\u002F\u002Froe.dev\u002F",[461],"Daniel Roe",[335,12351,12354],{"href":12352,"rel":12353},"https:\u002F\u002Fevanyou.me\u002F",[461],"Evan You",[335,12356,12359],{"href":12357,"rel":12358},"https:\u002F\u002Fboshen.dev\u002F",[461],"Boshen"," have done an amazing job with the ecosystem, Python has a few advantages for AI\u002FML work:\n",[368,12362,12363,12366],{},[371,12364,12365],{},"More popular in the AI\u002FML community - Python is the most popular language for AI\u002FML and has a large community of developers and researchers.",[371,12367,12368],{},"Better support for scientific computing - Python has a number of libraries for scientific computing that are not available in other languages.",[371,12370,12371,12375,12376],{},[335,12372,11225],{"href":12373,"rel":12374},"https:\u002F\u002Fdocs.astral.sh\u002Fuv\u002F",[461]," An extremely fast Python package and project manager, written in Rust.\n",[368,12377,12378,12381],{},[371,12379,12380],{},"It's like Poetry but faster. It has a number of features that make it a great choice for managing Python projects.",[371,12382,12383],{},"Previously, I tried Poetry and pyenv virtualenv, but uv is way easier to use and faster.",[371,12385,12386],{},"The number of peers that have Python as their primary language means getting them to install Node and npm is a barrier to entry.",[371,12388,12389],{},"While I should likely use Rust like my brother Patrick would prefer, Python still has the edge when it comes to AI\u002FML work.",[318,12391,12393],{"id":12392},"why-a-cli-tool","Why a CLI tool?",[302,12395,12396],{},"I wanted to create a CLI tool for a few reasons:",[368,12398,12399,12402,12405,12408],{},[371,12400,12401],{},"I use the command line a lot and wanted to create a tool that would make my life easier.",[371,12403,12404],{},"I already have a number of alias and helper scripts that I use on a regular basis, but in TypeScript or Bash.",[371,12406,12407],{},"I already use Python for a number of tasks.",[371,12409,12410],{},"I'll find an fzf or fzf equivalent for Python CLI lists like I'm used to in my TypeScript CLI tools.",[318,12412,12414],{"id":12413},"first-steps","First Steps",[302,12416,12417],{},"After pushing this repo the first steps are the following:",[368,12419,12420,12423,12426,12429,12432,12435,12438],{},[371,12421,12422],{},"create github issues",[371,12424,12425],{},"create pypi project",[371,12427,12428],{},"publish first version",[371,12430,12431],{},"setup github actions for ci\u002Fcd",[371,12433,12434],{},"test and document usage",[371,12436,12437],{},"create version cli commands",[371,12439,12428],{},[318,12441,12443],{"id":12442},"release","Release",[302,12445,12446],{},"The repo is now public:",[302,12448,12449],{},[335,12450,459],{"href":459,"rel":12451},[461],[302,12453,12454],{},"Excited to get started on this journey and share my best practices with the world. Stay tuned for more updates!",{"title":515,"searchDepth":516,"depth":516,"links":12456},[12457,12458,12459,12460],{"id":12330,"depth":516,"text":12331},{"id":12392,"depth":516,"text":12393},{"id":12413,"depth":516,"text":12414},{"id":12442,"depth":516,"text":12443},"Info about creating my own CLI tool and best practices",{"src":12463,"alt":12464},"\u002Fimages\u002Fblog\u002Fdesk-with-tool-of-universe-open-at-desk.png","Screenshot of VS Code configured for prompt engineering at a desk",{},{"title":57,"description":12461},"Rv8JLryg4MFq5GITHOw7ggZWp5cA_cZIHA94cCUZrBM",{"id":12469,"title":49,"authors":12470,"badge":12473,"body":12474,"date":12814,"description":12815,"extension":533,"image":12816,"meta":12819,"navigation":538,"path":50,"seo":12820,"status":540,"stem":51,"__hash__":12821},"posts\u002F2.blog\u002F20250528.adding-prompts-to-vscode.md",[12471],{"name":292,"to":293,"avatar":12472},{"src":295},{"label":1732},{"type":299,"value":12475,"toc":12802},[12476,12479,12482,12486,12489,12492,12495,12498,12502,12505,12508,12511,12514,12518,12521,12525,12528,12627,12631,12634,12644,12650,12718,12722,12725,12731,12734,12738,12741,12755,12759,12762,12782,12784,12787,12790,12793,12796,12799],[302,12477,12478],{},"Right, let's have a chat about something that's been driving me absolutely mental: watching developers fumble about with AI prompts like they're trying to communicate with aliens using interpretive dance.",[302,12480,12481],{},"You know the drill. You fire up GitHub Copilot or Claude in VS Code, type \"make this better\" and then wonder why the AI responds with the digital equivalent of a confused shrug. It's like asking your GPS for \"somewhere nice\" and then acting surprised when it takes you to a Walmart parking lot.",[318,12483,12485],{"id":12484},"the-problem-were-all-winging-it","The Problem: We're All Winging It",[302,12487,12488],{},"Here's the thing that nobody wants to admit: most of us are absolutely rubbish at prompting AI tools. We treat them like magic boxes that should somehow divine our intentions from the most vague possible instructions.",[302,12490,12491],{},"I've watched brilliant developers - people who can architect distributed systems in their sleep - completely lose their minds when it comes to writing a decent prompt. They'll spend ages crafting the perfect UI interface but then ask an AI to \"fix my code\" without any context whatsoever.",[302,12493,12494],{},"The result? You get back suggestions that are about as useful as you'd expect from someone who has never seen your codebase. The AI doesn't know your codebase, your conventions, or what you're actually trying to achieve. It's like hiring a consultant and then refusing to tell them what your company does.",[302,12496,12497],{},"And here's the kicker: everyone knows this is a problem, but we keep doing it anyway. Because admitting that you need to learn how to talk to a computer feels a bit embarrassing, doesn't it?",[318,12499,12501],{"id":12500},"why-this-keeps-happening","Why This Keeps Happening",[302,12503,12504],{},"The root cause is simple: we've been conditioned to think that AI should \"just work\" without any effort on our part. The marketing departments have done such a good job convincing us that these tools are magical that we've forgotten they're just very sophisticated autocomplete systems.",[302,12506,12507],{},"AI tools are brilliant, but they're not mind readers. They need context, structure, and clear instructions - just like any other tool in your development arsenal. You wouldn't use a database without understanding SQL, so why would you use AI without understanding how to prompt it properly?",[302,12509,12510],{},"The other issue is that most developers treat prompting as an afterthought. We spend hours setting up our development environment, configuring our editor, and organizing our code, but we can't be bothered to spend five minutes setting up proper prompts.",[302,12512,12513],{},"It's the equivalent of using a Ferrari as a shopping trolley - technically it works, but you're missing out on most of the benefits.",[318,12515,12517],{"id":12516},"how-to-actually-fix-this","How to Actually Fix This",[302,12519,12520],{},"Alright, enough moaning. Let's talk solutions. The good news is that VS Code has some absolutely brilliant features for prompt engineering that most people completely ignore.",[401,12522,12524],{"id":12523},"_1-create-prompt-files","1. Create Prompt Files",[302,12526,12527],{},"First things first: stop typing the same context over and over again. Create dedicated prompt files in your project:",[1119,12529,12531],{"className":9300,"code":12530,"language":9302,"meta":515,"style":515},"\u002F\u002F .vscode\u002Fprompts\u002Fcode-review.md\nYou are reviewing TypeScript code for a NuxtJS application.\n\nContext:\n\n- This is a personal blog built with Nuxt 3 and NuxtUI Pro\n- We use TypeScript with strict mode enabled\n- Code style: camelCase variables, PascalCase components, single quotes\n- We prefer composition API and async\u002Fawait\n\nWhen reviewing code, focus on:\n\n1. Type safety and proper TypeScript usage\n2. Performance implications\n3. Accessibility concerns\n4. Code readability and maintainability\n\nCurrent file context: [PASTE FILE CONTENT HERE]\n\nPlease review this code and suggest improvements.\n",[745,12532,12533,12538,12543,12547,12552,12556,12561,12566,12571,12576,12580,12585,12589,12594,12599,12604,12609,12613,12618,12622],{"__ignoreMap":515},[1127,12534,12535],{"class":1129,"line":1130},[1127,12536,12537],{},"\u002F\u002F .vscode\u002Fprompts\u002Fcode-review.md\n",[1127,12539,12540],{"class":1129,"line":516},[1127,12541,12542],{},"You are reviewing TypeScript code for a NuxtJS application.\n",[1127,12544,12545],{"class":1129,"line":523},[1127,12546,1517],{"emptyLinePlaceholder":538},[1127,12548,12549],{"class":1129,"line":1146},[1127,12550,12551],{},"Context:\n",[1127,12553,12554],{"class":1129,"line":1382},[1127,12555,1517],{"emptyLinePlaceholder":538},[1127,12557,12558],{"class":1129,"line":1388},[1127,12559,12560],{},"- This is a personal blog built with Nuxt 3 and NuxtUI Pro\n",[1127,12562,12563],{"class":1129,"line":1586},[1127,12564,12565],{},"- We use TypeScript with strict mode enabled\n",[1127,12567,12568],{"class":1129,"line":1599},[1127,12569,12570],{},"- Code style: camelCase variables, PascalCase components, single quotes\n",[1127,12572,12573],{"class":1129,"line":1647},[1127,12574,12575],{},"- We prefer composition API and async\u002Fawait\n",[1127,12577,12578],{"class":1129,"line":1910},[1127,12579,1517],{"emptyLinePlaceholder":538},[1127,12581,12582],{"class":1129,"line":1915},[1127,12583,12584],{},"When reviewing code, focus on:\n",[1127,12586,12587],{"class":1129,"line":1920},[1127,12588,1517],{"emptyLinePlaceholder":538},[1127,12590,12591],{"class":1129,"line":1926},[1127,12592,12593],{},"1. Type safety and proper TypeScript usage\n",[1127,12595,12596],{"class":1129,"line":1932},[1127,12597,12598],{},"2. Performance implications\n",[1127,12600,12601],{"class":1129,"line":1938},[1127,12602,12603],{},"3. Accessibility concerns\n",[1127,12605,12606],{"class":1129,"line":1944},[1127,12607,12608],{},"4. Code readability and maintainability\n",[1127,12610,12611],{"class":1129,"line":1949},[1127,12612,1517],{"emptyLinePlaceholder":538},[1127,12614,12615],{"class":1129,"line":1954},[1127,12616,12617],{},"Current file context: [PASTE FILE CONTENT HERE]\n",[1127,12619,12620],{"class":1129,"line":1960},[1127,12621,1517],{"emptyLinePlaceholder":538},[1127,12623,12624],{"class":1129,"line":1966},[1127,12625,12626],{},"Please review this code and suggest improvements.\n",[401,12628,12630],{"id":12629},"_2-use-vs-codes-built-in-prompt-features","2. Use VS Code's Built-in Prompt Features",[302,12632,12633],{},"VS Code has some amazing features that most people never discover:",[302,12635,12636,12639,12640,12643],{},[326,12637,12638],{},"Workspace Instructions",": Create a ",[745,12641,12642],{},".vscode\u002Fcopilot-instructions.md"," file (which you probably already have if you're reading this blog). This gives Copilot context about your entire project without you having to repeat yourself constantly.",[302,12645,12646,12649],{},[326,12647,12648],{},"Custom Commands",": Set up custom commands in your settings for common prompting tasks:",[1119,12651,12655],{"className":12652,"code":12653,"language":12654,"meta":515,"style":515},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"github.copilot.chat.welcomeMessage\": \"never\",\n  \"github.copilot.editor.enableAutoCompletions\": true,\n  \"github.copilot.chat.localeOverride\": \"en\"\n}\n","json",[745,12656,12657,12661,12682,12696,12714],{"__ignoreMap":515},[1127,12658,12659],{"class":1129,"line":1130},[1127,12660,1545],{"class":1501},[1127,12662,12663,12666,12669,12671,12673,12675,12678,12680],{"class":1129,"line":516},[1127,12664,12665],{"class":1501},"  \"",[1127,12667,12668],{"class":1493},"github.copilot.chat.welcomeMessage",[1127,12670,3736],{"class":1501},[1127,12672,1554],{"class":1501},[1127,12674,3750],{"class":1501},[1127,12676,12677],{"class":1621},"never",[1127,12679,3736],{"class":1501},[1127,12681,1570],{"class":1501},[1127,12683,12684,12686,12689,12691,12693],{"class":1129,"line":523},[1127,12685,12665],{"class":1501},[1127,12687,12688],{"class":1493},"github.copilot.editor.enableAutoCompletions",[1127,12690,3736],{"class":1501},[1127,12692,1554],{"class":1501},[1127,12694,12695],{"class":1501}," true,\n",[1127,12697,12698,12700,12703,12705,12707,12709,12712],{"class":1129,"line":1146},[1127,12699,12665],{"class":1501},[1127,12701,12702],{"class":1493},"github.copilot.chat.localeOverride",[1127,12704,3736],{"class":1501},[1127,12706,1554],{"class":1501},[1127,12708,3750],{"class":1501},[1127,12710,12711],{"class":1621},"en",[1127,12713,3756],{"class":1501},[1127,12715,12716],{"class":1129,"line":1382},[1127,12717,5978],{"class":1501},[401,12719,12721],{"id":12720},"_3-structure-your-prompts-like-code","3. Structure Your Prompts Like Code",[302,12723,12724],{},"Treat your prompts like any other code - they should be maintainable, reusable, and well-organized. Create a prompt library:",[1119,12726,12729],{"className":12727,"code":12728,"language":2028},[2026],".vscode\u002F\n├── prompts\u002F\n│   ├── code-review.md\n│   ├── bug-fix.md\n│   ├── refactor.md\n│   ├── test-generation.md\n│   └── documentation.md\n",[745,12730,12728],{"__ignoreMap":515},[302,12732,12733],{},"Each prompt should have a clear purpose and consistent structure. Think of them as functions - they should do one thing well.",[401,12735,12737],{"id":12736},"_4-use-progressive-context-building","4. Use Progressive Context Building",[302,12739,12740],{},"Instead of dumping everything into one massive prompt, build context progressively:",[851,12742,12743,12746,12749,12752],{},[371,12744,12745],{},"Start with the high-level context (project type, tech stack)",[371,12747,12748],{},"Add specific context (current file, related files)",[371,12750,12751],{},"State your specific request clearly",[371,12753,12754],{},"Provide examples of what good output looks like",[401,12756,12758],{"id":12757},"_5-leverage-vs-code-extensions","5. Leverage VS Code Extensions",[302,12760,12761],{},"There are some brilliant extensions that make prompt engineering much easier:",[368,12763,12764,12770,12776],{},[371,12765,12766,12769],{},[326,12767,12768],{},"Prompt Engineering Helper",": Provides templates and snippets for common prompts",[371,12771,12772,12775],{},[326,12773,12774],{},"AI Prompt Manager",": Lets you save and organize your favorite prompts",[371,12777,12778,12781],{},[326,12779,12780],{},"Context Manager",": Helps you include relevant file context automatically",[318,12783,7284],{"id":7283},[302,12785,12786],{},"Look, I get it. Setting up proper prompts feels like extra work when you just want to get stuff done. But here's the thing: spending a bit of time upfront to create good prompts will save you hours of frustration later.",[302,12788,12789],{},"Think of it like setting up your linting rules or configuring your build system - it's a one-time investment that pays dividends every single day.",[302,12791,12792],{},"And honestly? Once you start using AI tools properly, with good context and clear instructions, it's genuinely transformative. You'll wonder how you ever managed without them.",[302,12794,12795],{},"Just please, for the love of all that's holy, stop asking AI to \"make this better\" without any context. Your future self (and your colleagues) will thank you.",[302,12797,12798],{},"Now stop reading blog posts and go set up some proper prompts. Your productivity will thank you, and you might even enjoy working with AI tools instead of fighting them.",[1698,12800,12801],{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}",{"title":515,"searchDepth":516,"depth":516,"links":12803},[12804,12805,12806,12813],{"id":12484,"depth":516,"text":12485},{"id":12500,"depth":516,"text":12501},{"id":12516,"depth":516,"text":12517,"children":12807},[12808,12809,12810,12811,12812],{"id":12523,"depth":523,"text":12524},{"id":12629,"depth":523,"text":12630},{"id":12720,"depth":523,"text":12721},{"id":12736,"depth":523,"text":12737},{"id":12757,"depth":523,"text":12758},{"id":7283,"depth":516,"text":7284},"2025-05-28","Stop fumbling around with AI prompts and start engineering them like the professional you pretend to be",{"src":12817,"alt":12818},"\u002Fimages\u002Fblog\u002F20250528-2154-adding-prompts-to-vscode.png","A developer's dual monitor setup at night showing VS Code on the main screen with a well-organized `.vscode\u002Fprompts` folder structure open in the sidebar, glowing code snippets and markdown prompt files visible, a second monitor displaying an AI chat interface with contextual responses. Dramatic desk lamp illumination from the left creates warm pools of light on the mechanical keyboard and coffee mug, while cool blue monitor glow illuminates the developer's face in contemplation, shallow depth of field with focus on the organized prompt files. Cinematic realism with high contrast between warm practical lighting and cool screen glow, professional workspace photography, 8k quality, teal and orange color grading, rule of thirds composition with negative space on the right for text overlay.",{},{"title":49,"description":12815},"2NzUN53kV6dP_n1DVciOLvUMbDGAcurpnvB470snnMU",{"id":12823,"title":45,"authors":12824,"badge":12827,"body":12829,"date":12973,"description":12974,"extension":533,"image":12975,"meta":12978,"navigation":538,"path":46,"seo":12979,"status":540,"stem":47,"__hash__":12980},"posts\u002F2.blog\u002F20250509.two-weeks-with-cloudflare-aI-and-tools.md",[12825],{"name":292,"to":293,"avatar":12826},{"src":295},{"label":12828},"Cloudflare AI",{"type":299,"value":12830,"toc":12965},[12831,12835,12838,12842,12845,12849,12869,12872,12876,12883,12894,12911,12918,12921,12925,12928,12931,12935,12952,12956,12959,12962],[8293,12832,12834],{"id":12833},"two-weeks-with-cloudflare-ai-and-tools-my-odyssey-and-why-i-switched-to-aws-bedrock","Two Weeks with Cloudflare AI and Tools: My Odyssey (and Why I Switched to AWS Bedrock)",[302,12836,12837],{},"Let me set the scene: It’s late at night, my family’s asleep, and I’m working on a personal project, staring at yet another Cloudflare AI doc. For two weeks, I’ve been on a mission—get Cloudflare’s AI to use tools for my project. I’m a developer, so I’m stubborn. But even stubbornness has its limits.",[318,12839,12841],{"id":12840},"week-1-start-the-optimism-phase","Week 1 Start: The Optimism Phase",[302,12843,12844],{},"I started out like every developer does: full of hope, docs open in one tab, terminal in the other. Cloudflare’s pitch is strong—serverless, scalable, and AI at the edge. What could go wrong? I already have a Nuxt blog, which I just added AI chat to using the new Nuxt UI Pro. I thought, “This is going to be a breeze.” I mean, how hard could it be to get AI tools working with Cloudflare?",[318,12846,12848],{"id":12847},"week-2-start-the-debugging-spiral","Week 2 Start: The Debugging Spiral",[302,12850,12851,12852,12857,12858,12857,12863,12868],{},"By week two, I was deep in the weeds. I tried every example, every forum post, every Stack Overflow answer that even mentioned Cloudflare AI. I've been using ",[335,12853,12856],{"href":12854,"rel":12855},"https:\u002F\u002Fai-sdk.dev\u002F",[461],"ai-sdk"," + ",[335,12859,12862],{"href":12860,"rel":12861},"https:\u002F\u002Fhub.nuxt.com\u002F",[461],"NuxtHub",[335,12864,12867],{"href":12865,"rel":12866},"https:\u002F\u002Fdevelopers.cloudflare.com\u002Fai-gateway\u002F",[461],"Cloudflare AI Gateway",", and I even cloned down all their repos trying to debug it.",[302,12870,12871],{},"I've built AI tools with LangChain and Python at work, but wanted to keep to TypeScript for my site.",[318,12873,12875],{"id":12874},"week-2-end-acceptance-and-a-little-bit-of-rage","Week 2 End: Acceptance (and a Little Bit of Rage)",[302,12877,12878,12879,12882],{},"By the end of week two, I was a bit broken. I had made almost no progress on getting tools to work, but found tons of ways they didn’t. And let’s be clear: my ",[745,12880,12881],{},"tool"," was just calling a function to generate a random temperature. I couldn’t even get that to work. I was getting errors like:",[1119,12884,12888],{"className":12885,"code":12886,"language":12887,"meta":515,"style":515},"language-plaintext shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","NoSuchToolError [AI_NoSuchToolError]: Model tried to call unavailable tool 'undefined'. Available tools: getWeatherInformation.\n","plaintext",[745,12889,12890],{"__ignoreMap":515},[1127,12891,12892],{"class":1129,"line":1130},[1127,12893,12886],{},[302,12895,12896,12897,12900,12901,12906,12907,12910],{},"I tried different models, different configurations, and even adding unit tests, but the way Cloudflare injects its remote ",[745,12898,12899],{},"env.AI"," is really odd. During this time I saw this post by ",[335,12902,12905],{"href":12903,"rel":12904},"https:\u002F\u002Fx.com\u002F_pi0_\u002Fstatus\u002F1919336943680168375",[461],"Pooya Parsa"," which summed up my feelings perfectly. The injection of the ",[745,12908,12909],{},"env"," is a nightmare to write tests for. Go find an example on how—I'll wait.",[302,12912,12913,12914,12917],{},"The final blow was when I thought I had it working. It was giving me a response, I was getting random temperature values, supposedly from the tool. After checking the messages, it turned out that ",[745,12915,12916],{},"@cf\u002Fmeta\u002Fllama-4-scout-17b-16e-instruct"," was hallucinating that it called a tool and just gave me a number...",[302,12919,12920],{},"I realized I was spending more time fighting the platform than building my product. That’s when it hit me: it’s okay to give up. Sometimes, the best move is to walk away.",[318,12922,12924],{"id":12923},"the-switch-to-aws","The Switch to AWS",[302,12926,12927],{},"At work, I use AWS all day, every day. I know it like the back of my hand. But I also like to try new things. I thought Cloudflare would be a good change of pace. But after two weeks of wrestling with their AI tools, I decided to go back to what I know best: AWS.",[302,12929,12930],{},"So for now, the goal was to swap the AI chat to use Bedrock instead of the Cloudflare AI tools. I'll likely keep hosting the site on Cloudflare, but I needed a reliable AI backend. I wanted to use the same tools I was already familiar with, and AWS was calling my name.",[318,12932,12934],{"id":12933},"what-i-learned","What I Learned",[368,12936,12937,12943,12946,12949],{},[371,12938,12939,12940,12942],{},"The issue wasn't really Cloudflare AI, but likely ",[745,12941,12856],{}," not supporting tools when Cloudflare was the provider. That would have been fine if I ever got an error message that made sense. But between fighting the Cloudflare Env remote environment, streaming responses, and not getting any errors that made sense, I was stuck.",[371,12944,12945],{},"Sometimes, persistence is overrated. Know when to cut your losses.",[371,12947,12948],{},"Good docs and community support are worth their weight in gold.",[371,12950,12951],{},"It’s okay to switch tools. Your project (and your sanity) will thank you.",[318,12953,12955],{"id":12954},"final-thoughts","Final Thoughts",[302,12957,12958],{},"If you're thinking about using Cloudflare AI tools, go in with your eyes open. Maybe you'll have better luck than I did. But if you find yourself two weeks in, still fighting the same bugs—don't be afraid to stop. Timebox your problem, and if you're not making progress, then pivot.",[302,12960,12961],{},"Happy coding, and may your AI tools always work on the first try (but let’s be real, they probably won’t).",[1698,12963,12964],{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":515,"searchDepth":516,"depth":516,"links":12966},[12967,12968,12969,12970,12971,12972],{"id":12840,"depth":516,"text":12841},{"id":12847,"depth":516,"text":12848},{"id":12874,"depth":516,"text":12875},{"id":12923,"depth":516,"text":12924},{"id":12933,"depth":516,"text":12934},{"id":12954,"depth":516,"text":12955},"2025-05-09","My Odyssey (and Why I Switched to AWS Bedrock)",{"src":12976,"alt":12977},"\u002Fimages\u002Fblog\u002Fdeveloper-with-head-in-hands-at-desk.png","the man is seated at his desk at his computer with his back to the camera head in his hands crying",{},{"title":45,"description":12974},"nOOfmstEtV3dCnksMnZT1Kb2sA8cw22Xv2j7r6KDjP8",{"id":12982,"title":41,"authors":12983,"badge":12986,"body":12987,"date":13302,"description":13303,"extension":533,"image":13304,"meta":13307,"navigation":538,"path":42,"seo":13308,"status":540,"stem":43,"__hash__":13309},"posts\u002F2.blog\u002F20250422.debugging local-packages-with-pnpm-link.md",[12984],{"name":292,"to":293,"avatar":12985},{"src":295},{"label":249},{"type":299,"value":12988,"toc":13295},[12989,12996,12999,13004,13008,13011,13025,13031,13038,13125,13133,13137,13202,13206,13221,13225,13228,13277,13281,13292],[8293,12990,12992,12993],{"id":12991},"debugging-local-packages-with-pnpm-link","Debugging Local Packages with ",[745,12994,12995],{},"pnpm link",[302,12997,12998],{},"If you’re tired of copy-pasting your local library into your app or publishing endless pre-release versions just to test a small change, there’s a better way.",[302,13000,13001,13003],{},[745,13002,12995],{}," lets you connect your local package to your app, so you can debug and test changes without extra hassle.",[318,13005,13007],{"id":13006},"meet-the-cast","Meet the Cast",[302,13009,13010],{},"Picture this:",[368,13012,13013,13019],{},[371,13014,13015,13018],{},[326,13016,13017],{},"cool-package\u002F",": An open-source package you're working to contribute to because you're trying to fix a bug.",[371,13020,13021,13024],{},[326,13022,13023],{},"my-app\u002F",": The app that uses that package.",[1119,13026,13029],{"className":13027,"code":13028,"language":2028},[2026],"cool-package\u002F\n├── src\u002F\n│   └── index.js\n└── package.json\n\nmy-app\u002F\n├── src\u002F\n│   └── main.js\n└── package.json\n",[745,13030,13028],{"__ignoreMap":515},[302,13032,13033,13034,13037],{},"Your ",[745,13035,13036],{},"my-app\u002Fpackage.json"," might look like this:",[1119,13039,13041],{"className":12652,"code":13040,"language":12654,"meta":515,"style":515},"{\n  \"name\": \"my-app\",\n  \"version\": \"1.0.0\",\n  \"dependencies\": {\n    \"@cool\u002Fpackage\": \"1.0.0\"\n  }\n}\n",[745,13042,13043,13047,13066,13086,13099,13117,13121],{"__ignoreMap":515},[1127,13044,13045],{"class":1129,"line":1130},[1127,13046,1545],{"class":1501},[1127,13048,13049,13051,13053,13055,13057,13059,13062,13064],{"class":1129,"line":516},[1127,13050,12665],{"class":1501},[1127,13052,1995],{"class":1493},[1127,13054,3736],{"class":1501},[1127,13056,1554],{"class":1501},[1127,13058,3750],{"class":1501},[1127,13060,13061],{"class":1621},"my-app",[1127,13063,3736],{"class":1501},[1127,13065,1570],{"class":1501},[1127,13067,13068,13070,13073,13075,13077,13079,13082,13084],{"class":1129,"line":523},[1127,13069,12665],{"class":1501},[1127,13071,13072],{"class":1493},"version",[1127,13074,3736],{"class":1501},[1127,13076,1554],{"class":1501},[1127,13078,3750],{"class":1501},[1127,13080,13081],{"class":1621},"1.0.0",[1127,13083,3736],{"class":1501},[1127,13085,1570],{"class":1501},[1127,13087,13088,13090,13093,13095,13097],{"class":1129,"line":1146},[1127,13089,12665],{"class":1501},[1127,13091,13092],{"class":1493},"dependencies",[1127,13094,3736],{"class":1501},[1127,13096,1554],{"class":1501},[1127,13098,5832],{"class":1501},[1127,13100,13101,13104,13107,13109,13111,13113,13115],{"class":1129,"line":1382},[1127,13102,13103],{"class":1501},"    \"",[1127,13105,13106],{"class":2246},"@cool\u002Fpackage",[1127,13108,3736],{"class":1501},[1127,13110,1554],{"class":1501},[1127,13112,3750],{"class":1501},[1127,13114,13081],{"class":1621},[1127,13116,3756],{"class":1501},[1127,13118,13119],{"class":1129,"line":1388},[1127,13120,5964],{"class":1501},[1127,13122,13123],{"class":1129,"line":1586},[1127,13124,5978],{"class":1501},[302,13126,13127,13128,13130,13131,1207],{},"But you want to test changes in ",[745,13129,13106],{}," without publishing it every time. Here’s how to use ",[745,13132,12995],{},[318,13134,13136],{"id":13135},"the-two-step-process","The Two-Step Process",[851,13138,13139,13170],{},[371,13140,13141,1554,13144],{},[326,13142,13143],{},"Link the package globally",[1119,13145,13149],{"className":13146,"code":13147,"language":13148,"meta":515,"style":515},"language-zsh shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","cd @cool\u002Fpackage\npnpm link --global\n","zsh",[745,13150,13151,13159],{"__ignoreMap":515},[1127,13152,13153,13156],{"class":1129,"line":1130},[1127,13154,13155],{"class":1505},"cd",[1127,13157,13158],{"class":1621}," @cool\u002Fpackage\n",[1127,13160,13161,13164,13167],{"class":1129,"line":516},[1127,13162,13163],{"class":2246},"pnpm",[1127,13165,13166],{"class":1621}," link",[1127,13168,13169],{"class":1621}," --global\n",[371,13171,13172,1554,13175,13198,13201],{},[326,13173,13174],{},"Link it into your app",[1119,13176,13178],{"className":13146,"code":13177,"language":13148,"meta":515,"style":515},"cd ..\u002Fmy-app\npnpm link --global @cool\u002Fpackage\n",[745,13179,13180,13187],{"__ignoreMap":515},[1127,13181,13182,13184],{"class":1129,"line":1130},[1127,13183,13155],{"class":1505},[1127,13185,13186],{"class":1621}," ..\u002Fmy-app\n",[1127,13188,13189,13191,13193,13196],{"class":1129,"line":516},[1127,13190,13163],{"class":2246},[1127,13192,13166],{"class":1621},[1127,13194,13195],{"class":1621}," --global",[1127,13197,13158],{"class":1621},[13199,13200],"br",{},"Now, your app uses your local version.",[318,13203,13205],{"id":13204},"debugging","Debugging",[368,13207,13208,13213,13218],{},[371,13209,13210,13211,1207],{},"Edit code in ",[745,13212,13106],{},[371,13214,13215,13216,1207],{},"Run or debug ",[745,13217,13061],{},[371,13219,13220],{},"If you need to build your library, run your build command.",[318,13222,13224],{"id":13223},"unlink-when-youre-done","Unlink When You’re Done",[302,13226,13227],{},"To go back to the registry version:",[851,13229,13230,13260],{},[371,13231,13232,13233,2328,13235],{},"In ",[745,13234,13061],{},[1119,13236,13238],{"className":13146,"code":13237,"language":13148,"meta":515,"style":515},"pnpm unlink --global @cool\u002Fpackage\npnpm install --force\n",[745,13239,13240,13251],{"__ignoreMap":515},[1127,13241,13242,13244,13247,13249],{"class":1129,"line":1130},[1127,13243,13163],{"class":2246},[1127,13245,13246],{"class":1621}," unlink",[1127,13248,13195],{"class":1621},[1127,13250,13158],{"class":1621},[1127,13252,13253,13255,13257],{"class":1129,"line":516},[1127,13254,13163],{"class":2246},[1127,13256,6295],{"class":1621},[1127,13258,13259],{"class":1621}," --force\n",[371,13261,13232,13262,2328,13264],{},[745,13263,13106],{},[1119,13265,13267],{"className":13146,"code":13266,"language":13148,"meta":515,"style":515},"pnpm unlink --global\n",[745,13268,13269],{"__ignoreMap":515},[1127,13270,13271,13273,13275],{"class":1129,"line":1130},[1127,13272,13163],{"class":2246},[1127,13274,13246],{"class":1621},[1127,13276,13169],{"class":1621},[318,13278,13280],{"id":13279},"summary","Summary",[302,13282,13283,13285,13286,13291],{},[745,13284,12995],{}," is a useful tool for local package development. It makes stepping into the code with breakpoints and debugging a breeze. See the ",[335,13287,13290],{"href":13288,"rel":13289},"https:\u002F\u002Fpnpm.io\u002Fcli\u002Flink",[461],"PNPM docs on link"," for more details.",[1698,13293,13294],{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}",{"title":515,"searchDepth":516,"depth":516,"links":13296},[13297,13298,13299,13300,13301],{"id":13006,"depth":516,"text":13007},{"id":13135,"depth":516,"text":13136},{"id":13204,"depth":516,"text":13205},{"id":13223,"depth":516,"text":13224},{"id":13279,"depth":516,"text":13280},"2025-04-22","Debug your local Node.js packages like a pro (and with less pain) using pnpm link.",{"src":13305,"alt":13306},"\u002Fimages\u002Fblog\u002Fdeveloper-debugging-code.png","A Developer looking at a monitor trying to debug code",{},{"title":41,"description":13303},"aqyJQlXXiPsXUuXG9DQqQXxI2C0XCJsFmv9-4ohrbLY",{"id":13311,"title":37,"authors":13312,"badge":13315,"body":13316,"date":13775,"description":13776,"extension":533,"image":13777,"meta":13780,"navigation":538,"path":38,"seo":13781,"status":540,"stem":39,"__hash__":13782},"posts\u002F2.blog\u002F20240723.using-ollama-and-continue-as-github-copilot-alternative.md",[13313],{"name":292,"to":293,"avatar":13314},{"src":295},{"label":297},{"type":299,"value":13317,"toc":13767},[13318,13321,13324,13339,13342,13356,13360,13367,13370,13373,13377,13380,13387,13401,13417,13429,13443,13449,13452,13466,13469,13473,13476,13482,13485,13526,13533,13723,13732,13735,13739,13745,13751,13757,13761,13764],[302,13319,13320],{},"Unless you've just awoken from a coma, you've likely tried using a Large Language Model (LLM) in your IDE.",[302,13322,13323],{},"Some hate it, while others love it.",[302,13325,13326,13327,13332,13333,13338],{},"You probably use ",[335,13328,13331],{"href":13329,"rel":13330},"https:\u002F\u002Fgithub.com\u002Ffeatures\u002Fcopilot",[461],"GitHub Copilot"," for your coding needs, and perhaps even ",[335,13334,13337],{"href":13335,"rel":13336},"https:\u002F\u002Fdocs.aws.amazon.com\u002Fcodewhisperer\u002Flatest\u002Fuserguide\u002Fwhisper-legacy.html",[461],"Code Whisperer"," if you're an AWS user. But what if you can't afford it, or your company doesn't permit the use of these services? To be clear, using these services involves sending a copy of your text and code to them for processing, and they use your data to train their models.",[302,13340,13341],{},"Anyway, back on topic...",[302,13343,13344,13345,1996,13350,13355],{},"Due to such limitations at work, I've been using ",[335,13346,13349],{"href":13347,"rel":13348},"https:\u002F\u002Follama.com\u002F",[461],"Ollama",[335,13351,13354],{"href":13352,"rel":13353},"https:\u002F\u002Fwww.continue.dev\u002F",[461],"Continue"," as alternatives to Copilot, and it has been working quite well so far!",[318,13357,13359],{"id":13358},"ollama-run-a-local-llm","Ollama - Run a Local LLM",[302,13361,13362,13363,13366],{},"If you haven't heard of it, ",[335,13364,13349],{"href":13347,"rel":13365},[461]," is an open-source alternative to GPT models like ChatGPT, focusing on privacy and control. It's designed to run locally (or privately) without sending your data to third parties. Woot!",[302,13368,13369],{},"After installing Ollama, you can run a local instance of an LLM and interact with it through your terminal or IDE plugins.",[302,13371,13372],{},"For this guide, let's install one model for prompting and another for autocompletion.",[401,13374,13376],{"id":13375},"pull-the-models","Pull the Models",[302,13378,13379],{},"First, keep in mind that models are constantly changing, so you need to ensure your models are up-to-date. Also, consider the amount of GPU and memory available on your machine.",[302,13381,13382,13383,13386],{},"As of writing this guide, ",[745,13384,13385],{},"llama3.1"," has just been released and is great. However, check the following resources for the latest recommended models:",[368,13388,13389,13395],{},[371,13390,13391],{},[335,13392,13393],{"href":13393,"rel":13394},"https:\u002F\u002Follama.com\u002Flibrary",[461],[371,13396,13397],{},[335,13398,13399],{"href":13399,"rel":13400},"https:\u002F\u002Fdocs.continue.dev\u002Fsetup\u002Fselect-model#chat",[461],[1119,13402,13404],{"className":3307,"code":13403,"language":3309,"meta":515,"style":515},"ollama pull llama3.1:8b\n",[745,13405,13406],{"__ignoreMap":515},[1127,13407,13408,13411,13414],{"class":1129,"line":1130},[1127,13409,13410],{"class":2246},"ollama",[1127,13412,13413],{"class":1621}," pull",[1127,13415,13416],{"class":1621}," llama3.1:8b\n",[302,13418,13419,13420,13423,13424,13428],{},"For autocompletion, ",[745,13421,13422],{},"deepseek-coder-v2"," is an excellent model, but check ",[335,13425,13426],{"href":13426,"rel":13427},"https:\u002F\u002Fdocs.continue.dev\u002Fsetup\u002Fselect-model#autocomplete",[461]," to see if there are any updates or newer models available.",[1119,13430,13432],{"className":3307,"code":13431,"language":3309,"meta":515,"style":515},"ollama pull deepseek-coder-v2:16b\n",[745,13433,13434],{"__ignoreMap":515},[1127,13435,13436,13438,13440],{"class":1129,"line":1130},[1127,13437,13410],{"class":2246},[1127,13439,13413],{"class":1621},[1127,13441,13442],{"class":1621}," deepseek-coder-v2:16b\n",[302,13444,13445],{},[467,13446],{"alt":13447,"src":13448},"ollama-pull-llama-3-1","\u002Fimages\u002Fblog\u002Follama-pull-llama-3-1.png",[302,13450,13451],{},"Once the models are downloaded, you can run them locally:",[1119,13453,13455],{"className":3307,"code":13454,"language":3309,"meta":515,"style":515},"ollama run llama3.1:8b\n",[745,13456,13457],{"__ignoreMap":515},[1127,13458,13459,13461,13464],{"class":1129,"line":1130},[1127,13460,13410],{"class":2246},[1127,13462,13463],{"class":1621}," run",[1127,13465,13416],{"class":1621},[302,13467,13468],{},"Next, we'll configure VS Code with the Continue extension to use these models for autocompletion and prompting.",[318,13470,13472],{"id":13471},"continue-llm-extension-for-vs-code","Continue - LLM Extension for VS Code",[302,13474,13475],{},"Install the Continue Extension from the VS Code Marketplace.",[302,13477,13478],{},[335,13479,13480],{"href":13480,"rel":13481},"https:\u002F\u002Fmarketplace.visualstudio.com\u002Fitems?itemName=Continue.continue",[461],[302,13483,13484],{},"Once installed, we'll modify its configuration to use the models we just downloaded. Open the configuration file:",[1119,13486,13488],{"className":3307,"code":13487,"language":3309,"meta":515,"style":515},"# On Linux\u002FmacOS\ncode ~\u002F.continue\u002Fconfig.json\n\n# On Windows (using Command Prompt)\n# code %USERPROFILE%\\.continue\\config.json\n# or (using PowerShell)\n# code $env:USERPROFILE\\.continue\\config.json\n",[745,13489,13490,13495,13502,13506,13511,13516,13521],{"__ignoreMap":515},[1127,13491,13492],{"class":1129,"line":1130},[1127,13493,13494],{"class":1487},"# On Linux\u002FmacOS\n",[1127,13496,13497,13499],{"class":1129,"line":516},[1127,13498,745],{"class":2246},[1127,13500,13501],{"class":1621}," ~\u002F.continue\u002Fconfig.json\n",[1127,13503,13504],{"class":1129,"line":523},[1127,13505,1517],{"emptyLinePlaceholder":538},[1127,13507,13508],{"class":1129,"line":1146},[1127,13509,13510],{"class":1487},"# On Windows (using Command Prompt)\n",[1127,13512,13513],{"class":1129,"line":1382},[1127,13514,13515],{"class":1487},"# code %USERPROFILE%\\.continue\\config.json\n",[1127,13517,13518],{"class":1129,"line":1388},[1127,13519,13520],{"class":1487},"# or (using PowerShell)\n",[1127,13522,13523],{"class":1129,"line":1586},[1127,13524,13525],{"class":1487},"# code $env:USERPROFILE\\.continue\\config.json\n",[302,13527,13528,13529,13532],{},"Add the following two entries into your ",[745,13530,13531],{},"~\u002F.continue\u002Fconfig.json"," file:",[1119,13534,13536],{"className":12652,"code":13535,"language":12654,"meta":515,"style":515},"{\n  \"models\": [\n    \u002F\u002F ... other models if any ...\n    {\n      \"title\": \"Llama 3.1 8B (Ollama)\", \u002F\u002F Descriptive title\n      \"provider\": \"ollama\",\n      \"model\": \"llama3.1:8b\"\n    }\n    \u002F\u002F ...\n  ],\n  \"tabAutocompleteModel\": {\n    \"title\": \"Deepseek Coder V2 16B (Ollama)\", \u002F\u002F Descriptive title\n    \"provider\": \"ollama\",\n    \"model\": \"deepseek-coder-v2:16b\"\n  }\n  \u002F\u002F ... rest of config ...\n}\n",[745,13537,13538,13542,13556,13561,13566,13590,13609,13626,13631,13636,13641,13654,13675,13693,13710,13714,13719],{"__ignoreMap":515},[1127,13539,13540],{"class":1129,"line":1130},[1127,13541,1545],{"class":1501},[1127,13543,13544,13546,13549,13551,13553],{"class":1129,"line":516},[1127,13545,12665],{"class":1501},[1127,13547,13548],{"class":1493},"models",[1127,13550,3736],{"class":1501},[1127,13552,1554],{"class":1501},[1127,13554,13555],{"class":1501}," [\n",[1127,13557,13558],{"class":1129,"line":523},[1127,13559,13560],{"class":1487},"    \u002F\u002F ... other models if any ...\n",[1127,13562,13563],{"class":1129,"line":1146},[1127,13564,13565],{"class":1501},"    {\n",[1127,13567,13568,13571,13574,13576,13578,13580,13583,13585,13587],{"class":1129,"line":1382},[1127,13569,13570],{"class":1501},"      \"",[1127,13572,13573],{"class":2246},"title",[1127,13575,3736],{"class":1501},[1127,13577,1554],{"class":1501},[1127,13579,3750],{"class":1501},[1127,13581,13582],{"class":1621},"Llama 3.1 8B (Ollama)",[1127,13584,3736],{"class":1501},[1127,13586,1628],{"class":1501},[1127,13588,13589],{"class":1487}," \u002F\u002F Descriptive title\n",[1127,13591,13592,13594,13597,13599,13601,13603,13605,13607],{"class":1129,"line":1388},[1127,13593,13570],{"class":1501},[1127,13595,13596],{"class":2246},"provider",[1127,13598,3736],{"class":1501},[1127,13600,1554],{"class":1501},[1127,13602,3750],{"class":1501},[1127,13604,13410],{"class":1621},[1127,13606,3736],{"class":1501},[1127,13608,1570],{"class":1501},[1127,13610,13611,13613,13615,13617,13619,13621,13624],{"class":1129,"line":1586},[1127,13612,13570],{"class":1501},[1127,13614,1567],{"class":2246},[1127,13616,3736],{"class":1501},[1127,13618,1554],{"class":1501},[1127,13620,3750],{"class":1501},[1127,13622,13623],{"class":1621},"llama3.1:8b",[1127,13625,3756],{"class":1501},[1127,13627,13628],{"class":1129,"line":1599},[1127,13629,13630],{"class":1501},"    }\n",[1127,13632,13633],{"class":1129,"line":1647},[1127,13634,13635],{"class":1487},"    \u002F\u002F ...\n",[1127,13637,13638],{"class":1129,"line":1910},[1127,13639,13640],{"class":1501},"  ],\n",[1127,13642,13643,13645,13648,13650,13652],{"class":1129,"line":1915},[1127,13644,12665],{"class":1501},[1127,13646,13647],{"class":1493},"tabAutocompleteModel",[1127,13649,3736],{"class":1501},[1127,13651,1554],{"class":1501},[1127,13653,5832],{"class":1501},[1127,13655,13656,13658,13660,13662,13664,13666,13669,13671,13673],{"class":1129,"line":1920},[1127,13657,13103],{"class":1501},[1127,13659,13573],{"class":2246},[1127,13661,3736],{"class":1501},[1127,13663,1554],{"class":1501},[1127,13665,3750],{"class":1501},[1127,13667,13668],{"class":1621},"Deepseek Coder V2 16B (Ollama)",[1127,13670,3736],{"class":1501},[1127,13672,1628],{"class":1501},[1127,13674,13589],{"class":1487},[1127,13676,13677,13679,13681,13683,13685,13687,13689,13691],{"class":1129,"line":1926},[1127,13678,13103],{"class":1501},[1127,13680,13596],{"class":2246},[1127,13682,3736],{"class":1501},[1127,13684,1554],{"class":1501},[1127,13686,3750],{"class":1501},[1127,13688,13410],{"class":1621},[1127,13690,3736],{"class":1501},[1127,13692,1570],{"class":1501},[1127,13694,13695,13697,13699,13701,13703,13705,13708],{"class":1129,"line":1932},[1127,13696,13103],{"class":1501},[1127,13698,1567],{"class":2246},[1127,13700,3736],{"class":1501},[1127,13702,1554],{"class":1501},[1127,13704,3750],{"class":1501},[1127,13706,13707],{"class":1621},"deepseek-coder-v2:16b",[1127,13709,3756],{"class":1501},[1127,13711,13712],{"class":1129,"line":1938},[1127,13713,5964],{"class":1501},[1127,13715,13716],{"class":1129,"line":1944},[1127,13717,13718],{"class":1487},"  \u002F\u002F ... rest of config ...\n",[1127,13720,13721],{"class":1129,"line":1949},[1127,13722,5978],{"class":1501},[330,13724,13725],{},[302,13726,13727,13728,13731],{},"Note: The config file does not support comments. Ensure you maintain the correct JSON format. Remove the example comments (",[745,13729,13730],{},"\u002F\u002F ...",") before saving.",[302,13733,13734],{},"Now, restart VS Code and try out the new configuration!",[318,13736,13738],{"id":13737},"try-it-out","Try It Out",[302,13740,13741,13742,13744],{},"On the activity bar, click the Continue icon. At the bottom of the prompt input area, select the ",[745,13743,13582],{}," model (or the title you chose) from the dropdown menu. Then, try typing a prompt and see if you get helpful suggestions!",[302,13746,13747],{},[467,13748],{"alt":13749,"src":13750},"Continue-extension-prompt-example","\u002Fimages\u002Fblog\u002FContinue-extension-prompt-example-vscode.png",[302,13752,13753,13754,13756],{},"Now, edit any code file and start typing to see if the autocompletion works with your ",[745,13755,13668],{}," model!",[318,13758,13760],{"id":13759},"conclusion","Conclusion",[302,13762,13763],{},"Congratulations! You've successfully integrated custom LLMs into VS Code using the Continue Extension. This setup runs the LLMs locally on your machine, offering a free and private alternative to cloud-based AI assistants.",[1698,13765,13766],{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}",{"title":515,"searchDepth":516,"depth":516,"links":13768},[13769,13772,13773,13774],{"id":13358,"depth":516,"text":13359,"children":13770},[13771],{"id":13375,"depth":523,"text":13376},{"id":13471,"depth":516,"text":13472},{"id":13737,"depth":516,"text":13738},{"id":13759,"depth":516,"text":13760},"2024-07-23","A guide on how Ollama and Continue can serve as an alternative to GitHub Copilot.",{"src":13778,"alt":13779},"\u002Fimages\u002Fblog\u002Follama-and-continue.png","A llama looking at a screen with code on it",{},{"title":37,"description":13776},"Qp4uEhMY8tm63cPE3tUGTKBZKXSPtMOh1FuUut-FbEs",{"id":13784,"title":33,"authors":13785,"badge":13788,"body":13790,"date":14115,"description":14116,"extension":533,"image":14117,"meta":14120,"navigation":538,"path":34,"seo":14121,"status":540,"stem":35,"__hash__":14122},"posts\u002F2.blog\u002F20240714.fire-tablet-and-youtube-kids.md",[13786],{"name":292,"to":293,"avatar":13787},{"src":295},{"label":13789},"android",{"type":299,"value":13791,"toc":14105},[13792,13795,13798,13802,13805,13808,13811,13815,13818,13822,13825,13828,13832,13835,13843,13860,13863,13866,13870,13878,13881,13884,13903,13907,13913,13919,13930,14045,14048,14054,14063,14066,14069,14094,14096,14099,14102],[302,13793,13794],{},"So if you have kids you likely either have android or iOS tablets.",[302,13796,13797],{},"We're all Android at my house for tablets and phones. We use Amazon Fire Tablets but the Amazon Fire Store is lacking a native YouTube or YouTube Kids app. There are apps called that in the Fire App Store, but they're imitations! Go check and look at the developer page for many apps. They are knockoffs and always have been. And not good ones.",[318,13799,13801],{"id":13800},"problems","Problems",[302,13803,13804],{},"I want to limit YouTube to better quality content. I don't care if it's YouTube or YouTube Kids.",[302,13806,13807],{},"Now if you're familiar with how the Amazon Kids app works, you can create a profile for each kid and set apps on their profiles. The issue is you can allow the generic YouTube, but it doesn't support family profiles.",[302,13809,13810],{},"So we need to get the real Google Play apps to do this. That sounds simple, but after many hours of doing so, it's not so straightforward.",[318,13812,13814],{"id":13813},"solutions-that-do-not-work-or-limited","Solutions that DO NOT WORK or Limited",[302,13816,13817],{},"So let's talk about what doesn't work.",[401,13819,13821],{"id":13820},"sideload-an-app-on-main-profile","Sideload an app on main profile",[302,13823,13824],{},"Sideload any app on the main profile and enable it on the kids profile.",[302,13826,13827],{},"So you can sideload apps (we'll cover Google ones, we'll get to that), and even in the Fire Kids app share it to them, but once you switch to their profile, the app—if not installed from the Fire App Store—you cannot see it in the Fire Launcher to select it.",[401,13829,13831],{"id":13830},"sideload-youtube-app-on-kids-profile","Sideload YouTube App on Kids Profile",[302,13833,13834],{},"This will work for some apps but not for Google apps, because they require Google Play Services and Play Store to run.",[302,13836,13837,13838],{},"You can install the Google Play Store and services on the main profile. The best guide I've seen is: ",[335,13839,13842],{"href":13840,"rel":13841},"https:\u002F\u002Fwww.howtogeek.com\u002F232726\u002Fhow-to-install-the-google-play-store-on-your-amazon-fire-tablet\u002F#if-you-39-re-using-a-fire-7-2022-12th-gen-or-newer",[461],"how-to-install-the-google-play-store-on-your-amazon-fire-tablet",[302,13844,13845,13846,1199,13849,1199,13852,13855,13856,13859],{},"Even if you follow that guide, it works on the main tablet profile, but when on the kids profile, it lets you install ",[745,13847,13848],{},"com.google.android.gsf.login",[745,13850,13851],{},"com.google.android.gsf",[745,13853,13854],{},"com.google.android.gms"," but fails to install Play Store (aka ",[745,13857,13858],{},"com.android.vending",") when on the child profile.",[302,13861,13862],{},"Also, I'll add that this information is as of 2024-07-14 for Amazon tablets 10th and 11th gen. Amazon is notorious for updating them over the wire to disable features on a product you paid for.",[302,13864,13865],{},"So what can we do?",[318,13867,13869],{"id":13868},"best-solution-so-far","Best Solution So Far",[302,13871,13872,13873,1207],{},"Looking for alternatives, I found mrhaydendp's ",[335,13874,13877],{"href":13875,"rel":13876},"https:\u002F\u002Fgithub.com\u002Fmrhaydendp\u002FFire-Tools",[461],"Fire Tools",[302,13879,13880],{},"It's a nice Python tool that will use the ADB tool to modify the tablet. It's not a perfect solution, but it's good enough for me.",[302,13882,13883],{},"The end result will be as such:",[368,13885,13886,13889,13892,13900],{},[371,13887,13888],{},"Only the main profile will exist on the tablet.",[371,13890,13891],{},"It won't have the Fire App Store",[371,13893,13894,13895],{},"We can install Google Play Store and services,\n",[368,13896,13897],{},[371,13898,13899],{},"followed by YouTube Kids and such.",[371,13901,13902],{},"We'll hide anything else.",[318,13904,13906],{"id":13905},"fire-tools-instructions","Fire Tools Instructions",[302,13908,13909,13910,1207],{},"We enable developer mode, then follow the instructions at ",[335,13911,13875],{"href":13875,"rel":13912},[461],[302,13914,13915,13916,1207],{},"We'll use it to remove tons of Amazon apps, or as it says, ",[745,13917,13918],{},"Debloat",[330,13920,13921],{},[302,13922,13923,13924,13929],{},"Note: I always use ",[335,13925,13928],{"href":13926,"rel":13927},"https:\u002F\u002Fgithub.com\u002Fpyenv\u002Fpyenv",[461],"pyenv"," for my Python environments.",[1119,13931,13933],{"className":3307,"code":13932,"language":3309,"meta":515,"style":515},"# move to a temp folder\n\ncurl -LO https:\u002F\u002Fgithub.com\u002Fmrhaydendp\u002Ffire-tools\u002Freleases\u002Flatest\u002Fdownload\u002FFire-Tools.zip\nunzip Fire-Tools.zip && rm Fire-Tools.zip\ncd Fire-Tools\npyenv virtualenv 3.12.4 Fire-Tools\n\n# use a virtual env\npyenv local Fire-Tools\npyenv shell Fire-Tools\n\n# install the requirements in that virtual env\npip install -r requirements.txt\npython main.py\n",[745,13934,13935,13940,13944,13954,13971,13978,13990,13994,13999,14008,14017,14021,14026,14038],{"__ignoreMap":515},[1127,13936,13937],{"class":1129,"line":1130},[1127,13938,13939],{"class":1487},"# move to a temp folder\n",[1127,13941,13942],{"class":1129,"line":516},[1127,13943,1517],{"emptyLinePlaceholder":538},[1127,13945,13946,13948,13951],{"class":1129,"line":523},[1127,13947,11384],{"class":2246},[1127,13949,13950],{"class":1621}," -LO",[1127,13952,13953],{"class":1621}," https:\u002F\u002Fgithub.com\u002Fmrhaydendp\u002Ffire-tools\u002Freleases\u002Flatest\u002Fdownload\u002FFire-Tools.zip\n",[1127,13955,13956,13959,13962,13965,13968],{"class":1129,"line":1146},[1127,13957,13958],{"class":2246},"unzip",[1127,13960,13961],{"class":1621}," Fire-Tools.zip",[1127,13963,13964],{"class":1501}," &&",[1127,13966,13967],{"class":2246}," rm",[1127,13969,13970],{"class":1621}," Fire-Tools.zip\n",[1127,13972,13973,13975],{"class":1129,"line":1382},[1127,13974,13155],{"class":1505},[1127,13976,13977],{"class":1621}," Fire-Tools\n",[1127,13979,13980,13982,13985,13988],{"class":1129,"line":1388},[1127,13981,13928],{"class":2246},[1127,13983,13984],{"class":1621}," virtualenv",[1127,13986,13987],{"class":1580}," 3.12.4",[1127,13989,13977],{"class":1621},[1127,13991,13992],{"class":1129,"line":1586},[1127,13993,1517],{"emptyLinePlaceholder":538},[1127,13995,13996],{"class":1129,"line":1599},[1127,13997,13998],{"class":1487},"# use a virtual env\n",[1127,14000,14001,14003,14006],{"class":1129,"line":1647},[1127,14002,13928],{"class":2246},[1127,14004,14005],{"class":1621}," local",[1127,14007,13977],{"class":1621},[1127,14009,14010,14012,14015],{"class":1129,"line":1910},[1127,14011,13928],{"class":2246},[1127,14013,14014],{"class":1621}," shell",[1127,14016,13977],{"class":1621},[1127,14018,14019],{"class":1129,"line":1915},[1127,14020,1517],{"emptyLinePlaceholder":538},[1127,14022,14023],{"class":1129,"line":1920},[1127,14024,14025],{"class":1487},"# install the requirements in that virtual env\n",[1127,14027,14028,14031,14033,14035],{"class":1129,"line":1926},[1127,14029,14030],{"class":2246},"pip",[1127,14032,6295],{"class":1621},[1127,14034,9549],{"class":1621},[1127,14036,14037],{"class":1621}," requirements.txt\n",[1127,14039,14040,14042],{"class":1129,"line":1932},[1127,14041,3836],{"class":2246},[1127,14043,14044],{"class":1621}," main.py\n",[302,14046,14047],{},"The UI is pretty self-explanatory.",[302,14049,14050],{},[467,14051],{"alt":14052,"src":14053},"fire-tools",".\u002Fimages\u002Fblog\u002Ffire-tools-ui.png",[302,14055,14056,14057,14062],{},"I won't cover how to have ADB setup but here are my notes on setting up ",[335,14058,14061],{"href":14059,"rel":14060},"https:\u002F\u002Fgithub.com\u002FChrisTowles\u002Fdotfiles\u002Fblob\u002Fmain\u002Fdocs\u002Fapps\u002Fandriod-studio.md",[461],"Android Studio on Linux"," which pretty awful for 2024, honestly.",[302,14064,14065],{},"Anyway, the tool is pretty amazing.",[302,14067,14068],{},"I ran the following:",[368,14070,14071,14076,14079,14082],{},[371,14072,14073,14074],{},"Ran ",[745,14075,13918],{},[371,14077,14078],{},"Install Google Play Services",[371,14080,14081],{},"set custom DNS to use Cloudflare",[371,14083,14084,14085,14088,14089],{},"Installed the ",[745,14086,14087],{},"Lawnchair"," Launcher\n",[368,14090,14091],{},[371,14092,14093],{},"Used that to hide apps like \"App Store\" (not that it would work as the app wasn't registered, but still nice to hide)",[318,14095,13760],{"id":13759},[302,14097,14098],{},"I'll follow up later, but this is a good start. During the summer I take the kids to the pool every day and their mother plays games, but there is still too much tablet time! Here's hoping that at least the quality of videos is better with these hacks!",[302,14100,14101],{},"To all the other parents out there: Best of luck!",[1698,14103,14104],{},"html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":515,"searchDepth":516,"depth":516,"links":14106},[14107,14108,14112,14113,14114],{"id":13800,"depth":516,"text":13801},{"id":13813,"depth":516,"text":13814,"children":14109},[14110,14111],{"id":13820,"depth":523,"text":13821},{"id":13830,"depth":523,"text":13831},{"id":13868,"depth":516,"text":13869},{"id":13905,"depth":516,"text":13906},{"id":13759,"depth":516,"text":13760},"2024-07-14","Getting YouTube and YouTube Kids to work on Amazon Fire for kids",{"src":14118,"alt":14119},"\u002Fimages\u002Fblog\u002Fyoutube-kids-fire-tablet.png","Kids holding fire tablet",{},{"title":33,"description":14116},"0PqbieIAoD75jhC2FjxVpi1_Of88rL8Jx3stnRaEPD8",{"id":14124,"title":29,"authors":14125,"badge":14128,"body":14130,"date":14657,"description":14658,"extension":533,"image":14659,"meta":14662,"navigation":538,"path":30,"seo":14663,"status":540,"stem":31,"__hash__":14664},"posts\u002F2.blog\u002F20240711.oh-my-zsh-on-your-server.md",[14126],{"name":292,"to":293,"avatar":14127},{"src":295},{"label":14129},"productivity",{"type":299,"value":14131,"toc":14652},[14132,14135,14156,14159,14169,14172,14178,14180,14188,14425,14432,14455,14459,14465,14546,14549,14555,14561,14633,14636,14642,14646,14649],[302,14133,14134],{},"So recently I've been helping other teams that have a lot of EC2 instances and find myself ssh'ing into them and running common and similar commands a lot!",[302,14136,14137,14138,1996,14143,14148,14149,14152,14153,1207],{},"On my personal machine I have my terminal using ",[335,14139,14142],{"href":14140,"rel":14141},"https:\u002F\u002Fgithub.com\u002Fohmyzsh\u002Fohmyzsh",[461],"oh-my-zsh",[335,14144,14147],{"href":14145,"rel":14146},"https:\u002F\u002Fgithub.com\u002Fspaceship-prompt\u002Fspaceship-prompt",[461],"Spaceship-prompt",". My ",[745,14150,14151],{},".zshrc"," is public here: ",[335,14154,7829],{"href":7829,"rel":14155},[461],[302,14157,14158],{},"I take for granted all the useful behavior and commands that I use on my personal machine. Autocomplete previous commands, better syntax highlighting, and more.",[302,14160,14161,14162,2388,14165,14168],{},"When I ssh into a server I find myself grepping the history and looking for commands that I use all the time. On top of that, the default prompt doesn't have the server name. So it's SOOOO easy to be on the wrong server. Are you in ",[745,14163,14164],{},"production",[745,14166,14167],{},"nonprod","?",[302,14170,14171],{},"I'm wasting time and it's only a matter of time before I make a change to the wrong server and impact users by mistake.",[302,14173,14174,14175,14177],{},"After many weeks of helping out with this I decided to try and make it easier for myself. I've started setting up ",[745,14176,14142],{}," on the servers for my profiles I'm in constantly.",[318,14179,7020],{"id":7019},[302,14181,14182,14183],{},"In my case these machines are Amazon Linux 2 and I found a great starting place at ",[335,14184,14187],{"href":14185,"rel":14186},"https:\u002F\u002Fblog.devops.dev\u002Finstalling-zsh-oh-my-zsh-on-amazon-ec2-amazon-linux-2-ami-88b5fc83109",[461],"here",[1119,14189,14191],{"className":3307,"code":14190,"language":3309,"meta":515,"style":515},"# Installing ZSH\nsudo yum -y install zsh\n\n# Check ZSH has been installed\nzsh --version\n\n# Install \"util-linux-user\" because \"chsh\" is not available by default - https:\u002F\u002Fsuperuser.com\u002Fa\u002F1389273\u002F599050\nsudo yum -y install util-linux-user\n\n# Change default shell for current user\nchsh -s \"$(which zsh)\" $(whoami)\n\n# Install oh-my-zsh from https:\u002F\u002Fgithub.com\u002Fohmyzsh\u002Fohmyzsh#basic-installation\n# using unattended means not trying to change the default shell, and it also won't run zsh when the installation has finished.\nsh -c \"$(curl -fsSL https:\u002F\u002Fraw.githubusercontent.com\u002Fohmyzsh\u002Fohmyzsh\u002Fmaster\u002Ftools\u002Finstall.sh)\" \"\" --unattended\n\n# some of the most useful oh my zsh plugins\ngit clone https:\u002F\u002Fgithub.com\u002Fzsh-users\u002Fzsh-syntax-highlighting.git ${ZSH_CUSTOM:-~\u002F.oh-my-zsh\u002Fcustom}\u002Fplugins\u002Fzsh-syntax-highlighting\ngit clone https:\u002F\u002Fgithub.com\u002Fzsh-users\u002Fzsh-autosuggestions ${ZSH_CUSTOM:-~\u002F.oh-my-zsh\u002Fcustom}\u002Fplugins\u002Fzsh-autosuggestions\n\n# open new shell\nsudo su - $(whoami)\n\n",[745,14192,14193,14198,14214,14218,14223,14229,14233,14238,14251,14255,14260,14288,14292,14297,14302,14325,14329,14334,14370,14400,14404,14409],{"__ignoreMap":515},[1127,14194,14195],{"class":1129,"line":1130},[1127,14196,14197],{"class":1487},"# Installing ZSH\n",[1127,14199,14200,14203,14206,14209,14211],{"class":1129,"line":516},[1127,14201,14202],{"class":2246},"sudo",[1127,14204,14205],{"class":1621}," yum",[1127,14207,14208],{"class":1621}," -y",[1127,14210,6295],{"class":1621},[1127,14212,14213],{"class":1621}," zsh\n",[1127,14215,14216],{"class":1129,"line":523},[1127,14217,1517],{"emptyLinePlaceholder":538},[1127,14219,14220],{"class":1129,"line":1146},[1127,14221,14222],{"class":1487},"# Check ZSH has been installed\n",[1127,14224,14225,14227],{"class":1129,"line":1382},[1127,14226,13148],{"class":2246},[1127,14228,5177],{"class":1621},[1127,14230,14231],{"class":1129,"line":1388},[1127,14232,1517],{"emptyLinePlaceholder":538},[1127,14234,14235],{"class":1129,"line":1586},[1127,14236,14237],{"class":1487},"# Install \"util-linux-user\" because \"chsh\" is not available by default - https:\u002F\u002Fsuperuser.com\u002Fa\u002F1389273\u002F599050\n",[1127,14239,14240,14242,14244,14246,14248],{"class":1129,"line":1599},[1127,14241,14202],{"class":2246},[1127,14243,14205],{"class":1621},[1127,14245,14208],{"class":1621},[1127,14247,6295],{"class":1621},[1127,14249,14250],{"class":1621}," util-linux-user\n",[1127,14252,14253],{"class":1129,"line":1647},[1127,14254,1517],{"emptyLinePlaceholder":538},[1127,14256,14257],{"class":1129,"line":1910},[1127,14258,14259],{"class":1487},"# Change default shell for current user\n",[1127,14261,14262,14265,14268,14271,14274,14277,14280,14283,14286],{"class":1129,"line":1915},[1127,14263,14264],{"class":2246},"chsh",[1127,14266,14267],{"class":1621}," -s",[1127,14269,14270],{"class":1501}," \"$(",[1127,14272,14273],{"class":1505},"which",[1127,14275,14276],{"class":1621}," zsh",[1127,14278,14279],{"class":1501},")\"",[1127,14281,14282],{"class":1501}," $(",[1127,14284,14285],{"class":2246},"whoami",[1127,14287,8783],{"class":1501},[1127,14289,14290],{"class":1129,"line":1920},[1127,14291,1517],{"emptyLinePlaceholder":538},[1127,14293,14294],{"class":1129,"line":1926},[1127,14295,14296],{"class":1487},"# Install oh-my-zsh from https:\u002F\u002Fgithub.com\u002Fohmyzsh\u002Fohmyzsh#basic-installation\n",[1127,14298,14299],{"class":1129,"line":1932},[1127,14300,14301],{"class":1487},"# using unattended means not trying to change the default shell, and it also won't run zsh when the installation has finished.\n",[1127,14303,14304,14307,14310,14312,14314,14317,14319,14322],{"class":1129,"line":1938},[1127,14305,14306],{"class":2246},"sh",[1127,14308,14309],{"class":1621}," -c",[1127,14311,14270],{"class":1501},[1127,14313,11384],{"class":2246},[1127,14315,14316],{"class":1621}," -fsSL https:\u002F\u002Fraw.githubusercontent.com\u002Fohmyzsh\u002Fohmyzsh\u002Fmaster\u002Ftools\u002Finstall.sh",[1127,14318,14279],{"class":1501},[1127,14320,14321],{"class":1501}," \"\"",[1127,14323,14324],{"class":1621}," --unattended\n",[1127,14326,14327],{"class":1129,"line":1944},[1127,14328,1517],{"emptyLinePlaceholder":538},[1127,14330,14331],{"class":1129,"line":1949},[1127,14332,14333],{"class":1487},"# some of the most useful oh my zsh plugins\n",[1127,14335,14336,14338,14341,14344,14347,14350,14353,14355,14357,14360,14362,14365,14367],{"class":1129,"line":1954},[1127,14337,9595],{"class":2246},[1127,14339,14340],{"class":1621}," clone",[1127,14342,14343],{"class":1621}," https:\u002F\u002Fgithub.com\u002Fzsh-users\u002Fzsh-syntax-highlighting.git",[1127,14345,14346],{"class":1501}," ${",[1127,14348,14349],{"class":1497},"ZSH_CUSTOM",[1127,14351,14352],{"class":1501},":-",[1127,14354,11296],{"class":1497},[1127,14356,1454],{"class":1501},[1127,14358,14359],{"class":1497},".oh-my-zsh",[1127,14361,1454],{"class":1501},[1127,14363,14364],{"class":1497},"custom",[1127,14366,1639],{"class":1501},[1127,14368,14369],{"class":1621},"\u002Fplugins\u002Fzsh-syntax-highlighting\n",[1127,14371,14372,14374,14376,14379,14381,14383,14385,14387,14389,14391,14393,14395,14397],{"class":1129,"line":1960},[1127,14373,9595],{"class":2246},[1127,14375,14340],{"class":1621},[1127,14377,14378],{"class":1621}," https:\u002F\u002Fgithub.com\u002Fzsh-users\u002Fzsh-autosuggestions",[1127,14380,14346],{"class":1501},[1127,14382,14349],{"class":1497},[1127,14384,14352],{"class":1501},[1127,14386,11296],{"class":1497},[1127,14388,1454],{"class":1501},[1127,14390,14359],{"class":1497},[1127,14392,1454],{"class":1501},[1127,14394,14364],{"class":1497},[1127,14396,1639],{"class":1501},[1127,14398,14399],{"class":1621},"\u002Fplugins\u002Fzsh-autosuggestions\n",[1127,14401,14402],{"class":1129,"line":1966},[1127,14403,1517],{"emptyLinePlaceholder":538},[1127,14405,14406],{"class":1129,"line":1971},[1127,14407,14408],{"class":1487},"# open new shell\n",[1127,14410,14411,14413,14416,14419,14421,14423],{"class":1129,"line":1977},[1127,14412,14202],{"class":2246},[1127,14414,14415],{"class":1621}," su",[1127,14417,14418],{"class":1621}," -",[1127,14420,14282],{"class":1501},[1127,14422,14285],{"class":2246},[1127,14424,8783],{"class":1501},[302,14426,14427,14428,14431],{},"Now modify the ",[745,14429,14430],{},"~\u002F.zshrc"," to update the plugins",[1119,14433,14435],{"className":3307,"code":14434,"language":3309,"meta":515,"style":515},"plugins=(git zsh-autosuggestions zsh-syntax-highlighting)\n",[745,14436,14437],{"__ignoreMap":515},[1127,14438,14439,14442,14445,14447,14450,14453],{"class":1129,"line":1130},[1127,14440,14441],{"class":1497},"plugins",[1127,14443,14444],{"class":1501},"=(",[1127,14446,9595],{"class":1621},[1127,14448,14449],{"class":1621}," zsh-autosuggestions",[1127,14451,14452],{"class":1621}," zsh-syntax-highlighting",[1127,14454,8783],{"class":1501},[318,14456,14458],{"id":14457},"update-the-prompt-to-include-server-name","Update the prompt to include server name",[302,14460,14461,14462,14464],{},"So I want to quickly know what server I'm on you can modify the prompt in ",[745,14463,14430],{}," by adding this line:",[1119,14466,14468],{"className":3307,"code":14467,"language":3309,"meta":515,"style":515},"\nSERVER_FRIENDLY_NAME=REPLACE_WITH_FRIENDLY_SERVER_NAME\n# add user and host to ohmyzsh terminal prompt - https:\u002F\u002Fstackoverflow.com\u002Fquestions\u002F30199068\u002Fzsh-prompt-and-hostnameE\nautoload -U colors && colors\nPS1=\"%{$fg[green]%}%n%{$reset_color%}@%{$fg[cyan]%}%m %{$fg[yellow]%}%~ %{$reset_color%}%% \"\n\n",[745,14469,14470,14474,14484,14489,14505],{"__ignoreMap":515},[1127,14471,14472],{"class":1129,"line":1130},[1127,14473,1517],{"emptyLinePlaceholder":538},[1127,14475,14476,14479,14481],{"class":1129,"line":516},[1127,14477,14478],{"class":1497},"SERVER_FRIENDLY_NAME",[1127,14480,1502],{"class":1501},[1127,14482,14483],{"class":1621},"REPLACE_WITH_FRIENDLY_SERVER_NAME\n",[1127,14485,14486],{"class":1129,"line":523},[1127,14487,14488],{"class":1487},"# add user and host to ohmyzsh terminal prompt - https:\u002F\u002Fstackoverflow.com\u002Fquestions\u002F30199068\u002Fzsh-prompt-and-hostnameE\n",[1127,14490,14491,14494,14497,14500,14502],{"class":1129,"line":1146},[1127,14492,14493],{"class":1505},"autoload",[1127,14495,14496],{"class":1621}," -U",[1127,14498,14499],{"class":1621}," colors",[1127,14501,13964],{"class":1501},[1127,14503,14504],{"class":2246}," colors\n",[1127,14506,14507,14510,14512,14514,14517,14520,14523,14526,14529,14531,14534,14536,14539,14541,14544],{"class":1129,"line":1382},[1127,14508,14509],{"class":1497},"PS1",[1127,14511,1502],{"class":1501},[1127,14513,3736],{"class":1501},[1127,14515,14516],{"class":1621},"%{",[1127,14518,14519],{"class":1497},"$fg",[1127,14521,14522],{"class":1621},"[green]%}%n%{",[1127,14524,14525],{"class":1497},"$reset_color",[1127,14527,14528],{"class":1621},"%}@%{",[1127,14530,14519],{"class":1497},[1127,14532,14533],{"class":1621},"[cyan]%}%m %{",[1127,14535,14519],{"class":1497},[1127,14537,14538],{"class":1621},"[yellow]%}%~ %{",[1127,14540,14525],{"class":1497},[1127,14542,14543],{"class":1621},"%}%% ",[1127,14545,3756],{"class":1501},[302,14547,14548],{},"But what if the default hostname is the EC2 IP? Here is AWS advice on changing the prompt without changing the DNS or hostname.",[302,14550,14551],{},[335,14552,14553],{"href":14553,"rel":14554},"https:\u002F\u002Fdocs.aws.amazon.com\u002Flinux\u002Fal2\u002Fug\u002Fset-hostname.html#set-hostname-shell",[461],[302,14556,14557,14558,14560],{},"Here we'll append this to the ",[745,14559,14430],{}," file.",[1119,14562,14564],{"className":3307,"code":14563,"language":3309,"meta":515,"style":515},"\nSERVER_FRIENDLY_NAME=REPLACE_WITH_FRIENDLY_SERVER_NAME\n# add user and host to ohmyzsh terminal prompt - https:\u002F\u002Fstackoverflow.com\u002Fquestions\u002F30199068\u002Fzsh-prompt-and-hostnameE\nautoload -U colors && colors\nPS1=\"%{$fg[green]%}%n%{$reset_color%}@%{$fg[cyan]%}$SERVER_FRIENDLY_NAME %{$fg[yellow]%}%~ %{$reset_color%}%% \"\n\n",[745,14565,14566,14570,14578,14582,14594],{"__ignoreMap":515},[1127,14567,14568],{"class":1129,"line":1130},[1127,14569,1517],{"emptyLinePlaceholder":538},[1127,14571,14572,14574,14576],{"class":1129,"line":516},[1127,14573,14478],{"class":1497},[1127,14575,1502],{"class":1501},[1127,14577,14483],{"class":1621},[1127,14579,14580],{"class":1129,"line":523},[1127,14581,14488],{"class":1487},[1127,14583,14584,14586,14588,14590,14592],{"class":1129,"line":1146},[1127,14585,14493],{"class":1505},[1127,14587,14496],{"class":1621},[1127,14589,14499],{"class":1621},[1127,14591,13964],{"class":1501},[1127,14593,14504],{"class":2246},[1127,14595,14596,14598,14600,14602,14604,14606,14608,14610,14612,14614,14617,14620,14623,14625,14627,14629,14631],{"class":1129,"line":1382},[1127,14597,14509],{"class":1497},[1127,14599,1502],{"class":1501},[1127,14601,3736],{"class":1501},[1127,14603,14516],{"class":1621},[1127,14605,14519],{"class":1497},[1127,14607,14522],{"class":1621},[1127,14609,14525],{"class":1497},[1127,14611,14528],{"class":1621},[1127,14613,14519],{"class":1497},[1127,14615,14616],{"class":1621},"[cyan]%}",[1127,14618,14619],{"class":1497},"$SERVER_FRIENDLY_NAME",[1127,14621,14622],{"class":1621}," %{",[1127,14624,14519],{"class":1497},[1127,14626,14538],{"class":1621},[1127,14628,14525],{"class":1497},[1127,14630,14543],{"class":1621},[1127,14632,3756],{"class":1501},[302,14634,14635],{},"Here is a screenshot of what this looks like.",[302,14637,14638],{},[467,14639],{"alt":14640,"src":14641},"h-my-zsh-server-friendly-name-in-prompt","\u002Fimages\u002Fblog\u002Foh-my-zsh-server-friendly-name-in-prompt.png",[318,14643,14645],{"id":14644},"security","Security",[302,14647,14648],{},"So the reasons for not doing this are mainly security. Any additional piece of code on the machine is another attack vector. So this is a judgment call. What is the impact if oh-my-zsh is compromised versus the benefits? Based on the popularity of oh-my-zsh, I'm leaning towards this being safe enough to do in some environments.",[1698,14650,14651],{},"html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":515,"searchDepth":516,"depth":516,"links":14653},[14654,14655,14656],{"id":7019,"depth":516,"text":7020},{"id":14457,"depth":516,"text":14458},{"id":14644,"depth":516,"text":14645},"2024-07-11","Why I'm installing it on servers I ssh into a lot.",{"src":14660,"alt":14661},"\u002Fimages\u002Fblog\u002Fimprove-server-terminal.png","desk with 3 monitors and lots of code open",{},{"title":29,"description":14658},"v189JR8AnIceAGD3jbGjw1bZ3nzh0z7DYdOymZ7V2y4",{"id":14666,"title":25,"authors":14667,"badge":14670,"body":14672,"date":14858,"description":14859,"extension":533,"image":14860,"meta":14863,"navigation":538,"path":26,"seo":14864,"status":540,"stem":27,"__hash__":14865},"posts\u002F2.blog\u002F20240710.apache-airflow-part-1-why-and-goals.md",[14668],{"name":292,"to":293,"avatar":14669},{"src":295},{"label":14671},"airflow",{"type":299,"value":14673,"toc":14852},[14674,14683,14686,14690,14696,14709,14713,14716,14758,14761,14765,14768,14838,14842,14849],[302,14675,14676,14677,14682],{},"At work, at ",[335,14678,14681],{"href":14679,"rel":14680},"https:\u002F\u002Fwww.geaerospace.com\u002F",[461],"GE Aerospace",", I work around supporting data ingestion into a Datalake. I'm not going to go into the details here, but I would love to use Airflow instead of the current stack we have today.",[302,14684,14685],{},"I've done a few proofs of concept with Airflow in the past. It is a solid solution, and with the hype of AI these days, quick and reliable data ingestion has never been more critical.",[318,14687,14689],{"id":14688},"why-apache-airflow","Why Apache Airflow?",[302,14691,14692],{},[467,14693],{"alt":14694,"src":14695},"Apache Airflow","\u002Fimages\u002Fblog\u002Fairflow-logo.png",[368,14697,14698,14701],{},[371,14699,14700],{},"It's open source",[371,14702,14703,14704],{},"Hugely popular and used by many companies.\n",[368,14705,14706],{},[371,14707,14708],{},"Features and integrations are available with nearly everything",[318,14710,14712],{"id":14711},"why-not-other-solutions","Why not other solutions?",[302,14714,14715],{},"Over the last few years every provider seems to be reducing their on-premises options to only their hosted solution.",[368,14717,14718,14726,14734,14742,14750],{},[371,14719,14720,14725],{},[335,14721,14724],{"href":14722,"rel":14723},"https:\u002F\u002Fwww.talend.com\u002Fproducts\u002Ftalend-open-studio\u002F",[461],"Talend"," and other features are already being deprecated",[371,14727,14728,14733],{},[335,14729,14732],{"href":14730,"rel":14731},"https:\u002F\u002Ffivetran.com",[461],"Fivetran"," moving to their own cloud based solution.",[371,14735,14736,14741],{},[335,14737,14740],{"href":14738,"rel":14739},"https:\u002F\u002Fdocs.databricks.com\u002Fen\u002Fresources\u002Fsupported-regions.html",[461],"Databricks"," not in us-gov-east-1 as of (2024-07-10)",[371,14743,14744,14749],{},[335,14745,14748],{"href":14746,"rel":14747},"https:\u002F\u002Fdocs.prefect.io\u002Flatest\u002Fguides\u002Fhost\u002F",[461],"Prefect"," - lots of cloud-only features, like audit logs, Workspaces, and Automation",[371,14751,14752,14757],{},[335,14753,14756],{"href":14754,"rel":14755},"https:\u002F\u002Fgithub.com\u002Fdagster-io\u002Fdagster\u002Fissues\u002F2219",[461],"Dagster"," - Dagit lacks any authentication when self-hosted.",[302,14759,14760],{},"And I get why—for small to midsize companies, it's easier to just deploy a cloud-based solution. But when you have a really large and\u002For regulation-heavy environment, it's more important to be able to self-host and manage your own data. No shipping it off to a third party and trusting them with your data.",[318,14762,14764],{"id":14763},"my-goals","My goals",[302,14766,14767],{},"I am however going to put a few constraints in place around how I want to use Airflow.",[368,14769,14770,14779,14787,14795,14812,14820],{},[371,14771,14772,14773,14778],{},"Can't use ",[335,14774,14777],{"href":14775,"rel":14776},"https:\u002F\u002Faws.amazon.com\u002Fmwaa\u002F",[461],"AWS MWAA"," (it's not offered in AWS US Gov East)",[371,14780,14781,14782],{},"Local Development\n",[368,14783,14784],{},[371,14785,14786],{},"Changes to a job must be able to be tested locally before being pushed",[371,14788,14789,14790],{},"CI\u002FCD Pipeline\n",[368,14791,14792],{},[371,14793,14794],{},"Changes to a job must be able to be deployed to production via a CI\u002FCD pipeline.",[371,14796,14797,14798],{},"Job Management\n",[368,14799,14800,14803,14806,14809],{},[371,14801,14802],{},"Offer Web UI to view and re-trigger jobs",[371,14804,14805],{},"Prefer code-first and config rather than UI-based.",[371,14807,14808],{},"Time to modify a job should be less than 5 minutes.",[371,14810,14811],{},"Time to create a job should be less than 30 minutes.",[371,14813,14814,14815],{},"Cost\n",[368,14816,14817],{},[371,14818,14819],{},"I'd like as close to zero cost as possible, ideally spinning down to near no resource usage when no jobs running.",[371,14821,14822,14823],{},"Maintenance\n",[368,14824,14825],{},[371,14826,14827,14828],{},"Would like to be able to deploy new versions of the Airflow container on ECS.\n",[368,14829,14830],{},[371,14831,14832,14833],{},"This isn't a hard requirement—could use an EC2 instance and update in place, but that's another box to maintain long term.\n",[368,14834,14835],{},[371,14836,14837],{},"If instead it was just ECS pointing at an RDS database, you could restore the DB from snapshot and test a deployment before release to production.",[318,14839,14841],{"id":14840},"repo","Repo",[302,14843,14844,14845],{},"Just started with a repo at: ",[335,14846,14847],{"href":14847,"rel":14848},"https:\u002F\u002Fgithub.com\u002FChrisTowles\u002Fairflow-playground",[461],[302,14850,14851],{},"I don't usually post Proofs of Concept like this publicly, but I'm doing it on my own time, so let's see how this goes and where it takes me.",{"title":515,"searchDepth":516,"depth":516,"links":14853},[14854,14855,14856,14857],{"id":14688,"depth":516,"text":14689},{"id":14711,"depth":516,"text":14712},{"id":14763,"depth":516,"text":14764},{"id":14840,"depth":516,"text":14841},"2024-07-10","Reasons I want to use Airflow for a Proof of Concept near Serverless ELT",{"src":14861,"alt":14862},"\u002Fimages\u002Fblog\u002Fairflow-part-1-blog-image.png","A laptop with a data analytics",{},{"title":25,"description":14859},"pRdrsfV0D6PBLbFdk4FfgwUGTziJc5Za3Wj5U4F5LI8",{"id":14867,"title":21,"authors":14868,"badge":14871,"body":14872,"date":14999,"description":15000,"extension":533,"image":15001,"meta":15004,"navigation":538,"path":22,"seo":15005,"status":540,"stem":23,"__hash__":15006},"posts\u002F2.blog\u002F20240630.Why-you-should-make-a-toolbox-repository.md",[14869],{"name":292,"to":293,"avatar":14870},{"src":295},{"label":14129},{"type":299,"value":14873,"toc":14987},[14874,14877,14884,14888,14891,14895,14898,14902,14905,14909,14930,14934,14937,14941,14952,14955,14958,14972,14976,14979,14981,14984],[302,14875,14876],{},"As a software developer, you're probably no stranger to writing code. But have you ever stopped to think about the benefits of keeping a personal repository of your code? Think of it like a digital scrapbook, where you collect and organize all your coding adventures, tips, and tricks.",[302,14878,14879,14880,14883],{},"I keep one called ",[745,14881,14882],{},"Toolbox"," that I use for everything. It's a place to put things that don't belong anywhere else.",[318,14885,14887],{"id":14886},"one-off-learning","One-off Learning",[302,14889,14890],{},"Let's face it; we've all had those \"A-ha!\" moments where we figured out a tricky problem or learned a new skill. But what happens to that knowledge when you move on to the next project? It gets lost in the void of your brain, right? Instead, keep a personal repository. You're creating a journal of sorts, where you can store those \"A-ha!\" moments and reference them later. Think of it like a digital version of your favorite recipe book – only instead of cakes, you're collecting coding gems!",[318,14892,14894],{"id":14893},"journal-of-skills-you-learned","Journal of Skills You Learned",[302,14896,14897],{},"When you revisit an old piece of code or a problem you solved in the past, it's like re-examining a familiar friend. You'll catch yourself thinking, \"Ah, I did that! And look how clever I was!\" This process reinforces your skills and helps solidify them in your long-term memory. It's like exercising your coding muscles – the more you use them, the stronger they get!",[318,14899,14901],{"id":14900},"examples-i-have-in-my-toolbox","Examples I have in my toolbox",[302,14903,14904],{},"Now, let me give you some examples to illustrate these benefits:",[401,14906,14908],{"id":14907},"daily-note-taking","Daily Note-Taking",[302,14910,14911,14912,14919,14920,2388,14925,14929],{},"I'd bet most developers keep a scratch file somewhere. Used to pasting an error you're working on, quick tasks to remember to do. Meeting notes. Yeah, I keep all those in my toolbox repo. I even have a utility script so that when I run the command ",[335,14913,14916],{"href":14914,"rel":14915},"https:\u002F\u002Fgithub.com\u002FChrisTowles\u002Fdotfiles\u002Fblob\u002Fmain\u002Fcli\u002Fsrc\u002Fcommands\u002FtodayCommand.ts",[461],[745,14917,14918],{},"today"," to create a markdown file in my toolbox named with the date of the week.\nIf you find that useful, you may find other \"Zettelkasten method\" apps like ",[335,14921,14924],{"href":14922,"rel":14923},"https:\u002F\u002Fobsidian.md\u002F",[461],"obsidian",[335,14926,9190],{"href":14927,"rel":14928},"https:\u002F\u002Fevernote.com\u002F",[461]," useful. I've tried but just a weekly scratch file I can search has been what I've found most useful.",[401,14931,14933],{"id":14932},"sql","SQL",[302,14935,14936],{},"Remember that one off tricky SQL query you wrote using Common Table Expressions (CTEs)? I use them so rarely, but having an example in my own style always makes re-learning how to do them much easier! You can revisit that code and recall the logic behind it. Boom! One-off learning and skill reinforcement!",[401,14938,14940],{"id":14939},"bash-script-to-fix-a-problem","Bash Script to fix a Problem",[302,14942,14943,14944,14947,14948,14951],{},"Ah, yes, those pesky shell scripting issues! How does ",[745,14945,14946],{},"awk"," work again, or is it ",[745,14949,14950],{},"sed"," I should use in this case. When you write a bash script to fix a problem, you might think it's just a one-time solution. But what if you need to use that same or similar script again?",[401,14953,8080],{"id":14954},"other",[302,14956,14957],{},"Just odd things that don't really have a place.",[368,14959,14960,14963,14969],{},[371,14961,14962],{},"Profile Pic I normally use",[371,14964,14965,14966],{},"It's where I used to keep most of my dot files before moving them to their own public repo ",[335,14967,14187],{"href":7829,"rel":14968},[461],[371,14970,14971],{},"etc.",[318,14973,14975],{"id":14974},"less-time-spent-re-inventing-the-wheel","Less Time Spent Re-inventing the Wheel",[302,14977,14978],{},"Your personal repository becomes a treasure trove of tried-and-true solutions!",[318,14980,13760],{"id":13759},[302,14982,14983],{},"And hey, if you're still unsure, I'll give you another thing to consider: imagine having a collection of 10-20 code snippets or scripts that you've written over the last year. Now imagine 5-10 years. Those might seem insignificant on their own, but when combined, they become a valuable resource for learning and growth.",[302,14985,14986],{},"Now, go forth and create your personal repository! It doesn't have to be public, mine isn't.",{"title":515,"searchDepth":516,"depth":516,"links":14988},[14989,14990,14991,14997,14998],{"id":14886,"depth":516,"text":14887},{"id":14893,"depth":516,"text":14894},{"id":14900,"depth":516,"text":14901,"children":14992},[14993,14994,14995,14996],{"id":14907,"depth":523,"text":14908},{"id":14932,"depth":523,"text":14933},{"id":14939,"depth":523,"text":14940},{"id":14954,"depth":523,"text":8080},{"id":14974,"depth":516,"text":14975},{"id":13759,"depth":516,"text":13760},"2024-06-30","the perfect place to put everything that doesn't belong anywhere else",{"src":15002,"alt":15003},"\u002Fimages\u002Fblog\u002Ftoolbox-hand-reaching-in.png","A Toolbox with hand reaching in",{},{"title":21,"description":15000},"DQu59-oRkGNOxUbQPUDZZ0z-TPDhFEztR-Ch4k-bI2U",{"id":15008,"title":17,"authors":15009,"badge":15012,"body":15014,"date":15303,"description":15304,"extension":533,"image":15305,"meta":15307,"navigation":538,"path":18,"seo":15308,"status":540,"stem":19,"__hash__":15309},"posts\u002F2.blog\u002F20240623.using-conventional-commits.md",[15010],{"name":292,"to":293,"avatar":15011},{"src":295},{"label":15013},"Productivity",{"type":299,"value":15015,"toc":15290},[15016,15025,15028,15032,15035,15039,15042,15061,15065,15068,15108,15115,15119,15122,15142,15150,15155,15159,15162,15165,15169,15183,15186,15195,15199,15250,15254,15271,15276,15279,15281,15284,15287],[302,15017,15018,15019,15024],{},"As a developer, you're probably no stranger to the world of version control systems like Git. But even if you're well-versed in the basics of Git, using ",[335,15020,15023],{"href":15021,"rel":15022},"https:\u002F\u002Fwww.conventionalcommits.org\u002F",[461],"conventional commits"," can be a game-changer when it comes to communicating with your peers and yourself.",[302,15026,15027],{},"In this post, we'll take a deep dive into what conventional commits are, why they're important, and how to use them effectively. So, let's get started!",[318,15029,15031],{"id":15030},"step-1-what-are-conventional-commits","Step 1: What Are Conventional Commits?",[302,15033,15034],{},"A conventional commit is a type of commit message that follows a specific format, making it easy for others (and yourself) to understand the purpose and scope of each change.",[401,15036,15038],{"id":15037},"why-are-conventional-commits-important","Why Are Conventional Commits Important?",[302,15040,15041],{},"Using conventional commits has several benefits:",[368,15043,15044,15050],{},[371,15045,15046,15049],{},[326,15047,15048],{},"Better collaboration",": Conventional commits help team members work together more effectively, as everyone knows what to expect from a particular type of commit.",[371,15051,15052,15055,15056],{},[326,15053,15054],{},"Better release management:"," When you use conventional commits, it's easier to generate a changelog that reflects the changes in your release.\n",[368,15057,15058],{},[371,15059,15060],{},"Not a requirement for personal or many web projects, but many OSS projects need to generate a changelog.",[318,15062,15064],{"id":15063},"step-2-choose-your-commit-type","Step 2: Choose Your Commit Type",[302,15066,15067],{},"When writing your commit message, choose one of the following types:",[368,15069,15070,15076,15082,15096,15102],{},[371,15071,15072,15075],{},[745,15073,15074],{},"fix:"," For fixing bugs or resolving issues",[371,15077,15078,15081],{},[745,15079,15080],{},"fix(item):"," calling out which item was fixed",[371,15083,15084,15087,15088],{},[745,15085,15086],{},"feat:"," For adding new features or functionality\n",[368,15089,15090],{},[371,15091,15092,15095],{},[745,15093,15094],{},"feat(item):"," For calling out which feature",[371,15097,15098,15101],{},[745,15099,15100],{},"docs:"," For updating documentation or improving readability",[371,15103,15104,15107],{},[745,15105,15106],{},"chore:"," For maintenance tasks like dependency updates",[302,15109,15110,15111,15114],{},"I tend to use ",[335,15112,15023],{"href":15021,"rel":15113},[461]," styles for my commits. But not enforced, just manual best effort. However, some repos have strict enforcement to generate the changelog from the commits. I'll dig into that below.",[318,15116,15118],{"id":15117},"step-3-write-your-commit-message","Step 3: Write Your Commit Message",[302,15120,15121],{},"When writing your commit message, follow these best practices:",[368,15123,15124,15130,15136],{},[371,15125,15126,15129],{},[326,15127,15128],{},"Be concise:"," Keep your commit message short and to the point.",[371,15131,15132,15135],{},[326,15133,15134],{},"Use present tense:"," Instead of saying \"fixed,\" say \"fix.\"",[371,15137,15138,15141],{},[326,15139,15140],{},"Include relevant details:"," Add context or explanations where necessary.",[302,15143,15144,2377,15147],{},[326,15145,15146],{},"Example commit message:",[745,15148,15149],{},"fix: Update README.md to include new feature",[302,15151,15152],{},[467,15153],{"alt":515,"src":15154},"\u002Fimages\u002Fblog\u002Fconventional-commit-example-ui-pro.png",[318,15156,15158],{"id":15157},"step-4-make-it-a-habit","Step 4: Make It a Habit",[302,15160,15161],{},"At first, it may seem like a lot of work to write a commit message. But you'll find that writing good commit messages becomes easier as you get used to doing it. I also recommend committing more often.",[302,15163,15164],{},"I often teach people to think about making commits like save checkpoints in a video game. When you beat a boss, or complete a level, it creates a save point. Do the same with your commits. It makes it much easier to review and track down issues compared to a three-day coding bender where half the repo is changed in a single commit.",[318,15166,15168],{"id":15167},"strictly-enforce-conventional-commits","Strictly enforce conventional commits",[302,15170,15171,15172,15177,15178,1207],{},"Many open source projects use conventional commits, ",[335,15173,15176],{"href":15174,"rel":15175},"https:\u002F\u002Fgithub.com\u002Fvitejs\u002Fvite\u002Fblob\u002Fmain\u002F.github\u002Fcommit-convention.md",[461],"vite"," for example and some even enforce it via tools like ",[335,15179,15182],{"href":15180,"rel":15181},"https:\u002F\u002Fgithub.com\u002Fconventional-changelog\u002Fcommitlint",[461],"commitlint",[302,15184,15185],{},"This is great for a couple of reasons. The standard makes it easier to generate release notes and changelog from the commit messages.",[302,15187,15188,15189,15194],{},"In those cases I use the ",[335,15190,15193],{"href":15191,"rel":15192},"https:\u002F\u002Fgithub.com\u002Fcommitizen\u002Fcz-cli",[461],"commitizen"," tool to enforce the conventional commits.",[401,15196,15198],{"id":15197},"install","Install",[1119,15200,15202],{"className":3307,"code":15201,"language":3309,"meta":515,"style":515},"## Install\npnpm install -g commitizen\npnpm install -g cz-conventional-changelog\necho '{ \"path\": \"cz-conventional-changelog\" }' > ~\u002F.czrc\n",[745,15203,15204,15209,15221,15232],{"__ignoreMap":515},[1127,15205,15206],{"class":1129,"line":1130},[1127,15207,15208],{"class":1487},"## Install\n",[1127,15210,15211,15213,15215,15218],{"class":1129,"line":516},[1127,15212,13163],{"class":2246},[1127,15214,6295],{"class":1621},[1127,15216,15217],{"class":1621}," -g",[1127,15219,15220],{"class":1621}," commitizen\n",[1127,15222,15223,15225,15227,15229],{"class":1129,"line":523},[1127,15224,13163],{"class":2246},[1127,15226,6295],{"class":1621},[1127,15228,15217],{"class":1621},[1127,15230,15231],{"class":1621}," cz-conventional-changelog\n",[1127,15233,15234,15237,15239,15242,15244,15247],{"class":1129,"line":1146},[1127,15235,15236],{"class":1505},"echo",[1127,15238,1618],{"class":1501},[1127,15240,15241],{"class":1621},"{ \"path\": \"cz-conventional-changelog\" }",[1127,15243,1625],{"class":1501},[1127,15245,15246],{"class":1501}," >",[1127,15248,15249],{"class":1621}," ~\u002F.czrc\n",[401,15251,15253],{"id":15252},"usage","Usage",[1119,15255,15257],{"className":3307,"code":15256,"language":3309,"meta":515,"style":515},"## Usage\ngit cz\n\n",[745,15258,15259,15264],{"__ignoreMap":515},[1127,15260,15261],{"class":1129,"line":1130},[1127,15262,15263],{"class":1487},"## Usage\n",[1127,15265,15266,15268],{"class":1129,"line":516},[1127,15267,9595],{"class":2246},[1127,15269,15270],{"class":1621}," cz\n",[302,15272,15273],{},[467,15274],{"alt":515,"src":15275},"\u002Fimages\u002Fblog\u002Fconventional-commits.png",[302,15277,15278],{},"But be sure to review the rules for the repository you're contributing to.",[318,15280,13760],{"id":13759},[302,15282,15283],{},"Using conventional commits doesn't take much time. I've found it makes it easier to come up with commit messages. And it improves your code's readability and enhances collaboration. It's an easy habit to get into, and you'll find it a requirement for many open source projects.",[302,15285,15286],{},"Might as well start doing it everywhere.",[1698,15288,15289],{},"html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":515,"searchDepth":516,"depth":516,"links":15291},[15292,15295,15296,15297,15298,15302],{"id":15030,"depth":516,"text":15031,"children":15293},[15294],{"id":15037,"depth":523,"text":15038},{"id":15063,"depth":516,"text":15064},{"id":15117,"depth":516,"text":15118},{"id":15157,"depth":516,"text":15158},{"id":15167,"depth":516,"text":15168,"children":15299},[15300,15301],{"id":15197,"depth":523,"text":15198},{"id":15252,"depth":523,"text":15253},{"id":13759,"depth":516,"text":13760},"2024-06-23","Helping everyone to understand the commit history and its purpose",{"src":15275,"alt":15306},"A laptop with a dark matter theme",{},{"title":17,"description":15304},"HDenyW57d9KNcGB5QZelo2GE0aleN-8jTUOMk1AyLtw",{"id":15311,"title":13,"authors":15312,"badge":15315,"body":15316,"date":15602,"description":15603,"extension":533,"image":15604,"meta":15606,"navigation":538,"path":14,"seo":15607,"status":540,"stem":15,"__hash__":15608},"posts\u002F2.blog\u002F20220626.i-am-a-dark-matter-developer.md",[15313],{"name":292,"to":293,"avatar":15314},{"src":295},{"label":230},{"type":299,"value":15317,"toc":15588},[15318,15321,15327,15331,15339,15344,15353,15356,15364,15367,15371,15379,15388,15415,15418,15428,15431,15443,15446,15455,15459,15466,15476,15479,15482,15486,15489,15492,15495,15499,15519,15522,15526,15529,15532,15538,15542,15545,15550,15554,15557,15560,15564,15567,15571,15585],[302,15319,15320],{},"So a few things have happened lately that have made me reflect on my career and the type of developer I am.",[302,15322,15323,15324,1207],{},"And the conclusion I've come to is that I have become a ",[326,15325,15326],{},"Dark Matter Developer",[318,15328,15330],{"id":15329},"let-me-try-to-explain","Let me try to explain",[302,15332,15333,15334,1207],{},"Way back in 2012 I remember a post by Scott Hanselman called ",[335,15335,15338],{"href":15336,"rel":15337},"https:\u002F\u002Fwww.hanselman.com\u002Fblog\u002Fdark-matter-developers-the-unseen-99",[461],"Dark Matter Developers: The Unseen 99%",[330,15340,15341],{},[302,15342,15343],{},"You can't see dark matter, but we're pretty sure it's there. Not only is it there, but it's MOST of what's there. We know it and we can't see it. It never shows up.",[302,15345,15346,15347,15352],{},"The analogy was a good one. But at the time I had a ",[335,15348,15351],{"href":15349,"rel":15350},"https:\u002F\u002Fchristowles.blogspot.com\u002F",[461],"Blogspot blog"," with about half a million views. I was active in the developer community and even attended a VMWorld as a speaker on a panel.",[302,15354,15355],{},"But over time I stopped growing publicly.",[302,15357,15358,15359,15361],{},"I stopped posting at the request of a new employer.",[13199,15360],{},[920,15362,15363],{},"PS. I should have left that job that second but I didn't.",[302,15365,15366],{},"I've been thinking about my software career, not the Craftsmanship. Not just do I write tests or refactor but am I a good developer for the community and for my career.",[401,15368,15370],{"id":15369},"tweet-reply-and-re-tweet-from-a-programming-hero","Tweet reply and Re-tweet from a programming hero",[302,15372,15373,15374,15378],{},"First, you need to know that I never ",[335,15375,15377],{"href":293,"rel":15376},[461],"tweet",". I think less than ten times in my life.",[302,15380,15381,15382,15387],{},"Anyway, after using and reading the source code of ",[335,15383,15386],{"href":15384,"rel":15385},"https:\u002F\u002Fgithub.com\u002Fglideapps\u002Fglide-data-grid",[461],"glide data grid"," I just tweeted thanks, it deserved it.",[330,15389,15391,15410,15411],{"className":15390},[333],[302,15392,15394,15395,1996,15399,15403,15404,15406,15407],{"lang":12711,"dir":15393},"ltr","Thank You ",[335,15396,15398],{"href":15397},"https:\u002F\u002Ftwitter.com\u002Fglideapps?ref_src=twsrc%5Etfw","@glideapps",[335,15400,15402],{"href":15401},"https:\u002F\u002Ftwitter.com\u002Fjassmith87?ref_src=twsrc%5Etfw","@jassmith87","! Your Glide Data Grid is without a doubt the best data grid on the internet. I'm even using it in a vue app because its just that much better than everything else! ",[13199,15405],{},"And trust me I looked. ",[335,15408,15409],{"href":15409},"https:\u002F\u002Ft.co\u002FdPsxTYuF2Z","— Chris Towles (@Chris_Towles) ",[335,15412,15414],{"href":15413},"https:\u002F\u002Ftwitter.com\u002FChris_Towles\u002Fstatus\u002F1539814088666238976?ref_src=twsrc%5Etfw","June 23, 2022",[302,15416,15417],{},"To my shock I got a reply from Jason himself.",[330,15419,15421,15424,15425],{"className":15420},[333],[302,15422,15423],{"lang":12711,"dir":15393},"Thank you so much amigo :) Let me know if you have any problems.","— Jason Smith (@jassmith87) ",[335,15426,15414],{"href":15427},"https:\u002F\u002Ftwitter.com\u002Fjassmith87\u002Fstatus\u002F1539816474054840320?ref_src=twsrc%5Etfw",[302,15429,15430],{},"And he even retweeted my tweet.",[330,15432,15434,15424,15440],{"className":15433},[333],[302,15435,15436,15437],{"lang":12711,"dir":15393},"Shameless retweet because I'm proud. ",[335,15438,15439],{"href":15439},"https:\u002F\u002Ft.co\u002Ft23VqcI7Mq",[335,15441,15414],{"href":15442},"https:\u002F\u002Ftwitter.com\u002Fjassmith87\u002Fstatus\u002F1539816533261619200?ref_src=twsrc%5Etfw",[302,15444,15445],{},"I was really surprised. It made my day and more importantly made me think. I use Open Source all the time and never give back. I learn so much by standing on the shoulders of giants. I have the skills to help, to contribute to the open source community, and never find the time. And to Jason it's not a Shameless retweet, you should be proud. Thanks for sharing your code with the rest of us.",[330,15447,15448],{},[302,15449,15450,15451,15454],{},"TODO: I will do another post about just the amazing ",[335,15452,15386],{"href":15384,"rel":15453},[461],". It's basically a fully functional, easy to use data grid with really similar Excel or Google Sheets-like functionality for things like keyboard navigation, filling, filtering, copying, and pasting. It is a really great library considering how historically bad data grid libraries are.",[401,15456,15458],{"id":15457},"the-github-copilot-debate","The Github Copilot Debate",[302,15460,15461,15462,15465],{},"So while everyone I follow on Twitter had a take on ",[745,15463,15464],{},"Microsoft\u002FGithub"," beginning to charge for the service.",[330,15467,15469,15472,15473],{"className":15468},[333],[302,15470,15471],{"lang":12711,"dir":15393},"It would have been very simple for github to be ethical when they made copilot. All they had to do was add an opt-in to github where you could mark your project as allowing copilot or not. Whether or not what they're doing turns out to be legal, they eschewed the ethical option.","— Casey Muratori (@cmuratori) ",[335,15474,15414],{"href":15475},"https:\u002F\u002Ftwitter.com\u002Fcmuratori\u002Fstatus\u002F1540078652246749184?ref_src=twsrc%5Etfw",[302,15477,15478],{},"Every developer I follow had code that had been used in training github copilot.",[302,15480,15481],{},"I had a different take, I had already got my credit card and was quick to pay for the GitHub copilot service. I should have been more impacted by the problem. It didn't hurt me and it should have.",[401,15483,15485],{"id":15484},"career-direction","Career Direction",[302,15487,15488],{},"At work, at times I'm not sure how much I contribute to the big picture. I work on my projects and help others but can not always tell if the work I do is impacting the future of the company.",[302,15490,15491],{},"I think most people feel this way and we all have some impostor syndrome.",[302,15493,15494],{},"The issue is I have some ideas on how to change that but wasn't sure if the work that would require is the direction I want my career to go. It would mean a lot more systems architecture and maybe DevOps than strict development. I concluded that I am ok with that.",[318,15496,15498],{"id":15497},"solution","Solution",[302,15500,15501,15502,1199,15507,15512,15513,15518],{},"I follow people like ",[335,15503,15506],{"href":15504,"rel":15505},"https:\u002F\u002Ftwitter.com\u002Fjassmith87",[461],"jassmith87",[335,15508,15511],{"href":15509,"rel":15510},"https:\u002F\u002Ftwitter.com\u002Fantfu7",[461],"antfu7"," (maybe the most productive developer on the planet), and ",[335,15514,15517],{"href":15515,"rel":15516},"https:\u002F\u002Ftwitter.com\u002Fremi_rousselet",[461],"remi_rousselet",". I learn from these giants and stand on their shoulders. I should try to let some others stand on mine.",[302,15520,15521],{},"I'm going to break the problem into a few weekly and monthly tasks. The goal is to change my habits, not to set impossible goals.",[401,15523,15525],{"id":15524},"goal-commit-publicly-at-least-twice-per-week","Goal: Commit Publicly at least twice per week",[302,15527,15528],{},"So this should hopefully be clear.",[302,15530,15531],{},"I constantly write code, at work, on weekends, and late nights but tend to continue working on whatever work project I found interesting. I've done this for the last 25 years.... (another post on realizing I've been doing this a long time later.)",[302,15533,15534,15537],{},[326,15535,15536],{},"Rules:"," Two public commits per week, only one of which can be a blog post.",[401,15539,15541],{"id":15540},"goal-at-least-one-pr-merged-into-an-open-source-project-quarterly","Goal: at least one PR merged into an Open Source Project quarterly",[302,15543,15544],{},"I use tons of Open Source and it's time I started giving back to the community that has given me and the world so much. This career lets me live a comfortable life with my wife and kids and I should help others do the same.",[302,15546,15547,15549],{},[326,15548,15536],{}," Must have more than 100 Stars.",[401,15551,15553],{"id":15552},"goal-finish-a-certification","Goal: Finish a Certification",[302,15555,15556],{},"I am a jack of all trades. I haven't focused in any one area, and considering how much AWS work I do, I'm going to focus there, completing a certification as a measurable task.",[302,15558,15559],{},"This seems like a good habit to improve my skills.",[401,15561,15563],{"id":15562},"results","Results",[302,15565,15566],{},"The plan is to follow up on this post next month and see if I changed. I set a calendar event to update this post next month.",[318,15568,15570],{"id":15569},"follow-up-on-2022-07-14","Follow up on 2022-07-14",[302,15572,15573,15574,15579,15580,1207],{},"So I have been committing publicly more and even got a simple PR merged into ",[335,15575,15578],{"href":15576,"rel":15577},"https:\u002F\u002Fgithub.com\u002Fvitest-dev\u002Fvitest\u002Fpull\u002F1558",[461],"Vitest"," and opened another one for ",[335,15581,15584],{"href":15582,"rel":15583},"https:\u002F\u002Fgithub.com\u002Fvuejs\u002Fvitepress\u002F",[461],"Vitepress",[302,15586,15587],{},"It is a start!",{"title":515,"searchDepth":516,"depth":516,"links":15589},[15590,15595,15601],{"id":15329,"depth":516,"text":15330,"children":15591},[15592,15593,15594],{"id":15369,"depth":523,"text":15370},{"id":15457,"depth":523,"text":15458},{"id":15484,"depth":523,"text":15485},{"id":15497,"depth":516,"text":15498,"children":15596},[15597,15598,15599,15600],{"id":15524,"depth":523,"text":15525},{"id":15540,"depth":523,"text":15541},{"id":15552,"depth":523,"text":15553},{"id":15562,"depth":523,"text":15563},{"id":15569,"depth":516,"text":15570},"2022-06-26","Reflecting on my career and the type of developer I am.",{"src":15605,"alt":15306},"\u002Fimages\u002Fblog\u002Fdark-matter-closing-laptop.jpg",{},{"title":13,"description":15603},"TZcYJ_ng60cwsuck6FA9Qeau8VF5Q4b1QrwUA4kRxAo",{"id":15610,"title":9,"authors":15611,"badge":15614,"body":15615,"date":15908,"description":15909,"extension":533,"image":15910,"meta":15913,"navigation":538,"path":10,"seo":15914,"status":540,"stem":11,"__hash__":15915},"posts\u002F2.blog\u002F20220109.migrate-vue-2-with-vuetify-and-jest-to-vite-and-vitest.md",[15612],{"name":292,"to":293,"avatar":15613},{"src":295},null,{"type":299,"value":15616,"toc":15902},[15617,15649,15670,15692,15696,15711,15714,15719,15723,15733,15754,15760,15777,15785,15789,15809,15828,15831,15866,15869,15879,15882,15886],[302,15618,15619,15620,1996,15625,15630,15631,15635,15636,15641,15642,15645,15646,15648],{},"So my main project at work is a ",[335,15621,15624],{"href":15622,"rel":15623},"https:\u002F\u002Fvuejs.org\u002F",[461],"Vue 2",[335,15626,15629],{"href":15627,"rel":15628},"https:\u002F\u002Fvuetifyjs.com\u002F",[461],"Vuetify 2"," site, but privately I have been playing with ",[335,15632,15634],{"href":15622,"rel":15633},[461],"Vue 3"," and loved the ",[335,15637,15640],{"href":15638,"rel":15639},"https:\u002F\u002Fstaging.vuejs.org\u002Fguide\u002Fintroduction.html#api-styles",[461],"Composition API"," to avoid ",[745,15643,15644],{},"mixins",". Due to some new features, we are planning to build soon. I wanted to write it in ",[745,15647,15634],{},", to prevent needing to migrate it later.",[302,15650,15651,15652,15654,15655,15657,15658,15663,15664,15666,15667,15669],{},"I wanted to investigate how to migrate from ",[745,15653,15624],{}," to ",[745,15656,15634],{},". Furthermore, I planned to use the amazing ",[335,15659,15662],{"href":15660,"rel":15661},"https:\u002F\u002Fv3.vuejs.org\u002Fguide\u002Fmigration\u002Fmigration-build.html",[461],"Migration Build"," to allow ",[745,15665,15634],{}," to use most ",[745,15668,15624],{}," components during a migration period. Which is much less risky for a large project.",[302,15671,15672,15673,15676,15677,15680,15681,15684,15685,1996,15688,15691],{},"I took a rough hack at doing the migration leaving only a handful of pages to test over a day to see how likely the migration was. I had to upgrade ",[745,15674,15675],{},"Vuetify"," from ",[745,15678,15679],{},"2.X.X"," to an early beta version of ",[745,15682,15683],{},"3.X.X",". However I was unable to get anything more than a few ",[745,15686,15687],{},"v-cards",[745,15689,15690],{},"v-btn"," was working. A peer on another work team had said as much, but I hadn't listened. My bad.",[318,15693,15695],{"id":15694},"vuetify-3-is-not-ready-as-of-2021-12-18","Vuetify 3 is not ready as of 2021-12-18",[302,15697,15698,15699,15701,15702,15704,15705,15710],{},"Unfortunately, ",[745,15700,15675],{}," is not ready for ",[745,15703,15634],{}," as of 2021-12-18. I tried the beta ",[335,15706,15709],{"href":15707,"rel":15708},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@vuetify\u002Fnightly",[461],"@vuetify\u002Fnightly",", but it's far from ready. The documentation said it's to ship in February but looking at the missing functionality I doubted it.",[302,15712,15713],{},"I joined the discord community and got caught up on the most recent updates. Basically it's going to take a little longer which is ok. It's open source and it's not like I've contributed any pull requests. It's been a great framework and I recommend it to everyone.",[302,15715,15716,15717,1207],{},"I'll update this post when it is ready and has support for ",[745,15718,15634],{},[318,15720,15722],{"id":15721},"original-goal-vue-3","Original Goal - Vue 3",[302,15724,15725,15726,15729,15730,15732],{},"So the dream would be to get to ",[745,15727,15728],{},"vue 3",", but that's not practical without ",[745,15731,15675],{},". That leaves two options:",[368,15734,15735,15740],{},[371,15736,5322,15737,15739],{},[745,15738,15675],{}," with a different component framework",[371,15741,15742,15743,15745,15746,15749],{},"Don't upgrade to ",[745,15744,15634],{}," and keep ",[745,15747,15748],{},"Vuetify 2.X.X",[368,15750,15751],{},[371,15752,15753],{},"Upgrade to v3 once it's ready",[302,15755,15756,15757,15759],{},"To be clear, replacing ",[745,15758,15675],{}," has almost no upside for my employer.",[368,15761,15762,15765,15768,15771,15774],{},[371,15763,15764],{},"It would take a lot of time to convert the large codebase.",[371,15766,15767],{},"It is likely to introduce bugs",[371,15769,15770],{},"No improvement for the user",[371,15772,15773],{},"Time and effort retraining the team.",[371,15775,15776],{},"Moving away from a framework others in the company also use.",[302,15778,15779,15780,1996,15782,1207],{},"So it's pretty easy to decide to wait on migrating to ",[745,15781,15634],{},[745,15783,15784],{},"Vuetify 3",[318,15786,15788],{"id":15787},"new-goal-vite-and-composition-api-with-vue-2","New Goal - Vite and Composition API with vue 2",[302,15790,15791,15792,15794,15795,15800,15801,1996,15805,15808],{},"Thinking about the problem I realized that a lot of the benefits of the migration to ",[745,15793,15728],{}," was the improvement of the tooling. ",[335,15796,15799],{"href":15797,"rel":15798},"https:\u002F\u002Fvitejs.dev\u002Fguide\u002Fwhy.html",[461],"Vite"," is so fast you have to see to believe. I follow ",[335,15802,12354],{"href":15803,"rel":15804},"https:\u002F\u002Ftwitter.com\u002Fyouyuxi",[461],[335,15806,12344],{"href":15509,"rel":15807},[461]," on twitter so have been watching it come to life.",[302,15810,15811,15812,15814,15815,15820,15821,15824,15825,15827],{},"So I decided to try to migrate to ",[745,15813,15176],{}," and allow the ",[335,15816,15819],{"href":15817,"rel":15818},"https:\u002F\u002Fgithub.com\u002Fvuejs\u002Fcomposition-api",[461],"@vue\u002Fcomposition-api"," with ",[745,15822,15823],{},"vue 2",". This would also make it easier to upgrade to ",[745,15826,15634],{}," once it's ready.",[302,15829,15830],{},"So the new goal looks like this.",[368,15832,15833,15841,15847,15852,15857,15862],{},[371,15834,15835,15836,1996,15838],{},"keep ",[745,15837,15823],{},[745,15839,15840],{},"vuetify 2.X.X",[371,15842,15843,15844],{},"remove ",[745,15845,15846],{},"@vue\u002Fcli-service",[371,15848,15843,15849],{},[745,15850,15851],{},"webpack",[371,15853,15843,15854],{},[745,15855,15856],{},"babel",[371,15858,15859,15860],{},"add ",[745,15861,15176],{},[371,15863,15859,15864],{},[745,15865,15819],{},[302,15867,15868],{},"This gives a lot of benefits and a clear upgrade path!",[302,15870,15871,15872,1996,15874,15820,15876,15878],{},"It was pretty easy to clone a simple example repo with ",[745,15873,15823],{},[745,15875,15840],{},[745,15877,15846],{},". And tested out the upgrade there.",[302,15880,15881],{},"Once that worked I then did the upgrade on the more complex monorepo at work.",[318,15883,15885],{"id":15884},"update-2022-07-12","Update 2022-07-12",[302,15887,15888,15889,15894,15895,15898,15899,6566],{},"With ",[335,15890,15893],{"href":15891,"rel":15892},"https:\u002F\u002Fblog.vuejs.org\u002Fposts\u002Fvue-2-7-naruto.html",[461],"Vue 2.7 \"Naruto\" Released"," I'm now on ",[745,15896,15897],{},"Vue 2.7"," and was able to remove the ",[335,15900,15819],{"href":15817,"rel":15901},[461],{"title":515,"searchDepth":516,"depth":516,"links":15903},[15904,15905,15906,15907],{"id":15694,"depth":516,"text":15695},{"id":15721,"depth":516,"text":15722},{"id":15787,"depth":516,"text":15788},{"id":15884,"depth":516,"text":15885},"2022-01-09","So my main project at work is a Vue 2 and Vuetify 2 site, but privately I have been playing with Vue 3 and loved the Composition API to avoid mixins. Due to some new features, we are planning to build soon. I wanted to write it in Vue 3, to prevent needing to migrate it later.",{"src":15911,"alt":15912},"\u002Fimages\u002Fblog\u002Fcss-migration.jpg","css on screen",{},{"title":9,"description":15909},"uKTT9kQfTbhkza-0AeImkqv6_Yg2eu0yl7RmbaTAZNA",{"id":15917,"title":5,"authors":15918,"badge":15614,"body":15921,"date":15990,"description":15925,"extension":533,"image":15991,"meta":15994,"navigation":538,"path":6,"seo":15995,"status":540,"stem":7,"__hash__":15996},"posts\u002F2.blog\u002F20211217.you-do-not-have-time-to-not-have-tests.md",[15919],{"name":292,"to":293,"avatar":15920},{"src":295},{"type":299,"value":15922,"toc":15985},[15923,15926,15929,15933,15936,15939,15942,15945,15959,15962,15966,15969,15972,15975,15979,15982],[302,15924,15925],{},"So first a full disclosure: I was late to get on the testing bandwagon.",[302,15927,15928],{},"It's shamefully obvious now, but I had heard about testing for years before I understood its value. I wish I had fully incorporated it into my development practices sooner. So maybe I can convince you to do the same.",[318,15930,15932],{"id":15931},"life-without-tests","Life without Tests",[302,15934,15935],{},"You may have thought you didn't have time to write tests. You ship features fast and adding tests would slow you down. And the first week or two of a project you may be right.",[302,15937,15938],{},"But the good news, the project is a success. Now users want new features and more features. You need to maintain this project for a long time. Maybe years.",[302,15940,15941],{},"You need to add features, add different code paths and scenarios. How do you ensure that new features work and old features didn't break?",[302,15943,15944],{},"You manually just have to test them. Things like:",[368,15946,15947,15950,15953,15956],{},[371,15948,15949],{},"Account creation, login, logout, etc.",[371,15951,15952],{},"User profile, settings, etc.",[371,15954,15955],{},"User's posts, comments, etc.",[371,15957,15958],{},"checkout and payment, etc.",[302,15960,15961],{},"But because your project is a success, you can't be breaking things in production. So you have to be very careful. Every new feature affects the whole system. It's slow to test everything for every change, and you can't refactor or make large changes because the impact is too high to risk breaking things.",[318,15963,15965],{"id":15964},"life-with-tests","Life with Tests",[302,15967,15968],{},"At the start of the project, decide to write a few tests. Not everything but happy paths. It takes a bit of time, but it's worth it. You have confidence that things are likely to work before deploying them.",[302,15970,15971],{},"As you add people, and you find bugs, you can add tests and the bugs stay fixed.",[302,15973,15974],{},"Now you decide that you have some Tech Debt that you need to address, but the change impacts the entire system. That's Ok, you can make big changes and your tests will likely ensure that you find the issues instead of your customers. Developers can submit Pull Requests if the tests pass, so chances are high it's good to merge. It might not be perfect, but it can't be so bad that happy paths fail to work.",[318,15976,15978],{"id":15977},"long-term","Long Term",[302,15980,15981],{},"Now guess which product will be faster to deliver and make changes on. Which one is it easier to onboard new developers?",[302,15983,15984],{},"Add the tests and thank me later.",{"title":515,"searchDepth":516,"depth":516,"links":15986},[15987,15988,15989],{"id":15931,"depth":516,"text":15932},{"id":15964,"depth":516,"text":15965},{"id":15977,"depth":516,"text":15978},"2021-12-17",{"src":15992,"alt":15993},"\u002Fimages\u002Fblog\u002Fblog-passing-tests.png","picture of tests passing in vitest",{},{"title":5,"description":15925},"nKyfLmYQ2NXkf2g-Fpyvzu8I_mUFeqkC2lGygnhWYik",1776221196164]