<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Llm | Roy Gabriel</title><link>https://roygabriel.dev/tags/llm/</link><description>Roy Gabriel: DevOps Architect &amp; Applied AI Engineer. Technical blog on Go, MCP servers, Kubernetes, and production AI systems.</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Fri, 27 Feb 2026 03:18:04 +0000</lastBuildDate><atom:link href="https://roygabriel.dev/tags/llm/index.xml" rel="self" type="application/rss+xml"/><item><title>Agent Swarms: The New Workforce Architects and Engineers Must Lead</title><link>https://roygabriel.dev/blog/agent-swarms-new-workforce/</link><pubDate>Thu, 26 Feb 2026 13:00:00 -0500</pubDate><guid>https://roygabriel.dev/blog/agent-swarms-new-workforce/</guid><description>&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;&lt;strong&gt;As-of note:&lt;/strong&gt; This is a production engineering perspective based on building and running agent swarms in production in early 2026. The workflows, numbers, and fine-tuning example come from real runs on my hardware and standards.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="why-this-shift-keeps-showing-up"&gt;Why this shift keeps showing up&lt;/h2&gt;
&lt;p&gt;If you build production systems long enough, you see the same pattern:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The “tool choice” is not what breaks velocity.&lt;/li&gt;
&lt;li&gt;The operational model and who does the work usually are.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When architects and engineers compare traditional coding to agent swarms, they are really asking:&lt;/p&gt;</description><content:encoded>
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;&lt;strong&gt;As-of note:&lt;/strong&gt; This is a production engineering perspective based on building and running agent swarms in production in early 2026. The workflows, numbers, and fine-tuning example come from real runs on my hardware and standards.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="why-this-shift-keeps-showing-up"&gt;Why this shift keeps showing up&lt;/h2&gt;
&lt;p&gt;If you build production systems long enough, you see the same pattern:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The “tool choice” is not what breaks velocity.&lt;/li&gt;
&lt;li&gt;The operational model and who does the work usually are.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When architects and engineers compare traditional coding to agent swarms, they are really asking:&lt;/p&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;“What will it cost to ship features at scale in the next 12 to 36 months, and who will actually build them?”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Single agents autocomplete code. Agent swarms plan features, assign tasks, review security, run tests, and deploy. The output is cleaner and more consistent than what most senior engineers produce alone.&lt;/p&gt;
&lt;p&gt;Anthropic&amp;rsquo;s 2026 Agentic Coding Trends Report shows single agents evolving into coordinated teams that handle long-running tasks across the full development lifecycle. Multi-agent orchestration is the breakthrough.&lt;/p&gt;
&lt;p&gt;Forbes reported in December 2025 that Gartner expects 40 percent of enterprise applications to embed task-specific agents by the end of 2026. Orchestrated swarms already deliver 30 to 50 percent faster feature delivery in early adopters.&lt;/p&gt;
&lt;p&gt;O&amp;rsquo;Reilly&amp;rsquo;s Signals for 2026 confirms the pattern: engineers move from writing code to orchestrating agents. Fundamentals stay essential. The difference is scale.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Agent swarms already build production code at higher quality and speed than the top 1 percent of FAANG engineers.&lt;/li&gt;
&lt;li&gt;The new job is writing precise specs, designing the agent workforce, and verifying outcomes.&lt;/li&gt;
&lt;li&gt;I built &lt;a href="https://cruvero.ai" target="_blank" rel="noopener noreferrer"&gt;Cruvero&lt;/a&gt;
exactly for this model. It is the production control plane that manages swarms in production.&lt;/li&gt;
&lt;li&gt;In one run I used &lt;a href="https://cruvero.ai" target="_blank" rel="noopener noreferrer"&gt;Cruvero&lt;/a&gt;
to prep my entire personal knowledge base and fine-tune Qwen2.5-Coder-72B on two RTX 5090 GPUs. The resulting model now writes code exactly to my standards.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cruvero.ai" target="_blank" rel="noopener noreferrer"&gt;Cruvero&lt;/a&gt;
will be released as open source in the next two weeks so anyone can run the same production-grade agent swarm control plane.&lt;/li&gt;
&lt;li&gt;Start today or watch the gap widen.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="contents"&gt;Contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#what-agent-swarms-do-today"&gt;What Agent Swarms Do Today&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cruvero.ai" target="_blank" rel="noopener noreferrer"&gt;Cruvero&lt;/a&gt;
as the &lt;a href="#cruvero-as-the-working-example"&gt;Working Example&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#the-new-role-for-architects-and-engineers"&gt;The New Role for Architects and Engineers&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#why-you-must-start-today"&gt;Why You Must Start Today&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#references"&gt;References&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="what-agent-swarms-do-today"&gt;What Agent Swarms Do Today&lt;/h2&gt;
&lt;p&gt;A single agent writes a function. A swarm plans an entire feature, breaks it into tasks, assigns roles, iterates on failures, runs tests, and deploys. The output is cleaner, more consistent, and more reliable than what most senior engineers produce alone.&lt;/p&gt;
&lt;p&gt;Multi-agent orchestration lets one agent plan, another implement, a third review for security, and a fourth measure performance. They collaborate without human prompts for hours or days.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="cruvero-as-the-working-example"&gt;&lt;a href="https://cruvero.ai" target="_blank" rel="noopener noreferrer"&gt;Cruvero&lt;/a&gt;
as the Working Example&lt;/h2&gt;
&lt;p&gt;Over the last 2 months on weekends and nights, I built &lt;a href="https://cruvero.ai" target="_blank" rel="noopener noreferrer"&gt;Cruvero&lt;/a&gt;
as a full workflow builder and the complete DevOps/SRE agent swarm platform. It is 350k lines of clean Go and React running as a production control plane, with a clean UI and API layer for knowledge bases, multi-agent runs, agent registration, cost tracking, flows, and MCP bindings in Kubernetes. In early 2026, I have not seen another platform that ships this full stack in one place.&lt;/p&gt;
&lt;p&gt;Core capabilities include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Knowledge bases that store versioned domain context so agents never repeat mistakes&lt;/li&gt;
&lt;li&gt;Runs page for launching, monitoring, and intervening in complex multi-agent workflows with patterns like Delegate&lt;/li&gt;
&lt;li&gt;Agents page that lets you register, trust-score, deploy, and bind agents directly from the UI&lt;/li&gt;
&lt;li&gt;Incident triage that runs faster than human response, then posts root-cause analysis and recommended fixes directly into Slack or Microsoft Teams&lt;/li&gt;
&lt;li&gt;Pre-run previews, compliance checks, per-agent overrides, full audit trails, and cost tracking&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This turns raw agent swarms into a manageable, auditable workforce. This week the platform reached the point where its own agent swarms are building new features inside &lt;a href="https://cruvero.ai" target="_blank" rel="noopener noreferrer"&gt;Cruvero&lt;/a&gt;
itself.&lt;/p&gt;
&lt;p&gt;In one recent run, a swarm of 12 agents took a high-level spec for a new MCP gateway, generated the Go handlers, added observability, wrote tests, and produced a Helm chart ready for deployment. The entire process took 47 minutes. I reviewed the plan, approved two overrides, and signed off. The code passed every gate I set.&lt;/p&gt;
&lt;p&gt;Here is a concrete example of how deeply I integrated my own standards. This week I used &lt;a href="https://cruvero.ai" target="_blank" rel="noopener noreferrer"&gt;Cruvero&lt;/a&gt;
to create a domain-specific fine-tuned model. I pointed the swarm at my private knowledge base: every personal(not employer code) code example I have written in the last five years, my strict documentation standards (every public function must include invariants, performance notes, and failure modes in a precise JSDoc format), my architecture standards (hexagonal with CQRS and explicit boundaries), and my full infrastructure layout (multi-region Kubernetes with Cilium CNI, ArgoCD GitOps, external secrets, and cross-cluster service mesh using Istio).&lt;/p&gt;
&lt;p&gt;The swarm prepped the entire dataset in 18 minutes. It extracted, cleaned, deduplicated, and converted everything into instruction-response pairs that perfectly match the way I write and review code. Then it launched a QLoRA fine-tune of Qwen2.5-Coder-72B across my two RTX 5090 GPUs. The training completed overnight. The resulting model, now called &lt;a href="https://cruvero.ai" target="_blank" rel="noopener noreferrer"&gt;Cruvero&lt;/a&gt;
-Gabriel-72B, is registered directly inside the agent swarm as a first-class capability.&lt;/p&gt;
&lt;p&gt;When I give the swarm a new spec today, it calls my fine-tuned model for every code generation step. The output follows my exact coding style, documentation format, architecture patterns, and infrastructure conventions without any manual correction. The swarm literally thinks and builds like I do, at 100 times the speed.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://cruvero.ai" target="_blank" rel="noopener noreferrer"&gt;Cruvero&lt;/a&gt;
will be released as open source in the next two weeks so any engineer or team can self-host the same production-grade agent swarm control plane I use daily.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="the-new-role-for-architects-and-engineers"&gt;The New Role for Architects and Engineers&lt;/h2&gt;
&lt;p&gt;You will spend your time on three things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Write precise specification documents.&lt;/strong&gt; Define goals, constraints, acceptance criteria, security boundaries, and stop rules. These become the source of truth the swarm follows.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Design the agent workforce.&lt;/strong&gt; Choose which agents handle planning, implementation, review, and verification. Set trust scores, capabilities, and escalation paths.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Verify and steer.&lt;/strong&gt; Run preflight checks, inspect outputs against intent, and adjust the swarm in real time. Your judgment determines whether the final system meets business needs.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is harder than writing code. It requires deep systems thinking, clear communication, and production discipline. The best architects already excel at it. The rest must learn fast.&lt;/p&gt;
&lt;p&gt;Pragmatic Engineer noted in January 2026 that teams where AI writes 90 percent of the code still need senior engineers for architecture decisions and coherence. Karpathy has said the same: technical expertise becomes more valuable because skilled people extract far more from agents.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="why-you-must-start-today"&gt;Why You Must Start Today&lt;/h2&gt;
&lt;p&gt;The gap between those who manage agent swarms and those who do not will widen quickly. In 12 months, the best teams will ship features that used to take quarters. In 36 months, organizations without swarm capability will struggle to compete on velocity and quality.&lt;/p&gt;
&lt;p&gt;Start small. Take one workflow you own. Break it into phases. Build a prompt library. Run a swarm on a non-critical task. Measure the output against your own work. Iterate.&lt;/p&gt;
&lt;p&gt;The tools exist now: Claude Code, Codex, open MCP gateways, and platforms like &lt;a href="https://cruvero.ai" target="_blank" rel="noopener noreferrer"&gt;Cruvero&lt;/a&gt;
. The question is whether you will lead the workforce or watch someone else do it.&lt;/p&gt;
&lt;p&gt;The next generation of software systems will be built by agent swarms under human direction. Architects and engineers who master this model will define the future. Those who wait will find their skills replaced.&lt;/p&gt;
&lt;p&gt;The shift is here. Lead it.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Anthropic. 2026 Agentic Coding Trends Report. January 2026.&lt;/li&gt;
&lt;li&gt;Minevich, Mark. &amp;ldquo;Agentic AI Takes Over — 11 Shocking 2026 Predictions.&amp;rdquo; Forbes. December 31, 2025.&lt;/li&gt;
&lt;li&gt;O&amp;rsquo;Reilly Media. &amp;ldquo;Signals for 2026.&amp;rdquo; January 9, 2026.&lt;/li&gt;
&lt;li&gt;Various sources on Karpathy statements compiled in Pragmatic Engineer and The New Stack, 2025–2026.&lt;/li&gt;
&lt;/ol&gt;</content:encoded></item><item><title>LLM Development Guide</title><link>https://roygabriel.dev/blog/llm-development-guide/</link><pubDate>Mon, 16 Feb 2026 12:00:00 -0500</pubDate><guid>https://roygabriel.dev/blog/llm-development-guide/</guid><description>&lt;p&gt;This series turns LLM assistance into something you can run repeatedly without losing context.&lt;/p&gt;
&lt;p&gt;You will be able to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Turn vague work into explicit plans with verification and stop rules.&lt;/li&gt;
&lt;li&gt;Write prompt documents that survive across sessions and handoffs.&lt;/li&gt;
&lt;li&gt;Run large projects with phase documents and phase implementation prompt sets.&lt;/li&gt;
&lt;li&gt;Preserve state with work notes so you can resume deterministically.&lt;/li&gt;
&lt;li&gt;Execute in small units with review discipline and commit discipline.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Last updated: 2026-02-16&lt;/p&gt;</description><content:encoded>&lt;p&gt;This series turns LLM assistance into something you can run repeatedly without losing context.&lt;/p&gt;
&lt;p&gt;You will be able to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Turn vague work into explicit plans with verification and stop rules.&lt;/li&gt;
&lt;li&gt;Write prompt documents that survive across sessions and handoffs.&lt;/li&gt;
&lt;li&gt;Run large projects with phase documents and phase implementation prompt sets.&lt;/li&gt;
&lt;li&gt;Preserve state with work notes so you can resume deterministically.&lt;/li&gt;
&lt;li&gt;Execute in small units with review discipline and commit discipline.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Last updated: 2026-02-16&lt;/p&gt;
&lt;p&gt;Questions? Contact me via my site contact form.&lt;/p&gt;
&lt;p&gt;Found an issue? Open a GitHub issue.&lt;/p&gt;</content:encoded></item><item><title>Chapter 16: Worked Example: Converting an Ansible Playbook to a Go Temporal Workflow</title><link>https://roygabriel.dev/blog/llm-development-guide/15-worked-example-ansible-to-temporal/</link><pubDate>Fri, 13 Feb 2026 09:00:00 -0500</pubDate><guid>https://roygabriel.dev/blog/llm-development-guide/15-worked-example-ansible-to-temporal/</guid><description>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 16 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/14-worked-example-helm-chart/"&gt;Chapter 15: Worked Example: Creating a Helm Chart From a Reference Chart&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to migrate a procedural automation (for example, an Ansible playbook) into a durable Temporal workflow:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Extract discrete steps from the playbook.&lt;/li&gt;
&lt;li&gt;Map steps to activities.&lt;/li&gt;
&lt;li&gt;Implement a workflow that follows your team&amp;rsquo;s existing Temporal patterns.&lt;/li&gt;
&lt;li&gt;Add verification and tests so the migration is not faith-based.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Start from a working reference workflow in your repo.&lt;/li&gt;
&lt;li&gt;Paste both the playbook and the reference into the planning prompt.&lt;/li&gt;
&lt;li&gt;Define activities first, then the workflow.&lt;/li&gt;
&lt;li&gt;Verify with Temporal workflow tests and any integration checks you can run safely.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#scenario"&gt;Scenario&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#reference-inputs"&gt;Reference inputs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#plan-and-phase-structure"&gt;Plan and phase structure&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#implementation-skeleton-go"&gt;Implementation skeleton (Go)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#gotchas"&gt;Gotchas&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="scenario"&gt;Scenario&lt;/h2&gt;
&lt;p&gt;Example: convert a playbook that creates a Kubernetes namespace and resource quota into a Temporal workflow.&lt;/p&gt;</description><content:encoded>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 16 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/14-worked-example-helm-chart/"&gt;Chapter 15: Worked Example: Creating a Helm Chart From a Reference Chart&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to migrate a procedural automation (for example, an Ansible playbook) into a durable Temporal workflow:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Extract discrete steps from the playbook.&lt;/li&gt;
&lt;li&gt;Map steps to activities.&lt;/li&gt;
&lt;li&gt;Implement a workflow that follows your team&amp;rsquo;s existing Temporal patterns.&lt;/li&gt;
&lt;li&gt;Add verification and tests so the migration is not faith-based.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Start from a working reference workflow in your repo.&lt;/li&gt;
&lt;li&gt;Paste both the playbook and the reference into the planning prompt.&lt;/li&gt;
&lt;li&gt;Define activities first, then the workflow.&lt;/li&gt;
&lt;li&gt;Verify with Temporal workflow tests and any integration checks you can run safely.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#scenario"&gt;Scenario&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#reference-inputs"&gt;Reference inputs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#plan-and-phase-structure"&gt;Plan and phase structure&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#implementation-skeleton-go"&gt;Implementation skeleton (Go)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#gotchas"&gt;Gotchas&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="scenario"&gt;Scenario&lt;/h2&gt;
&lt;p&gt;Example: convert a playbook that creates a Kubernetes namespace and resource quota into a Temporal workflow.&lt;/p&gt;
&lt;p&gt;Why this is a good fit:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Work is step-based.&lt;/li&gt;
&lt;li&gt;You want retries and observability.&lt;/li&gt;
&lt;li&gt;You want an execution history.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="reference-inputs"&gt;Reference inputs&lt;/h2&gt;
&lt;p&gt;Paste these into your planning prompt:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The playbook file (or the relevant section): &lt;code&gt;playbooks/create-namespace.yml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A reference workflow file that represents your team&amp;rsquo;s patterns.&lt;/li&gt;
&lt;li&gt;A reference activity implementation file (if you have one).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Suggested commands:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sed -n &lt;span class="s1"&gt;&amp;#39;1,200p&amp;#39;&lt;/span&gt; playbooks/create-namespace.yml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sed -n &lt;span class="s1"&gt;&amp;#39;1,200p&amp;#39;&lt;/span&gt; internal/workflows/provision_cluster.go
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ls -la internal/activities &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="plan-and-phase-structure"&gt;Plan and phase structure&lt;/h2&gt;
&lt;p&gt;A reasonable phase split:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Phase 1: define activity I/O and implement activities.&lt;/li&gt;
&lt;li&gt;Phase 2: implement workflow with retries and timeouts.&lt;/li&gt;
&lt;li&gt;Phase 3: add tests.&lt;/li&gt;
&lt;li&gt;Phase 4: register and deploy.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The plan should include verification per phase.&lt;/p&gt;
&lt;h2 id="implementation-skeleton-go"&gt;Implementation skeleton (Go)&lt;/h2&gt;
&lt;p&gt;This is a minimal skeleton to illustrate structure. It is intentionally not a full program.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;workflows&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;time&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;go.temporal.io/sdk/temporal&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;go.temporal.io/sdk/workflow&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CreateNamespaceInput&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CPULimit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;MemLimit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CreateNamespaceOutput&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="c1"&gt;// CreateNamespaceWorkflow orchestrates namespace creation.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="c1"&gt;// It assumes there are activities registered for create + quota + verify.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;CreateNamespaceWorkflow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CreateNamespaceInput&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;CreateNamespaceOutput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;starting namespace workflow&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;namespace&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Namespace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithActivityOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ActivityOptions&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;StartToCloseTimeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Minute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;RetryPolicy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;temporal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RetryPolicy&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;MaximumAttempts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Pseudocode: adapt to your activity names and input/output types.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// var nsResult activities.CreateNamespaceOutput&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// err := workflow.ExecuteActivity(ctx, activities.CreateNamespace, activities.CreateNamespaceInput{...}).Get(ctx, &amp;amp;nsResult)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// if err != nil { return nil, err }&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// var quotaResult activities.CreateResourceQuotaOutput&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// err = workflow.ExecuteActivity(ctx, activities.CreateResourceQuota, activities.CreateResourceQuotaInput{...}).Get(ctx, &amp;amp;quotaResult)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// if err != nil { return nil, err }&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// var verifyResult activities.VerifyNamespaceOutput&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// err = workflow.ExecuteActivity(ctx, activities.VerifyNamespace, activities.VerifyNamespaceInput{...}).Get(ctx, &amp;amp;verifyResult)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// if err != nil { return nil, err }&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;CreateNamespaceOutput&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Namespace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Namespace&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;workflow.ExecuteActivity&lt;/code&gt; calls are left as pseudocode because activity package names and types are repo-specific.&lt;/li&gt;
&lt;li&gt;Keep the skeleton syntactically correct.&lt;/li&gt;
&lt;li&gt;Use your reference workflow as the style guide.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="verification"&gt;Verification&lt;/h2&gt;
&lt;p&gt;Your verification should include at least one of these:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Temporal workflow unit tests (Temporal test framework).&lt;/li&gt;
&lt;li&gt;Activity unit tests (mock external systems).&lt;/li&gt;
&lt;li&gt;A safe integration test against a non-production environment.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Example commands (adapt to your repo):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Run unit tests.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;go &lt;span class="nb"&gt;test&lt;/span&gt; ./...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# If you have a focused workflow test package.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;go &lt;span class="nb"&gt;test&lt;/span&gt; ./internal/workflows -run TestCreateNamespaceWorkflow
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Expected results:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tests exit with code 0.&lt;/li&gt;
&lt;li&gt;Failures are actionable (not timeouts with no logs).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="gotchas"&gt;Gotchas&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;If you skip the reference workflow, your new workflow will not match team patterns.&lt;/li&gt;
&lt;li&gt;If you skip tests, you will not know whether retries and timeouts behave correctly.&lt;/li&gt;
&lt;li&gt;LLMs will happily invent Temporal APIs. Verify imports and method names exist in your actual SDK version.&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>Cruvero - AI Agent Ecosystem Platform</title><link>https://roygabriel.dev/projects/cruvero/</link><pubDate>Thu, 12 Feb 2026 19:25:00 -0500</pubDate><guid>https://roygabriel.dev/projects/cruvero/</guid><description>A production-grade, Temporal-native AI agent orchestration platform. 90,000+ lines of Go powering durable multi-agent workflows, neuro-inspired intelligence, enterprise governance, and a full React operational UI.</description><content:encoded>&lt;h2 id="summary"&gt;Summary&lt;/h2&gt;
&lt;p&gt;Cruvero is a production-grade AI agent orchestration platform I designed and built from the ground up in Go. It treats durability, observability, and operational control as infrastructure guarantees, not library afterthoughts.&lt;/p&gt;
&lt;p&gt;Where frameworks like LangGraph bolt checkpointing onto a graph abstraction, Cruvero inverts the model: Temporal&amp;rsquo;s battle-tested workflow engine &lt;em&gt;is&lt;/em&gt; the foundation, and the agent abstraction compiles down to it. The result is a platform where retry logic, failure recovery, human-in-the-loop approval, and multi-agent coordination aren&amp;rsquo;t library features; they&amp;rsquo;re infrastructure guarantees backed by the same technology that runs Uber&amp;rsquo;s and Stripe&amp;rsquo;s most critical workflows.&lt;/p&gt;
&lt;p&gt;The system currently spans 90,000+ lines of Go and TypeScript, with a comprehensive React UI, Kubernetes deployment via Helm and ArgoCD, and an enterprise MCP gateway architecture designed to support 1,000+ concurrent agents across 150+ integrations.&lt;/p&gt;
&lt;h2 id="the-problem"&gt;The Problem&lt;/h2&gt;
&lt;p&gt;Every major agent framework optimizes for the same thing: time-to-demo. Spin up a LangGraph chain, wire a few tools, get a result in 30 seconds. Impressive on a slide. Catastrophic in production.&lt;/p&gt;
&lt;p&gt;The failure modes are predictable. An agent workflow running for 40 minutes crashes mid-execution; state is gone. A tool call to an external API times out; the entire run fails with no recovery. A billing-sensitive agent hallucinates a $50,000 API call; no cost guardrails existed to stop it. An agent enters a reasoning loop, calling the same tool 15 times with near-identical arguments; nothing detects the degeneration.&lt;/p&gt;
&lt;p&gt;These aren&amp;rsquo;t edge cases. They&amp;rsquo;re the baseline reality of running AI agents at enterprise scale. Cruvero was built to make them structurally impossible.&lt;/p&gt;
&lt;h2 id="architecture"&gt;Architecture&lt;/h2&gt;
&lt;p&gt;Cruvero&amp;rsquo;s architecture is layered around a single principle: every agent action is a Temporal activity, and every workflow survives infrastructure failure by default.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Core Runtime:&lt;/strong&gt; The agent loop follows a deterministic &lt;code&gt;decide → act → observe → repeat&lt;/code&gt; state machine. Each cycle produces an immutable &lt;code&gt;DecisionRecord&lt;/code&gt; with content-addressed hashes of the prompt, state, tool schemas, and model config. This gives you complete forensic capability: for any decision an agent made, you can see the exact inputs, replay the decision with a different model, or run counterfactual analysis (&amp;ldquo;what if it had chosen differently at step 4?&amp;rdquo;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Durable Execution:&lt;/strong&gt; Temporal manages all workflow state. Agent runs survive process crashes, worker restarts, and infrastructure failures transparently. Long-running workflows (minutes to hours) use continue-as-new with automatic state compaction. There is zero data loss on agent failure, guaranteed by Temporal&amp;rsquo;s event sourcing, not by application-level retry logic.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Multi-Agent Coordination:&lt;/strong&gt; A first-class supervisor pattern supports seven coordination strategies: delegate, broadcast, debate, pipeline, map-reduce, voting, and saga with compensation. Agents communicate through signals, shared blackboard state, and pub/sub events. A supervisor can launch child agents, aggregate their results, and handle partial failures; all as durable Temporal workflows with full replay capability.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Graph DSL &amp;amp; Workflow Engine:&lt;/strong&gt; A custom graph DSL compiles structured execution plans (steps, conditional routes, parallel branches, join semantics, subgraphs) into Temporal workflows. Join modes include all, any, N-of-M, and voting. The visual workflow builder (React Flow) provides bidirectional serialization between the visual canvas and the underlying graph definition.&lt;/p&gt;
&lt;h2 id="neuro-inspired-intelligence"&gt;Neuro-Inspired Intelligence&lt;/h2&gt;
&lt;p&gt;This is the feature set that no other agent framework implements. Drawing from neuroscience and cognitive architecture research, this layer introduces eight subsystems that fundamentally change how agents reason, learn, and self-correct.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Metacognitive Monitoring:&lt;/strong&gt; Modeled on prefrontal cortex performance monitoring. The system tracks tool call hashes, observation hashes, progress deltas, confidence entropy, and goal-drift scores (via embedding cosine similarity against the original prompt). When it detects degradation, such as repetition loops, stalled progress, drifting goals, or collapsing confidence, it triggers graduated backpressure: forced reflection, model escalation (swap to a more capable model mid-run), context reset, mandatory strategy pivots, or human escalation. No more agents spinning their wheels for 200 steps.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Attention-Weighted Context Windows:&lt;/strong&gt; Inspired by hippocampal memory replay. Instead of dumping context linearly into the prompt, a multi-factor salience scorer (relevance, recency, confidence, usage frequency) re-ranks all memory before assembly. A dynamic token budget allocator shifts allocation by task phase. Planning phases boost semantic/procedural memory, execution phases boost tool schemas, and review phases boost episodic memory. An interference detector flags contradictory facts explicitly in the prompt rather than letting the LLM silently pick one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Temporal Reasoning:&lt;/strong&gt; Deadline-aware execution with soft and hard deadlines, graduated pressure levels (relaxed through critical), automatic model switching under time pressure, and structured time context injection into every prompt.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Agent Immune System:&lt;/strong&gt; Anomaly signature tracking with automatic tool quarantine. When a tool&amp;rsquo;s behavior degrades or produces anomalous outputs, the immune system hashes the failure pattern, tracks hit counts, and quarantines the tool after a configurable threshold. A vaccination CLI injects procedural memory to teach agents how to work around quarantined capabilities.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Compositional Tool Synthesis:&lt;/strong&gt; Meta-tools that chain multiple tool calls into atomic pipelines with pre/postcondition contracts, typed argument mapping, and enforcement of non-retryable errors on contract violations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Federated Trust &amp;amp; Delegation:&lt;/strong&gt; Trust scoring for multi-agent delegation. Agents build trust through successful task completion; supervisors automatically select agents based on capability manifests and accumulated trust scores. Delegation chains provide full accountability tracking for post-mortem analysis.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Execution Provenance Graph:&lt;/strong&gt; A tamper-evident DAG tracking every action, decision, and data dependency in an agent run. Supports ancestor/descendant queries, subgraph extraction, and run diffing to compare two executions and identify the exact point of divergence.&lt;/p&gt;
&lt;h2 id="enterprise-governance"&gt;Enterprise Governance&lt;/h2&gt;
&lt;p&gt;Cruvero&amp;rsquo;s enterprise hardening philosophy is &amp;ldquo;tenant isolation is a property of the architecture, not a feature.&amp;rdquo; Every boundary is enforced at the infrastructure layer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Multi-Tenancy &amp;amp; Namespace Isolation:&lt;/strong&gt; Temporal namespaces, Postgres row-level security, and network policies enforce tenant boundaries. Per-tenant model selection, tool access control, and resource quotas are infrastructure-level guarantees that cannot be bypassed by application code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rate Limiting, Quotas &amp;amp; Cost Guardrails:&lt;/strong&gt; Per-decision cost tracking (estimated and actual) with configurable policies: max cost per run, max cost per step, prefer-cheaper-model flags. Budget enforcement halts runs before they exceed limits. A model catalog with pricing metadata enables real-time cost optimization across providers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Audit Logging &amp;amp; Compliance:&lt;/strong&gt; Every tool call, LLM invocation, and state mutation is authenticated, authorized, and recorded in a tamper-evident audit trail. SOC 2-ready export formats. PII detection across five enforcement boundaries (audit, output, tool I/O, memory, events) with 12 PII types, unified secret detection, Shannon entropy analysis, HMAC-based stable tokenization, and a risk scoring engine.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Security Hardening:&lt;/strong&gt; OWASP Top 10 mitigations, RBAC with four role levels (Viewer, Editor, Admin, Super Admin), OIDC authentication, CSRF protection, input sanitization, and CSP headers.&lt;/p&gt;
&lt;h2 id="tool-ecosystem--mcp-integration"&gt;Tool Ecosystem &amp;amp; MCP Integration&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Semantic Tool Discovery:&lt;/strong&gt; A three-stage pipeline (keyword search → embedding similarity → quality-weighted reranking) selects tools dynamically rather than dumping all tool schemas into every prompt. Tool quality tracking quarantines degraded tools automatically.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;MCP Protocol:&lt;/strong&gt; 150+ Model Context Protocol integrations (Notion, GitHub, AWS, Azure, O365, ServiceNow, Slack, and more) with standardized tool interfaces. The current architecture uses stdio subprocesses; the enterprise target architecture introduces a gateway-mediated Streamable HTTP model with per-integration scaling, Dragonfly response caching, circuit breakers, Vault-backed credential isolation, and KEDA autoscaling, designed for 1,000+ concurrent agents.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Event-Driven Architecture:&lt;/strong&gt; NATS provides async event fan-out alongside Temporal&amp;rsquo;s durable execution. MCP server lifecycle management, embedding pipeline intake, audit/telemetry buffering, and external consumer subscriptions (Teams/Telegram bots, dashboards, webhook relays) all flow through NATS, without ever entering the workflow deterministic path.&lt;/p&gt;
&lt;h2 id="observability--operations"&gt;Observability &amp;amp; Operations&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Distributed Tracing:&lt;/strong&gt; OpenTelemetry spans per decision cycle, tool call, memory operation, and MCP invocation. Full correlation IDs from workflow entry through every activity.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Structured Logging:&lt;/strong&gt; Zap-based structured logging with per-tenant, per-run, and per-step context propagation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Production API:&lt;/strong&gt; RESTful API with automatic OpenAPI 3.1 documentation, SSE streaming for live run updates, and comprehensive endpoints for run management, approval workflows, replay, tracing, cost queries, and tool management.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;React Operational UI:&lt;/strong&gt; A full-featured React 18 / TypeScript interface replacing the original htmx console. Surfaces every runtime capability: run management with live SSE streaming, approval queues, replay console with counterfactual analysis, causal trace explorer, tool registry browser, memory explorer with salience scores, cost dashboards (ECharts), supervisor multi-agent visualization, visual workflow builder (React Flow), live workflow inspection, speculative execution, and differential model testing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kubernetes Deployment:&lt;/strong&gt; Helm chart with environment-aware value overlays, ArgoCD ApplicationSet for GitOps promotion (dev/staging/prod), ServiceMonitor templates, and ingress configuration.&lt;/p&gt;
&lt;h2 id="key-decisions"&gt;Key Decisions&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Go over Python:&lt;/strong&gt; Single-binary deploys, predictable latency, deterministic resource usage, and a strong concurrency model for managing hundreds of concurrent agent sessions. No GIL, no dependency hell, no runtime surprises.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Temporal over custom durability:&lt;/strong&gt; Rather than implementing checkpointing, retry logic, and state recovery as library features, Cruvero delegates all of it to Temporal&amp;rsquo;s battle-tested workflow engine. This is the same infrastructure that runs mission-critical systems at companies processing millions of transactions per day.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Neuroscience-grounded intelligence:&lt;/strong&gt; The cognitive architecture isn&amp;rsquo;t marketing. Each subsystem maps to a specific neuroscience principle (prefrontal monitoring, hippocampal salience, temporal reasoning, immune response). The result is agents that self-correct, learn from failures, and degrade gracefully, capabilities no other framework offers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Context management as a competitive advantage:&lt;/strong&gt; Most frameworks dump everything into the context window and pray. Cruvero&amp;rsquo;s context pipeline includes phase-aware budget allocation, five-component salience scoring, semantic tool search, interference detection, observation masking, and proactive compression triggers. The competitive analysis shows clear advantages over LangChain/LangGraph across every dimension.&lt;/p&gt;
&lt;h2 id="outcome"&gt;Outcome&lt;/h2&gt;
&lt;p&gt;Cruvero runs production agent workloads with infrastructure-grade reliability guarantees. The platform handles long-running workflows (minutes to hours), survives arbitrary infrastructure failures without data loss, enforces per-tenant cost and security policies, and provides complete observability from workflow entry through every LLM decision and tool call.&lt;/p&gt;
&lt;p&gt;The codebase represents 90,000+ lines of production code, 80%+ test coverage, comprehensive documentation published via Hugo, and a development methodology designed for systematic LLM-assisted engineering at scale.&lt;/p&gt;
&lt;h2 id="stack"&gt;Stack&lt;/h2&gt;
&lt;p&gt;Go · Temporal · PostgreSQL · NATS · React 18 · TypeScript · Vite · React Flow · ECharts · Tailwind CSS · Kubernetes · Helm · ArgoCD · Qdrant · Dragonfly · Ollama · OpenTelemetry · Zap · Keycloak · Docker&lt;/p&gt;</content:encoded></item><item><title>Chapter 15: Worked Example: Creating a Helm Chart From a Reference Chart</title><link>https://roygabriel.dev/blog/llm-development-guide/14-worked-example-helm-chart/</link><pubDate>Wed, 11 Feb 2026 07:00:00 -0500</pubDate><guid>https://roygabriel.dev/blog/llm-development-guide/14-worked-example-helm-chart/</guid><description>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 15 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/13-building-a-prompt-library/"&gt;Chapter 14: Building a Prompt Library: Governance + Quality Bar&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/15-worked-example-ansible-to-temporal/"&gt;Chapter 16: Worked Example: Converting an Ansible Playbook to a Go Temporal Workflow&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to create a production-quality Helm chart by following an existing chart in your repo as the reference:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Gather high-signal reference inputs.&lt;/li&gt;
&lt;li&gt;Produce a phased plan and prompt docs.&lt;/li&gt;
&lt;li&gt;Execute in reviewable commits.&lt;/li&gt;
&lt;li&gt;Verify the chart renders and lints cleanly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The reference chart is the source of truth for structure and conventions.&lt;/li&gt;
&lt;li&gt;Paste the reference inputs into your planning prompt.&lt;/li&gt;
&lt;li&gt;Execute one file at a time, with &lt;code&gt;helm lint&lt;/code&gt; and &lt;code&gt;helm template&lt;/code&gt; as gates.&lt;/li&gt;
&lt;li&gt;If you do not have a real reference chart, pick a different worked example.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#scenario"&gt;Scenario&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#reference-inputs"&gt;Reference inputs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-1-plan"&gt;Phase 1: Plan&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-2-prompt-docs"&gt;Phase 2: Prompt docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-3-execute-in-logical-units"&gt;Phase 3: Execute in logical units&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#gotchas"&gt;Gotchas&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="scenario"&gt;Scenario&lt;/h2&gt;
&lt;p&gt;Goal: create a new chart (example: &lt;code&gt;metrics-gateway&lt;/code&gt;) based on a known-good reference chart (example: &lt;code&gt;event-processor&lt;/code&gt;).&lt;/p&gt;</description><content:encoded>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 15 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/13-building-a-prompt-library/"&gt;Chapter 14: Building a Prompt Library: Governance + Quality Bar&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/15-worked-example-ansible-to-temporal/"&gt;Chapter 16: Worked Example: Converting an Ansible Playbook to a Go Temporal Workflow&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to create a production-quality Helm chart by following an existing chart in your repo as the reference:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Gather high-signal reference inputs.&lt;/li&gt;
&lt;li&gt;Produce a phased plan and prompt docs.&lt;/li&gt;
&lt;li&gt;Execute in reviewable commits.&lt;/li&gt;
&lt;li&gt;Verify the chart renders and lints cleanly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The reference chart is the source of truth for structure and conventions.&lt;/li&gt;
&lt;li&gt;Paste the reference inputs into your planning prompt.&lt;/li&gt;
&lt;li&gt;Execute one file at a time, with &lt;code&gt;helm lint&lt;/code&gt; and &lt;code&gt;helm template&lt;/code&gt; as gates.&lt;/li&gt;
&lt;li&gt;If you do not have a real reference chart, pick a different worked example.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#scenario"&gt;Scenario&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#reference-inputs"&gt;Reference inputs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-1-plan"&gt;Phase 1: Plan&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-2-prompt-docs"&gt;Phase 2: Prompt docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-3-execute-in-logical-units"&gt;Phase 3: Execute in logical units&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#gotchas"&gt;Gotchas&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="scenario"&gt;Scenario&lt;/h2&gt;
&lt;p&gt;Goal: create a new chart (example: &lt;code&gt;metrics-gateway&lt;/code&gt;) based on a known-good reference chart (example: &lt;code&gt;event-processor&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;This is a workflow example. You will need to substitute your real chart names and paths.&lt;/p&gt;
&lt;h2 id="reference-inputs"&gt;Reference inputs&lt;/h2&gt;
&lt;p&gt;Run these commands in your repo and paste the output into the planning prompt.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Chart structure and key files.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tree charts/event-processor/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sed -n &lt;span class="s1"&gt;&amp;#39;1,200p&amp;#39;&lt;/span&gt; charts/event-processor/Chart.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sed -n &lt;span class="s1"&gt;&amp;#39;1,200p&amp;#39;&lt;/span&gt; charts/event-processor/values.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sed -n &lt;span class="s1"&gt;&amp;#39;1,200p&amp;#39;&lt;/span&gt; charts/event-processor/templates/_helpers.tpl
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# If your reference chart uses these, include them too.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ls -la charts/event-processor &lt;span class="p"&gt;|&lt;/span&gt; rg -n &lt;span class="s2"&gt;&amp;#34;values-&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Why this matters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Structure: avoids &amp;ldquo;generic Helm&amp;rdquo; output.&lt;/li&gt;
&lt;li&gt;Naming and labels: keeps your charts consistent.&lt;/li&gt;
&lt;li&gt;Values shape: keeps operator UX consistent.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="phase-1-plan"&gt;Phase 1: Plan&lt;/h2&gt;
&lt;p&gt;Create a plan that is mostly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What files will exist.&lt;/li&gt;
&lt;li&gt;What differences are specific to &lt;code&gt;metrics-gateway&lt;/code&gt; (ports, probes, resources).&lt;/li&gt;
&lt;li&gt;How you will verify each phase.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Example plan skeleton:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# metrics-gateway Helm Chart Plan
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Goals
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; Create charts/metrics-gateway matching reference structure.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Render successfully with helm template.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Lint cleanly.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## References
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; charts/event-processor/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Phase 1: Analysis
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; Document naming conventions from reference.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Verification:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; tree charts/event-processor
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Phase 2: Scaffold
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; Create Chart.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; Create values.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; Create templates/_helpers.tpl
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Verification:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; helm lint charts/metrics-gateway
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Phase 3: Core templates
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; deployment
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; service
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; configmap
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Verification:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; helm template charts/metrics-gateway &amp;gt; /tmp/rendered.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Definition of done
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; helm lint exits 0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; helm template exits 0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="phase-2-prompt-docs"&gt;Phase 2: Prompt docs&lt;/h2&gt;
&lt;p&gt;Generate one prompt file per phase. Include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The plan path.&lt;/li&gt;
&lt;li&gt;The work-notes path.&lt;/li&gt;
&lt;li&gt;Reference chart file paths.&lt;/li&gt;
&lt;li&gt;Deliverables (exact files).&lt;/li&gt;
&lt;li&gt;Constraints (MUST and MUST NOT).&lt;/li&gt;
&lt;li&gt;Verification commands.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A good constraint to include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Match reference structure exactly.&amp;rdquo; (and name what that means)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="phase-3-execute-in-logical-units"&gt;Phase 3: Execute in logical units&lt;/h2&gt;
&lt;p&gt;You have two implementation strategies.&lt;/p&gt;
&lt;h3 id="strategy-a-recommended-copy-the-reference-chart-then-adapt"&gt;Strategy A (recommended): copy the reference chart, then adapt&lt;/h3&gt;
&lt;p&gt;This is often the fastest way to guarantee structure consistency.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cp -R charts/event-processor charts/metrics-gateway
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Then rename strings and values in a controlled way.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Review each replacement before committing.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rg -n &lt;span class="s2"&gt;&amp;#34;event-processor&amp;#34;&lt;/span&gt; charts/metrics-gateway
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now execute in logical units:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;Chart.yaml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Update &lt;code&gt;values.yaml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Update &lt;code&gt;_helpers.tpl&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Update one template file at a time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For each logical unit:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Update work notes.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;helm lint&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Propose a commit.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="strategy-b-scaffold-from-scratch-guided-by-the-reference"&gt;Strategy B: scaffold from scratch, guided by the reference&lt;/h3&gt;
&lt;p&gt;Use this when copying would bring too much baggage.&lt;/p&gt;
&lt;p&gt;You still paste the reference files, but ask the model to reproduce the structure explicitly.&lt;/p&gt;
&lt;h2 id="verification"&gt;Verification&lt;/h2&gt;
&lt;p&gt;Run both linting and rendering.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;helm lint charts/metrics-gateway
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;helm template charts/metrics-gateway &amp;gt; /tmp/metrics-gateway.rendered.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;test&lt;/span&gt; -s /tmp/metrics-gateway.rendered.yaml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Expected results:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;All commands exit with code 0.&lt;/li&gt;
&lt;li&gt;The rendered YAML is non-empty.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Optional: diff against the reference chart structure:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Compare structure only.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; charts/event-processor &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; find . -type f &lt;span class="p"&gt;|&lt;/span&gt; sort&lt;span class="o"&gt;)&lt;/span&gt; &amp;gt; /tmp/ref-files.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; charts/metrics-gateway &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; find . -type f &lt;span class="p"&gt;|&lt;/span&gt; sort&lt;span class="o"&gt;)&lt;/span&gt; &amp;gt; /tmp/new-files.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;diff -u /tmp/ref-files.txt /tmp/new-files.txt &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Expected result:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The file lists are close, with only intentional differences.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="gotchas"&gt;Gotchas&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;If you do not paste the reference files, you will get generic charts.&lt;/li&gt;
&lt;li&gt;Be explicit about service ports, probe paths, and resource defaults.&lt;/li&gt;
&lt;li&gt;Add negative constraints (&amp;ldquo;do not add ingress yet&amp;rdquo;) so scope doesn&amp;rsquo;t expand.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Continue -&amp;gt; &lt;a href="https://roygabriel.dev/blog/llm-development-guide/15-worked-example-ansible-to-temporal/"&gt;Chapter 16: Worked Example: Converting an Ansible Playbook to a Go Temporal Workflow&lt;/a&gt;
&lt;/p&gt;</content:encoded></item><item><title>Chapter 14: Building a Prompt Library: Governance + Quality Bar</title><link>https://roygabriel.dev/blog/llm-development-guide/13-building-a-prompt-library/</link><pubDate>Mon, 09 Feb 2026 06:00:00 -0500</pubDate><guid>https://roygabriel.dev/blog/llm-development-guide/13-building-a-prompt-library/</guid><description>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 14 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/12-templates-checklists/"&gt;Chapter 13: Templates + Checklists: The Copy/Paste Kit&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/14-worked-example-helm-chart/"&gt;Chapter 15: Worked Example: Creating a Helm Chart From a Reference Chart&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to build a prompt library that doesn&amp;rsquo;t turn into a junk drawer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Organize prompts by task type.&lt;/li&gt;
&lt;li&gt;Define a consistent prompt entry format.&lt;/li&gt;
&lt;li&gt;Set a contribution and maintenance policy.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A prompt library is a shared collection of prompts proven in real usage.&lt;/li&gt;
&lt;li&gt;Require prereqs, recommended model tier, expected output, and common failure fixes.&lt;/li&gt;
&lt;li&gt;Assign maintainers.&lt;/li&gt;
&lt;li&gt;Version prompts with a changelog.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#library-structure"&gt;Library structure&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#prompt-entry-template"&gt;Prompt entry template&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#contribution-guidelines"&gt;Contribution guidelines&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#governance"&gt;Governance&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="library-structure"&gt;Library structure&lt;/h2&gt;
&lt;p&gt;A simple layout that scales:&lt;/p&gt;</description><content:encoded>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 14 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/12-templates-checklists/"&gt;Chapter 13: Templates + Checklists: The Copy/Paste Kit&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/14-worked-example-helm-chart/"&gt;Chapter 15: Worked Example: Creating a Helm Chart From a Reference Chart&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to build a prompt library that doesn&amp;rsquo;t turn into a junk drawer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Organize prompts by task type.&lt;/li&gt;
&lt;li&gt;Define a consistent prompt entry format.&lt;/li&gt;
&lt;li&gt;Set a contribution and maintenance policy.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A prompt library is a shared collection of prompts proven in real usage.&lt;/li&gt;
&lt;li&gt;Require prereqs, recommended model tier, expected output, and common failure fixes.&lt;/li&gt;
&lt;li&gt;Assign maintainers.&lt;/li&gt;
&lt;li&gt;Version prompts with a changelog.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#library-structure"&gt;Library structure&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#prompt-entry-template"&gt;Prompt entry template&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#contribution-guidelines"&gt;Contribution guidelines&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#governance"&gt;Governance&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="library-structure"&gt;Library structure&lt;/h2&gt;
&lt;p&gt;A simple layout that scales:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;prompt-library/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; README.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; CONTRIBUTING.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; planning/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; implementation/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; testing/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; review/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; debugging/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Keep it boring. Avoid inventing new categories every week.&lt;/p&gt;
&lt;h2 id="prompt-entry-template"&gt;Prompt entry template&lt;/h2&gt;
&lt;p&gt;Require a consistent format so prompts are reusable:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# &amp;lt;Task Name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## When to use
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Prerequisites
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;-
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Recommended model tier
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## The prompt
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Customization points
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Expected output
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Common issues and fixes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Examples
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Changelog
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; YYYY-MM-DD: &amp;lt;what changed&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="contribution-guidelines"&gt;Contribution guidelines&lt;/h2&gt;
&lt;p&gt;Set a quality bar:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A prompt must have been used successfully multiple times.&lt;/li&gt;
&lt;li&gt;It must specify required reference files.&lt;/li&gt;
&lt;li&gt;It must include verification.&lt;/li&gt;
&lt;li&gt;It must include common failure modes and fixes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A contribution checklist:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Used successfully 3+ times.&lt;/li&gt;
&lt;li&gt;Another person can run it with the listed prereqs.&lt;/li&gt;
&lt;li&gt;Changelog updated.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="governance"&gt;Governance&lt;/h2&gt;
&lt;p&gt;If nobody owns it, it rots.&lt;/p&gt;
&lt;p&gt;Assign 1 to 2 maintainers to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Review new prompts.&lt;/li&gt;
&lt;li&gt;De-duplicate similar prompts.&lt;/li&gt;
&lt;li&gt;Archive prompts that no longer work.&lt;/li&gt;
&lt;li&gt;Run a quarterly cleanup.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="verification"&gt;Verification&lt;/h2&gt;
&lt;p&gt;Bootstrap the skeleton:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p prompt-library/&lt;span class="o"&gt;{&lt;/span&gt;planning,implementation,testing,review,debugging&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;touch prompt-library/README.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;touch prompt-library/CONTRIBUTING.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &amp;gt; prompt-library/planning/new-task.md &lt;span class="s"&gt;&amp;lt;&amp;lt;&amp;#39;MD&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;# New Task Planning
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## When to use
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Prerequisites
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Recommended model tier
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## The prompt
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Verification
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;MD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Expected result:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You have a real place to put prompts that worked, with enough structure to keep it maintainable.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Continue -&amp;gt; &lt;a href="https://roygabriel.dev/blog/llm-development-guide/14-worked-example-helm-chart/"&gt;Chapter 15: Worked Example: Creating a Helm Chart From a Reference Chart&lt;/a&gt;
&lt;/p&gt;</content:encoded></item><item><title>Chapter 13: Templates + Checklists: The Copy/Paste Kit</title><link>https://roygabriel.dev/blog/llm-development-guide/12-templates-checklists/</link><pubDate>Sat, 07 Feb 2026 04:00:00 -0500</pubDate><guid>https://roygabriel.dev/blog/llm-development-guide/12-templates-checklists/</guid><description>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 13 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/11-team-collaboration/"&gt;Chapter 12: Team Collaboration: Handoffs, Shared Prompts, and Review&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/13-building-a-prompt-library/"&gt;Chapter 14: Building a Prompt Library: Governance + Quality Bar&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to bootstrap the workflow in minutes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create &lt;code&gt;plan/&lt;/code&gt;, &lt;code&gt;prompts/&lt;/code&gt;, and &lt;code&gt;work-notes/&lt;/code&gt; with consistent templates.&lt;/li&gt;
&lt;li&gt;Add a phase spec template for large, multi-phase projects.&lt;/li&gt;
&lt;li&gt;Add a phase implementation prompt template for prompt-by-prompt execution.&lt;/li&gt;
&lt;li&gt;Use session start and end checklists.&lt;/li&gt;
&lt;li&gt;Generate PR descriptions that explain intent and verification.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Templates reduce prompt drift.&lt;/li&gt;
&lt;li&gt;Keep them short and consistent.&lt;/li&gt;
&lt;li&gt;Add verification to every phase.&lt;/li&gt;
&lt;li&gt;For large projects, pair phase specs with implementation prompt docs.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#plan-template"&gt;Plan template&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#prompt-template"&gt;Prompt template&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-spec-template-large-projects"&gt;Phase spec template (large projects)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-implementation-prompt-template-large-projects"&gt;Phase implementation prompt template (large projects)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#work-notes-template"&gt;Work notes template&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#session-checklists"&gt;Session checklists&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#pr-description-template"&gt;PR description template&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="plan-template"&gt;Plan template&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# &amp;lt;Project&amp;gt; Plan
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Overview
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Goals
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;-
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Context
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; Reference implementation:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Environment:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Phases
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Definition of done
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; [ ]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Out of scope
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;-
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Risks / open questions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;-
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="prompt-template"&gt;Prompt template&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# Phase &amp;lt;X&amp;gt; - &amp;lt;Name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Role
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Context
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; Plan:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Work notes:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; References:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Task
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Deliverables
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;1.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Constraints
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; MUST
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; MUST NOT
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Session management
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;Update work notes with decisions, assumptions, open questions, and a session log entry.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Verification
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; Command:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Expected:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Commit discipline
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;Propose a commit message and wait for approval.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="phase-spec-template-large-projects"&gt;Phase spec template (large projects)&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# Phase &amp;lt;N&amp;gt;&amp;lt;Letter&amp;gt; - &amp;lt;Phase Name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Status
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;Planned
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Depends on
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;Phase dependency&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Feature flag
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;flag name or n/a&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Migration
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;none or required steps&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Design rationale
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&amp;lt;Why this phase exists and what risk it reduces&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Tasks
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Prompt 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;task&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Prompt 2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;task&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Files
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### New
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;path&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Modified
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;path&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Referenced (read-only)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;path&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Exit criteria
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; &amp;lt;build command&amp;gt; exits 0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; &amp;lt;vet/lint command&amp;gt; exits 0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; &amp;lt;test command&amp;gt; exits 0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; No ignored returned errors
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Progress notes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="phase-implementation-prompt-template-large-projects"&gt;Phase implementation prompt template (large projects)&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# Phase &amp;lt;N&amp;gt;&amp;lt;Letter&amp;gt; - Implementation Prompts
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Complete prompts sequentially. Do not continue when verification fails.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Prompt 1 of &amp;lt;Total&amp;gt;: &amp;lt;Prompt Name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Context files to load:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;4 to 6 explicit paths&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Task:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;exact implementation task&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Constraints:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Stay within this prompt&amp;#39;s scope.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Handle all returned errors.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Keep code small and reviewable.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Do not proceed to the next prompt until verification passes.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Verification:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;build command&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;vet/lint command&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;test command&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Commit discipline:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Summarize what changed.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Propose commit message.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Wait for approval before moving on.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="work-notes-template"&gt;Work notes template&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# Phase &amp;lt;X&amp;gt; - &amp;lt;Name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Status
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; Not started
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; In progress
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; Blocked
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; Complete
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Decisions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Assumptions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Open questions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Session log
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Commits
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="session-checklists"&gt;Session checklists&lt;/h2&gt;
&lt;p&gt;Session start:&lt;/p&gt;</description><content:encoded>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 13 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/11-team-collaboration/"&gt;Chapter 12: Team Collaboration: Handoffs, Shared Prompts, and Review&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/13-building-a-prompt-library/"&gt;Chapter 14: Building a Prompt Library: Governance + Quality Bar&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to bootstrap the workflow in minutes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create &lt;code&gt;plan/&lt;/code&gt;, &lt;code&gt;prompts/&lt;/code&gt;, and &lt;code&gt;work-notes/&lt;/code&gt; with consistent templates.&lt;/li&gt;
&lt;li&gt;Add a phase spec template for large, multi-phase projects.&lt;/li&gt;
&lt;li&gt;Add a phase implementation prompt template for prompt-by-prompt execution.&lt;/li&gt;
&lt;li&gt;Use session start and end checklists.&lt;/li&gt;
&lt;li&gt;Generate PR descriptions that explain intent and verification.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Templates reduce prompt drift.&lt;/li&gt;
&lt;li&gt;Keep them short and consistent.&lt;/li&gt;
&lt;li&gt;Add verification to every phase.&lt;/li&gt;
&lt;li&gt;For large projects, pair phase specs with implementation prompt docs.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#plan-template"&gt;Plan template&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#prompt-template"&gt;Prompt template&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-spec-template-large-projects"&gt;Phase spec template (large projects)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-implementation-prompt-template-large-projects"&gt;Phase implementation prompt template (large projects)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#work-notes-template"&gt;Work notes template&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#session-checklists"&gt;Session checklists&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#pr-description-template"&gt;PR description template&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="plan-template"&gt;Plan template&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# &amp;lt;Project&amp;gt; Plan
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Overview
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Goals
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;-
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Context
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; Reference implementation:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Environment:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Phases
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Definition of done
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; [ ]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Out of scope
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;-
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Risks / open questions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;-
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="prompt-template"&gt;Prompt template&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# Phase &amp;lt;X&amp;gt; - &amp;lt;Name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Role
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Context
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; Plan:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Work notes:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; References:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Task
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Deliverables
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;1.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Constraints
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; MUST
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; MUST NOT
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Session management
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;Update work notes with decisions, assumptions, open questions, and a session log entry.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Verification
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; Command:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Expected:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Commit discipline
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;Propose a commit message and wait for approval.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="phase-spec-template-large-projects"&gt;Phase spec template (large projects)&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# Phase &amp;lt;N&amp;gt;&amp;lt;Letter&amp;gt; - &amp;lt;Phase Name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Status
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;Planned
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Depends on
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;Phase dependency&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Feature flag
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;flag name or n/a&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Migration
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;none or required steps&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Design rationale
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&amp;lt;Why this phase exists and what risk it reduces&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Tasks
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Prompt 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;task&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Prompt 2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;task&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Files
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### New
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;path&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Modified
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;path&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Referenced (read-only)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;path&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Exit criteria
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; &amp;lt;build command&amp;gt; exits 0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; &amp;lt;vet/lint command&amp;gt; exits 0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; &amp;lt;test command&amp;gt; exits 0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; No ignored returned errors
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Progress notes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="phase-implementation-prompt-template-large-projects"&gt;Phase implementation prompt template (large projects)&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# Phase &amp;lt;N&amp;gt;&amp;lt;Letter&amp;gt; - Implementation Prompts
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Complete prompts sequentially. Do not continue when verification fails.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Prompt 1 of &amp;lt;Total&amp;gt;: &amp;lt;Prompt Name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Context files to load:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;4 to 6 explicit paths&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Task:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;exact implementation task&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Constraints:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Stay within this prompt&amp;#39;s scope.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Handle all returned errors.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Keep code small and reviewable.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Do not proceed to the next prompt until verification passes.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Verification:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;build command&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;vet/lint command&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;test command&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Commit discipline:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Summarize what changed.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Propose commit message.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Wait for approval before moving on.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="work-notes-template"&gt;Work notes template&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# Phase &amp;lt;X&amp;gt; - &amp;lt;Name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Status
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; Not started
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; In progress
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; Blocked
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; Complete
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Decisions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Assumptions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Open questions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Session log
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Commits
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="session-checklists"&gt;Session checklists&lt;/h2&gt;
&lt;p&gt;Session start:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Identify the phase.&lt;/li&gt;
&lt;li&gt;Load the phase prompt.&lt;/li&gt;
&lt;li&gt;Load the current work notes.&lt;/li&gt;
&lt;li&gt;Re-state the smallest goal for this session.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Session end:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Work notes updated.&lt;/li&gt;
&lt;li&gt;Decisions logged with rationale.&lt;/li&gt;
&lt;li&gt;Verification run.&lt;/li&gt;
&lt;li&gt;Commits made (or clearly blocked).&lt;/li&gt;
&lt;li&gt;Next step written down.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="pr-description-template"&gt;PR description template&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Summary
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Changes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;-
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Out of scope
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;-
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Verification
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;-
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Review guide
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Follow-up
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; [ ]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## References
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; Work notes:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Plan:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="verification"&gt;Verification&lt;/h2&gt;
&lt;p&gt;Create a local &lt;code&gt;templates/&lt;/code&gt; folder and seed the files:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p templates
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &amp;gt; templates/PLAN-template.md &lt;span class="s"&gt;&amp;lt;&amp;lt;&amp;#39;MD&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;# Project Plan
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Overview
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Goals
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Phases
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Definition of done
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;MD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &amp;gt; templates/PROMPT-template.md &lt;span class="s"&gt;&amp;lt;&amp;lt;&amp;#39;MD&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;# Phase - Prompt
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Role
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Context
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Task
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Constraints
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Verification
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Commit discipline
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;MD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &amp;gt; templates/WORK-NOTES-template.md &lt;span class="s"&gt;&amp;lt;&amp;lt;&amp;#39;MD&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;# Phase - Work Notes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Status
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Decisions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Session log
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;MD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Expected result:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can start a new project by copying these templates and editing the placeholders.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Continue -&amp;gt; &lt;a href="https://roygabriel.dev/blog/llm-development-guide/13-building-a-prompt-library/"&gt;Chapter 14: Building a Prompt Library: Governance + Quality Bar&lt;/a&gt;
&lt;/p&gt;</content:encoded></item><item><title>Chapter 12: Team Collaboration: Handoffs, Shared Prompts, and Review</title><link>https://roygabriel.dev/blog/llm-development-guide/11-team-collaboration/</link><pubDate>Thu, 05 Feb 2026 02:00:00 -0500</pubDate><guid>https://roygabriel.dev/blog/llm-development-guide/11-team-collaboration/</guid><description>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 12 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/10-measuring-success/"&gt;Chapter 11: Measuring Success: Solo + Team Metrics Without Fake Precision&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/12-templates-checklists/"&gt;Chapter 13: Templates + Checklists: The Copy/Paste Kit&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to run this workflow on a team without turning it into process theater:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hand off work mid-phase without a meeting.&lt;/li&gt;
&lt;li&gt;Share prompts that actually work.&lt;/li&gt;
&lt;li&gt;Review LLM-assisted code with the same rigor as human code.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Teams fail at LLM work because chat context is not shareable.&lt;/li&gt;
&lt;li&gt;Plans, prompt docs, and work notes make context portable.&lt;/li&gt;
&lt;li&gt;Keep review focused on code and verification, not on how the code was produced.&lt;/li&gt;
&lt;li&gt;Maintain a small set of &amp;ldquo;golden&amp;rdquo; reference implementations.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#handoff-patterns"&gt;Handoff patterns&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#shared-prompt-libraries"&gt;Shared prompt libraries&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#review-checklist"&gt;Review checklist&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="handoff-patterns"&gt;Handoff patterns&lt;/h2&gt;
&lt;h3 id="mid-phase-handoff"&gt;Mid-phase handoff&lt;/h3&gt;
&lt;p&gt;If you hand off in the middle of a phase, provide:&lt;/p&gt;</description><content:encoded>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 12 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/10-measuring-success/"&gt;Chapter 11: Measuring Success: Solo + Team Metrics Without Fake Precision&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/12-templates-checklists/"&gt;Chapter 13: Templates + Checklists: The Copy/Paste Kit&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to run this workflow on a team without turning it into process theater:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hand off work mid-phase without a meeting.&lt;/li&gt;
&lt;li&gt;Share prompts that actually work.&lt;/li&gt;
&lt;li&gt;Review LLM-assisted code with the same rigor as human code.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Teams fail at LLM work because chat context is not shareable.&lt;/li&gt;
&lt;li&gt;Plans, prompt docs, and work notes make context portable.&lt;/li&gt;
&lt;li&gt;Keep review focused on code and verification, not on how the code was produced.&lt;/li&gt;
&lt;li&gt;Maintain a small set of &amp;ldquo;golden&amp;rdquo; reference implementations.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#handoff-patterns"&gt;Handoff patterns&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#shared-prompt-libraries"&gt;Shared prompt libraries&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#review-checklist"&gt;Review checklist&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="handoff-patterns"&gt;Handoff patterns&lt;/h2&gt;
&lt;h3 id="mid-phase-handoff"&gt;Mid-phase handoff&lt;/h3&gt;
&lt;p&gt;If you hand off in the middle of a phase, provide:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Updated work notes with status, decisions, open questions, and exact next step.&lt;/li&gt;
&lt;li&gt;The phase prompt doc.&lt;/li&gt;
&lt;li&gt;The reference implementation paths used.&lt;/li&gt;
&lt;li&gt;Any verification output (test results, lint output).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Handoff template:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Handoff: &amp;lt;Phase&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Status
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&amp;lt;What&amp;#39;s done, what&amp;#39;s in progress, what&amp;#39;s blocked&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Files to review
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;file 1&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;file 2&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Key decisions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;Decision&amp;gt;: &amp;lt;Rationale&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Open questions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; &amp;lt;Question&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Immediate next step
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&amp;lt;Exact command or file edit to do next&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### How to resume
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;1.&lt;/span&gt; Load prompts/&amp;lt;phase&amp;gt;.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;2.&lt;/span&gt; Load work-notes/&amp;lt;phase&amp;gt;.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;3.&lt;/span&gt; Continue from the last session log entry
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="phase-boundary-handoff"&gt;Phase boundary handoff&lt;/h3&gt;
&lt;p&gt;Phase boundary handoffs are easier:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Work notes are marked complete.&lt;/li&gt;
&lt;li&gt;The next phase starts cleanly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="shared-prompt-libraries"&gt;Shared prompt libraries&lt;/h2&gt;
&lt;p&gt;A shared library reduces rework and increases consistency.&lt;/p&gt;
&lt;p&gt;A reasonable structure:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;prompt-library/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; planning/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; implementation/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; testing/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; review/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Quality bar:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prompts are specific enough to be useful.&lt;/li&gt;
&lt;li&gt;Prompts are general enough to be reused.&lt;/li&gt;
&lt;li&gt;Prompts record &amp;ldquo;when to use&amp;rdquo; and &amp;ldquo;prereqs&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;Prompts have been used successfully multiple times.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="review-checklist"&gt;Review checklist&lt;/h2&gt;
&lt;p&gt;LLM-assisted work should be reviewed like any other work.&lt;/p&gt;
&lt;p&gt;High-signal checks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Imports and APIs exist (no hallucinations).&lt;/li&gt;
&lt;li&gt;Error handling is complete.&lt;/li&gt;
&lt;li&gt;Output matches reference patterns.&lt;/li&gt;
&lt;li&gt;Verification was actually run.&lt;/li&gt;
&lt;li&gt;Commits are atomic and explain intent.&lt;/li&gt;
&lt;li&gt;Tests test behavior, not just existence.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="verification"&gt;Verification&lt;/h2&gt;
&lt;p&gt;Create a shared template file so handoffs are consistent:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p docs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &amp;gt; docs/llm-handoff-template.md &lt;span class="s"&gt;&amp;lt;&amp;lt;&amp;#39;MD&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;# LLM Work Handoff Template
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Phase
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Status
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Files to review
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Key decisions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Open questions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Verification run
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- &amp;lt;command&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- Expected: &amp;lt;...&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Next step
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## How to resume
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- Prompt:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- Work notes:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- References:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;MD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Expected result:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Anyone can hand off work in under five minutes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Continue -&amp;gt; &lt;a href="https://roygabriel.dev/blog/llm-development-guide/12-templates-checklists/"&gt;Chapter 13: Templates + Checklists: The Copy/Paste Kit&lt;/a&gt;
&lt;/p&gt;</content:encoded></item><item><title>Chapter 11: Measuring Success: Solo + Team Metrics Without Fake Precision</title><link>https://roygabriel.dev/blog/llm-development-guide/10-measuring-success/</link><pubDate>Tue, 03 Feb 2026 00:00:00 -0500</pubDate><guid>https://roygabriel.dev/blog/llm-development-guide/10-measuring-success/</guid><description>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 11 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/09-stop-rules-pitfalls/"&gt;Chapter 10: Stop Rules + Pitfalls: When to Upgrade, Bail, or Go Manual&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/11-team-collaboration/"&gt;Chapter 12: Team Collaboration: Handoffs, Shared Prompts, and Review&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to tell, with reasonable honesty, whether the workflow is helping:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pick a small set of metrics you can actually measure.&lt;/li&gt;
&lt;li&gt;Separate leading indicators (process) from lagging indicators (outcomes).&lt;/li&gt;
&lt;li&gt;Avoid fake precision and vanity metrics.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;If you can&amp;rsquo;t measure reliably, don&amp;rsquo;t invent numbers.&lt;/li&gt;
&lt;li&gt;Track a baseline (a few representative tasks) before you claim improvement.&lt;/li&gt;
&lt;li&gt;Favor cheap metrics: time to first commit, PR revision rounds, post-merge bugs.&lt;/li&gt;
&lt;li&gt;Use leading indicators daily; use lagging indicators in retros.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#what-to-measure"&gt;What to measure&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#solo-baseline"&gt;Solo baseline&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#leading-vs-lagging-indicators"&gt;Leading vs lagging indicators&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#lightweight-reporting-template"&gt;Lightweight reporting template&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-to-measure"&gt;What to measure&lt;/h2&gt;
&lt;p&gt;Pick a small set that maps to real outcomes.&lt;/p&gt;</description><content:encoded>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 11 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/09-stop-rules-pitfalls/"&gt;Chapter 10: Stop Rules + Pitfalls: When to Upgrade, Bail, or Go Manual&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/11-team-collaboration/"&gt;Chapter 12: Team Collaboration: Handoffs, Shared Prompts, and Review&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to tell, with reasonable honesty, whether the workflow is helping:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pick a small set of metrics you can actually measure.&lt;/li&gt;
&lt;li&gt;Separate leading indicators (process) from lagging indicators (outcomes).&lt;/li&gt;
&lt;li&gt;Avoid fake precision and vanity metrics.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;If you can&amp;rsquo;t measure reliably, don&amp;rsquo;t invent numbers.&lt;/li&gt;
&lt;li&gt;Track a baseline (a few representative tasks) before you claim improvement.&lt;/li&gt;
&lt;li&gt;Favor cheap metrics: time to first commit, PR revision rounds, post-merge bugs.&lt;/li&gt;
&lt;li&gt;Use leading indicators daily; use lagging indicators in retros.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#what-to-measure"&gt;What to measure&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#solo-baseline"&gt;Solo baseline&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#leading-vs-lagging-indicators"&gt;Leading vs lagging indicators&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#lightweight-reporting-template"&gt;Lightweight reporting template&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-to-measure"&gt;What to measure&lt;/h2&gt;
&lt;p&gt;Pick a small set that maps to real outcomes.&lt;/p&gt;
&lt;p&gt;Velocity indicators:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Time to first commit.&lt;/li&gt;
&lt;li&gt;Phase completion time.&lt;/li&gt;
&lt;li&gt;PR cycle time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Quality indicators:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PR revision rounds.&lt;/li&gt;
&lt;li&gt;Bugs caught in review.&lt;/li&gt;
&lt;li&gt;Post-merge bugs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Efficiency indicators:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rework rate (time fixing output vs total time).&lt;/li&gt;
&lt;li&gt;Session count per task.&lt;/li&gt;
&lt;li&gt;Handoff success (can someone else continue without re-explaining).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="solo-baseline"&gt;Solo baseline&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re working solo, you can still create a baseline.&lt;/p&gt;
&lt;p&gt;Track per task:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start time.&lt;/li&gt;
&lt;li&gt;First commit time.&lt;/li&gt;
&lt;li&gt;Total time to done.&lt;/li&gt;
&lt;li&gt;Number of &amp;ldquo;LLM retries&amp;rdquo; (how many prompt iterations for the same logical unit).&lt;/li&gt;
&lt;li&gt;Bugs you found after &amp;ldquo;done&amp;rdquo;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The point is not perfect measurement. The point is noticing patterns.&lt;/p&gt;
&lt;h2 id="leading-vs-lagging-indicators"&gt;Leading vs lagging indicators&lt;/h2&gt;
&lt;p&gt;Leading indicators predict success:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Work notes are updated.&lt;/li&gt;
&lt;li&gt;Prompts contain verification.&lt;/li&gt;
&lt;li&gt;Commits are atomic.&lt;/li&gt;
&lt;li&gt;References are provided.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Lagging indicators confirm success:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PR merged with low rework.&lt;/li&gt;
&lt;li&gt;Low post-merge bug rate.&lt;/li&gt;
&lt;li&gt;Handoffs succeed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="lightweight-reporting-template"&gt;Lightweight reporting template&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## LLM-Assisted Development Summary (Month)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Adoption
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; Tasks completed with workflow: &amp;lt;N&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Velocity
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; Median time to first commit: &amp;lt;X&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Median PR cycle time: &amp;lt;Y&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Quality
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; Median PR revision rounds: &amp;lt;Z&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Post-merge bugs: &amp;lt;N&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Costs
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; LLM cost estimate: &amp;lt;X&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Notes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; What worked:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; What failed:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Changes for next month:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="verification"&gt;Verification&lt;/h2&gt;
&lt;p&gt;Keep a simple CSV so you can graph later if you want.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p work-notes
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &amp;gt; work-notes/metrics.csv &lt;span class="s"&gt;&amp;lt;&amp;lt;&amp;#39;CSV&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;date,task,time_to_first_commit_minutes,total_time_minutes,llm_retries,pr_revision_rounds,post_merge_bugs,notes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;CSV&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Expected result:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can append one row per task in under a minute.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Continue -&amp;gt; &lt;a href="https://roygabriel.dev/blog/llm-development-guide/11-team-collaboration/"&gt;Chapter 12: Team Collaboration: Handoffs, Shared Prompts, and Review&lt;/a&gt;
&lt;/p&gt;</content:encoded></item><item><title>Chapter 10: Stop Rules + Pitfalls: When to Upgrade, Bail, or Go Manual</title><link>https://roygabriel.dev/blog/llm-development-guide/09-stop-rules-pitfalls/</link><pubDate>Sat, 31 Jan 2026 23:00:00 -0500</pubDate><guid>https://roygabriel.dev/blog/llm-development-guide/09-stop-rules-pitfalls/</guid><description>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 10 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/08-security-sensitive-data/"&gt;Chapter 9: Security &amp;amp; Sensitive Data: Sanitize, Don&amp;rsquo;t Paste Secrets&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/10-measuring-success/"&gt;Chapter 11: Measuring Success: Solo + Team Metrics Without Fake Precision&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to avoid the two common failure outcomes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Spending hours fighting the model.&lt;/li&gt;
&lt;li&gt;Shipping output you can&amp;rsquo;t review.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You&amp;rsquo;ll do it with explicit stop rules, upgrade triggers, and a short recovery checklist.&lt;/p&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;If the change is under a minute manually, do it manually.&lt;/li&gt;
&lt;li&gt;If you can&amp;rsquo;t review the output competently, don&amp;rsquo;t ship it.&lt;/li&gt;
&lt;li&gt;If you&amp;rsquo;re on your third attempt for the same logical unit, upgrade or re-scope.&lt;/li&gt;
&lt;li&gt;Add verification steps to plans and prompts so &amp;ldquo;done&amp;rdquo; is testable.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#stop-rules"&gt;Stop rules&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#top-pitfalls"&gt;Top pitfalls&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#recovery-checklist"&gt;Recovery checklist&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="stop-rules"&gt;Stop rules&lt;/h2&gt;
&lt;p&gt;These are pragmatic defaults. Tune them to your environment.&lt;/p&gt;</description><content:encoded>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 10 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/08-security-sensitive-data/"&gt;Chapter 9: Security &amp;amp; Sensitive Data: Sanitize, Don&amp;rsquo;t Paste Secrets&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/10-measuring-success/"&gt;Chapter 11: Measuring Success: Solo + Team Metrics Without Fake Precision&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to avoid the two common failure outcomes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Spending hours fighting the model.&lt;/li&gt;
&lt;li&gt;Shipping output you can&amp;rsquo;t review.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You&amp;rsquo;ll do it with explicit stop rules, upgrade triggers, and a short recovery checklist.&lt;/p&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;If the change is under a minute manually, do it manually.&lt;/li&gt;
&lt;li&gt;If you can&amp;rsquo;t review the output competently, don&amp;rsquo;t ship it.&lt;/li&gt;
&lt;li&gt;If you&amp;rsquo;re on your third attempt for the same logical unit, upgrade or re-scope.&lt;/li&gt;
&lt;li&gt;Add verification steps to plans and prompts so &amp;ldquo;done&amp;rdquo; is testable.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#stop-rules"&gt;Stop rules&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#top-pitfalls"&gt;Top pitfalls&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#recovery-checklist"&gt;Recovery checklist&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="stop-rules"&gt;Stop rules&lt;/h2&gt;
&lt;p&gt;These are pragmatic defaults. Tune them to your environment.&lt;/p&gt;
&lt;h3 id="stop-rule-1-tiny-changes"&gt;Stop rule 1: tiny changes&lt;/h3&gt;
&lt;p&gt;If it is a tiny change (one line, one rename, one version bump), do it manually.&lt;/p&gt;
&lt;p&gt;LLM overhead is real:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You still have to explain.&lt;/li&gt;
&lt;li&gt;You still have to review.&lt;/li&gt;
&lt;li&gt;You still have to verify.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="stop-rule-2-you-cant-review-it"&gt;Stop rule 2: you can&amp;rsquo;t review it&lt;/h3&gt;
&lt;p&gt;Never commit code you could not explain in a review.&lt;/p&gt;
&lt;p&gt;If you don&amp;rsquo;t understand the domain:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;break the work into smaller pieces you can understand, or&lt;/li&gt;
&lt;li&gt;involve a reviewer who does.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="stop-rule-3-youre-fighting-output-quality"&gt;Stop rule 3: you&amp;rsquo;re fighting output quality&lt;/h3&gt;
&lt;p&gt;The 10-minute rule:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you&amp;rsquo;ve spent about 10 minutes fighting the output, stop.&lt;/li&gt;
&lt;li&gt;Upgrade the model tier, or shrink the scope to a smaller logical unit.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="stop-rule-4-high-risk-code-needs-extra-caution"&gt;Stop rule 4: high-risk code needs extra caution&lt;/h3&gt;
&lt;p&gt;Be cautious with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Authentication and authorization.&lt;/li&gt;
&lt;li&gt;Cryptography.&lt;/li&gt;
&lt;li&gt;Payment flows.&lt;/li&gt;
&lt;li&gt;Input validation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can still use LLMs, but the bar for review and verification is higher.&lt;/p&gt;
&lt;h2 id="top-pitfalls"&gt;Top pitfalls&lt;/h2&gt;
&lt;p&gt;These show up repeatedly.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Trusting output without review.&lt;/li&gt;
&lt;li&gt;Skipping planning.&lt;/li&gt;
&lt;li&gt;Not providing reference implementations.&lt;/li&gt;
&lt;li&gt;Letting sessions run too long.&lt;/li&gt;
&lt;li&gt;Scope creep mid-session.&lt;/li&gt;
&lt;li&gt;Vague prompts.&lt;/li&gt;
&lt;li&gt;Not capturing decisions.&lt;/li&gt;
&lt;li&gt;No verification step.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A simple rule:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you wouldn&amp;rsquo;t merge a junior developer&amp;rsquo;s PR without review, don&amp;rsquo;t merge LLM output without review.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="recovery-checklist"&gt;Recovery checklist&lt;/h2&gt;
&lt;p&gt;When things go wrong:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stop iterating on bad output.&lt;/li&gt;
&lt;li&gt;Decide what kind of problem it is:
&lt;ul&gt;
&lt;li&gt;prompt problem,&lt;/li&gt;
&lt;li&gt;model capability problem,&lt;/li&gt;
&lt;li&gt;task is a poor fit.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Simplify:
&lt;ul&gt;
&lt;li&gt;smaller logical unit,&lt;/li&gt;
&lt;li&gt;more references,&lt;/li&gt;
&lt;li&gt;clearer constraints.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Fresh session if context has drifted.&lt;/li&gt;
&lt;li&gt;Manual fallback is a valid outcome.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="verification"&gt;Verification&lt;/h2&gt;
&lt;p&gt;Create a one-page stop-rules file so you can apply this consistently across tasks:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p work-notes
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &amp;gt; work-notes/stop-rules.md &lt;span class="s"&gt;&amp;lt;&amp;lt;&amp;#39;MD&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;# Stop Rules (Personal Defaults)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Manual first
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- If change is &amp;lt;= 1 minute manually, do it manually.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Upgrade triggers
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- Third attempt on same logical unit.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- Repeated misunderstandings.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- Output ignores constraints.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Bail triggers
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- I cannot review this competently.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- Task requires live debugging with runtime state.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- Sensitive data would be required to reproduce.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Required gates
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- Verification commands exist in plan.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- Verification commands exist in prompt.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- Work notes updated before continuing.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;MD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Expected result:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You have a written policy you can apply without debating every time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Continue -&amp;gt; &lt;a href="https://roygabriel.dev/blog/llm-development-guide/10-measuring-success/"&gt;Chapter 11: Measuring Success: Solo + Team Metrics Without Fake Precision&lt;/a&gt;
&lt;/p&gt;</content:encoded></item><item><title>MCP Servers in Production: Hardening, Backpressure, and Observability (Go)</title><link>https://roygabriel.dev/blog/mcp-servers-production-hardening-go/</link><pubDate>Sat, 31 Jan 2026 09:00:00 -0500</pubDate><guid>https://roygabriel.dev/blog/mcp-servers-production-hardening-go/</guid><description>&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;&lt;strong&gt;As-of note:&lt;/strong&gt; MCP is evolving. This article references the MCP specification versioned &lt;strong&gt;2025-11-25&lt;/strong&gt; and related docs; verify details against the current spec before shipping changes. [1][2][4]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="why-this-matters"&gt;Why this matters&lt;/h2&gt;
&lt;p&gt;Most “agent demos” fail in production for boring reasons: missing timeouts, unbounded concurrency, ambiguous tool interfaces, and logging that accidentally turns into data exfiltration.&lt;/p&gt;
&lt;p&gt;An &lt;strong&gt;MCP server&lt;/strong&gt; isn’t “just an integration.” It’s a &lt;strong&gt;capability boundary&lt;/strong&gt; between an LLM host (IDE, desktop app, agent runner) and the real world: files, APIs, databases, tickets, home automation, and anything else you wire up. MCP uses JSON-RPC 2.0 messages over transports like stdio (local) and Streamable HTTP (remote). [1][2][5]&lt;/p&gt;</description><content:encoded>
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;&lt;strong&gt;As-of note:&lt;/strong&gt; MCP is evolving. This article references the MCP specification versioned &lt;strong&gt;2025-11-25&lt;/strong&gt; and related docs; verify details against the current spec before shipping changes. [1][2][4]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="why-this-matters"&gt;Why this matters&lt;/h2&gt;
&lt;p&gt;Most “agent demos” fail in production for boring reasons: missing timeouts, unbounded concurrency, ambiguous tool interfaces, and logging that accidentally turns into data exfiltration.&lt;/p&gt;
&lt;p&gt;An &lt;strong&gt;MCP server&lt;/strong&gt; isn’t “just an integration.” It’s a &lt;strong&gt;capability boundary&lt;/strong&gt; between an LLM host (IDE, desktop app, agent runner) and the real world: files, APIs, databases, tickets, home automation, and anything else you wire up. MCP uses JSON-RPC 2.0 messages over transports like stdio (local) and Streamable HTTP (remote). [1][2][5]&lt;/p&gt;
&lt;p&gt;That means an MCP server is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;an API gateway for tools&lt;/li&gt;
&lt;li&gt;a policy enforcement point (whether you intended it or not)&lt;/li&gt;
&lt;li&gt;a reliability hotspot (tool calls are where latency and failure concentrate)&lt;/li&gt;
&lt;li&gt;a security hotspot (tools are where “read” becomes “exfil” and “write” becomes “impact”)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This post is a pragmatic checklist + a set of Go patterns to harden an MCP server so it keeps working when it’s under real load, and remains safe when the model gets “creative.”&lt;/p&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Treat tool inputs as &lt;strong&gt;untrusted&lt;/strong&gt;. Validate and constrain everything.&lt;/li&gt;
&lt;li&gt;Put &lt;strong&gt;budgets&lt;/strong&gt; everywhere: timeouts, concurrency limits, rate limits, and payload caps.&lt;/li&gt;
&lt;li&gt;Build for &lt;strong&gt;partial failure&lt;/strong&gt;: retries, idempotency keys, circuit breaking, fallbacks.&lt;/li&gt;
&lt;li&gt;Log like a security engineer: &lt;strong&gt;structured&lt;/strong&gt;, &lt;strong&gt;redacted&lt;/strong&gt;, &lt;strong&gt;auditable&lt;/strong&gt;, and &lt;strong&gt;useful&lt;/strong&gt;. [11]&lt;/li&gt;
&lt;li&gt;Instrument with traces/metrics early; “we’ll add telemetry later” is a trap. [13]&lt;/li&gt;
&lt;li&gt;Prefer Go for MCP servers because deployment and operational behavior are predictable: single binary, fast startup, structured concurrency via &lt;code&gt;context&lt;/code&gt;, and a strong standard library.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="contents"&gt;Contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#a-production-mental-model-for-mcp-servers"&gt;A production mental model for MCP servers&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#threat-model-what-actually-goes-wrong"&gt;Threat model: what actually goes wrong&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#hardening-layer-1-identity-and-authorization"&gt;Hardening layer 1: identity and authorization&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#hardening-layer-2-tool-contracts-that-resist-ambiguity"&gt;Hardening layer 2: tool contracts that resist ambiguity&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#hardening-layer-3-budgets-and-backpressure"&gt;Hardening layer 3: budgets and backpressure&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#hardening-layer-4-safe-networking-and-ssrf-containment"&gt;Hardening layer 4: safe networking and SSRF containment&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#hardening-layer-5-observability-without-leaking-secrets"&gt;Hardening layer 5: observability without leaking secrets&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#hardening-layer-6-versioning-and-rollout-discipline"&gt;Hardening layer 6: versioning and rollout discipline&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#a-production-checklist"&gt;A production checklist&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#references"&gt;References&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="a-production-mental-model-for-mcp-servers"&gt;A production mental model for MCP servers&lt;/h2&gt;
&lt;p&gt;MCP’s docs describe a host (the AI application), a client (connector inside the host), and servers (capabilities/providers). Servers can be “local” (stdio) or “remote” (Streamable HTTP). [2][3]&lt;/p&gt;
&lt;p&gt;Here’s the production mental model that matters:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Your MCP server is a tool gateway.&lt;/strong&gt;&lt;br&gt;
Every tool is effectively an RPC method exposed to an agent. MCP uses JSON-RPC 2.0 semantics for requests/responses/notifications. [1][5]&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;LLM tool arguments are not trustworthy.&lt;/strong&gt;&lt;br&gt;
Even if the LLM is “helpful,” arguments can be malformed, overbroad, or dangerous, especially under prompt injection or user-provided hostile input.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The host UI is not a security boundary.&lt;/strong&gt;&lt;br&gt;
The spec emphasizes user consent and tool safety, but the protocol can’t enforce your policy for you. You still need server-side controls. [1]&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Transport changes your blast radius, not your responsibilities.&lt;/strong&gt;&lt;br&gt;
Stdio reduces network exposure, but doesn’t remove safety requirements. Streamable HTTP adds multi-client/multi-tenant concerns and requires real auth. [2][3]&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you remember nothing else: treat the MCP server like a production API you’d be willing to put on call for.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="threat-model-what-actually-goes-wrong"&gt;Threat model: what actually goes wrong&lt;/h2&gt;
&lt;p&gt;When MCP servers cause incidents, it’s usually one of these:&lt;/p&gt;
&lt;h3 id="1-input-ambiguity--destructive-actions"&gt;1) Input ambiguity → destructive actions&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;A “delete” tool with optional filters&lt;/li&gt;
&lt;li&gt;A “run command” tool with free-form strings&lt;/li&gt;
&lt;li&gt;A “sync” tool that can touch thousands of objects&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Mitigation:&lt;/strong&gt; schema + semantic validation, safe defaults, two-phase commit patterns (preview then apply), and explicit “danger gates.”&lt;/p&gt;
&lt;h3 id="2-prompt-injection--tool-misuse"&gt;2) Prompt injection → tool misuse&lt;/h3&gt;
&lt;p&gt;The model can be tricked into calling tools with attacker-provided arguments. If your tool can read internal data or call internal APIs, you’ve created an exfil path.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mitigation:&lt;/strong&gt; least privilege, allowlists, strong auth, egress controls, and redaction.&lt;/p&gt;
&lt;h3 id="3-ssrf--network-pivoting"&gt;3) SSRF / network pivoting&lt;/h3&gt;
&lt;p&gt;Any tool that fetches URLs, loads webhooks, or calls dynamic endpoints can be abused to hit internal networks or metadata endpoints. OWASP treats SSRF as a major category for a reason. [10]&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mitigation:&lt;/strong&gt; deny-by-default networking (CIDR blocks, DNS/IP resolution checks, allowlisted destinations).&lt;/p&gt;
&lt;h3 id="4-unbounded-concurrency--resource-collapse"&gt;4) Unbounded concurrency → resource collapse&lt;/h3&gt;
&lt;p&gt;Agents can fire tools in parallel. Without limits you’ll blow up:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;API quotas&lt;/li&gt;
&lt;li&gt;DB connections&lt;/li&gt;
&lt;li&gt;CPU/memory&lt;/li&gt;
&lt;li&gt;downstream latency&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Mitigation:&lt;/strong&gt; per-tenant rate limiting, concurrency caps, queues, and backpressure.&lt;/p&gt;
&lt;h3 id="5-helpful-logs--data-leak"&gt;5) “Helpful logs” → data leak&lt;/h3&gt;
&lt;p&gt;Tool arguments and tool responses often contain secrets, tokens, or private data. If you log everything, you’ve built an involuntary data lake.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mitigation:&lt;/strong&gt; structured + redacted logging, security logging guidelines, and minimal retention. [11][12]&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="hardening-layer-1-identity-and-authorization"&gt;Hardening layer 1: identity and authorization&lt;/h2&gt;
&lt;p&gt;If you run &lt;strong&gt;Streamable HTTP&lt;/strong&gt;, assume:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;multiple clients&lt;/li&gt;
&lt;li&gt;untrusted networks&lt;/li&gt;
&lt;li&gt;tokens will leak eventually&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;MCP’s architecture guidance recommends standard HTTP authentication methods and mentions OAuth as a recommended way to obtain tokens for remote servers. [2][3]&lt;/p&gt;
&lt;h3 id="practical-rules"&gt;Practical rules&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Authenticate every request.&lt;/strong&gt;&lt;br&gt;
Use bearer tokens or mTLS depending on environment.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Authorize per tool.&lt;/strong&gt;&lt;br&gt;
“Authenticated” ≠ “allowed to run &lt;code&gt;delete_everything&lt;/code&gt;”.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prefer short-lived tokens&lt;/strong&gt; and rotate them. [12]&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi-tenant?&lt;/strong&gt; Put the tenant identity into:
&lt;ul&gt;
&lt;li&gt;auth token claims, or&lt;/li&gt;
&lt;li&gt;an explicit, validated tenant header (signed), then&lt;/li&gt;
&lt;li&gt;enforce it everywhere.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="go-pattern-a-minimal-auth-middleware-skeleton-http-transport"&gt;Go pattern: a minimal auth middleware skeleton (HTTP transport)&lt;/h3&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;This is &lt;em&gt;not&lt;/em&gt; a full MCP implementation, just the hardening pattern you’ll wrap around your MCP handler.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Pseudocode-ish middleware skeleton. Replace verifyToken with your auth logic.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;authMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Handler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HandlerFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TrimPrefix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Authorization&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Bearer &amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;missing auth&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StatusUnauthorized&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ident&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;verifyToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// includes tenant + scopes&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;invalid auth&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StatusUnauthorized&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ctxKeyIdentity&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ident&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ServeHTTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; authorization should happen &lt;em&gt;after&lt;/em&gt; you parse the requested tool name, but &lt;em&gt;before&lt;/em&gt; you execute anything.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="hardening-layer-2-tool-contracts-that-resist-ambiguity"&gt;Hardening layer 2: tool contracts that resist ambiguity&lt;/h2&gt;
&lt;p&gt;Most MCP tool failures are self-inflicted: tool interfaces are too vague.&lt;/p&gt;
&lt;h3 id="design-tools-like-production-apis"&gt;Design tools like production APIs&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Bad tool signature:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;run(command: string)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Better:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;run_command(program: enum, args: string[], cwd: string, timeout_ms: int, dry_run: bool)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Why it’s better:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;forces structure&lt;/li&gt;
&lt;li&gt;allows you to enforce allowlists&lt;/li&gt;
&lt;li&gt;gives you timeouts and safe defaults&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="add-a-preview--apply-flow-for-risky-tools"&gt;Add a “preview → apply” flow for risky tools&lt;/h3&gt;
&lt;p&gt;For any tool that writes data or triggers side effects, do a two-step approach:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;plan_*&lt;/code&gt; returns a machine-readable plan + a &lt;code&gt;plan_id&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;apply_*&lt;/code&gt; requires &lt;code&gt;plan_id&lt;/code&gt; and optional user confirmation token&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This mirrors how we run infra changes (plan/apply) and dramatically reduces accidental blast radius.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="hardening-layer-3-budgets-and-backpressure"&gt;Hardening layer 3: budgets and backpressure&lt;/h2&gt;
&lt;p&gt;Production systems are budget systems.&lt;/p&gt;
&lt;p&gt;If you don’t set explicit budgets, your MCP server will eventually allocate them for you via outages.&lt;/p&gt;
&lt;h3 id="budget-checklist"&gt;Budget checklist&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Server timeouts&lt;/strong&gt; (header read, request read, write, idle)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Request body caps&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outbound timeouts&lt;/strong&gt; to dependencies&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Concurrency caps&lt;/strong&gt; per tool and per tenant&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rate limits&lt;/strong&gt; per tenant and per identity&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Queue limits&lt;/strong&gt; (bounded channels) to avoid memory blowups&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Circuit breaking&lt;/strong&gt; for flaky downstream dependencies&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="go-server-timeouts-are-not-optional"&gt;Go: server timeouts are not optional&lt;/h3&gt;
&lt;p&gt;Go’s &lt;code&gt;net/http&lt;/code&gt; provides explicit server timeouts; leaving them at zero is a common footgun. [6][7]&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;srv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Addr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;:8080&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// your MCP handler + middleware&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ReadHeaderTimeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ReadTimeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;WriteTimeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IdleTimeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;srv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="go-propagate-cancellation-everywhere-with-context"&gt;Go: propagate cancellation everywhere with &lt;code&gt;context&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;context.Context&lt;/code&gt; is the backbone of “structured concurrency” in Go: deadlines and cancellation signals flow through your call stack. [8][9]&lt;/p&gt;
&lt;p&gt;Rule: &lt;strong&gt;every tool execution must accept a &lt;code&gt;context.Context&lt;/code&gt;&lt;/strong&gt;, and every outbound call must honor it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;toolCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ToolRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ToolResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cancel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ... outbound calls use ctx&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;integration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="go-per-tenant-rate-limiting-with-xtimerate"&gt;Go: per-tenant rate limiting with &lt;code&gt;x/time/rate&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;golang.org/x/time/rate&lt;/code&gt; implements a token bucket limiter. [9]&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;limiters&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;mu&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Mutex&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Limiter&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;limiters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Limiter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Limiter&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lim&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lim&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Example: 5 req/sec with bursts up to 10&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lim&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewLimiter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lim&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lim&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;rateLimitMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lims&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;limiters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Handler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HandlerFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ident&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;mustIdentity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;lims&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ident&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TenantID&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Allow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;rate limited&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StatusTooManyRequests&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ServeHTTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="backpressure-choose-a-policy"&gt;Backpressure: choose a policy&lt;/h3&gt;
&lt;p&gt;When you’re overloaded, you need a policy. Pick one explicitly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Fail fast&lt;/strong&gt; with 429 / “busy” (simplest, safest)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Queue&lt;/strong&gt; with bounded depth (more complex; must cap memory)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Degrade&lt;/strong&gt; by disabling expensive tools first&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The “fail fast” approach is often correct for tool gateways.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="hardening-layer-4-safe-networking-and-ssrf-containment"&gt;Hardening layer 4: safe networking and SSRF containment&lt;/h2&gt;
&lt;p&gt;If any tool can fetch a user-provided URL or call a user-influenced endpoint, SSRF is on the table. [10]&lt;/p&gt;
&lt;h3 id="ssrf-containment-strategies-that-actually-work"&gt;SSRF containment strategies that actually work&lt;/h3&gt;
&lt;p&gt;OWASP’s SSRF guidance boils down to a few themes: don’t trust user-controlled URLs, use allowlists, and enforce network controls. [10]&lt;/p&gt;
&lt;p&gt;In practice, for MCP servers:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Prefer allowlists over blocklists.&lt;/strong&gt;&lt;br&gt;
“Only these domains” beats “block internal IPs.” Attackers are creative.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Resolve and validate IPs before dialing.&lt;/strong&gt;&lt;br&gt;
DNS can be weaponized. Validate the final destination IP (and re-validate on redirects).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Disable redirects or re-validate each hop.&lt;/strong&gt;&lt;br&gt;
Redirect chains are SSRF’s favorite tool.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Enforce egress policy at the network layer too.&lt;/strong&gt;&lt;br&gt;
Kubernetes NetworkPolicies / firewall rules are your last line of defense.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="go-pattern-an-outbound-http-client-with-strict-timeouts"&gt;Go pattern: an outbound HTTP client with strict timeouts&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// whole request budget&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Transport&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Transport&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Proxy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ProxyFromEnvironment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;DialContext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;net&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Dialer&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;KeepAlive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;DialContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TLSHandshakeTimeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ResponseHeaderTimeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ExpectContinueTimeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;MaxIdleConns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IdleConnTimeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then wrap URL validation around any request creation. Keep it boring and strict.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="hardening-layer-5-observability-without-leaking-secrets"&gt;Hardening layer 5: observability without leaking secrets&lt;/h2&gt;
&lt;p&gt;Telemetry is how you prove:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;you’re within budgets&lt;/li&gt;
&lt;li&gt;tools behave as expected&lt;/li&gt;
&lt;li&gt;failures are localized&lt;/li&gt;
&lt;li&gt;incidents can be diagnosed without “ssh and guess”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But logging is also where teams accidentally leak sensitive data.&lt;/p&gt;
&lt;p&gt;OWASP’s logging guidance emphasizes logging that supports detection/response while avoiding sensitive data exposure. [11] Pair that with secrets management discipline. [12]&lt;/p&gt;
&lt;h3 id="what-to-measure-minimum-viable-mcp-telemetry"&gt;What to measure (minimum viable MCP telemetry)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Counters&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;tool_calls_total{tool, tenant, status}&lt;/li&gt;
&lt;li&gt;auth_failures_total{reason}&lt;/li&gt;
&lt;li&gt;rate_limited_total{tenant}&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Histograms&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;tool_latency_seconds{tool}&lt;/li&gt;
&lt;li&gt;outbound_latency_seconds{dependency}&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Gauges&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;in_flight_tool_calls{tool}&lt;/li&gt;
&lt;li&gt;queue_depth{tool}&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="trace-boundaries"&gt;Trace boundaries&lt;/h3&gt;
&lt;p&gt;Instrument:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;request → tool routing&lt;/li&gt;
&lt;li&gt;tool execution span&lt;/li&gt;
&lt;li&gt;downstream calls span&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;OpenTelemetry’s Go docs show how to add instrumentation and emit traces/metrics. [13]&lt;/p&gt;
&lt;h3 id="logging-rules-that-save-you-later"&gt;Logging rules that save you later&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Use structured logging (JSON).&lt;/li&gt;
&lt;li&gt;Add correlation IDs (trace IDs) to logs.&lt;/li&gt;
&lt;li&gt;Redact:
&lt;ul&gt;
&lt;li&gt;Authorization headers&lt;/li&gt;
&lt;li&gt;tokens&lt;/li&gt;
&lt;li&gt;cookies&lt;/li&gt;
&lt;li&gt;tool payload fields known to contain secrets&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Log &lt;em&gt;events&lt;/em&gt;, not raw payloads:
&lt;ul&gt;
&lt;li&gt;“tool X called”&lt;/li&gt;
&lt;li&gt;“resource Y read”&lt;/li&gt;
&lt;li&gt;“write operation requested (dry_run=true)”&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Audit logs&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For high-impact tools, write an append-only audit record:
&lt;ul&gt;
&lt;li&gt;who (identity)&lt;/li&gt;
&lt;li&gt;what (tool + parameters summary)&lt;/li&gt;
&lt;li&gt;when&lt;/li&gt;
&lt;li&gt;result (success/failure)&lt;/li&gt;
&lt;li&gt;plan_id / idempotency_key&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Audit logs should be treated as security data.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="hardening-layer-6-versioning-and-rollout-discipline"&gt;Hardening layer 6: versioning and rollout discipline&lt;/h2&gt;
&lt;p&gt;MCP uses string-based version identifiers like &lt;code&gt;YYYY-MM-DD&lt;/code&gt; to represent the last date of backwards-incompatible changes. [4]&lt;/p&gt;
&lt;p&gt;That’s helpful, but it doesn’t solve the operational problem:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;clients upgrade at different times&lt;/li&gt;
&lt;li&gt;schema changes drift&lt;/li&gt;
&lt;li&gt;hosts differ in which capabilities they support&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="practical-compatibility-rules"&gt;Practical compatibility rules&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pin your server’s supported protocol version&lt;/strong&gt; and expose it in &lt;code&gt;health&lt;/code&gt; or diagnostics.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Add contract tests&lt;/strong&gt; that run against:
&lt;ul&gt;
&lt;li&gt;one “current” client&lt;/li&gt;
&lt;li&gt;one “previous” client version&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Support additive changes&lt;/strong&gt; first:
&lt;ul&gt;
&lt;li&gt;new tools&lt;/li&gt;
&lt;li&gt;new optional fields&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Use feature flags for risky tools.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="rollout-like-a-platform-team"&gt;Rollout like a platform team&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Canaries for remote servers&lt;/li&gt;
&lt;li&gt;“Shadow mode” for new tools (log what would happen)&lt;/li&gt;
&lt;li&gt;Slow ramp with budget monitoring&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="a-production-checklist"&gt;A production checklist&lt;/h2&gt;
&lt;p&gt;If you’re building (or inheriting) an MCP server, run this checklist:&lt;/p&gt;
&lt;h3 id="safety"&gt;Safety&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Tool contracts are structured (no free-form “do anything” strings).&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Every tool has a safe default (&lt;code&gt;dry_run=true&lt;/code&gt;, &lt;code&gt;limit&lt;/code&gt; required, etc.).&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Destructive tools require a plan/apply step (or explicit confirmation gates).&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Tool inputs are validated and bounded (length, ranges, enums).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="identity--access"&gt;Identity &amp;amp; access&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Remote transport requires authentication and per-tool authorization.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Tokens are short-lived and rotated; secrets are not in source control. [12]&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Tenant identity is enforced at every access point (not “best effort”).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="budgets--resilience"&gt;Budgets &amp;amp; resilience&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; HTTP server timeouts are configured. [6][7]&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Outbound clients have timeouts and connection limits.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Rate limiting exists per tenant/identity. [9]&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Concurrency caps exist per tool; overload behavior is explicit (fail fast / queue).&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Retries are bounded and idempotent where side effects exist.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="networking"&gt;Networking&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; URL fetch tools have allowlists and SSRF protections. [10]&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Redirect policies are explicit (disabled or re-validated).&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Egress is constrained at the network layer (not only in code).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="observability"&gt;Observability&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Metrics cover tool calls, latency, errors, and rate limiting.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Tracing exists across tool execution and downstream calls. [13]&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Logs are structured, correlated, and redacted. [11]&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Audit logging exists for high-impact tools.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="operations"&gt;Operations&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Health checks and readiness checks exist.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Configuration is explicit and validated on startup.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Versioning strategy is documented and tested. [4]&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Model Context Protocol (MCP) Specification (version 2025-11-25): &lt;a href="https://modelcontextprotocol.io/specification/2025-11-25" target="_blank" rel="noopener noreferrer"&gt;https://modelcontextprotocol.io/specification/2025-11-25&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;MCP Architecture Overview (participants, transports, concepts): &lt;a href="https://modelcontextprotocol.io/docs/learn/architecture" target="_blank" rel="noopener noreferrer"&gt;https://modelcontextprotocol.io/docs/learn/architecture&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;MCP Transport details (Streamable HTTP transport overview): &lt;a href="https://modelcontextprotocol.io/specification/2025-03-26/basic/transports" target="_blank" rel="noopener noreferrer"&gt;https://modelcontextprotocol.io/specification/2025-03-26/basic/transports&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;MCP Versioning: &lt;a href="https://modelcontextprotocol.io/specification/versioning" target="_blank" rel="noopener noreferrer"&gt;https://modelcontextprotocol.io/specification/versioning&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;JSON-RPC 2.0 Specification: &lt;a href="https://www.jsonrpc.org/specification" target="_blank" rel="noopener noreferrer"&gt;https://www.jsonrpc.org/specification&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Go &lt;code&gt;net/http&lt;/code&gt; package documentation: &lt;a href="https://pkg.go.dev/net/http" target="_blank" rel="noopener noreferrer"&gt;https://pkg.go.dev/net/http&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Cloudflare: “The complete guide to Go net/http timeouts”: &lt;a href="https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/" target="_blank" rel="noopener noreferrer"&gt;https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Go &lt;code&gt;context&lt;/code&gt; package documentation: &lt;a href="https://pkg.go.dev/context" target="_blank" rel="noopener noreferrer"&gt;https://pkg.go.dev/context&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Go &lt;code&gt;x/time/rate&lt;/code&gt; documentation: &lt;a href="https://pkg.go.dev/golang.org/x/time/rate" target="_blank" rel="noopener noreferrer"&gt;https://pkg.go.dev/golang.org/x/time/rate&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;OWASP SSRF Prevention Cheat Sheet / SSRF category references:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html" target="_blank" rel="noopener noreferrer"&gt;https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://owasp.org/Top10/2021/A10_2021-Server-Side_Request_Forgery_%28SSRF%29/" target="_blank" rel="noopener noreferrer"&gt;https://owasp.org/Top10/2021/A10_2021-Server-Side_Request_Forgery_%28SSRF%29/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="11"&gt;
&lt;li&gt;OWASP Logging Cheat Sheet (security-focused logging guidance): &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html" target="_blank" rel="noopener noreferrer"&gt;https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Secrets management guidance:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;OWASP Secrets Management Cheat Sheet: &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html" target="_blank" rel="noopener noreferrer"&gt;https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Kubernetes “Good practices for Kubernetes Secrets”: &lt;a href="https://kubernetes.io/docs/concepts/security/secrets-good-practices/" target="_blank" rel="noopener noreferrer"&gt;https://kubernetes.io/docs/concepts/security/secrets-good-practices/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="13"&gt;
&lt;li&gt;OpenTelemetry Go instrumentation docs: &lt;a href="https://opentelemetry.io/docs/languages/go/instrumentation/" target="_blank" rel="noopener noreferrer"&gt;https://opentelemetry.io/docs/languages/go/instrumentation/&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;</content:encoded></item><item><title>Chapter 9: Security &amp; Sensitive Data: Sanitize, Don't Paste Secrets</title><link>https://roygabriel.dev/blog/llm-development-guide/08-security-sensitive-data/</link><pubDate>Thu, 29 Jan 2026 21:00:00 -0500</pubDate><guid>https://roygabriel.dev/blog/llm-development-guide/08-security-sensitive-data/</guid><description>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 9 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/07-choosing-the-right-model/"&gt;Chapter 8: Choosing the Right Model: Capability Tiers, Not Hype&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/09-stop-rules-pitfalls/"&gt;Chapter 10: Stop Rules + Pitfalls: When to Upgrade, Bail, or Go Manual&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to use LLMs without doing something reckless:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Apply a concrete &amp;ldquo;never paste&amp;rdquo; list.&lt;/li&gt;
&lt;li&gt;Sanitize code, config, and logs into safe examples.&lt;/li&gt;
&lt;li&gt;Add a verification step so you don&amp;rsquo;t ship secrets.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Assume anything you paste could be logged or retained.&lt;/li&gt;
&lt;li&gt;If you wouldn&amp;rsquo;t publish it publicly, don&amp;rsquo;t paste it.&lt;/li&gt;
&lt;li&gt;Replace real values with placeholders.&lt;/li&gt;
&lt;li&gt;Sanitize logs aggressively.&lt;/li&gt;
&lt;li&gt;Verify your workspace for leaked secrets before you commit.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#the-core-principle"&gt;The core principle&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#never-paste-list"&gt;Never paste list&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#sanitization-patterns"&gt;Sanitization patterns&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#failure-modes"&gt;Failure modes&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-core-principle"&gt;The core principle&lt;/h2&gt;
&lt;p&gt;Assume anything you send to an LLM could be stored.&lt;/p&gt;</description><content:encoded>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 9 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/07-choosing-the-right-model/"&gt;Chapter 8: Choosing the Right Model: Capability Tiers, Not Hype&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/09-stop-rules-pitfalls/"&gt;Chapter 10: Stop Rules + Pitfalls: When to Upgrade, Bail, or Go Manual&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to use LLMs without doing something reckless:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Apply a concrete &amp;ldquo;never paste&amp;rdquo; list.&lt;/li&gt;
&lt;li&gt;Sanitize code, config, and logs into safe examples.&lt;/li&gt;
&lt;li&gt;Add a verification step so you don&amp;rsquo;t ship secrets.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Assume anything you paste could be logged or retained.&lt;/li&gt;
&lt;li&gt;If you wouldn&amp;rsquo;t publish it publicly, don&amp;rsquo;t paste it.&lt;/li&gt;
&lt;li&gt;Replace real values with placeholders.&lt;/li&gt;
&lt;li&gt;Sanitize logs aggressively.&lt;/li&gt;
&lt;li&gt;Verify your workspace for leaked secrets before you commit.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#the-core-principle"&gt;The core principle&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#never-paste-list"&gt;Never paste list&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#sanitization-patterns"&gt;Sanitization patterns&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#failure-modes"&gt;Failure modes&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-core-principle"&gt;The core principle&lt;/h2&gt;
&lt;p&gt;Assume anything you send to an LLM could be stored.&lt;/p&gt;
&lt;p&gt;Even with enterprise offerings, policies change. Check vendor policy as of 2026-02-14 (and your organization&amp;rsquo;s approved tools list) before using any tool with internal data.&lt;/p&gt;
&lt;h2 id="never-paste-list"&gt;Never paste list&lt;/h2&gt;
&lt;p&gt;Do not paste:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Credentials: API keys, tokens, passwords, private keys.&lt;/li&gt;
&lt;li&gt;PII: customer names, emails, addresses, health data.&lt;/li&gt;
&lt;li&gt;Production data: real records, full dumps, support tickets.&lt;/li&gt;
&lt;li&gt;Security configs: firewall rules, IAM policies, internal IPs.&lt;/li&gt;
&lt;li&gt;Proprietary secrets: unreleased product details, trade secrets.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Use the &amp;ldquo;Would I post this publicly?&amp;rdquo; test.&lt;/p&gt;
&lt;h2 id="sanitization-patterns"&gt;Sanitization patterns&lt;/h2&gt;
&lt;p&gt;Replace sensitive values with descriptive placeholders.&lt;/p&gt;
&lt;p&gt;Go example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Before (do not paste)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="c1"&gt;// db, err := sql.Open(&amp;#34;postgres&amp;#34;, &amp;#34;host=prod-db.internal user=admin password=SuperSecret123 dbname=customers&amp;#34;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="c1"&gt;// After (safe to paste)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;postgres&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;host=DATABASE_HOST user=DATABASE_USER password=DATABASE_PASSWORD dbname=DATABASE_NAME&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;YAML example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# Before (do not paste)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="c"&gt;# data:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="c"&gt;# api-key: YWN0dWFsLWFwaS1rZXktaGVyZQ==&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="c"&gt;# After (safe to paste)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;api-key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;&amp;lt;BASE64_ENCODED_API_KEY&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;webhook-secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;&amp;lt;BASE64_ENCODED_WEBHOOK_SECRET&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Logs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Remove emails.&lt;/li&gt;
&lt;li&gt;Replace internal hostnames.&lt;/li&gt;
&lt;li&gt;Replace IPs with documentation ranges (&lt;code&gt;192.0.2.0/24&lt;/code&gt;, &lt;code&gt;198.51.100.0/24&lt;/code&gt;, &lt;code&gt;203.0.113.0/24&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="verification"&gt;Verification&lt;/h2&gt;
&lt;p&gt;Before you paste or commit, search your workspace for obvious secret patterns.&lt;/p&gt;
&lt;p&gt;These commands are noisy, but useful:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# High-signal patterns.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rg -n &lt;span class="s2"&gt;&amp;#34;(AKIA[0-9A-Z]{16}|BEGIN (RSA|OPENSSH) PRIVATE KEY|xox[baprs]-|ghp_[A-Za-z0-9]{36})&amp;#34;&lt;/span&gt; . &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Common key/value names.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rg -n &lt;span class="s2"&gt;&amp;#34;(?i)(api[_-]?key|secret|token|password)\s*[:=]&amp;#34;&lt;/span&gt; . &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Emails (often indicates logs or real data got copied).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rg -n &lt;span class="s2"&gt;&amp;#34;[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}&amp;#34;&lt;/span&gt; . &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Check staged changes specifically.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git diff --cached
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Expected results:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No obvious credentials or private keys appear in diffs.&lt;/li&gt;
&lt;li&gt;If matches exist, sanitize and regenerate the example.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="failure-modes"&gt;Failure modes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Sharing real logs that contain tokens in URLs.&lt;/li&gt;
&lt;li&gt;Copying a Kubernetes &lt;code&gt;Secret&lt;/code&gt; verbatim.&lt;/li&gt;
&lt;li&gt;Letting an IDE plugin send your whole file without noticing.&lt;/li&gt;
&lt;li&gt;Assuming &amp;ldquo;enterprise&amp;rdquo; means &amp;ldquo;no risk&amp;rdquo; without verifying current policy.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Continue -&amp;gt; &lt;a href="https://roygabriel.dev/blog/llm-development-guide/09-stop-rules-pitfalls/"&gt;Chapter 10: Stop Rules + Pitfalls: When to Upgrade, Bail, or Go Manual&lt;/a&gt;
&lt;/p&gt;</content:encoded></item><item><title>Chapter 8: Choosing the Right Model: Capability Tiers, Not Hype</title><link>https://roygabriel.dev/blog/llm-development-guide/07-choosing-the-right-model/</link><pubDate>Tue, 27 Jan 2026 19:00:00 -0500</pubDate><guid>https://roygabriel.dev/blog/llm-development-guide/07-choosing-the-right-model/</guid><description>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 8 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/07-phase-documents-implementation-prompts/"&gt;Chapter 7: Large Projects with Phase Documents + Implementation Prompts&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/08-security-sensitive-data/"&gt;Chapter 9: Security &amp;amp; Sensitive Data: Sanitize, Don&amp;rsquo;t Paste Secrets&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to pick a model and interface deliberately:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use capability tiers instead of memorizing brand names.&lt;/li&gt;
&lt;li&gt;Upgrade quickly when quality is the bottleneck.&lt;/li&gt;
&lt;li&gt;Avoid wasting flagship models on structured boilerplate.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Treat model choice as a cost-of-mistakes problem.&lt;/li&gt;
&lt;li&gt;Use flagship models for planning, debugging, and high-stakes decisions.&lt;/li&gt;
&lt;li&gt;Use mid-tier models for implementation with strong references.&lt;/li&gt;
&lt;li&gt;Use fast/cheap models for boilerplate and simple transformations.&lt;/li&gt;
&lt;li&gt;If you&amp;rsquo;ve spent ~10 minutes fighting output quality, upgrade or shrink scope.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="as-of-note"&gt;As-of note&lt;/h2&gt;
&lt;p&gt;As of 2026-02-14, model names, pricing, and product policies change frequently. Prefer tier-based guidance, and verify vendor policies directly before using tools with sensitive data.&lt;/p&gt;</description><content:encoded>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 8 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/07-phase-documents-implementation-prompts/"&gt;Chapter 7: Large Projects with Phase Documents + Implementation Prompts&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/08-security-sensitive-data/"&gt;Chapter 9: Security &amp;amp; Sensitive Data: Sanitize, Don&amp;rsquo;t Paste Secrets&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to pick a model and interface deliberately:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use capability tiers instead of memorizing brand names.&lt;/li&gt;
&lt;li&gt;Upgrade quickly when quality is the bottleneck.&lt;/li&gt;
&lt;li&gt;Avoid wasting flagship models on structured boilerplate.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Treat model choice as a cost-of-mistakes problem.&lt;/li&gt;
&lt;li&gt;Use flagship models for planning, debugging, and high-stakes decisions.&lt;/li&gt;
&lt;li&gt;Use mid-tier models for implementation with strong references.&lt;/li&gt;
&lt;li&gt;Use fast/cheap models for boilerplate and simple transformations.&lt;/li&gt;
&lt;li&gt;If you&amp;rsquo;ve spent ~10 minutes fighting output quality, upgrade or shrink scope.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="as-of-note"&gt;As-of note&lt;/h2&gt;
&lt;p&gt;As of 2026-02-14, model names, pricing, and product policies change frequently. Prefer tier-based guidance, and verify vendor policies directly before using tools with sensitive data.&lt;/p&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#the-capability-tiers"&gt;The capability tiers&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#task-to-tier-mapping"&gt;Task-to-tier mapping&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#red-flags-upgrade-now"&gt;Red flags: upgrade now&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#a-selection-checklist"&gt;A selection checklist&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-capability-tiers"&gt;The capability tiers&lt;/h2&gt;
&lt;p&gt;Think in tiers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Flagship: best reasoning and instruction-following for novel work.&lt;/li&gt;
&lt;li&gt;Mid-tier: strong general performance for structured work with references.&lt;/li&gt;
&lt;li&gt;Fast/cheap: good for simple tasks, higher error rate on complex reasoning.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This framing stays useful even when names change.&lt;/p&gt;
&lt;h2 id="task-to-tier-mapping"&gt;Task-to-tier mapping&lt;/h2&gt;
&lt;p&gt;Use flagship for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Planning and architecture.&lt;/li&gt;
&lt;li&gt;Debugging complex failures.&lt;/li&gt;
&lt;li&gt;Security-sensitive review.&lt;/li&gt;
&lt;li&gt;Anything where mistakes are expensive.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Use mid-tier for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Implementation that follows existing patterns.&lt;/li&gt;
&lt;li&gt;Refactors with clear examples.&lt;/li&gt;
&lt;li&gt;Writing tests when the behavior is already defined.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Use fast/cheap for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Syntax lookups.&lt;/li&gt;
&lt;li&gt;Boilerplate you will review.&lt;/li&gt;
&lt;li&gt;Mechanical transformations.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="red-flags-upgrade-now"&gt;Red flags: upgrade now&lt;/h2&gt;
&lt;p&gt;Upgrade when you see:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The model repeats the same misunderstanding.&lt;/li&gt;
&lt;li&gt;Output ignores constraints.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Looks right&amp;rdquo; code fails in tests.&lt;/li&gt;
&lt;li&gt;You are on the third prompt iteration for the same unit.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The cheapest model is the one that gets you to a correct verified change with the least total time.&lt;/p&gt;
&lt;h2 id="a-selection-checklist"&gt;A selection checklist&lt;/h2&gt;
&lt;p&gt;Before you start, answer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Is this novel or pattern-following?&lt;/li&gt;
&lt;li&gt;Do I have reference implementations?&lt;/li&gt;
&lt;li&gt;What is the cost of mistakes?&lt;/li&gt;
&lt;li&gt;Is this structured or ambiguous?&lt;/li&gt;
&lt;li&gt;Am I debugging or implementing?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If uncertain:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start with flagship for planning.&lt;/li&gt;
&lt;li&gt;Drop to mid-tier once you have a stable pattern and good references.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="verification"&gt;Verification&lt;/h2&gt;
&lt;p&gt;A practical way to keep this from being hand-wavy is to force a written decision per phase.&lt;/p&gt;
&lt;p&gt;Create a small note file per task:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p work-notes
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &amp;gt; work-notes/model-selection.md &lt;span class="s"&gt;&amp;lt;&amp;lt;&amp;#39;MD&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;# Model Selection (Per Task)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Task
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;&amp;lt;What are we doing?&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Risk
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- Cost of mistakes:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- Can I review the output competently?
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## References
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- &amp;lt;Paths to reference implementations&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Model decision
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- Tier: &amp;lt;flagship|mid-tier|fast&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- Why:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- When to upgrade:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Outcome
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- Did we upgrade?
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- What broke / what worked:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;MD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Expected result:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can justify the model choice in one minute.&lt;/li&gt;
&lt;li&gt;You have a trigger for upgrading when output quality is the bottleneck.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Continue -&amp;gt; &lt;a href="https://roygabriel.dev/blog/llm-development-guide/08-security-sensitive-data/"&gt;Chapter 9: Security &amp;amp; Sensitive Data: Sanitize, Don&amp;rsquo;t Paste Secrets&lt;/a&gt;
&lt;/p&gt;</content:encoded></item><item><title>Chapter 7: Large Projects with Phase Documents + Implementation Prompts</title><link>https://roygabriel.dev/blog/llm-development-guide/07-phase-documents-implementation-prompts/</link><pubDate>Mon, 26 Jan 2026 20:00:00 -0500</pubDate><guid>https://roygabriel.dev/blog/llm-development-guide/07-phase-documents-implementation-prompts/</guid><description>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 7 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/06-scaling-the-workflow/"&gt;Chapter 6: Scaling the Workflow: Phases, Parallelism, Hygiene&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/07-choosing-the-right-model/"&gt;Chapter 8: Choosing the Right Model: Capability Tiers, Not Hype&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to run large, multi-phase delivery with less drift by introducing two explicit artifacts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A phase specification document that defines scope, dependencies, files, and exit criteria.&lt;/li&gt;
&lt;li&gt;A phase implementation prompt document that defines the prompt-by-prompt execution contract.&lt;/li&gt;
&lt;li&gt;A repeatable operating cadence for execution, verification, and commits.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Large projects fail when a single prompt tries to carry the whole implementation plan.&lt;/li&gt;
&lt;li&gt;Use one phase spec and one implementation-prompt file per sub-phase.&lt;/li&gt;
&lt;li&gt;Execute prompts sequentially; do not continue if build/vet/test gates fail.&lt;/li&gt;
&lt;li&gt;Keep context loading explicit for each prompt.&lt;/li&gt;
&lt;li&gt;For copy/paste templates, use &lt;a href="https://roygabriel.dev/blog/llm-development-guide/12-templates-checklists/"&gt;Chapter 13: Templates + Checklists: The Copy/Paste Kit&lt;/a&gt;
.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#why-this-pattern-exists"&gt;Why this pattern exists&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#the-two-document-system"&gt;The two-document system&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#worked-example-a-multi-phase-engineering-initiative"&gt;Worked example: a multi-phase engineering initiative&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#execution-protocol-for-prompt-files"&gt;Execution protocol for prompt files&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#failure-modes"&gt;Failure modes&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-this-pattern-exists"&gt;Why this pattern exists&lt;/h2&gt;
&lt;p&gt;For a one-day task, a plan plus one execution prompt is usually enough.&lt;/p&gt;</description><content:encoded>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 7 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/06-scaling-the-workflow/"&gt;Chapter 6: Scaling the Workflow: Phases, Parallelism, Hygiene&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/07-choosing-the-right-model/"&gt;Chapter 8: Choosing the Right Model: Capability Tiers, Not Hype&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to run large, multi-phase delivery with less drift by introducing two explicit artifacts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A phase specification document that defines scope, dependencies, files, and exit criteria.&lt;/li&gt;
&lt;li&gt;A phase implementation prompt document that defines the prompt-by-prompt execution contract.&lt;/li&gt;
&lt;li&gt;A repeatable operating cadence for execution, verification, and commits.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Large projects fail when a single prompt tries to carry the whole implementation plan.&lt;/li&gt;
&lt;li&gt;Use one phase spec and one implementation-prompt file per sub-phase.&lt;/li&gt;
&lt;li&gt;Execute prompts sequentially; do not continue if build/vet/test gates fail.&lt;/li&gt;
&lt;li&gt;Keep context loading explicit for each prompt.&lt;/li&gt;
&lt;li&gt;For copy/paste templates, use &lt;a href="https://roygabriel.dev/blog/llm-development-guide/12-templates-checklists/"&gt;Chapter 13: Templates + Checklists: The Copy/Paste Kit&lt;/a&gt;
.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#why-this-pattern-exists"&gt;Why this pattern exists&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#the-two-document-system"&gt;The two-document system&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#worked-example-a-multi-phase-engineering-initiative"&gt;Worked example: a multi-phase engineering initiative&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#execution-protocol-for-prompt-files"&gt;Execution protocol for prompt files&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#failure-modes"&gt;Failure modes&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-this-pattern-exists"&gt;Why this pattern exists&lt;/h2&gt;
&lt;p&gt;For a one-day task, a plan plus one execution prompt is usually enough.&lt;/p&gt;
&lt;p&gt;For multi-week work, that breaks down:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Context gets too large and detail gets dropped.&lt;/li&gt;
&lt;li&gt;Sessions diverge when constraints are implied instead of written.&lt;/li&gt;
&lt;li&gt;Verification becomes optional instead of required.&lt;/li&gt;
&lt;li&gt;Commits become large and hard to review.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The fix is to treat phase docs and implementation prompt docs as first-class project artifacts.&lt;/p&gt;
&lt;h2 id="the-two-document-system"&gt;The two-document system&lt;/h2&gt;
&lt;p&gt;For each sub-phase, create two files.&lt;/p&gt;
&lt;h3 id="1-phase-spec-document"&gt;1) Phase spec document&lt;/h3&gt;
&lt;p&gt;Purpose: define what this sub-phase must accomplish and how completion is validated.&lt;/p&gt;
&lt;p&gt;Typical sections:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Status, dependency, and migration notes.&lt;/li&gt;
&lt;li&gt;Design rationale (why this slice exists now).&lt;/li&gt;
&lt;li&gt;Tasks grouped by prompt number.&lt;/li&gt;
&lt;li&gt;Files: new, modified, and referenced-only.&lt;/li&gt;
&lt;li&gt;Exit criteria with concrete commands and expected results.&lt;/li&gt;
&lt;li&gt;Progress notes placeholder.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-phase-implementation-prompt-document"&gt;2) Phase implementation prompt document&lt;/h3&gt;
&lt;p&gt;Purpose: define exactly how execution happens, prompt by prompt.&lt;/p&gt;
&lt;p&gt;Each prompt should include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Context files to load (small, explicit list).&lt;/li&gt;
&lt;li&gt;Task details: signatures, interfaces, constraints.&lt;/li&gt;
&lt;li&gt;Quality gates and required verification commands.&lt;/li&gt;
&lt;li&gt;Stop condition: do not proceed until the current prompt passes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A useful pattern is to couple one prompt to one logical implementation unit.&lt;/p&gt;
&lt;h2 id="worked-example-a-multi-phase-engineering-initiative"&gt;Worked example: a multi-phase engineering initiative&lt;/h2&gt;
&lt;p&gt;Assume you are delivering a new runtime capability over six weeks.&lt;/p&gt;
&lt;p&gt;You split work into:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Phase A: contracts and types.&lt;/li&gt;
&lt;li&gt;Phase B: core implementation.&lt;/li&gt;
&lt;li&gt;Phase C: API and integration points.&lt;/li&gt;
&lt;li&gt;Phase D: tests and validation.&lt;/li&gt;
&lt;li&gt;Phase E: observability and rollout safety.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For &lt;code&gt;Phase B&lt;/code&gt;, your phase spec might look like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# Phase B - Core Implementation
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Status
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;Planned
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Depends on
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;Phase A
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Design rationale
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;Phase B isolates core behavior behind the contracts from Phase A.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;This prevents API and infrastructure concerns from polluting the core logic.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Tasks
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Prompt 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; Implement core orchestration types and constructor.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Prompt 2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; Implement main execution method with deterministic error paths.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Prompt 3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; Add unit tests for success and failure branches.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Files
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### New
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; internal/core/runtime.go
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; internal/core/runtime_test.go
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Modified
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; internal/core/types.go
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Referenced (read-only)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; internal/contracts/interfaces.go
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Exit criteria
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; &lt;span class="sb"&gt;`go build ./internal/core/...`&lt;/span&gt; exits 0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; &lt;span class="sb"&gt;`go vet ./internal/core/...`&lt;/span&gt; exits 0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; &lt;span class="sb"&gt;`go test ./internal/core/...`&lt;/span&gt; exits 0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; No unchecked returned errors
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Progress notes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now pair it with a &lt;code&gt;Phase B&lt;/code&gt; implementation prompt file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# Phase B - Implementation Prompts
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Prompt 1 of 3: Runtime skeleton
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Context files to load:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; docs/phases/PHASEB.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; internal/contracts/interfaces.go
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; internal/core/types.go
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; README.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Task:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Create &lt;span class="sb"&gt;`internal/core/runtime.go`&lt;/span&gt; with constructor and public methods.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Constraints:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Do not change files outside listed scope.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Handle all returned errors explicitly.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Keep methods short enough to remain reviewable.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Verification:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`go build ./internal/core/...`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`go vet ./internal/core/...`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Stop rule:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Do not proceed to Prompt 2 until both commands pass.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is intentionally boring. Boring is what scales.&lt;/p&gt;
&lt;h2 id="execution-protocol-for-prompt-files"&gt;Execution protocol for prompt files&lt;/h2&gt;
&lt;p&gt;Use the same cadence for every prompt in a sub-phase:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Load only listed context files.&lt;/li&gt;
&lt;li&gt;Execute exactly one prompt.&lt;/li&gt;
&lt;li&gt;Update work notes (decisions, assumptions, blockers, next step).&lt;/li&gt;
&lt;li&gt;Run required verification gates.&lt;/li&gt;
&lt;li&gt;Commit one logical unit.&lt;/li&gt;
&lt;li&gt;Move to the next prompt.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Suggested commit discipline:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;One commit per prompt when prompts are independent.&lt;/li&gt;
&lt;li&gt;One commit per tightly coupled prompt pair when separation creates broken intermediate states.&lt;/li&gt;
&lt;li&gt;Message format should state scope and intent clearly.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When prompt counts are high, add a completion table in work notes:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Prompt progress
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;- [x]&lt;/span&gt; Prompt 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [x]&lt;/span&gt; Prompt 2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; Prompt 3
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; Prompt 4
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="verification"&gt;Verification&lt;/h2&gt;
&lt;p&gt;You can verify this system is functioning with mechanical checks.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# All phase specs have exit criteria.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rg -n &lt;span class="s2"&gt;&amp;#34;^## Exit criteria&amp;#34;&lt;/span&gt; docs/phases/PHASE*.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# All prompt docs define context loading and verification.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rg -n &lt;span class="s2"&gt;&amp;#34;^Context files to load:|^Verification:&amp;#34;&lt;/span&gt; docs/phases/*-PROMPT.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Work notes track progression.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rg -n &lt;span class="s2"&gt;&amp;#34;^## Prompt progress|^## Session log&amp;#34;&lt;/span&gt; work-notes &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Expected results:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Every phase spec has explicit exit criteria.&lt;/li&gt;
&lt;li&gt;Every prompt file defines context and verification.&lt;/li&gt;
&lt;li&gt;Session state is recoverable without re-explaining the whole project.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="failure-modes"&gt;Failure modes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Phase docs describe architecture but skip executable gates.&lt;/li&gt;
&lt;li&gt;Prompt docs are too broad (&amp;ldquo;implement phase&amp;rdquo;) and lose determinism.&lt;/li&gt;
&lt;li&gt;Prompts proceed despite failing verification.&lt;/li&gt;
&lt;li&gt;Context file lists are bloated and include unrelated material.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If this starts happening, shrink prompt scope and tighten exit criteria before continuing.&lt;/p&gt;
&lt;p&gt;Continue -&amp;gt; &lt;a href="https://roygabriel.dev/blog/llm-development-guide/07-choosing-the-right-model/"&gt;Chapter 8: Choosing the Right Model: Capability Tiers, Not Hype&lt;/a&gt;
&lt;/p&gt;</content:encoded></item><item><title>Chapter 6: Scaling the Workflow: Phases, Parallelism, Hygiene</title><link>https://roygabriel.dev/blog/llm-development-guide/06-scaling-the-workflow/</link><pubDate>Sun, 25 Jan 2026 18:00:00 -0500</pubDate><guid>https://roygabriel.dev/blog/llm-development-guide/06-scaling-the-workflow/</guid><description>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 6 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/05-execution-loop-commit-discipline/"&gt;Chapter 5: The Execution Loop: Review Discipline + Commit Discipline&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/07-phase-documents-implementation-prompts/"&gt;Chapter 7: Large Projects with Phase Documents + Implementation Prompts&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to take the same workflow and scale it up without chaos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Split work into phases that do not overlap on files.&lt;/li&gt;
&lt;li&gt;Run parallel sessions or agents safely.&lt;/li&gt;
&lt;li&gt;Decide when artifacts stay local vs. get committed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Scale by splitting phases, not by writing bigger prompts.&lt;/li&gt;
&lt;li&gt;Keep phase files small (rule of thumb: under ~200 lines).&lt;/li&gt;
&lt;li&gt;Parallel work requires clean boundaries and explicit interfaces.&lt;/li&gt;
&lt;li&gt;Decide up front whether &lt;code&gt;plan/&lt;/code&gt;, &lt;code&gt;prompts/&lt;/code&gt;, &lt;code&gt;work-notes/&lt;/code&gt; live in git.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#when-to-sub-phase"&gt;When to sub-phase&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#parallel-execution-requirements"&gt;Parallel execution requirements&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#repository-hygiene"&gt;Repository hygiene&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#gotchas"&gt;Gotchas&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="when-to-sub-phase"&gt;When to sub-phase&lt;/h2&gt;
&lt;p&gt;Sub-phase when:&lt;/p&gt;</description><content:encoded>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 6 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/05-execution-loop-commit-discipline/"&gt;Chapter 5: The Execution Loop: Review Discipline + Commit Discipline&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/07-phase-documents-implementation-prompts/"&gt;Chapter 7: Large Projects with Phase Documents + Implementation Prompts&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to take the same workflow and scale it up without chaos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Split work into phases that do not overlap on files.&lt;/li&gt;
&lt;li&gt;Run parallel sessions or agents safely.&lt;/li&gt;
&lt;li&gt;Decide when artifacts stay local vs. get committed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Scale by splitting phases, not by writing bigger prompts.&lt;/li&gt;
&lt;li&gt;Keep phase files small (rule of thumb: under ~200 lines).&lt;/li&gt;
&lt;li&gt;Parallel work requires clean boundaries and explicit interfaces.&lt;/li&gt;
&lt;li&gt;Decide up front whether &lt;code&gt;plan/&lt;/code&gt;, &lt;code&gt;prompts/&lt;/code&gt;, &lt;code&gt;work-notes/&lt;/code&gt; live in git.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#when-to-sub-phase"&gt;When to sub-phase&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#parallel-execution-requirements"&gt;Parallel execution requirements&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#repository-hygiene"&gt;Repository hygiene&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#gotchas"&gt;Gotchas&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="when-to-sub-phase"&gt;When to sub-phase&lt;/h2&gt;
&lt;p&gt;Sub-phase when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A phase touches too many files.&lt;/li&gt;
&lt;li&gt;The phase cannot be verified independently.&lt;/li&gt;
&lt;li&gt;The phase depends on decisions that are not written down.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Example layout:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;plan/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; phase-1a-analysis.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; phase-1b-design.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; phase-2a-scaffold.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; phase-2b-core-impl.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; phase-3-validation.md
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Keep each phase &amp;ldquo;one session friendly&amp;rdquo;: small enough to complete (or at least checkpoint) in 1 to 2 sessions.&lt;/p&gt;
&lt;p&gt;At this point, many teams benefit from formalizing each sub-phase with two files: a phase spec and a phase implementation prompt file. The next chapter walks through that pattern in detail.&lt;/p&gt;
&lt;h2 id="parallel-execution-requirements"&gt;Parallel execution requirements&lt;/h2&gt;
&lt;p&gt;Parallel work is possible, but only if you make boundaries explicit.&lt;/p&gt;
&lt;p&gt;Requirements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No overlapping files between parallel phases.&lt;/li&gt;
&lt;li&gt;Explicit interfaces (types, APIs, data shapes) written down.&lt;/li&gt;
&lt;li&gt;A merge plan (who rebases, who resolves conflicts, how often you sync).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A simple pattern:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Phase A defines interfaces and contracts.&lt;/li&gt;
&lt;li&gt;Phase B implements with those interfaces.&lt;/li&gt;
&lt;li&gt;Phase C adds tests and validation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="repository-hygiene"&gt;Repository hygiene&lt;/h2&gt;
&lt;p&gt;Decide whether artifacts are local scaffolding or part of the repo.&lt;/p&gt;
&lt;p&gt;Common default:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Keep &lt;code&gt;plan/&lt;/code&gt;, &lt;code&gt;prompts/&lt;/code&gt;, &lt;code&gt;work-notes/&lt;/code&gt; local (gitignored).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Commit them deliberately when they become:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Long-lived docs.&lt;/li&gt;
&lt;li&gt;Reusable templates.&lt;/li&gt;
&lt;li&gt;Onboarding material.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you commit them, consider moving to &lt;code&gt;docs/&lt;/code&gt; and editing for humans.&lt;/p&gt;
&lt;h2 id="verification"&gt;Verification&lt;/h2&gt;
&lt;p&gt;These checks help you catch &amp;ldquo;phases are too big&amp;rdquo; early:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Find phase files that are getting too large.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# (This uses line count as a blunt proxy.)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;find plan -type f -name &lt;span class="s1"&gt;&amp;#39;*.md&amp;#39;&lt;/span&gt; -maxdepth &lt;span class="m"&gt;2&lt;/span&gt; -print0 &lt;span class="p"&gt;|&lt;/span&gt; xargs -0 wc -l &lt;span class="p"&gt;|&lt;/span&gt; sort -n
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Find prompts that do not reference work notes.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rg -n &lt;span class="s2"&gt;&amp;#34;work-notes/&amp;#34;&lt;/span&gt; prompts &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Find phases that might overlap on files (manual review).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Start by listing deliverables per phase in each prompt doc.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rg -n &lt;span class="s2"&gt;&amp;#34;^## Deliverables&amp;#34;&lt;/span&gt; -n prompts
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="gotchas"&gt;Gotchas&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Parallelization without clean boundaries just creates merge conflicts faster.&lt;/li&gt;
&lt;li&gt;If you don&amp;rsquo;t define interfaces early, later phases stall.&lt;/li&gt;
&lt;li&gt;If artifacts are committed, treat them like code: review, version, maintain.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Continue -&amp;gt; &lt;a href="https://roygabriel.dev/blog/llm-development-guide/07-phase-documents-implementation-prompts/"&gt;Chapter 7: Large Projects with Phase Documents + Implementation Prompts&lt;/a&gt;
&lt;/p&gt;</content:encoded></item><item><title>Chapter 5: The Execution Loop: Review Discipline + Commit Discipline</title><link>https://roygabriel.dev/blog/llm-development-guide/05-execution-loop-commit-discipline/</link><pubDate>Fri, 23 Jan 2026 16:00:00 -0500</pubDate><guid>https://roygabriel.dev/blog/llm-development-guide/05-execution-loop-commit-discipline/</guid><description>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 5 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/04-work-notes-session-memory/"&gt;Chapter 4: Work Notes: External Memory + Running Log&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/06-scaling-the-workflow/"&gt;Chapter 6: Scaling the Workflow: Phases, Parallelism, Hygiene&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to run an LLM through implementation work in a way that stays reviewable:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;One logical unit at a time.&lt;/li&gt;
&lt;li&gt;Verification before claiming &amp;ldquo;done&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;Atomic commits with clear intent.&lt;/li&gt;
&lt;li&gt;Notes updated as part of the loop.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Never skip: update notes, verify, propose commit, review.&lt;/li&gt;
&lt;li&gt;A &amp;ldquo;logical unit&amp;rdquo; is the smallest change that is independently reviewable.&lt;/li&gt;
&lt;li&gt;Treat LLM output like junior output: it needs review.&lt;/li&gt;
&lt;li&gt;Keep commits small to make rollback cheap.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#the-execution-loop"&gt;The execution loop&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#what-counts-as-a-logical-unit"&gt;What counts as a logical unit&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#commit-discipline"&gt;Commit discipline&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#failure-modes"&gt;Failure modes&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-execution-loop"&gt;The execution loop&lt;/h2&gt;
&lt;p&gt;This loop is intentionally repetitive:&lt;/p&gt;</description><content:encoded>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 5 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/04-work-notes-session-memory/"&gt;Chapter 4: Work Notes: External Memory + Running Log&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/06-scaling-the-workflow/"&gt;Chapter 6: Scaling the Workflow: Phases, Parallelism, Hygiene&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to run an LLM through implementation work in a way that stays reviewable:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;One logical unit at a time.&lt;/li&gt;
&lt;li&gt;Verification before claiming &amp;ldquo;done&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;Atomic commits with clear intent.&lt;/li&gt;
&lt;li&gt;Notes updated as part of the loop.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Never skip: update notes, verify, propose commit, review.&lt;/li&gt;
&lt;li&gt;A &amp;ldquo;logical unit&amp;rdquo; is the smallest change that is independently reviewable.&lt;/li&gt;
&lt;li&gt;Treat LLM output like junior output: it needs review.&lt;/li&gt;
&lt;li&gt;Keep commits small to make rollback cheap.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#the-execution-loop"&gt;The execution loop&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#what-counts-as-a-logical-unit"&gt;What counts as a logical unit&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#commit-discipline"&gt;Commit discipline&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#failure-modes"&gt;Failure modes&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-execution-loop"&gt;The execution loop&lt;/h2&gt;
&lt;p&gt;This loop is intentionally repetitive:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Load prompt + work-notes
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-&amp;gt; implement one logical unit
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-&amp;gt; update work-notes
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-&amp;gt; verify
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-&amp;gt; propose commit
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-&amp;gt; you review
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-&amp;gt; commit
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-&amp;gt; repeat
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you skip the middle steps, your &amp;ldquo;agent&amp;rdquo; becomes a vibes-based code generator.&lt;/p&gt;
&lt;h2 id="what-counts-as-a-logical-unit"&gt;What counts as a logical unit&lt;/h2&gt;
&lt;p&gt;A logical unit is a change that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Has a clear purpose.&lt;/li&gt;
&lt;li&gt;Can be verified.&lt;/li&gt;
&lt;li&gt;Can be reviewed in isolation.&lt;/li&gt;
&lt;li&gt;Does not leave the repo in a half-broken state.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add one Kubernetes template file.&lt;/li&gt;
&lt;li&gt;Add one Go type + its tests.&lt;/li&gt;
&lt;li&gt;Add one API endpoint handler.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Non-examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Implement everything for phase 2&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Half a refactor&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Quick fixes&amp;rdquo;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="commit-discipline"&gt;Commit discipline&lt;/h2&gt;
&lt;p&gt;Use a consistent commit format so you can scan history later.&lt;/p&gt;
&lt;p&gt;Example commit message:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;feat(helm): add service template for metrics-gateway
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- Exposes port 9090 as ClusterIP
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- Follows event-processor naming and labels
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- No ingress in this commit
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Refs: work-notes/phase-2b-core-resources.md
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In prompts, require the model to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Summarize what changed.&lt;/li&gt;
&lt;li&gt;Explain why.&lt;/li&gt;
&lt;li&gt;Propose a message.&lt;/li&gt;
&lt;li&gt;Wait for approval.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="verification"&gt;Verification&lt;/h2&gt;
&lt;p&gt;Verification is context-specific, but the shape is consistent:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Build.&lt;/li&gt;
&lt;li&gt;Test.&lt;/li&gt;
&lt;li&gt;Lint.&lt;/li&gt;
&lt;li&gt;Render config.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Generic verification commands you can adapt:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Make sure you know what is staged and what is not.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git status --porcelain
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git diff
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Run the repo&amp;#39;s verification gates.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Replace these with your actual commands.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;go &lt;span class="nb"&gt;test&lt;/span&gt; ./...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# After the commit, ensure you&amp;#39;re clean.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git status --porcelain
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Expected results:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Before committing, &lt;code&gt;git diff&lt;/code&gt; matches the logical unit scope.&lt;/li&gt;
&lt;li&gt;After committing, &lt;code&gt;git status --porcelain&lt;/code&gt; is empty.&lt;/li&gt;
&lt;li&gt;Tests and other gates exit 0.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="failure-modes"&gt;Failure modes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The model keeps &amp;ldquo;just one more change&amp;rdquo;-ing.
&lt;ul&gt;
&lt;li&gt;Fix: put explicit stop points in the prompt.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;You don&amp;rsquo;t verify.
&lt;ul&gt;
&lt;li&gt;Fix: add verification commands to plan and prompt docs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Commits include unrelated changes.
&lt;ul&gt;
&lt;li&gt;Fix: shrink the logical unit and split the work.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;You approve output you can&amp;rsquo;t review.
&lt;ul&gt;
&lt;li&gt;Fix: stop and do it manually or bring in a reviewer.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Continue -&amp;gt; &lt;a href="https://roygabriel.dev/blog/llm-development-guide/06-scaling-the-workflow/"&gt;Chapter 6: Scaling the Workflow: Phases, Parallelism, Hygiene&lt;/a&gt;
&lt;/p&gt;</content:encoded></item><item><title>Chapter 4: Work Notes: External Memory + Running Log</title><link>https://roygabriel.dev/blog/llm-development-guide/04-work-notes-session-memory/</link><pubDate>Wed, 21 Jan 2026 14:00:00 -0500</pubDate><guid>https://roygabriel.dev/blog/llm-development-guide/04-work-notes-session-memory/</guid><description>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 4 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/03-prompt-documents/"&gt;Chapter 3: Prompt Documents: Prompts That Survive Sessions&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/05-execution-loop-commit-discipline/"&gt;Chapter 5: The Execution Loop: Review Discipline + Commit Discipline&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to keep multi-session work consistent by maintaining work notes that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Preserve the model&amp;rsquo;s working state outside the chat.&lt;/li&gt;
&lt;li&gt;Capture decisions and rationale for later review.&lt;/li&gt;
&lt;li&gt;Make handoffs possible.&lt;/li&gt;
&lt;li&gt;Provide a deterministic &amp;ldquo;resume&amp;rdquo; prompt.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;LLMs have no durable memory. If it&amp;rsquo;s not written down, it doesn&amp;rsquo;t exist next session.&lt;/li&gt;
&lt;li&gt;Mirror &lt;code&gt;work-notes/&lt;/code&gt; files to your phases exactly.&lt;/li&gt;
&lt;li&gt;Track: status, decisions, assumptions, open questions, session log, commits.&lt;/li&gt;
&lt;li&gt;In your prompts, require the model to update notes before moving forward.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#directory-alignment"&gt;Directory alignment&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#a-work-notes-template-you-can-paste"&gt;A work-notes template you can paste&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#session-start-and-session-end-prompts"&gt;Session start and session end prompts&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#gotchas"&gt;Gotchas&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="directory-alignment"&gt;Directory alignment&lt;/h2&gt;
&lt;p&gt;Keep your three directories aligned so you can load one phase without dragging unrelated context into the session:&lt;/p&gt;</description><content:encoded>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 4 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/03-prompt-documents/"&gt;Chapter 3: Prompt Documents: Prompts That Survive Sessions&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/05-execution-loop-commit-discipline/"&gt;Chapter 5: The Execution Loop: Review Discipline + Commit Discipline&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to keep multi-session work consistent by maintaining work notes that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Preserve the model&amp;rsquo;s working state outside the chat.&lt;/li&gt;
&lt;li&gt;Capture decisions and rationale for later review.&lt;/li&gt;
&lt;li&gt;Make handoffs possible.&lt;/li&gt;
&lt;li&gt;Provide a deterministic &amp;ldquo;resume&amp;rdquo; prompt.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;LLMs have no durable memory. If it&amp;rsquo;s not written down, it doesn&amp;rsquo;t exist next session.&lt;/li&gt;
&lt;li&gt;Mirror &lt;code&gt;work-notes/&lt;/code&gt; files to your phases exactly.&lt;/li&gt;
&lt;li&gt;Track: status, decisions, assumptions, open questions, session log, commits.&lt;/li&gt;
&lt;li&gt;In your prompts, require the model to update notes before moving forward.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#directory-alignment"&gt;Directory alignment&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#a-work-notes-template-you-can-paste"&gt;A work-notes template you can paste&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#session-start-and-session-end-prompts"&gt;Session start and session end prompts&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#gotchas"&gt;Gotchas&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="directory-alignment"&gt;Directory alignment&lt;/h2&gt;
&lt;p&gt;Keep your three directories aligned so you can load one phase without dragging unrelated context into the session:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;plan/phase-2a-scaffolding.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;prompts/phase-2a-scaffolding.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;work-notes/phase-2a-scaffolding.md
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This makes sessions resumable and makes parallel work possible.&lt;/p&gt;
&lt;h2 id="a-work-notes-template-you-can-paste"&gt;A work-notes template you can paste&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# Phase &amp;lt;X&amp;gt; - &amp;lt;Phase Name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Status
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; Not started
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; In progress
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; Blocked
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; Complete
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Decisions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;Decision&amp;gt;: &amp;lt;Rationale&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Assumptions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;Assumption&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Open questions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; &amp;lt;Question&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Session log
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### &amp;lt;YYYY-MM-DD HH:MM&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; What changed:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Why:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Blockers:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Next:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Commits
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;hash&amp;gt; - &amp;lt;message&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can keep it simple. The win is consistency.&lt;/p&gt;
&lt;h2 id="session-start-and-session-end-prompts"&gt;Session start and session end prompts&lt;/h2&gt;
&lt;h3 id="start-a-session"&gt;Start a session&lt;/h3&gt;
&lt;p&gt;Paste your phase prompt and current work notes, and tell the model to continue from the last session.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;I&amp;#39;m continuing work on Phase &amp;lt;X&amp;gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Prompt:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;paste prompts/phase-X.md&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Current state:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;paste work-notes/phase-X.md&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Please:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1. Summarize where we are (3 to 4 sentences).
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2. List blockers and open questions.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;3. Confirm the next logical unit.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;4. Proceed with the next logical unit.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="end-a-session"&gt;End a session&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Before we stop:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1. Update the session log with what we did and what is next.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2. Ensure decisions, assumptions, and open questions are current.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;3. Propose a commit message for any completed logical unit.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;4. Show the updated work-notes file.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="verification"&gt;Verification&lt;/h2&gt;
&lt;p&gt;You can verify your notes are doing their job by forcing a cold start:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Start a new chat.&lt;/li&gt;
&lt;li&gt;Paste only the phase prompt and the work-notes file.&lt;/li&gt;
&lt;li&gt;See if you can resume without re-explaining anything.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Mechanical checks:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Work notes exist and are non-empty.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;find work-notes -type f -name &lt;span class="s1"&gt;&amp;#39;*.md&amp;#39;&lt;/span&gt; -maxdepth &lt;span class="m"&gt;2&lt;/span&gt; -print -exec &lt;span class="nb"&gt;test&lt;/span&gt; -s &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Work notes have at least the core sections.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rg -n &lt;span class="s2"&gt;&amp;#34;^## (Status|Decisions|Assumptions|Open questions|Session log|Commits)&amp;#34;&lt;/span&gt; work-notes
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="gotchas"&gt;Gotchas&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Notes without rationale are not useful later.&lt;/li&gt;
&lt;li&gt;If you let the model continue without updating notes, the next session will drift.&lt;/li&gt;
&lt;li&gt;Avoid dumping raw logs with sensitive data. Sanitize first.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Continue -&amp;gt; &lt;a href="https://roygabriel.dev/blog/llm-development-guide/05-execution-loop-commit-discipline/"&gt;Chapter 5: The Execution Loop: Review Discipline + Commit Discipline&lt;/a&gt;
&lt;/p&gt;</content:encoded></item><item><title>Chapter 3: Prompt Documents: Prompts That Survive Sessions</title><link>https://roygabriel.dev/blog/llm-development-guide/03-prompt-documents/</link><pubDate>Mon, 19 Jan 2026 12:00:00 -0500</pubDate><guid>https://roygabriel.dev/blog/llm-development-guide/03-prompt-documents/</guid><description>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 3 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/02-planning-artifacts/"&gt;Chapter 2: Planning: Plan Artifacts, Constraints, Definition of Done&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/04-work-notes-session-memory/"&gt;Chapter 4: Work Notes: External Memory + Running Log&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to create prompt documents that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Encode intent precisely so you don&amp;rsquo;t re-explain yourself.&lt;/li&gt;
&lt;li&gt;Align to plan phases so scope stays tight.&lt;/li&gt;
&lt;li&gt;Include verification steps and explicit stop points.&lt;/li&gt;
&lt;li&gt;Tell the model how to update work notes and propose commits.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A prompt doc is an artifact, not a chat message.&lt;/li&gt;
&lt;li&gt;Use one prompt file per phase.&lt;/li&gt;
&lt;li&gt;Always include: role, context, task, constraints, deliverables, verification, session management.&lt;/li&gt;
&lt;li&gt;Put negative constraints in writing (&amp;ldquo;MUST NOT&amp;rdquo;).&lt;/li&gt;
&lt;li&gt;Keep prompts copy/pasteable and path-specific.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#why-prompt-docs-matter"&gt;Why prompt docs matter&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#anatomy-of-a-good-prompt"&gt;Anatomy of a good prompt&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#a-template-you-can-copy"&gt;A template you can copy&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#failure-modes"&gt;Failure modes&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-prompt-docs-matter"&gt;Why prompt docs matter&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re doing anything bigger than a one-off snippet, the prompt itself becomes part of the system.&lt;/p&gt;</description><content:encoded>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 3 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/02-planning-artifacts/"&gt;Chapter 2: Planning: Plan Artifacts, Constraints, Definition of Done&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/04-work-notes-session-memory/"&gt;Chapter 4: Work Notes: External Memory + Running Log&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to create prompt documents that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Encode intent precisely so you don&amp;rsquo;t re-explain yourself.&lt;/li&gt;
&lt;li&gt;Align to plan phases so scope stays tight.&lt;/li&gt;
&lt;li&gt;Include verification steps and explicit stop points.&lt;/li&gt;
&lt;li&gt;Tell the model how to update work notes and propose commits.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A prompt doc is an artifact, not a chat message.&lt;/li&gt;
&lt;li&gt;Use one prompt file per phase.&lt;/li&gt;
&lt;li&gt;Always include: role, context, task, constraints, deliverables, verification, session management.&lt;/li&gt;
&lt;li&gt;Put negative constraints in writing (&amp;ldquo;MUST NOT&amp;rdquo;).&lt;/li&gt;
&lt;li&gt;Keep prompts copy/pasteable and path-specific.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#why-prompt-docs-matter"&gt;Why prompt docs matter&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#anatomy-of-a-good-prompt"&gt;Anatomy of a good prompt&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#a-template-you-can-copy"&gt;A template you can copy&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#failure-modes"&gt;Failure modes&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-prompt-docs-matter"&gt;Why prompt docs matter&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re doing anything bigger than a one-off snippet, the prompt itself becomes part of the system.&lt;/p&gt;
&lt;p&gt;Prompt docs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reduce &amp;ldquo;prompt drift&amp;rdquo; across sessions.&lt;/li&gt;
&lt;li&gt;Make handoffs possible.&lt;/li&gt;
&lt;li&gt;Create an audit trail of what was asked.&lt;/li&gt;
&lt;li&gt;Force you to pin down deliverables and done-ness.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="anatomy-of-a-good-prompt"&gt;Anatomy of a good prompt&lt;/h2&gt;
&lt;p&gt;At minimum, include these sections:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Role: what expertise you&amp;rsquo;re invoking.&lt;/li&gt;
&lt;li&gt;Context: plan path, work-notes path, reference implementation paths.&lt;/li&gt;
&lt;li&gt;Task: what to do now.&lt;/li&gt;
&lt;li&gt;Constraints: what must and must not happen.&lt;/li&gt;
&lt;li&gt;Deliverables: exact files and outputs expected.&lt;/li&gt;
&lt;li&gt;Verification: commands and expected results.&lt;/li&gt;
&lt;li&gt;Session management: how to update work notes.&lt;/li&gt;
&lt;li&gt;Commit discipline: atomic commits, propose messages, wait for approval.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If your prompt is missing verification and stop rules, you&amp;rsquo;re inviting &amp;ldquo;looks right&amp;rdquo; output.&lt;/p&gt;
&lt;h2 id="a-template-you-can-copy"&gt;A template you can copy&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# Phase &amp;lt;X&amp;gt; - &amp;lt;Phase Name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Role
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;You are a senior software engineer.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Context
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; Plan: plan/&amp;lt;phase&amp;gt;.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Work notes: work-notes/&amp;lt;phase&amp;gt;.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Reference implementations:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;path 1&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;path 2&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Task
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;Implement the next logical unit for this phase.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Constraints (follow exactly)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; MUST follow patterns in the reference implementations.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; MUST keep changes scoped to this phase.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; MUST include tests when applicable.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; MUST propose verification commands.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; MUST NOT add new dependencies unless explicitly approved.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Deliverables
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;1.&lt;/span&gt; &amp;lt;file path&amp;gt; - &amp;lt;what it contains&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;2.&lt;/span&gt; &amp;lt;file path&amp;gt; - &amp;lt;what it contains&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Session management
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;As you work:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Update work-notes/&amp;lt;phase&amp;gt;.md:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;-&lt;/span&gt; Decisions (with rationale)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;-&lt;/span&gt; Assumptions
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;-&lt;/span&gt; Open questions
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;-&lt;/span&gt; Session log entry
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; After each logical unit, pause and show the updated notes section.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Verification
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;After implementing the logical unit, run or propose:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;command&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Expected: &amp;lt;exit 0 / output contains X&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Commit discipline
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;After verification:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;1.&lt;/span&gt; Summarize what changed and why.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;2.&lt;/span&gt; Propose a conventional commit message.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;3.&lt;/span&gt; Wait for approval before continuing.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Refs: work-notes/&amp;lt;phase&amp;gt;.md
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use real paths.&lt;/li&gt;
&lt;li&gt;Put constraints in a dedicated section.&lt;/li&gt;
&lt;li&gt;Repeat the most important constraints near the end.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="verification"&gt;Verification&lt;/h2&gt;
&lt;p&gt;You can verify prompt docs are usable by checking two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can paste the entire file verbatim into a new session.&lt;/li&gt;
&lt;li&gt;A new session produces the same behavior because paths and constraints are explicit.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Concrete checks:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Prompts exist and are non-empty.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;find prompts -type f -name &lt;span class="s1"&gt;&amp;#39;*.md&amp;#39;&lt;/span&gt; -maxdepth &lt;span class="m"&gt;2&lt;/span&gt; -print -exec &lt;span class="nb"&gt;test&lt;/span&gt; -s &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Prompts mention work-notes paths.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rg -n &lt;span class="s2"&gt;&amp;#34;work-notes/&amp;#34;&lt;/span&gt; prompts
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Expected results:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Each prompt file is non-empty.&lt;/li&gt;
&lt;li&gt;Each prompt references a work-notes file.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="failure-modes"&gt;Failure modes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Prompts that say &amp;ldquo;use the config file&amp;rdquo; without a path.&lt;/li&gt;
&lt;li&gt;Constraints buried in prose instead of a dedicated section.&lt;/li&gt;
&lt;li&gt;Prompts that do not mention verification.&lt;/li&gt;
&lt;li&gt;Prompts that do not tell the model to stop after a logical unit.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Continue -&amp;gt; &lt;a href="https://roygabriel.dev/blog/llm-development-guide/04-work-notes-session-memory/"&gt;Chapter 4: Work Notes: External Memory + Running Log&lt;/a&gt;
&lt;/p&gt;</content:encoded></item><item><title>Chapter 2: Planning: Plan Artifacts, Constraints, Definition of Done</title><link>https://roygabriel.dev/blog/llm-development-guide/02-planning-artifacts/</link><pubDate>Sat, 17 Jan 2026 11:00:00 -0500</pubDate><guid>https://roygabriel.dev/blog/llm-development-guide/02-planning-artifacts/</guid><description>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 2 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/01-practical-workflow-day-2/"&gt;Chapter 1: A Practical Workflow for LLM-Assisted Development That Doesn&amp;rsquo;t Collapse After Day 2&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/03-prompt-documents/"&gt;Chapter 3: Prompt Documents: Prompts That Survive Sessions&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to write a plan artifact that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Forces clarity on scope, constraints, and references.&lt;/li&gt;
&lt;li&gt;Produces verification steps (not just a task list).&lt;/li&gt;
&lt;li&gt;Is sized so an LLM can execute it phase-by-phase without drifting.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A plan is a shared source of truth between you and the model.&lt;/li&gt;
&lt;li&gt;Keep plans at the &amp;ldquo;what&amp;rdquo; level; keep &amp;ldquo;how&amp;rdquo; in prompt docs.&lt;/li&gt;
&lt;li&gt;Every phase needs verification and a definition of done.&lt;/li&gt;
&lt;li&gt;If a plan file would exceed ~200 lines, split it.&lt;/li&gt;
&lt;li&gt;Always point to reference implementations by path.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#what-belongs-in-a-plan-and-what-doesnt"&gt;What belongs in a plan (and what doesn&amp;rsquo;t)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#a-plan-template-you-can-paste"&gt;A plan template you can paste&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#sizing-rules"&gt;Sizing rules&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification-and-definition-of-done"&gt;Verification and definition of done&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#gotchas"&gt;Gotchas&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-belongs-in-a-plan-and-what-doesnt"&gt;What belongs in a plan (and what doesn&amp;rsquo;t)&lt;/h2&gt;
&lt;p&gt;Plans work when they are explicit and boring.&lt;/p&gt;</description><content:encoded>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 2 of 16&lt;/p&gt;
&lt;p&gt;Previous: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/01-practical-workflow-day-2/"&gt;Chapter 1: A Practical Workflow for LLM-Assisted Development That Doesn&amp;rsquo;t Collapse After Day 2&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/03-prompt-documents/"&gt;Chapter 3: Prompt Documents: Prompts That Survive Sessions&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to write a plan artifact that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Forces clarity on scope, constraints, and references.&lt;/li&gt;
&lt;li&gt;Produces verification steps (not just a task list).&lt;/li&gt;
&lt;li&gt;Is sized so an LLM can execute it phase-by-phase without drifting.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A plan is a shared source of truth between you and the model.&lt;/li&gt;
&lt;li&gt;Keep plans at the &amp;ldquo;what&amp;rdquo; level; keep &amp;ldquo;how&amp;rdquo; in prompt docs.&lt;/li&gt;
&lt;li&gt;Every phase needs verification and a definition of done.&lt;/li&gt;
&lt;li&gt;If a plan file would exceed ~200 lines, split it.&lt;/li&gt;
&lt;li&gt;Always point to reference implementations by path.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#what-belongs-in-a-plan-and-what-doesnt"&gt;What belongs in a plan (and what doesn&amp;rsquo;t)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#a-plan-template-you-can-paste"&gt;A plan template you can paste&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#sizing-rules"&gt;Sizing rules&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification-and-definition-of-done"&gt;Verification and definition of done&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#gotchas"&gt;Gotchas&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-belongs-in-a-plan-and-what-doesnt"&gt;What belongs in a plan (and what doesn&amp;rsquo;t)&lt;/h2&gt;
&lt;p&gt;Plans work when they are explicit and boring.&lt;/p&gt;
&lt;p&gt;Include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Goals and non-goals.&lt;/li&gt;
&lt;li&gt;Constraints and invariants.&lt;/li&gt;
&lt;li&gt;Reference implementations (by path).&lt;/li&gt;
&lt;li&gt;Phases in dependency order.&lt;/li&gt;
&lt;li&gt;Verification for each phase.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Avoid:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Full code blocks.&lt;/li&gt;
&lt;li&gt;Deep implementation detail.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Make it better&amp;rdquo; language.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you want the LLM to do a thing consistently across sessions, you need the thing written down.&lt;/p&gt;
&lt;h2 id="a-plan-template-you-can-paste"&gt;A plan template you can paste&lt;/h2&gt;
&lt;p&gt;Create one plan file per phase for larger work.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# &amp;lt;Project&amp;gt; Plan
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Overview
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&amp;lt;1 to 2 sentences about what we are building&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Goals
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;Goal 1&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;Goal 2&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Non-goals
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;Explicitly out of scope&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Constraints
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;Must follow reference style X&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;Must not add dependencies&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;Must keep backward compatibility&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## References
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;Path to reference implementation 1&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;Path to reference implementation 2&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Phase 1: &amp;lt;Name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; &amp;lt;Task 1&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; &amp;lt;Task 2&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Verification:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;Command&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Expected: &amp;lt;Exit 0 / output contains X&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Phase 2: &amp;lt;Name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; &amp;lt;Task 1&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Verification:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;Command&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Expected: &amp;lt;...&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Definition of done
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; &amp;lt;All phases verified&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; &amp;lt;Tests pass&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; &amp;lt;Docs updated as needed&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [ ]&lt;/span&gt; &amp;lt;No TODOs left behind&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Risks / open questions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;Open question 1&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; &amp;lt;Risk 1&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="sizing-rules"&gt;Sizing rules&lt;/h2&gt;
&lt;p&gt;You need the plan sized so the LLM can execute it without mixing unrelated changes.&lt;/p&gt;
&lt;p&gt;Use these rules of thumb:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Small (hours to 1 to 2 days): one &lt;code&gt;PLAN.md&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Medium (1 to 2 weeks): one &lt;code&gt;PLAN.md&lt;/code&gt; with explicit phases.&lt;/li&gt;
&lt;li&gt;Large (multi-week): &lt;code&gt;plan/phase-1a-...md&lt;/code&gt;, &lt;code&gt;plan/phase-1b-...md&lt;/code&gt;, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When in doubt:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Split by file ownership (phases should avoid editing the same files).&lt;/li&gt;
&lt;li&gt;Split by interface boundaries (one phase defines types/contracts; later phases implement).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="verification-and-definition-of-done"&gt;Verification and definition of done&lt;/h2&gt;
&lt;p&gt;Make verification explicit in the plan so you don&amp;rsquo;t have to negotiate it mid-session.&lt;/p&gt;
&lt;p&gt;Bad:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Add tests&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Better:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Add unit tests for &lt;code&gt;Foo&lt;/code&gt; and run &lt;code&gt;go test ./...&lt;/code&gt; (expected: exit 0).&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If your phase can&amp;rsquo;t be verified, it probably isn&amp;rsquo;t a phase yet.&lt;/p&gt;
&lt;h2 id="verification"&gt;Verification&lt;/h2&gt;
&lt;p&gt;If you follow the template above, you should be able to run something like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Example: lint and test gates.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Replace with your repo&amp;#39;s actual commands.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;go &lt;span class="nb"&gt;test&lt;/span&gt; ./...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git diff --stat
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Expected results:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;go test&lt;/code&gt; exits 0.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git diff --stat&lt;/code&gt; shows only the files you intended to touch in this phase.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="gotchas"&gt;Gotchas&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Plans that mix &amp;ldquo;what&amp;rdquo; and &amp;ldquo;how&amp;rdquo; become unreadable quickly.&lt;/li&gt;
&lt;li&gt;If you don&amp;rsquo;t write down constraints, the LLM will invent defaults.&lt;/li&gt;
&lt;li&gt;A &amp;ldquo;phase&amp;rdquo; that touches 30 files is usually multiple phases.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Continue -&amp;gt; &lt;a href="https://roygabriel.dev/blog/llm-development-guide/03-prompt-documents/"&gt;Chapter 3: Prompt Documents: Prompts That Survive Sessions&lt;/a&gt;
&lt;/p&gt;</content:encoded></item><item><title>Chapter 1: A Practical Workflow for LLM-Assisted Development That Doesn't Collapse After Day 2</title><link>https://roygabriel.dev/blog/llm-development-guide/01-practical-workflow-day-2/</link><pubDate>Thu, 15 Jan 2026 09:00:00 -0500</pubDate><guid>https://roygabriel.dev/blog/llm-development-guide/01-practical-workflow-day-2/</guid><description>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 1 of 16&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/02-planning-artifacts/"&gt;Chapter 2: Planning: Plan Artifacts, Constraints, Definition of Done&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to take a real development task and run an LLM through a repeatable loop that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Survives breaks and multi-day work.&lt;/li&gt;
&lt;li&gt;Produces output you can actually review.&lt;/li&gt;
&lt;li&gt;Includes verification steps, not just code.&lt;/li&gt;
&lt;li&gt;Creates a paper trail of decisions and assumptions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Treat the LLM like a senior engineer who can execute quickly, but has no durable memory.&lt;/li&gt;
&lt;li&gt;Externalize memory into three artifacts: &lt;code&gt;plan/&lt;/code&gt;, &lt;code&gt;prompts/&lt;/code&gt;, and &lt;code&gt;work-notes/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For large projects, add phase specification docs and phase implementation prompt docs (see Chapter 7).&lt;/li&gt;
&lt;li&gt;Execute in small logical units, with verification and atomic commits.&lt;/li&gt;
&lt;li&gt;If you&amp;rsquo;re fighting output quality, upgrade the model or shrink the scope.&lt;/li&gt;
&lt;li&gt;Never paste secrets, PII, or production data.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="trust-contract-read-this-before-you-paste-anything"&gt;Trust contract (read this before you paste anything)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Security: do not paste secrets, tokens, customer data, or anything you would not publish in a public repo.&lt;/li&gt;
&lt;li&gt;Staleness: model names, pricing, and vendor policies change frequently. Treat examples as illustrative as of 2026-02-14.&lt;/li&gt;
&lt;li&gt;Prereqs: you can run tests, review diffs, and explain the change in a code review.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#why-most-llm-assisted-development-fails"&gt;Why most LLM-assisted development fails&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#the-workflow"&gt;The workflow&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#quick-start-copypaste-kit"&gt;Quick start: copy/paste kit&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#worked-example-helm-chart-from-a-reference-chart"&gt;Worked example: Helm chart from a reference chart&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#failure-modes"&gt;Failure modes&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-most-llm-assisted-development-fails"&gt;Why most LLM-assisted development fails&lt;/h2&gt;
&lt;p&gt;Most failures are workflow failures, not &amp;ldquo;prompting&amp;rdquo; failures:&lt;/p&gt;</description><content:encoded>&lt;p&gt;Series: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/"&gt;LLM Development Guide&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Chapter 1 of 16&lt;/p&gt;
&lt;p&gt;Next: &lt;a href="https://roygabriel.dev/blog/llm-development-guide/02-planning-artifacts/"&gt;Chapter 2: Planning: Plan Artifacts, Constraints, Definition of Done&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="what-youll-be-able-to-do"&gt;What you&amp;rsquo;ll be able to do&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll be able to take a real development task and run an LLM through a repeatable loop that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Survives breaks and multi-day work.&lt;/li&gt;
&lt;li&gt;Produces output you can actually review.&lt;/li&gt;
&lt;li&gt;Includes verification steps, not just code.&lt;/li&gt;
&lt;li&gt;Creates a paper trail of decisions and assumptions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Treat the LLM like a senior engineer who can execute quickly, but has no durable memory.&lt;/li&gt;
&lt;li&gt;Externalize memory into three artifacts: &lt;code&gt;plan/&lt;/code&gt;, &lt;code&gt;prompts/&lt;/code&gt;, and &lt;code&gt;work-notes/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For large projects, add phase specification docs and phase implementation prompt docs (see Chapter 7).&lt;/li&gt;
&lt;li&gt;Execute in small logical units, with verification and atomic commits.&lt;/li&gt;
&lt;li&gt;If you&amp;rsquo;re fighting output quality, upgrade the model or shrink the scope.&lt;/li&gt;
&lt;li&gt;Never paste secrets, PII, or production data.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="trust-contract-read-this-before-you-paste-anything"&gt;Trust contract (read this before you paste anything)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Security: do not paste secrets, tokens, customer data, or anything you would not publish in a public repo.&lt;/li&gt;
&lt;li&gt;Staleness: model names, pricing, and vendor policies change frequently. Treat examples as illustrative as of 2026-02-14.&lt;/li&gt;
&lt;li&gt;Prereqs: you can run tests, review diffs, and explain the change in a code review.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#why-most-llm-assisted-development-fails"&gt;Why most LLM-assisted development fails&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#the-workflow"&gt;The workflow&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#quick-start-copypaste-kit"&gt;Quick start: copy/paste kit&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#worked-example-helm-chart-from-a-reference-chart"&gt;Worked example: Helm chart from a reference chart&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#failure-modes"&gt;Failure modes&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-most-llm-assisted-development-fails"&gt;Why most LLM-assisted development fails&lt;/h2&gt;
&lt;p&gt;Most failures are workflow failures, not &amp;ldquo;prompting&amp;rdquo; failures:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You jump straight to implementation without a plan.&lt;/li&gt;
&lt;li&gt;You don&amp;rsquo;t provide reference implementations, so you get generic output.&lt;/li&gt;
&lt;li&gt;You lose context across sessions.&lt;/li&gt;
&lt;li&gt;You don&amp;rsquo;t verify output.&lt;/li&gt;
&lt;li&gt;You batch changes into giant commits that are hard to review or revert.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-workflow"&gt;The workflow&lt;/h2&gt;
&lt;p&gt;This is the smallest loop I&amp;rsquo;ve found that stays stable after day 2:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Plan -&amp;gt; Prompt docs -&amp;gt; Work notes -&amp;gt; Execute -&amp;gt; Verify -&amp;gt; Commit
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The artifacts are simple:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;plan/&lt;/code&gt;: what we&amp;rsquo;re doing and how we&amp;rsquo;ll know it&amp;rsquo;s done.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;prompts/&lt;/code&gt;: the reusable prompts aligned to phases.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;work-notes/&lt;/code&gt;: state, decisions, assumptions, open questions, and a running session log.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When work scales to multi-week delivery, promote this into explicit phase specification docs plus phase implementation prompt files so scope and verification stay deterministic across sessions.&lt;/p&gt;
&lt;h2 id="quick-start-copypaste-kit"&gt;Quick start: copy/paste kit&lt;/h2&gt;
&lt;p&gt;This is intentionally minimal. It&amp;rsquo;s enough to make sessions resumable.&lt;/p&gt;
&lt;h3 id="1-create-the-artifact-directories"&gt;1) Create the artifact directories&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p plan prompts work-notes
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-create-a-minimal-plan"&gt;2) Create a minimal plan&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &amp;gt; plan/phase-1.md &lt;span class="s"&gt;&amp;lt;&amp;lt;&amp;#39;MD&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;# Phase 1: Plan
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Overview
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;&amp;lt;One sentence: what we are building&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Goals
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- &amp;lt;Goal 1&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- &amp;lt;Goal 2&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Constraints
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- &amp;lt;Constraint 1&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- &amp;lt;Constraint 2&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Definition of done
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- [ ] &amp;lt;Verification command + expected outcome&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- [ ] &amp;lt;Verification command + expected outcome&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Out of scope
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- &amp;lt;Thing we will not do in this phase&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;MD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-create-a-phase-prompt-doc"&gt;3) Create a phase prompt doc&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &amp;gt; prompts/phase-1.md &lt;span class="s"&gt;&amp;lt;&amp;lt;&amp;#39;MD&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;# Phase 1 - Execution Prompt
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Role
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;You are a senior software engineer.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Context
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- Plan: plan/phase-1.md
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- Work notes: work-notes/phase-1.md
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- Reference implementation(s): &amp;lt;paths&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Task
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;Implement the smallest logical unit that moves this phase forward.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Constraints (follow exactly)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- MUST follow patterns in the reference implementation.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- MUST propose verification commands.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- MUST NOT change files outside this phase scope.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Session management
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;As you work, update work-notes/phase-1.md:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- Decisions (with rationale)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- Assumptions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- Open questions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- Session log entry
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Commit discipline
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;After each logical unit:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;1. Stop and summarize what changed.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;2. Propose a commit message.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;3. Wait for approval.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;MD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="4-create-work-notes"&gt;4) Create work notes&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &amp;gt; work-notes/phase-1.md &lt;span class="s"&gt;&amp;lt;&amp;lt;&amp;#39;MD&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;# Phase 1 - Work Notes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Status
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- [ ] Not started
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- [ ] In progress
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- [ ] Blocked
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- [ ] Complete
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Decisions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Assumptions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Open questions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Session log
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;## Commits
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;MD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="worked-example-helm-chart-from-a-reference-chart"&gt;Worked example: Helm chart from a reference chart&lt;/h2&gt;
&lt;p&gt;This example is about correctness and maintainability, not &amp;ldquo;Helm tricks&amp;rdquo;.&lt;/p&gt;
&lt;h3 id="scenario"&gt;Scenario&lt;/h3&gt;
&lt;p&gt;Goal: create a new chart (for example, &lt;code&gt;metrics-gateway&lt;/code&gt;) by following a reference chart (for example, &lt;code&gt;event-processor&lt;/code&gt;) that already works in your environment.&lt;/p&gt;
&lt;p&gt;The important part is the inputs you give the model. Don&amp;rsquo;t describe the reference chart. Paste it.&lt;/p&gt;
&lt;h3 id="reference-inputs-what-to-paste"&gt;Reference inputs (what to paste)&lt;/h3&gt;
&lt;p&gt;Run these commands in your repo and paste their output into your planning prompt:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tree charts/event-processor/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sed -n &lt;span class="s1"&gt;&amp;#39;1,200p&amp;#39;&lt;/span&gt; charts/event-processor/Chart.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sed -n &lt;span class="s1"&gt;&amp;#39;1,200p&amp;#39;&lt;/span&gt; charts/event-processor/values.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sed -n &lt;span class="s1"&gt;&amp;#39;1,200p&amp;#39;&lt;/span&gt; charts/event-processor/templates/_helpers.tpl
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="plan-prompt-high-signal"&gt;Plan prompt (high-signal)&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;I want to create a new Helm chart for a service called `metrics-gateway`.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Reference implementation: charts/event-processor/ (this is our standard).
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;The new chart MUST follow the same structure and conventions.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Here are the reference inputs:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- tree output: ...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- Chart.yaml: ...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- values.yaml: ...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- templates/_helpers.tpl: ...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Please:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- Analyze the reference chart patterns.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- Produce a phased plan with verification steps.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- Call out any open questions you need answered (ports, probes, resources).
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="execution-prompt-phase-aligned"&gt;Execution prompt (phase-aligned)&lt;/h3&gt;
&lt;p&gt;Once you have the plan, generate prompt docs aligned to phases (scaffold, core templates, env overrides, validation). Each prompt should:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Name the deliverables.&lt;/li&gt;
&lt;li&gt;Repeat constraints.&lt;/li&gt;
&lt;li&gt;Include &amp;ldquo;update work notes&amp;rdquo; instructions.&lt;/li&gt;
&lt;li&gt;Include verification commands.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="what-done-looks-like"&gt;What &amp;ldquo;done&amp;rdquo; looks like&lt;/h3&gt;
&lt;p&gt;A good end state is boring:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The new chart is structurally identical to the reference chart.&lt;/li&gt;
&lt;li&gt;The values structure matches (so operators don&amp;rsquo;t re-learn config surfaces).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;helm lint&lt;/code&gt; and &lt;code&gt;helm template&lt;/code&gt; succeed.&lt;/li&gt;
&lt;li&gt;Changes are split into reviewable commits.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="verification"&gt;Verification&lt;/h2&gt;
&lt;p&gt;You can verify you&amp;rsquo;re actually following the workflow, not just producing text:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Artifacts exist.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;test&lt;/span&gt; -d plan &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt; -d prompts &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt; -d work-notes
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# A plan exists and is not empty.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;test&lt;/span&gt; -s plan/phase-1.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# A prompt doc exists.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;test&lt;/span&gt; -s prompts/phase-1.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Work notes exist.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;test&lt;/span&gt; -s work-notes/phase-1.md
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you are doing the Helm chart example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;helm lint charts/metrics-gateway
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;helm template charts/metrics-gateway &amp;gt;/tmp/metrics-gateway.rendered.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;test&lt;/span&gt; -s /tmp/metrics-gateway.rendered.yaml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Expected results:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The commands exit with code 0.&lt;/li&gt;
&lt;li&gt;The rendered YAML file is non-empty.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="failure-modes"&gt;Failure modes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Skipping references: you get generic output that doesn&amp;rsquo;t match your repo.&lt;/li&gt;
&lt;li&gt;Skipping verification: you ship code that &amp;ldquo;looked right.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Letting sessions run too long: context drifts and you lose earlier constraints.&lt;/li&gt;
&lt;li&gt;Batching commits: review slows down and rollback gets painful.&lt;/li&gt;
&lt;li&gt;Using the wrong model: cheap models are fine for boilerplate, but can burn hours on complex reasoning.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Continue -&amp;gt; &lt;a href="https://roygabriel.dev/blog/llm-development-guide/02-planning-artifacts/"&gt;Chapter 2: Planning: Plan Artifacts, Constraints, Definition of Done&lt;/a&gt;
&lt;/p&gt;</content:encoded></item><item><title>Cost Is a Reliability Problem</title><link>https://roygabriel.dev/blog/cost-is-a-reliability-problem/</link><pubDate>Sat, 13 Dec 2025 12:00:00 -0500</pubDate><guid>https://roygabriel.dev/blog/cost-is-a-reliability-problem/</guid><description>&lt;h2 id="why-this-matters"&gt;Why this matters&lt;/h2&gt;
&lt;p&gt;Traditional reliability focuses on uptime. AI systems add a second axis:&lt;/p&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;&lt;strong&gt;Your system can be &amp;ldquo;up&amp;rdquo; while your budget is on fire.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A runaway agent doesn&amp;rsquo;t always crash services. Sometimes it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;loops tool calls&lt;/li&gt;
&lt;li&gt;retries incorrectly&lt;/li&gt;
&lt;li&gt;escalates to larger models repeatedly&lt;/li&gt;
&lt;li&gt;expands context windows unnecessarily&lt;/li&gt;
&lt;li&gt;performs expensive searches without stopping&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The result: surprise bills, throttling, and eventually hard outages when quotas are hit.&lt;/p&gt;</description><content:encoded>&lt;h2 id="why-this-matters"&gt;Why this matters&lt;/h2&gt;
&lt;p&gt;Traditional reliability focuses on uptime. AI systems add a second axis:&lt;/p&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;&lt;strong&gt;Your system can be &amp;ldquo;up&amp;rdquo; while your budget is on fire.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A runaway agent doesn&amp;rsquo;t always crash services. Sometimes it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;loops tool calls&lt;/li&gt;
&lt;li&gt;retries incorrectly&lt;/li&gt;
&lt;li&gt;escalates to larger models repeatedly&lt;/li&gt;
&lt;li&gt;expands context windows unnecessarily&lt;/li&gt;
&lt;li&gt;performs expensive searches without stopping&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The result: surprise bills, throttling, and eventually hard outages when quotas are hit.&lt;/p&gt;
&lt;p&gt;Google&amp;rsquo;s SRE framing around &lt;strong&gt;error budgets&lt;/strong&gt; is a useful mental model: budgets create a control mechanism that balances stability with velocity. [1][2]
FinOps frames cost management as a collaboration practice between engineering, finance, and business. [3]&lt;/p&gt;
&lt;p&gt;This article is the practical bridge: &lt;strong&gt;use budgets and guardrails like you would for reliability.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Treat cost as an SLO: define acceptable spend per run / per tenant / per day.&lt;/li&gt;
&lt;li&gt;Enforce budgets at multiple layers:&lt;/li&gt;
&lt;li&gt;per request/run&lt;/li&gt;
&lt;li&gt;per tool&lt;/li&gt;
&lt;li&gt;per tenant&lt;/li&gt;
&lt;li&gt;per environment&lt;/li&gt;
&lt;li&gt;Use hard limits + soft limits:&lt;/li&gt;
&lt;li&gt;soft: degrade model/tool choices&lt;/li&gt;
&lt;li&gt;hard: stop the run and ask for approval&lt;/li&gt;
&lt;li&gt;Add cost circuit breakers:&lt;/li&gt;
&lt;li&gt;abort on runaway loops&lt;/li&gt;
&lt;li&gt;quarantine tools causing repeated retries&lt;/li&gt;
&lt;li&gt;Make cost visible (metrics + dashboards) so teams can improve it.&lt;/li&gt;
&lt;li&gt;Align with FinOps: shared accountability, not &amp;ldquo;billing surprises.&amp;rdquo; [3]&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="contents"&gt;Contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#cost-failure-modes-in-agent-systems"&gt;Cost failure modes in agent systems&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#define-cost-slos-and-budgets"&gt;Define cost SLOs and budgets&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#budget-layers-run-tool-tenant-environment"&gt;Budget layers: run, tool, tenant, environment&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#soft-limits-vs-hard-limits"&gt;Soft limits vs hard limits&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#circuit-breakers-for-runaway-behavior"&gt;Circuit breakers for runaway behavior&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#cost-aware-tool-and-model-selection"&gt;Cost-aware tool and model selection&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#dashboards-and-alerts"&gt;Dashboards and alerts&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#a-production-checklist"&gt;A production checklist&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#references"&gt;References&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="cost-failure-modes-in-agent-systems"&gt;Cost failure modes in agent systems&lt;/h2&gt;
&lt;h3 id="1-infinite-or-long-loops"&gt;1) Infinite or long loops&lt;/h3&gt;
&lt;p&gt;Common triggers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ambiguous tool outputs&lt;/li&gt;
&lt;li&gt;brittle parsing&lt;/li&gt;
&lt;li&gt;&amp;ldquo;try again&amp;rdquo; reflexes&lt;/li&gt;
&lt;li&gt;non-idempotent retries&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-tool-spam"&gt;2) Tool spam&lt;/h3&gt;
&lt;p&gt;Agents sometimes &amp;ldquo;search until confident.&amp;rdquo;
If you don&amp;rsquo;t cap it, you get 20+ tool calls on a single request.&lt;/p&gt;
&lt;h3 id="3-model-escalation-cascades"&gt;3) Model escalation cascades&lt;/h3&gt;
&lt;p&gt;If your policy says &amp;ldquo;if uncertain, use a better model,&amp;rdquo; you can create a cost escalator:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;cheap model -&amp;gt; &amp;ldquo;uncertain&amp;rdquo; -&amp;gt; expensive model&lt;/li&gt;
&lt;li&gt;expensive model -&amp;gt; still uncertain -&amp;gt; more calls&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="4-context-growth"&gt;4) Context growth&lt;/h3&gt;
&lt;p&gt;If you keep appending tool outputs to the prompt, costs grow superlinearly and performance can degrade.&lt;/p&gt;
&lt;h3 id="5-external-quotas-become-outages"&gt;5) External quotas become outages&lt;/h3&gt;
&lt;p&gt;Even if cost is acceptable, external services (email APIs, GitHub, calendars) can rate limit you.
Cost and reliability are coupled.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="define-cost-slos-and-budgets"&gt;Define cost SLOs and budgets&lt;/h2&gt;
&lt;p&gt;Start with simple &amp;ldquo;production truths&amp;rdquo;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How much is one agent run allowed to cost?&lt;/li&gt;
&lt;li&gt;What is an acceptable daily spend per tenant?&lt;/li&gt;
&lt;li&gt;What is the max &amp;ldquo;blast radius&amp;rdquo; of a single request?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This maps cleanly to SRE&amp;rsquo;s error budget concept: budgets constrain unsafe behavior while preserving velocity. [2]&lt;/p&gt;
&lt;h3 id="example-cost-slos-pragmatic"&gt;Example cost SLOs (pragmatic)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Per run:&lt;/strong&gt; &amp;lt;= $0.10 (p95), &lt;= $0.50 (max)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Per tenant/day:&lt;/strong&gt; &amp;lt;= $50/day&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Per user/day:&lt;/strong&gt; &amp;lt;= $5/day&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Per tool call:&lt;/strong&gt; &amp;lt;= 3 calls to expensive tools&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These aren&amp;rsquo;t universal. They&amp;rsquo;re explicit. That&amp;rsquo;s what matters.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="budget-layers-run-tool-tenant-environment"&gt;Budget layers: run, tool, tenant, environment&lt;/h2&gt;
&lt;h3 id="1-per-run-budget"&gt;1) Per-run budget&lt;/h3&gt;
&lt;p&gt;Tracks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;max model tokens&lt;/li&gt;
&lt;li&gt;max tool calls&lt;/li&gt;
&lt;li&gt;max wall-clock time&lt;/li&gt;
&lt;li&gt;max &amp;ldquo;expensive operations&amp;rdquo; count&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Most important budget.&lt;/strong&gt; This is where you stop runaway behavior early.&lt;/p&gt;
&lt;h3 id="2-per-tool-budget"&gt;2) Per-tool budget&lt;/h3&gt;
&lt;p&gt;Some tools are inherently expensive:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;large searches&lt;/li&gt;
&lt;li&gt;long-running jobs&lt;/li&gt;
&lt;li&gt;heavy data exports&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Budget these separately:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;max calls&lt;/li&gt;
&lt;li&gt;max payload size&lt;/li&gt;
&lt;li&gt;max time range&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-per-tenant-budget"&gt;3) Per-tenant budget&lt;/h3&gt;
&lt;p&gt;Without this, your best customers can melt your infra.&lt;/p&gt;
&lt;p&gt;Per-tenant limits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;requests/min&lt;/li&gt;
&lt;li&gt;concurrent runs&lt;/li&gt;
&lt;li&gt;daily cost cap&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="4-per-environment-budget"&gt;4) Per-environment budget&lt;/h3&gt;
&lt;p&gt;Environments have different rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;dev: cheap, permissive, more logging&lt;/li&gt;
&lt;li&gt;prod: bounded, gated, auditable&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is where you implement &amp;ldquo;read-only mode&amp;rdquo; during incidents.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="soft-limits-vs-hard-limits"&gt;Soft limits vs hard limits&lt;/h2&gt;
&lt;h3 id="soft-limits-degrade-gracefully"&gt;Soft limits (degrade gracefully)&lt;/h3&gt;
&lt;p&gt;When approaching budget:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;switch to cheaper models&lt;/li&gt;
&lt;li&gt;reduce context size (summarize)&lt;/li&gt;
&lt;li&gt;narrow tool search range&lt;/li&gt;
&lt;li&gt;skip non-essential steps&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="hard-limits-stop-the-run"&gt;Hard limits (stop the run)&lt;/h3&gt;
&lt;p&gt;When budget is exceeded:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;stop tool calls&lt;/li&gt;
&lt;li&gt;stop escalation&lt;/li&gt;
&lt;li&gt;request user confirmation / approval&lt;/li&gt;
&lt;li&gt;produce a partial answer with an explanation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is exactly the &amp;ldquo;control mechanism&amp;rdquo; idea behind error budgets: it gives the system permission to shift focus when constraints are exceeded. [1]&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="circuit-breakers-for-runaway-behavior"&gt;Circuit breakers for runaway behavior&lt;/h2&gt;
&lt;p&gt;Add circuit breakers that detect &amp;ldquo;this is going bad&amp;rdquo;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;loop detector&lt;/strong&gt;: same tool called with similar args repeatedly&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;retry storm&lt;/strong&gt;: high retry count for a tool within a run&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;no progress&lt;/strong&gt;: plan step count increases without new evidence&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;latency breaker&lt;/strong&gt;: tool p95 spikes beyond threshold&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When triggered:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;stop the run&lt;/li&gt;
&lt;li&gt;quarantine the tool for this run&lt;/li&gt;
&lt;li&gt;degrade to safe alternatives&lt;/li&gt;
&lt;li&gt;emit high-signal telemetry&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="cost-aware-tool-and-model-selection"&gt;Cost-aware tool and model selection&lt;/h2&gt;
&lt;p&gt;Cost control is easier if it&amp;rsquo;s designed into selection:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rank tools with a &amp;ldquo;cost weight&amp;rdquo; (latency + upstream cost + risk)&lt;/li&gt;
&lt;li&gt;Prefer read-only tools unless a write is required&lt;/li&gt;
&lt;li&gt;Use caches for common retrieval results&lt;/li&gt;
&lt;li&gt;Use deterministic summarization boundaries for tool outputs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you already implement a tool selector (see &amp;ldquo;Million Tool Problem&amp;rdquo;), cost becomes another rerank feature.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="dashboards-and-alerts"&gt;Dashboards and alerts&lt;/h2&gt;
&lt;p&gt;This is where FinOps and SRE meet: cost is an operational signal.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dashboards&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;spend/day by tenant&lt;/li&gt;
&lt;li&gt;cost per run distribution&lt;/li&gt;
&lt;li&gt;top cost drivers (tools and models)&lt;/li&gt;
&lt;li&gt;runaway breaker triggers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Alerts&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;daily spend exceeded&lt;/li&gt;
&lt;li&gt;sudden spend spikes (slope alerts)&lt;/li&gt;
&lt;li&gt;high frequency of loop breaker events&lt;/li&gt;
&lt;li&gt;high fraction of runs hitting hard limits&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AWS&amp;rsquo;s Well-Architected Cost Optimization pillar frames cost optimization as a continual process across the workload lifecycle. That mindset applies here too. [4]&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="a-production-checklist"&gt;A production checklist&lt;/h2&gt;
&lt;h3 id="budgets"&gt;Budgets&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Per-run cost and tool-call budgets exist.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Per-tenant daily caps exist.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Per-tool &amp;ldquo;expensive operation&amp;rdquo; caps exist.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="enforcement"&gt;Enforcement&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Soft limits degrade gracefully (cheaper models, narrower queries).&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Hard limits stop and request approval.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Circuit breakers detect loops/retry storms.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="telemetry"&gt;Telemetry&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Cost metrics emitted per run and per tenant.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Breaker events recorded and alertable.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="culture"&gt;Culture&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Cost management is a shared practice (FinOps), not a surprise invoice. [3]&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;p&gt;[1] Google SRE Workbook - Example Error Budget Policy: &lt;a href="https://sre.google/workbook/error-budget-policy/" target="_blank" rel="noopener noreferrer"&gt;https://sre.google/workbook/error-budget-policy/&lt;/a&gt;
[2] Google SRE Book - Embracing Risk (error budgets as control mechanism): &lt;a href="https://sre.google/sre-book/embracing-risk/" target="_blank" rel="noopener noreferrer"&gt;https://sre.google/sre-book/embracing-risk/&lt;/a&gt;
[3] FinOps Foundation - What is FinOps? (definition and principles): &lt;a href="https://www.finops.org/introduction/what-is-finops/" target="_blank" rel="noopener noreferrer"&gt;https://www.finops.org/introduction/what-is-finops/&lt;/a&gt;
[4] AWS Well-Architected Framework - Cost Optimization pillar: &lt;a href="https://docs.aws.amazon.com/wellarchitected/latest/framework/cost-optimization.html" target="_blank" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/wellarchitected/latest/framework/cost-optimization.html&lt;/a&gt;
&lt;/p&gt;</content:encoded></item><item><title>Go MCP Server Ecosystem</title><link>https://roygabriel.dev/projects/mcp-servers/</link><pubDate>Sun, 01 Sep 2024 00:00:00 +0000</pubDate><guid>https://roygabriel.dev/projects/mcp-servers/</guid><description>Production-grade MCP servers in Go that expose iCloud, Todoist, and Notion as safe, typed tools for LLM agents.</description><content:encoded>&lt;h2 id="summary"&gt;Summary&lt;/h2&gt;
&lt;p&gt;This project is a growing ecosystem of &lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt; servers written in &lt;strong&gt;Go&lt;/strong&gt;. Each server wraps a real service (calendar, email, task management, knowledge base, etc.) and exposes it as a &lt;strong&gt;typed, tool-based interface&lt;/strong&gt; for MCP clients (e.g., Claude Desktop / Claude Code). [1][2]&lt;/p&gt;
&lt;p&gt;The theme is simple: &lt;strong&gt;agents are only as useful as the tools they can call&lt;/strong&gt;, and &amp;ldquo;tooling&amp;rdquo; needs the same production bar as any other integration layer: security boundaries, backpressure, observability, and predictable failure modes.&lt;/p&gt;
&lt;h3 id="open-source-mcp-servers"&gt;Open-source MCP servers&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;iCloud Calendar MCP Server (CalDAV):&lt;/strong&gt; list calendars, search events, create/update/delete events; includes recurring event expansion, multi-account support, rate limiting, retries, audit logs, and Prometheus/health endpoints. [4]&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;iCloud Email MCP Server (IMAP/SMTP):&lt;/strong&gt; search and read mail, send/reply, manage folders, handle attachments, and apply safety annotations (read-only vs destructive) with strict input validation. [5]&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Todoist MCP Server (REST API v2 + Sync batching):&lt;/strong&gt; manage tasks/projects/labels/comments; supports bulk operations with rate-limit-aware batching and Todoist filter syntax. [6]&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Notion MCP Server (Notion REST API):&lt;/strong&gt; pages, databases, blocks, comments, users; includes templates, exports (Markdown/CSV), smart queries, and built-in throttling/retries. [7]&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="private--not-yet-open-sourced-connectors"&gt;Private / not-yet-open-sourced connectors&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;ve also built MCP connectors for enterprise systems that aren&amp;rsquo;t ready to open-source yet (either due to org-specific assumptions, credentials, or hard-coded domain models):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kubernetes&lt;/li&gt;
&lt;li&gt;Argo CD&lt;/li&gt;
&lt;li&gt;SonarQube&lt;/li&gt;
&lt;li&gt;GitHub&lt;/li&gt;
&lt;li&gt;Temporal&lt;/li&gt;
&lt;li&gt;OpenText Octane&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(These follow the same design patterns described below.)&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="problem"&gt;Problem&lt;/h2&gt;
&lt;p&gt;Agents need to interact with real systems: calendars, email, task systems, and internal developer platforms. Without a standard interface, every tool integration becomes a one-off, and reliability/guardrails drift between projects.&lt;/p&gt;
&lt;p&gt;MCP solves the &amp;ldquo;standard interface&amp;rdquo; problem by defining how a host/client can discover and call server-exposed tools over a consistent protocol. [1][2]
This ecosystem focuses on solving the remaining hard part: &lt;strong&gt;making those integrations production-grade&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="constraints"&gt;Constraints&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Local-first security boundary&lt;/strong&gt;: credentials live on the host where the server runs (env vars, secret mounts, keychain tooling); the server talks directly to the upstream service with no proxy SaaS. [4][5]&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Safety by design&lt;/strong&gt;: explicit tool schemas, input validation, and tool classification (read-only vs mutating) so clients can apply guardrails. [4][5]&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fast &amp;amp; predictable&lt;/strong&gt;: low startup time and bounded tool-call latency (timeouts + backpressure). [4][5][7]&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Operable like a real service&lt;/strong&gt;: logs that correlate per request, rate limiting, retries/backoff where appropriate, and health/metrics where it matters. [4][6][7]&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Portable distribution&lt;/strong&gt;: ship as single Go binaries (and containers where useful), so the &amp;ldquo;tool layer&amp;rdquo; is easy to deploy alongside agents. [4][5]&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="architecture"&gt;Architecture&lt;/h2&gt;
&lt;p&gt;At a high level, every server follows the same pattern:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;MCP client (hosted by Claude / an agent runtime)&lt;/strong&gt; communicates with the server (typically over stdio transport).&lt;/li&gt;
&lt;li&gt;The server validates inputs, applies middleware (timeouts, logging, rate limits), and calls the upstream API/protocol.&lt;/li&gt;
&lt;li&gt;Results are mapped into safe, typed tool outputs (and errors are normalized for the client).&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;┌───────────────────────────┐ MCP (tools) ┌────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ Claude Desktop / Code │ ───────────────────────────▶ │ mcp-&amp;lt;service&amp;gt; (Go binary) │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ (MCP host + client) │ ◀─────────────────────────── │ - tool schemas + handlers │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└───────────────────────────┘ JSON-RPC/session │ - auth + validation │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ - rate limit + retries │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └───────────┬────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ service protocol / API
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ▼
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ┌──────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ iCloud / Todoist / Notion ... │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └──────────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="cross-cutting-production-traits"&gt;Cross-cutting &amp;ldquo;production traits&amp;rdquo;&lt;/h3&gt;
&lt;p&gt;Instead of building one-off scripts, these servers implement common production patterns:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Timeout middleware&lt;/strong&gt; on every tool call (so agents don&amp;rsquo;t hang forever). [4][5][7]&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Request correlation IDs&lt;/strong&gt; and structured logs (debuggable across multi-step agent runs). [4][5]&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rate limiting + backoff&lt;/strong&gt; when upstream services throttle (e.g., iCloud and Notion). [4][7]&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bulk operation strategies&lt;/strong&gt; that reduce API calls (e.g., Todoist Sync API batching for bulk changes). [6]&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Health + metrics endpoints&lt;/strong&gt; where running in containers makes sense (notably the iCloud Calendar server). [4]&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automated CI&lt;/strong&gt; (race detector, linting, vulnerability checks) to keep &amp;ldquo;tool servers&amp;rdquo; from becoming unreviewed glue. [4][5]&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="key-decisions"&gt;Key decisions&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Go for tool servers&lt;/strong&gt;: predictable concurrency, easy cross-platform builds, and the &amp;ldquo;single static-ish binary&amp;rdquo; deployment model fits MCP servers well, especially when they&amp;rsquo;re launched per-session or run as small sidecars. [4][5]&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Independent binaries per integration&lt;/strong&gt;: calendar ≠ email ≠ tasks. Separate processes isolate failures, limit blast radius, and make upgrades/rollbacks straightforward.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Local-first auth&lt;/strong&gt;: app-specific passwords (iCloud), API tokens (Todoist), integration tokens (Notion). The servers are designed so secrets stay on your machine / in your cluster secrets manager, not copied into prompts. [4][5][6][7]&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use an MCP SDK, focus on semantics&lt;/strong&gt;: the implementations use the Go MCP SDK (&lt;code&gt;mark3labs/mcp-go&lt;/code&gt;) so most effort goes into tool behavior, validation, and safety. [8][9]&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="outcome"&gt;Outcome&lt;/h2&gt;
&lt;p&gt;This ecosystem has produced multiple MCP servers that are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;useful&lt;/strong&gt; (real workflows: schedule management, inbox operations, task execution, knowledge base automation),&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;operationally hardened&lt;/strong&gt; (timeouts, retries, rate limits, observability),&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;portable&lt;/strong&gt; (binaries + releases for easy distribution),&lt;/li&gt;
&lt;li&gt;and &lt;strong&gt;structured enough to be safe&lt;/strong&gt; (typed schemas, validation, tool annotations).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Concrete examples from the current repos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;iCloud Calendar server&lt;/strong&gt; exposes &lt;strong&gt;5 tools&lt;/strong&gt;, supports &lt;strong&gt;multi-account&lt;/strong&gt;, and includes &lt;strong&gt;health + Prometheus metrics&lt;/strong&gt;, &lt;strong&gt;audit logging without PII&lt;/strong&gt;, retries/backoff, and rate limiting. [4]&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;iCloud Email server&lt;/strong&gt; exposes &lt;strong&gt;14 tools&lt;/strong&gt; and includes &lt;strong&gt;thread-safe IMAP access&lt;/strong&gt;, request correlation IDs, strict validation, and &amp;ldquo;read-only vs destructive&amp;rdquo; tool annotations. [5]&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tagged releases&lt;/strong&gt; exist across the servers (e.g., iCloud Calendar &lt;code&gt;v1.1.0&lt;/code&gt;, iCloud Email &lt;code&gt;v0.6.0&lt;/code&gt;, Todoist &lt;code&gt;v1.0.0&lt;/code&gt;, Notion &lt;code&gt;v0.8.0&lt;/code&gt; published on Feb 7, 2026). [4][5][6][7]&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="stack"&gt;Stack&lt;/h2&gt;
&lt;p&gt;Go, MCP, &lt;code&gt;mark3labs/mcp-go&lt;/code&gt;, CalDAV, IMAP/SMTP, REST APIs (Todoist/Notion), Docker (distroless where applicable), Prometheus metrics (where applicable).&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;p&gt;[1] Model Context Protocol (MCP): Specification (Protocol Revision 2025-11-25). &lt;a href="https://modelcontextprotocol.io/specification/2025-11-25" target="_blank" rel="noopener noreferrer"&gt;https://modelcontextprotocol.io/specification/2025-11-25&lt;/a&gt;
[2] Model Context Protocol (MCP): Architecture (Protocol Revision 2025-06-18). &lt;a href="https://modelcontextprotocol.io/specification/2025-06-18/architecture" target="_blank" rel="noopener noreferrer"&gt;https://modelcontextprotocol.io/specification/2025-06-18/architecture&lt;/a&gt;
[3] Roy Gabriel: &amp;ldquo;Go MCP Server Ecosystem&amp;rdquo; (original portfolio page). &lt;a href="https://www.roygabriel.dev/projects/mcp-servers/" target="_blank" rel="noopener noreferrer"&gt;https://www.roygabriel.dev/projects/mcp-servers/&lt;/a&gt;
[4] GitHub: roygabriel/mcp-icloud-calendar. &lt;a href="https://github.com/roygabriel/mcp-icloud-calendar" target="_blank" rel="noopener noreferrer"&gt;https://github.com/roygabriel/mcp-icloud-calendar&lt;/a&gt;
[5] GitHub: roygabriel/mcp-icloud-email. &lt;a href="https://github.com/roygabriel/mcp-icloud-email" target="_blank" rel="noopener noreferrer"&gt;https://github.com/roygabriel/mcp-icloud-email&lt;/a&gt;
[6] GitHub: roygabriel/mcp-todoist. &lt;a href="https://github.com/roygabriel/mcp-todoist" target="_blank" rel="noopener noreferrer"&gt;https://github.com/roygabriel/mcp-todoist&lt;/a&gt;
[7] GitHub: roygabriel/mcp-notion. &lt;a href="https://github.com/roygabriel/mcp-notion" target="_blank" rel="noopener noreferrer"&gt;https://github.com/roygabriel/mcp-notion&lt;/a&gt;
[8] GitHub: mark3labs/mcp-go. &lt;a href="https://github.com/mark3labs/mcp-go" target="_blank" rel="noopener noreferrer"&gt;https://github.com/mark3labs/mcp-go&lt;/a&gt;
[9] go.mod (module dependencies) for the MCP servers (e.g., &lt;code&gt;mark3labs/mcp-go&lt;/code&gt; used in this ecosystem).
- &lt;a href="https://raw.githubusercontent.com/roygabriel/mcp-icloud-calendar/main/go.mod" target="_blank" rel="noopener noreferrer"&gt;https://raw.githubusercontent.com/roygabriel/mcp-icloud-calendar/main/go.mod&lt;/a&gt;
- &lt;a href="https://raw.githubusercontent.com/roygabriel/mcp-icloud-email/main/go.mod" target="_blank" rel="noopener noreferrer"&gt;https://raw.githubusercontent.com/roygabriel/mcp-icloud-email/main/go.mod&lt;/a&gt;
- &lt;a href="https://raw.githubusercontent.com/roygabriel/mcp-todoist/main/go.mod" target="_blank" rel="noopener noreferrer"&gt;https://raw.githubusercontent.com/roygabriel/mcp-todoist/main/go.mod&lt;/a&gt;
- &lt;a href="https://raw.githubusercontent.com/roygabriel/mcp-notion/main/go.mod" target="_blank" rel="noopener noreferrer"&gt;https://raw.githubusercontent.com/roygabriel/mcp-notion/main/go.mod&lt;/a&gt;
&lt;/p&gt;</content:encoded></item></channel></rss>