The Engineer + Agent Playbook
Part I — Foundations
§1 Mental models
Before any tooling, any skills file, any hook — you need three honest pictures of what this thing actually is. Get these wrong and every other chapter will quietly misfire. Get them right and most of the rest is bookkeeping.
The three models below are all variations on one underlying picture — the three-layer division of labor from the thesis. The pipeline does mechanics. The agent does elaboration. You do craft. Every rule in this chapter is a maneuver to keep the agent in the elaboration lane so you can stay in the craft lane. When a rule feels like friction, check which lane you're in — friction in §1 usually means the human is being pulled into a layer that isn't theirs.
Rule: Brief the agent like a smart colleague who just walked into the room.
Why: It has no conversation context and no project memory beyond what you give it right now. Every prompt is a cold start, whether it feels like one or not. How to apply: Every non-trivial prompt is a self-contained briefing — goal, what you've already ruled out, constraints, success criteria. If the prompt would make a new hire ask three follow-up questions, it will make the agent invent three answers.
The trap is that the agent sounds like it remembers. It picks up tone, reuses variable names, nods along. None of that is memory — it's the previous turn's text still in the window. A colleague who walked in five minutes ago would ask "wait, what are we trying to do, and what have you already tried?" The agent doesn't ask. It just starts typing. Terse command prompts produce shallow, generic work because that's the only kind a stranger can do without context. When we shipped v5.10, the difference between "clean up the CI pipeline" and "make this reference-quality — the kind you'd point to as an example" wasn't prose decoration. It was the whole brief. The first gets you a linter config. The second gets you eighteen issues across six layers.
Field note — case study 1: Name the quality bar before you start. A release framed as "clean up the CI pipeline" nearly shipped as a linter config. Reframed mid-sprint as "make this reference-quality — the kind you'd point to as an example," it became eighteen issues across six layers. Same week, same agents, same codebase. The brief was the whole release.
Rule: Delegate the task, not the understanding.
Why: Synthesis is your job; the agent is a force multiplier on execution. The moment you write "based on your findings, fix the bug," you've pushed the hard part onto the thing that's worst at it. How to apply: Do the synthesis yourself before delegating. Hand the agent a specific action with the context it needs to act — not a question with the action hidden inside it. "Investigate and fix" is two jobs taped together, and the tape is where things fall apart. Qualifier: the agent can do understanding when it lives in an authoritative external doc it can read end-to-end (an RFC, a protocol spec, a library reference). Case study 2 built dozens of protocol adapters this way — no human deeply understood the frame formats going in, and the agents built that understanding from the specs deterministically. What you must never delegate is understanding that lives in your head: scar tissue, team norms, last March's prod incident. That has no external source; if you don't write it down, the agent invents a substitute.
The tell is a prompt that reads like a riddle. "Figure out why the cache is slow and do what makes sense." What makes sense to whom? You're the one with the scar tissue, the prod incident from March, the unspoken rule that we don't touch Redis serialization without a migration. None of that is in the agent's head. Going into v5.7 we were terrified of ripping SQLite out of the test suite — months of latent debt, we assumed the worst. The synthesis was an afternoon of staring at it: the fear was the debt's last defense. Once we'd made the call, the removal was one test fix. Engineer decides. Agent executes. Reverse those roles and you ship the carnage you predicted.
Field note — case study 1: Latent-debt removal costs less than you fear. Months of dread around ripping SQLite out of a backend test suite. The synthesis took one afternoon. Once the call was made, the removal was one test fix. The fear had been doing the debt's work for it.
Rule: The agent is good at breadth and consistency. It is bad at judgment under ambiguity.
Why: It can search two hundred files in parallel or apply one pattern across fifty call sites without drifting. It cannot tell you which of three plausible trade-offs your team will actually accept. How to apply: Use it for the search, the refactor, the test-writing, the scaffolding, the fan-out. Make the trade-off call yourself. When you catch yourself asking "which approach is better," stop and make the call. Qualifier: agent judgment is weak on social trade-offs (what will the team tolerate, which pattern matches house style) and surprisingly strong on mechanical ones (does it compile, does the spec validate, does the race detector stay clean). If the judgment collapses to measurable signals, delegate. If it collapses to "what will the team say at code review," don't.
Breadth is the superpower. Fifty call sites updated in one pass, no typos, no drift — lean on it ruthlessly. Judgment is the anti-superpower. Ask it "should we simplify this flow" and it will happily simplify things you needed. That's how v5.1 shipped without a small lookup form on the landing page. The v5.0 design pass called it clutter. It was clutter. It was also the entire re-entry flow for anyone returning from a bookmark. Nobody noticed until a v5.1.1 bug report — thirty-six lines to put back what one aesthetic judgment had erased. The agent wasn't wrong; nothing in its context said "this element is load-bearing for a use case we don't test." That context is the engineer's job to supply. If you wouldn't hand this decision to an intern on their first afternoon, don't hand it to the agent either.
Field note — case study 1: Beautiful design that breaks the core use case is a regression. A design pass called a small landing-page lookup form "clutter" and removed it. It was clutter — and also the entire re-entry flow for anyone returning from a bookmark. Thirty-six lines went back in a patch later to restore what one aesthetic judgment had erased. Nothing in the agent's context said "this element is load-bearing for a use case we don't test."
Rule: Agent-authored domain content is a plausible first draft of the world, not the world.
Why: When the agent writes a keyword list, a heuristic, a prompt, a test corpus, or anything else that models how real people behave, it encodes the author's vocabulary — plausible-sounding, systematically skewed, and confident. Only real-world data and a human who actually knows the domain can close the gap. And the skew runs both directions: the agent will also faithfully amplify errors that are already in the spec, because fidelity to the brief is its whole job. How to apply: Treat every agent-generated wordlist, classifier rule, persona, and synthetic dataset as a hypothesis awaiting real inputs. Ship it behind a way to observe misses (see §10), then correct from actual usage, not from more agent brainstorming. And route anything that touches real-world facts through the human review layer — the agent cannot know which "fact" in the spec is subtly wrong.
The fifth case study routes journal entries to reply templates with a keyword classifier, and its retros are a controlled experiment in this rule. The agent-drafted contentment cluster contained nice day, simple pleasures, and at peace — "a cluster of words designed by someone trying to write literature about contentment" — and lacked happy. The rest-domain wordlist contained every verb of resting and every resting-place noun, and not the word rest. "The wordlist reveals what the writer was thinking about, not what the user is going to write." Meanwhile the heavy-affect list only spoke in extremes (devastated, hollow, grief), so an ordinary sad slid through unclassified for weeks. None of these were bugs in the code; all of them were bugs in the agent's model of how humans talk. Real entries fixed them; more agent effort would have produced more literature.
Field note — case study 5: The 143 pounds. A seed spec listed a historical figure's lifelong 143-pound weight under "regrets," and the agent faithfully wrote a reply template treating it as a burden. The human knew what the spec author didn't: the figure kept that weight deliberately — 1-4-3 was his private code for "I love you." The agent executed the spec with perfect fidelity, error included. The upstream fact was wrong, and no amount of agent diligence could have caught it, because catching it required knowing the world, not reading the file. Pin: the agent amplifies the spec, errors included. The human is the world-knowledge review layer.
§2 The model and the harness
(New in the second edition.) The first edition was written inside one ecosystem and let the ecosystem's names leak into the rules. This chapter exists to un-leak them. Two independent axes vary underneath every other chapter: which model is doing the elaboration (Claude Opus or Sonnet, GPT, GLM, Qwen — and whatever ships next quarter), and which harness is wrapping it (Claude Code, Codex, opencode, Cursor, Gemini CLI, an in-house runner). The rules of this playbook were pressure-tested across model generations and are written to survive harness swaps. This chapter says which parts of the practice move when those axes move, and which parts don't move at all.
Rule: The disciplines are model-invariant. Only the calibration moves.
Why: Every rule in this playbook is aimed at a structural property of the partnership, not at a deficiency of a particular model. Any model is a cold start without a briefing. Any model's "tests pass" is prose until the output is pasted. Any model will fill a context gap with a confident guess — the stronger the model, the more convincing the guess. Model upgrades change how much you can delegate per step; they do not change whether you verify, retro, or scope authorization. How to apply: When you switch or upgrade models, re-calibrate the qualifier lines, not the rules. The five-minute-step proxy (§14) can relax further when the model reliably holds a larger step. The mechanical-judgment qualifier (§1) widens as models get better at measurable trade-offs. What never relaxes: evidence before assertions (§8), the retro habit (§16), blast-radius confirmation (§9), and the human ownership of taste. If a model upgrade tempts you to drop a discipline rather than widen a qualifier, that's the tell you're about to re-learn a scar.
The trap is the honeymoon. A new model ships, the first week is dazzling, and the disciplines start to feel like overhead from a weaker era — the same psychology as "the fix is obvious, skip the brainstorm" (§7), scaled up to the whole practice. The case studies spanned multiple model generations, and the retro corpus is unambiguous about what changed: plans got bigger before they needed splitting, judgment calls that used to need a human got safely mechanical, exploration agents got good enough to hand entire survey passes to. And what didn't change: the confidently wrong health-check diagnosis, the green suite hiding a broken feature, the stale memory acted on without a lookup. Those failures are structural — they come from the shape of context windows and cold starts, not from model quality. A better model fails less often and more convincingly. The disciplines are how you catch the convincing ones. Pin: upgrade the model, keep the discipline. Re-tune the qualifiers, never the rules.
Rule: Pick the model tier by the shape of the work, not the size of the diff.
Why: Model tiers are priced and tuned differently, and the tempting heuristic — big change, big model — is wrong. What predicts the needed tier is the shape of the work: mechanical fan-out tolerates a cheaper tier with good gates; taste, voice, synthesis, and long-horizon coherence reward the top tier even when the diff is twenty lines. How to apply: Orchestration, dispatch bookkeeping, mechanical refactors, test scaffolds against a tight interface → the cheaper tier, backed by the gates from §13. Voice work, judgment-heavy synthesis, anything where drift between five similar-but-distinct outputs would be fatal → the top tier. When a subagent's output will be judged by ear rather than by a test, spend the tokens.
The fifth case study made this concrete on its reply-template corpus: a mid-tier dispatcher coordinated the work, and each historical figure's templates were written by a top-tier dispatch. The retro's verdict: "The opus dispatches were notably better at this than sonnet would have been — the model needed to hold five distinct voices in mind and not bleed them into each other." Voice differentiation is exactly the shape that rewards the expensive tier: no gate can catch a Marcus Aurelius template drifting toward generic stoicism, so the quality has to be in the generation, not the filter. The inverse holds too — the second case study ran fleets of adapter implementations against a five-method interface on whatever tier was cheap, because the compiler, the race detector, and the coverage matrix were doing the judging. Pin: gates can judge mechanics, so mechanics can go cheap. Nothing but the model judges voice, so voice goes expensive.
Rule: The harness is a dependency: map its layers, keep the knowledge portable.
Why: Every agent harness converges on the same five surfaces — an instructions file, a memory mechanism, invokable procedures, event hooks, and a permissions config (§3 covers what belongs in each). But the names differ, the maturity differs, and teams increasingly run more than one harness against the same repo. Knowledge locked in one harness's proprietary layer is knowledge the other harness's agent doesn't have.
How to apply: Learn the mapping once, then file knowledge by layer, not by filename. As of this writing: the instructions file is CLAUDE.md (Claude Code), AGENTS.md (the emerging cross-tool convention, honored by Codex, opencode, and a growing list), GEMINI.md, .cursorrules. Procedures are "skills" or "commands" or "prompts" depending on the tool. Hooks and permission configs live in each harness's settings file. Prefer the portable homes: project facts in AGENTS.md (symlink or mirror the harness-specific name to it), procedures in versioned files the repo carries, scar tissue in docs/ and retros — so the knowledge survives a harness swap the way it survives a laptop swap. Reserve harness-native layers for what genuinely needs them: hooks, permissions, per-user memory.
The test is the second harness. The day a teammate opens the repo in a different tool — or you point a new agent at an old project — everything that lived in the portable layers comes along, and everything that lived in a proprietary corner silently doesn't. The fleet (case study 6) runs this as standing practice: the durable decisions land in the instructions file and dated PRD amendments in the repo, and the retro directory is the transferable institutional memory. When a new instrument app spins up, its pipeline copies the last one's "in the how-soon tradition" — the tradition transfers because it lives in documents, not in one tool's cache. Pin: file knowledge by layer, not by filename. The repo is the only harness everything can read.
Rule: Trust harness claims the way you trust "tests pass": with evidence.
Why: The harness is software, and software lies under load. An edit tool can report success without persisting. A CLI can return a truncated secret and exit zero. A sandbox can be unable to kill the process it spawned. A CI provider can refuse all jobs over a billing dispute the day you need to ship. §8's evidence discipline is usually aimed at the agent's claims; this rule aims it at the tooling underneath the agent.
How to apply: For any harness operation whose silent failure would be expensive — file writes before a deploy, secret values before an auth change, "the branch is protected," "the hook fired" — verify with an independent read: git diff after the edit, a length check on the secret, the API call that shows the protection object. And because the harness includes SaaS you don't control, keep a rehearsed manual fallback for every automated rail (§3): a by-hand deploy path, a tracker-independent place to persist a found bug.
The scars here are recent and specific. The fifth case study shipped route components that nothing routed to because the harness's edit tool once reported success without persisting — compile-green in isolation, invisible in the app. The fleet's deploy session watched netlify env:get return a 20-character slice of a 64-character secret, and the function correctly rejecting the garbage looked exactly like a code bug — "tooling can hand you a truncated value and smile while it does it." And the first case study spent an afternoon deploying by hand because its CI provider was refusing all five jobs over someone else's unpaid bill, then couldn't file the regression it had just found because the issue tracker's free tier was full — the bug got written to three tracker-independent places instead. None of these are indictments of any particular tool. They're the reason the evidence discipline extends one layer down. Pin: the harness is part of the environment that matters. Verify it like one.
§3 The workspace
The workspace is the set of files and settings the agent reads before it does anything. The instructions file (CLAUDE.md, AGENTS.md, GEMINI.md, .cursorrules — §2 has the full mapping; the body of this chapter says CLAUDE.md because that's what the scars were written against), memory, skills, hooks, the harness config (settings.json in Claude Code) — each has a specific job, and the failure mode is always the same: the wrong thing in the wrong layer, quietly rotting. §1 was how to think about the agent; §2 was how to think about the tools underneath it. This chapter is where to put the things you want it to know.
Read the workspace as the interface between the craftsperson and the agent elaborator. Everything you file here is an instrument for protecting craft attention from the class of interruption the file is designed to absorb. CLAUDE.md absorbs cold-start context. Memory absorbs cross-session drift. Skills absorb procedural ritual. Hooks absorb mandatory checks. settings.json absorbs permission questions. The failure mode of each layer is the same shape: the craftsperson starts doing the work the layer was supposed to do.
Rule: Your pipeline is a precondition, not a feature.
Why: Every discipline in this playbook — verification, parallel agents, frequent commits, trust boundaries, the whole loop — silently assumes CI catches mechanical failures quickly, deploys are automated and rollbackable, health checks report real dependencies, and commits flow through the pipeline without a human babysitting each stage. When that assumption is broken, every rule in this book costs more. Worse, the human gets pulled into the mechanics layer to compensate — and the craft layer goes dark. A flaky pipeline is how the thesis gets inverted: the agent becomes the thing you baby-sit, and the human becomes the laborer. That is the failure mode the whole playbook is organized against, and it starts with the pipeline. How to apply: Before adopting the disciplines in Parts II–IV, walk the companion DevOps playbook's core rules: health endpoints that report dependencies and the build SHA, blue-green deploys with automated rollback, lint/test/scan on every push, conventional commits, manifest-driven state ("what's in production?" should have a precise queryable answer), Docker parity between dev and prod. (See DevOps Playbook Phases 0–4 for how to build each of these from scratch, and Phase 7 for the observability that makes the whole thing answerable.) Every one of these is a rail that lets the agent do its job without you holding its hand through the mechanics. The operational slogan is the DevOps playbook's, and it's worth pinning above your desk next to this one: you are done when the pipeline is boring. When the pipeline is boring, the agent can ship without supervision. When the agent can ship without supervision, you can stop being the laborer and start being the artist-engineer.
The second case study is the clean positive example. Its CI pipeline was explicitly "deferred from v0.1.0, landed in v0.2.0 where it mattered more — with six agents touching the codebase in parallel, automated gates weren't optional." That sentence is the whole rule. Parallel agents at scale are only safe when CI is doing the reading humans can't. Build+test+vet+race detector on every push, integration tests that spin up all adapters, a coverage matrix test that pins feature coverage — those aren't decoration, they're the thing that makes seven-agents-per-release possible. When the rails are that good, the humans are free to think about which work to do next and why — which is the craft layer doing its job.
The negative example is The Docker Port Mappings That Weren't (Part V): 180+ passing tests, zero data races, and a container unreachable for three releases because CI tested buildability, not connectivity. Boring pipelines are specifically not the pipelines that are silently wrong — they're the pipelines that loudly catch the thing they were built to catch.
Second-edition clause: every automated rail needs a rehearsed manual fallback. The pipeline is built from SaaS you don't control, and SaaS fails at the worst moment by construction — the worst moment is when you're using it hardest. The first case study lived this in a single release: the CI provider refused all five jobs over a billing dispute two layers of vendor above the project, forcing a local fast-forward merge and a by-hand run of the deploy script; an hour later the issue tracker's free-tier cap blocked filing the regression the release had just found. Neither failure was recoverable through the failed service, and both had cheap fallbacks only because the deploy script could be run manually and the bug could be written to the changelog, memory, and the retro instead of the tracker. The rule: for each automated rail — CI, deploy, issue tracking, secrets management — be able to answer "how do I do this by hand today?" before the day arrives. If the answer is "I can't," the rail isn't a convenience; it's a single point of failure wearing one. Pin: automation you can't bypass is a dependency you can't survive.
Field note — case study 1: The pipeline as the project's most load-bearing dependency. The CI/CD Excellence release (from the first case study) landed eighteen DevOps issues across six layers in one pass — none invented fresh, all cashed in from three retros of "we should fix this next time." That release isn't impressive because of the eighteen fixes. It's impressive because every fix moved pain earlier in the loop, where it was cheaper to pay. That is the definition of a pipeline becoming boring: the pain doesn't disappear; it just stops reaching the craftsperson.
Rule: CLAUDE.md is for facts that don't change. Memory is for facts that do.
Why: CLAUDE.md is loaded every conversation. Memory is updated per conversation. A stale line in CLAUDE.md is invisible — it looks like truth forever. A stale line in memory is one update away from being fixed. How to apply: Architecture, tech stack, conventions, file layout, the stable shape of the project → CLAUDE.md. Sprint state, current cycle ID, the gotcha you learned this afternoon, the user's preferences → memory.
CLAUDE.md wants to become an encyclopedia. Every project pulls the same direction: "this is important, I'll drop it in CLAUDE.md so the agent always sees it." Six months later CLAUDE.md is a 900-line landfill and the agent is reading eighty lines of v2-era minutiae on every cold start. Facts that move belong somewhere that moves. Put them in memory and they get corrected next time they're wrong. Put them in CLAUDE.md and they get cited as authoritative until someone burns an afternoon figuring out why the agent keeps insisting on the old thing.
Field note — case study 1: CLAUDE.md Gets a Haircut. A project's CLAUDE.md had grown into a 900-line landfill — architecture next to sprint state next to gotchas next to procedures. One pruning pass sorted every line into the right layer. Sixty percent smaller, and the agent got better at finding things.
A concrete example. Here's what one of the case studies' CLAUDE.md looks like in the field — roughly sixty lines, nothing inlined that belongs anywhere else:
# CLAUDE.md
This file provides guidance to Claude Code when working with code in this repository.
## Project Status (April 2026)
**Current**: v5.11.0 — Pipeline Polish (final CI/CD closeout)
**Next**: v6.0 — deferred; next cycle is feature work
**Live**: https://example.app
For version history, see CHANGELOG.md.
For the complete product requirements, see docs/PRD.md.
## Technical Stack
- **Frontend**: React 18 + TypeScript + Vite + Tailwind CSS
- **Backend**: FastAPI + SQLAlchemy 2.0 + Pydantic v2 + PostgreSQL 15+ + Redis 7
- **Observability**: Prometheus + Grafana + Sentry
- **Infrastructure**: Docker + Docker Compose + Alpine + Nginx
- **CI/CD**: GitHub Actions (9 jobs, BuildKit GHA cache) + release-please + SSH blue-green deploy with smoke tests and auto-rollback
## Essential Commands
(docker compose up/down, pytest, alembic, deploy — the short list, not a manual)
## Key Architecture Decisions
- **Anonymous by design** — no user accounts; three-word phrases are the only access credential.
- **Backend layers**: Routes (thin) → Services (business logic) → Repository (data access) → DB.
- **Frontend layers**: Pages (thin renderers) → Domain hooks → Foundation hooks → API service.
- **Security**: 4-layer defense (nginx → API auth → abuse detection → DB protection).
- **Deploy**: Blue-green via deploy-bluegreen.sh — builds, health-checks, smoke-tests, flips nginx upstream, post-flip verification with auto-rollback.
- **Release flow**: Conventional commits → release-please opens Release PR → merge → GitHub Release → deploy triggers.
## Agent Usage Guidelines
**Frontend** (use `ux-frontend-expert`): React components, UI/UX, design system, accessibility.
**Backend & Infra** (use `general-purpose`): API, security, database, deployment, testing.
## Task Tracking (Linear)
Project tracked in Linear with a short team key (e.g., `ABC`).
- **Sprint**: check CURRENT_SPRINT.md (auto-generated)
- **Commits**: `git commit -m "feat: add fuzzy search (ABC-42)"`
- **Branches**: `feat/ABC-42-fuzzy-search` or `fix/ABC-5-rate-limit-og`
What makes this work: a status block at the top so every cold start knows where the project is today; architecture decisions stated as bullets, not prose; essential commands as a terse list, not a manual; explicit agent routing so the harness picks the right specialist; and every detail-heavy thing (changelog, PRD, sprint state) pushed out to a linked doc instead of inlined. Anything that would move week-to-week lives somewhere else.
And for contrast, what the same file looked like when it went bad. A real excerpt from the pre-haircut version, anonymized:
## Important Procedures
When starting a new feature, first check CURRENT_SPRINT.md to see the active
sprint ID, then review the last three retros in docs/retros/ for any open
action items, then grep the codebase for TODO comments tagged with the sprint
ID, then run `make sprint-refresh` to update the local task list, then open
the relevant Linear ticket and cross-reference acceptance criteria against
the PRD, then…
## Gotchas
- Remember that the admin router is at routes/admin.py and also at
routes/v2/admin.py (legacy); edits usually need both.
- The audit middleware is registered in main.py but conditionally disabled
in test mode; check config.TESTING before adding new middleware.
- Always run `pytest -k "not slow"` locally; the full suite takes 45 minutes.
- Never commit without running pre-commit, even though pre-commit is in the
hook config (sometimes it doesn't fire).
Every line here is wrong-layer: the procedure is a skill hiding as a paragraph; the "admin is in two places" and "middleware wiring" gotchas belong in the code itself (one grep away); "run pytest -k" is atmosphere the agent will ignore; the pre-commit note admits the harness config is broken and asks the agent to compensate. Forty lines of this and the agent is reading more CLAUDE.md than code.
The layers, laid out. The workspace isn't one file — it's five surfaces, each catching a different class of thing. Here's what goes where:
| File / Surface | What it's for | How often it changes | Examples |
|---|---|---|---|
| CLAUDE.md | Stable project facts the agent needs on every cold start | Rarely — monthly at most | Tech stack, architecture layers, agent routing, essential commands |
| Memory | Live state, corrections, preferences, anything that moves | Per conversation | Current sprint ID, "next time, please…" corrections, user preferences |
| Skills | Procedures you want executed, not remembered | When the procedure itself changes | Release flow, retro writing, deploy, sprint refresh |
| Hooks | Non-negotiables the harness enforces without asking | When the rule changes | Sound notifications, pre-commit checks, format-on-save |
| settings.json | What the agent can do — permissions, tool access, MCP servers | When tooling changes | Allowed-tool lists, hook registrations, permission modes |
Each row is a layer; the failure mode is always the wrong thing in the wrong row. Write a procedure as a CLAUDE.md paragraph and the agent will read it and skip it. Write a permission rule in CLAUDE.md instead of settings.json and the agent will reinterpret it under pressure. Put live state in CLAUDE.md and it rots invisibly.
Rule: Skills are for procedures. CLAUDE.md is for facts.
Why: A multi-step procedure buried in CLAUDE.md is ambient noise — the agent reads it, then doesn't follow it, because it wasn't invoked. Skills are executed on purpose, step by step. CLAUDE.md is atmosphere. Skills are action. How to apply: If you find yourself writing "always do X when Y" in CLAUDE.md more than twice, stop and promote it to a skill. Release flow, deploy flow, retro writing, sprint refresh — all skill material.
The tell is a CLAUDE.md section that starts with "when you …" and ends with a numbered list. That's a runbook hiding in the wrong layer. You want the agent to follow a runbook, not vaguely remember it existed. Version-sync is the cleanest example: one VERSION file, one scripts/sync-version.py, one step in the release skill that calls them. No CLAUDE.md paragraph telling the agent "remember to update the footer." The script updates the footer. The skill runs the script. The fact — "version lives in VERSION" — is one line.
Field note — case study 1: The VERSION System. Version strings had been scattered across a footer, a package manifest, a Python constant, a Docker label, a changelog line. Every release someone forgot one. The fix was one
VERSIONfile, one sync script, one step in the release skill. No CLAUDE.md paragraph telling the agent "remember to update the footer." The script updates the footer.
Rule: Hooks make automation non-negotiable.
Why: Anything you ask the agent to "remember to do" will fail at least once. A hook is the harness doing it, which means it happens whether the agent is paying attention or not. How to apply: Sound notifications, pre-commit checks, format-on-save, status-line updates, post-response cleanup — these are hook material, not prompt material. If the rule is "this must happen every time," the harness must be the thing that makes it happen.
"Remember to X" is the prompt-engineer's cope. It works until it doesn't, and you won't notice when it doesn't, because the agent will confidently proceed as if it did. Hooks take the choice out of the loop. Our sound notification isn't in CLAUDE.md because it was in CLAUDE.md for a while and kept getting skipped. It's a hook now. It fires every time.
Field note — case study 1: The Great Script Purge. Deploy had accumulated into a scattering of one-off shell steps the on-call engineer was expected to remember in order. Consolidating them into one canonical script was the same move at a different layer: stop trusting memory, make the system do it. Sound notifications went the same way — lived in CLAUDE.md, got skipped, finally became a hook.
Rule: settings.json configures the harness. CLAUDE.md configures the agent. They are different layers.
Why: Settings determine what the agent can do. CLAUDE.md tells it what it should do. Mix them and you end up with behavioral rules the harness can't enforce and permission rules the agent can't read.
How to apply: Permission modes, allowed-tool lists, hook registrations, MCP server config → settings.json. Project context, conventions, behavioral norms → CLAUDE.md.
The mistake looks like this: you write "never run git push --force" in CLAUDE.md and think you're done. You're not. CLAUDE.md is a suggestion the agent is free to reinterpret under pressure. If you actually don't want that command to run, exclude it at the harness layer, where "can't" is enforced by the tool, not by politeness. The reverse error is putting project context in settings.json — nobody reads it there, and the agent can't. Two layers, two jobs.
§4 The first conversation
The first ten messages decide the rest of the conversation. The agent is calibrating from whatever you hand it — your tone, your files, your corrections, your omissions — and it calibrates fast. Get the first exchanges right and the session stays on rails for hours. Get them wrong and you'll spend the next fifty messages quietly fighting drift you seeded yourself.
Rule: Bootstrap with the smallest context that contains the answer.
Why: Dumping the whole repo into the window is wasteful and, worse, dilutes the signal the agent most needs. Token budget is attention budget. How to apply: Hand the agent the load-bearing files — CLAUDE.md or the relevant doc, the file you're editing, the test that pins its behavior. Let it pull more if it asks. Don't preload "just in case."
The instinct is to be generous: more context, more files, more background, surely that helps. It doesn't. A fresh agent reading eighty files skims all of them and remembers none. A fresh agent reading three files — the doc that tells it what "done" means, the file it's changing, the test it has to keep green — goes straight to the work. The God Module refactor (full story in Part V) was the release that made this concrete. Before the refactor, one admin module was 1,052 lines; any question about admin behavior meant loading the whole thing. After the split into five focused files, a subagent could be briefed on the sixty lines that mattered. The smaller workspace wasn't a cleanup — it was a briefing tool. Architecture is context design.
Field note — case study 1: God modules tell new readers nothing. A 1,052-line admin router held auth, records, stats, audit, and user management in one file. Any question about admin behavior meant loading the whole thing. Splitting it into five focused modules wasn't an aesthetic cleanup — it was making the workspace briefable. After the split, a subagent could receive sixty lines of context instead of a thousand.
Rule: Correct drift in message 2, not message 50.
Why: Corrections early are cheap. Corrections late are expensive, and by then the agent has built ten turns of work on top of the thing you should have caught. Drift compounds. How to apply: The moment the agent does something you don't want — naming, tone, pattern, where it put the file — stop and say so. Then ask whether the correction should become a memory entry so the next conversation starts already corrected.
The trap is politeness. The agent produces something 80% right and you think "close enough, I'll nudge it on the next turn." You won't. You'll accept the 80%, and on turn three you'll accept another 80% of that, and by turn ten you're reviewing a PR that's drifted in four directions at once. Early corrections are nearly free — one sentence, a re-run, done. The cost curve is brutal and it's worth burning a turn to stay on the early end of it. If you find yourself saying "next time, please…" — that's the memory entry. Write it down now. Half of what ends up in a bloated CLAUDE.md was originally a late-message nudge nobody wrote down when it was cheap.
Second-edition sharpening: the highest-leverage corrections are conceptual reframings, not code corrections. The fifth case study's retros tallied the corrections that mattered, and the pattern is striking: the ones that saved whole releases were single sentences that reframed the problem, not fixes to the diff. Mid-brainstorm: "this should be happy and heavy anticipation, not a bright_day register" — "the pivot cost maybe ten minutes of brainstorming and saved a release's worth of wrong abstraction." Mid-fix: "this feels like it should have an anticipation aspect" — the entry was future-tense, the ticket's diagnosis was wrong, and "Seth's one sentence of feedback saved us a release." Mid-debug: "I think the logic is right; I think we need to fix the debug page so it ignores the anti-repeat logic" — a sentence "which, once spoken, reads as obvious, and which we hadn't quite said until the user said it." Watch for the moment where your discomfort is with the framing rather than the code. That's the correction to make loudly and immediately, because everything downstream is built on the frame. Pin: correct the frame in one sentence now, or correct the code in one release later.
Rule: If the agent doesn't know something, tell it. Don't let it guess.
Why: Hallucination is most likely when the agent is confidently filling a gap. "It should know that" is the engineer's fault, not the agent's — the agent only knows what's in the window. How to apply: Any time you catch yourself thinking "well it should know" — stop and write it down. Feed it in. Then put it in CLAUDE.md or memory so the next session starts with it.
Trust Your Local Tests (full story in §12 and Part V) is the clearest version of this rule. Months of accumulated fear about ripping SQLite out of the backend test suite — and the move that made it tractable wasn't cleverness, it was finally telling the agent what "local green" was supposed to mean. Postgres only. Shared engine, per-test truncation. No SQLite branches anywhere in the bootstrap. Once that working agreement was written down and loaded into context, the removal was one afternoon. The fear had been doing the debt's work for it. The slogan exists because the team finally named the lesson out loud and handed it to the next conversation.
Rule: Make the agent tell you what it thinks you're building — then grill it.
Why: The previous three rules cover getting facts into the agent. This one covers getting the agent's model of the product out, where you can inspect it — because the agent will otherwise carry a confident, plausible, subtly wrong picture of what the project is for, and every plan it writes will be optimized toward that wrong picture. You cannot derive the value proposition from a type definition. The agent has to ask; better, you make it answer. How to apply: Before architecture, at project start and at every major re-scope, ask the agent directly: "Do you fully understand what we are building here?" Make it answer in its own words, at increasing depth, and correct what comes back. Then invert it — "anything you want to grill me on?" — and answer honestly. Budget an hour. The corrections at this stage cost one sentence each; the same corrections at message 50 cost a re-prioritized roadmap.
The sixth case study's health-instrument app ran this as a formal elicitation session before a line of code existed, and the transcript is the best argument for the rule. Asked to state what the product was, the agent confidently named the daily persona voice as the heart of the app. It was wrong — the heart was the long-view synthesis feature, the thing everything else existed to feed. "The cost of being wrong was one sentence of correction. The cost of being wrong in message 50 would have been a re-prioritized roadmap and a sulk." The same session caught the agent's proposed success metric — "you use it daily, unbroken" — as "a streak in a trenchcoat": the exact engagement mechanic the product's ethos forbade, smuggled into the meta-layer by an agent pattern-matching on what success metrics usually look like. Both catches happened because the human made the agent say its model out loud while saying it was still cheap. The product's four-word design ethos — the kind of sentence that vetoes eight specs — came out of the grilling, not out of any document the agent could have read. Pin: the agent's picture of your product is a guess until you've heard it recited and corrected it out loud.
§5 The loop
Every chapter after this one refers back to "the loop." The loop is explore → brainstorm → plan → TDD → verify → commit → retro, and it's the hub the rest of the playbook hangs off of. (The first edition's loop had six words; the second edition adds explore at the front — the evidence for why is the first rule below.) Memory (§6) is what you prune between loops. Skills (§7) are what you promote out of loops that kept repeating. Verification (§8) is a step in the loop. Retros (§16) are the step that teaches the next one. Remember the seven words in order — each one catches a class of failure the others can't.
Rule: Explore before you plan. The plan is not the codebase.
Why: A plan is written from a picture of the codebase, and the picture is stale the moment it's formed — features quietly shipped in earlier releases, test files that already exist with their own conventions, schema fields named differently than the spec remembers. Ten minutes of reading reality deletes hours of planning against a memory of it. And exploration has a second yield the plan can't predict: it finds the bugs nobody filed. How to apply: Before writing any plan, run the cheap reads: grep for the feature you're about to build, list the directory you're about to add to, check the migration state, open the schema. For release-scale work, dispatch a survey agent whose only job is to read the relevant surface and report what's actually there. Feed the findings into the brainstorm. If the exploration contradicts the spec or the ticket, the exploration wins — go update the spec.
The first case study's v6.0 waves made this a standing step, and the numbers sell it. Wave 1's first three commands — a grep, a migration-state check, an ls — took ten minutes and deleted sixty minutes of plan: five of the ticket's acceptance criteria had quietly shipped two versions earlier, and a twenty-task plan collapsed to five. The retro's line became the rule's name: "The plan is not the codebase. The codebase knows things the plan doesn't." Wave 2's survey agent flagged, almost as an aside, that nginx was blocking social-media crawlers by default — four curls confirmed that every shared link's preview image had been silently broken for three releases, and the release's most valuable fix was one nobody had asked for. Broken share previews don't generate bug reports; "the silence is the symptom." Exploration is the only loop step that can hear that kind of silence. Pin: run the greps before you believe the plan. Ten minutes of reading reality is the cheapest step in the loop.
Rule: Run the whole loop. Skip a step out loud or pay for it silently.
Why: Each step catches a different class of failure. Exploration catches plans built on a stale picture of the codebase. Brainstorming catches scope drift. Planning catches missing files. TDD catches wrong implementation. Verification catches "tests green, feature broken." Commit creates a rollback point. Retro catches the mistake you're about to repeat. Skip one and the class of bug it would have caught reappears later wearing a different hat. How to apply: Run all seven for every non-trivial task. If you're going to skip one, say which one and why — "I'm skipping TDD because this is a doc-only change" is fine. Silently skipping it is how you get surprise regressions on Thursday.
The temptation is always to compress. Plan-and-code. Code-and-ship. You tell yourself the loop is overhead for small work. It isn't — it's the harness that keeps small work small. v4.0.0 shipped with what the retro later called the Onion: six layers of CI failure, peeled one at a time over a week. Every layer was a step of the loop we'd quietly short-circuited on an earlier release. No plan meant no file map meant a test we didn't know existed. No verification in the right environment meant "green locally" meant nothing. No retro meant the previous onion's lessons never made it into the next loop. CI failure isn't an interruption — it's the loop telling you which step you skipped.
Field note — case study 1: The Onion: Six Layers of CI Failure. One release shipped with six layers of CI failure peeled one at a time over a week. Every layer was a step of the loop we'd quietly short-circuited on an earlier release — no plan meant no file map meant a test we didn't know existed; no verification in the right environment meant "green locally" meant nothing; no retro meant the previous onion's lessons never made it into the next loop. CI failure isn't an interruption — it's the loop telling you which step you skipped.
Rule: Brainstorm before planning. Plan before code.
Why: A plan written from a vague idea is a wish list. Code written from a vague plan is a mess you have to rewrite. The brainstorm is where scope gets named; the plan is where scope gets bounded; the code is what executes inside those bounds. Out of order, the bounds are hallucinated. How to apply: Even for a one-day task, brainstorm first. Fifteen minutes. Articulate what you actually want, what you've ruled out, what "done" looks like. Then plan. Then code. The cost is a coffee. The payoff is not rewriting the thing on Thursday. Qualifier: the brainstorm can amortize across multiple cycles when the work is repetitive and the upfront thinking was rigorous. The second case study brainstormed once, into a PRD with more than a hundred items across ten releases, and then each release went straight to plan → execute → validate → retro. That's not skipping the brainstorm — it's reusing the one you already did. The test is whether the current cycle's decisions are actually pinned by the earlier brainstorm or are quietly being reinvented each release. If reinvention is happening, the brainstorm is stale; redo it at the current scope.
The Four Scoping Gaps story is the canonical version of this mistake and we shipped it with our eyes open (full catalog in Part V). "Add one line to the release-automation config and flip one checkbox" — five-minute fix, no brainstorm required. We merged it. It didn't work. Diagnosis surfaced four separate scoping gaps, each plausible in isolation. A fifteen-minute brainstorm would have surfaced every one by asking the only question that mattered: what exactly does this tool read, and from where? We skipped the brainstorm because the plan felt obvious. A plan that feels obvious is a plan you haven't pressure-tested.
Rule: Frequent commits are not optional.
Why: Agents introduce subtle bugs across many files at once. Bisecting works only if the commits are small enough to bisect against. One giant commit is an unbisectable wall — you'll revert the whole thing or keep the whole thing, and neither is the fix you wanted. How to apply: One logical change, one commit. If you can't summarize the diff in one sentence, split it. Commit before the reviewer asks, not after. The loop has "commit" as a step for a reason — it's the rollback point, not a formality. Precondition: this rule depends on CI validating each commit quickly. A pipeline that takes forty minutes per push inverts the rule — the cadence collapses to whatever the pipeline will tolerate, and the agent starts batching changes to amortize the wait. Fast commits are a property of a boring pipeline, not of discipline. See §3's pipeline-as-precondition rule: if the rail isn't fast enough to support frequent commits, fix the rail first.
The Three-Deploys-to-Green release took three deploys to go green, and the only reason it was three and not three weeks was that every fix was its own small commit. Layer by layer: a missing env-file flag on a compose call, a self-updating deploy script that had to be hand-pulled once to fix itself, a long-abandoned Python dependency finally caving to a new version of the thing underneath it. Each was a separate diff, so each could be reverted independently when the next layer turned out to need the previous fix plus something else. If those had been one "deploy hotfix" commit, we'd have spent the same week untangling which change broke which other thing. Small commits are how you debug in the dark.
Field note — case study 1: Three Deploys to Green. The first end-to-end successful deploy took three tries, each uncovering a layer the previous fix had been sitting on top of. A missing compose flag hid a self-modifying deploy script that hid an abandoned Python dependency. Because every fix was its own commit, each layer was reversible when it turned out to need help from the one underneath. One "deploy hotfix" mega-commit would have turned a week of triage into a month.
Rule: Retros feed the next loop.
Why: The lesson learned in retro N becomes the rule applied in loop N+1. Without retros, the loop forgets — and a loop with no memory is just a hamster wheel that happens to compile. How to apply: A retro is mandatory at the end of every release. It doesn't have to be long. It has to be honest. Name what broke, name what you'll do differently, and — this is the load-bearing part — actually do it differently next loop.
The CI/CD Excellence release is what happens when retros are taken seriously. It wasn't a feature release — it was an eighteen-issue CI/CD pass across six layers, and every issue traced back to a line in a previous retro that said "we should fix this next time." BuildKit caching, pip-audit, blue-green smoke tests with auto-rollback, release-please automation, Slack Block Kit — none of it was invented in that release. All of it was cashed in. The line the retro kept coming back to was "each safety gate turns production risk into dev friction" — which is what retros do in aggregate. They move the pain earlier in the loop, where it's cheaper to pay. That move only happens if someone wrote the pain down last time. Skip the retro and next loop starts from zero.
Field note — case study 1: CI/CD Pipeline Excellence, cashed in from three retros of notes. Eighteen issues across six layers — none of them invented fresh, all of them traced back to retro lines from earlier releases that said "we should fix this next time." The retros were the ledger. The release was the settlement.
Rule: Cycles nest. Each level needs a theme, a boundary, and all three phases.
Why: A loop at the wrong scale is either too small to ship anything meaningful or too big to retro honestly. And at every scale, an upfront plan, an execution phase, and a validation phase all have to be present — compress any one of them and the cycle stops being legible. A cycle without a theme gets named by its date and forgotten. A cycle without a shippable boundary can't have a retro because you can't tell what "done" looked like. A cycle without explicit validation ships vibes. How to apply: The task-level loop is §5 as written — brainstorm, plan, TDD, verify, commit, retro. The release-level loop is the same shape on a larger canvas: a themed slice of the roadmap, an upfront plan (often a file map for parallel work), execution (often in waves), validation in the environment that matters, and a retro written in voice with a nickname. The project level is the same again: a PRD that sets the arc, a roadmap, a final retro. Each level needs a name you could say in one sentence and a boundary someone outside the work would recognize as shippable.
The second case study is the exemplar. Nine releases, each a themed slice of the same PRD, each with a clean boundary, each with a retro that reads like a story — every release title a thesis, every thesis a cycle you could retro honestly. The themes are what made the retros writable — a named theme wants to be a story; "Sprint 23" doesn't — and the retros are what made each next release plannable, because the lesson from one cycle became the opening move of the next. The wave pattern from an early release ("trivial work first, to shake out the build/config/test harness before committing agents to heavyweight implementations") became standard practice for every release after it. That transfer only happens if the cycle had a name worth remembering.
The negative example is the Onion release from the first case study — six layers of CI failure peeled one at a time over a week, with no theme, no single thing you could name the cycle for. That is why the layers were able to hide inside one release: the cycle had no shape, so nothing about the retro-able boundary forced the hidden work out into the open. Themed cycles aren't a ceremony; they're how the work becomes legible enough to improve.
Field note — case study 1: Nine retros that taught the tenth. The second case study's retro practice is the proof of concept for this rule. Each release was themed; each theme was one sentence; each retro had a "what we learned" section that became the next release's plan. By release nine, the wave pattern, the zero-dependency posture, the merge-point discipline, and the descoping rules were all things the team had written down to themselves in earlier retros and then honored in the next cycle. The cycles nested because each level had a theme, a boundary, and a lesson worth carrying forward. Pin: name the cycle before you start it; retro it the moment it closes.