Last week, I wrote a whole post arguing that giant agent skill repos won’t survive unattended 2027 workflows. I even put up a chart bragging about how lean Leaf, my local Level 5 dark software factory, kept its startup context compared to interactive terminal sessions.

Nothing humbles you faster than bragging about your architecture in public.

Over the nine days right around that post, a quiet pathology inside my own factory was doing the exact opposite of what I was preaching. By yesterday morning, the Planner role prompt had grown 4.5 times larger than it was at the start of October, and the shared _base.md file that every single agent pod reads on Turn 1 had ballooned 15 times larger, hitting 2,861 words.

So yesterday afternoon, we took hedge shears to the prompts/ directory. We cut total prompt words across the factory by 65% (from 17,072 words down to 5,899), and we took _base.md from 2,861 words down to 55.

We did it because our prompts had grown by one rule per incident for a month, and the rules had started causing the very failures they were written to stop.

The nuance: incident-driven prompt accretion

The most dangerous phrase in an unattended agent harness is “when an agent misbehaves, fix its prompt.”

That exact sentence was sitting right inside our repository’s AGENTS.md file. Nobody sat down and designed a 17,000-word prompt library. Each individual rule was written by a well-meaning post-mortem for a real incident. Taken one at a time, every rule looked reasonable. Stacked together, they buried the rules that actually mattered.

If you haven’t read the earlier posts on how my stack is wired, two pieces of nomenclature help make sense of how we got stuck:

  • Factory is the unattended multi-agent engine that takes an issue, plans a dependency graph, spawns isolated container pods to write and review code, and runs deterministic CI/CD.
  • /leaf is the interactive skill I run with my Product Owner hat on when I’m scoping new work or running a retrospective on a run that went sideways.

Over the 30 days before yesterday’s cut, 170 commits touched prompts/. My interactive /leaf sessions wrote 85 of them, automated plans built from /leaf issues wrote 68 of them, and I wrote 17 by hand.

That loop operated like a one-way ratchet:

  1. A run went sideways. A retrospective session dug through the SQLite telemetry and found what the agent did wrong.
  2. The retro filed a rule for that specific instance. Our principle of “fix causes, not instances” quietly degraded into “write a stern sentence forbidding the thing that just happened.”
  3. A unit test pinned the prose in place. Whenever a plan landed a new prompt rule, it also added an assertion in src/bridge.prompts.test.ts checking that the exact text existed in the markdown file. That test file grew to 1,022 lines and 162 assertions. Removing a stale sentence from a prompt literally broke CI.

Prompts could only grow. They could never shrink.

When the cure costs more than the disease

When you never delete a rule, you end up taxing 100% of your runs to defend against failures that happen once in a thousand turns:

  • The /tmp/run.log redirect tax: After a rare output buffering hiccup that occurred 0.2 times per 100 runs, a post-mortem added a rule telling every pod to redirect every shell command to /tmp/run.log and inspect it. The container harness already returns stdout, stderr, and the exit code directly to the model. Every pod in the factory was burning extra turns managing temporary log files for a bug that almost never happened.
  • The shell heredoc panic: A rule banning shell heredocs (<< 'EOF') was added for a failure rate of 0.1 per 100 runs. By yesterday morning, the rule itself was triggering problem moments inside build rooms, with engineer pods stopping mid-task to confess in the logs: “I wrote it with a shell heredoc, which the environment rules forbid,” and then burning turns redoing working edits.
  • The adversarial phase-gate trap: Across three separate incident fixes and a 230-line state reducer in src/refinement.ts, we had turned the Product Manager (PM) into a courtroom judge and the Planner into a defendant. They were locked in rigid readiness, research, and review phases where they couldn’t just talk directly, and the PM wasn’t allowed to question the token cost of a plan.

Yesterday morning, the whole pile finally collapsed under its own weight during a run on Calamus. Calamus is an agentic long-form writing and publishing experiment I’ve been building inside the factory to test how multi-agent workflows handle research, drafting, and editorial review outside of pure application code.

First, a Planner pod on Calamus spent 10 of its 16 minutes running test suites that taught it nothing, because four lines in planner.md told it to run them. Our reflex was so ingrained that /leaf immediately filed an issue adding more rules to planner.md.

A few hours later, after a primary frontier model hung, a fallback model planned 10 simple styling tasks on Calamus at Class 5 (max effort) because it decided styling work was “creative.” As I covered in Moneyball for AI Agents, Class 5 is our heavy multi-module tier, and throwing trivial styling nodes at it torches quota for zero gain. We already had a rule forbidding that exact behavior, but it was one sentence buried inside 4,113 words of prompt instructions.

When /leaf looked at that run and proposed adding yet another rule to pm.md, I finally pulled the plug.

We weren’t engineering a harness anymore.
We were writing an HOA bylaw binder that no model could hold in its head.

Two tests for every line (and moving rules to code)

We threw out the incident-driven patches and rewrote the core role prompts from scratch around themes rather than past bugs. While we were in there, we also cleaned up the role names end-to-end across code, docs, and SQLite settings: planner became architect, foreman became tech-lead, and worker became engineer.

To keep a single line of text in a prompt, that line had to pass two tests:

  1. It is verifiably true right now. We checked every claim against the live TypeScript code, the container image, and the SQLite schema, never against memory or the old prompt. During the first draft of the prune, our own /leaf session tried to carry forward the /tmp/run.log redirect, referenced a /opt/factory/docs/plans.md file that doesn’t exist inside a pod container, and told the PM to send a rev=<n> parameter that the chat tool explicitly rejects. Every one of those zombie lines got caught only because we forced a check against the code.
  2. It changes what the agent does on a >1% problem. If the harness, the deterministic CI gate, or the model’s baseline training already produces the behavior, the line gets cut. And a rare failure (under 1 occurrence per 100 runs) does not earn a permanent tax that every pod has to read on every turn.

Look at how much dead weight dropped out of the Turn 1 context across each seat, alongside what happened in the first 29 hours of runs after the deploy:

Comparison chart showing Factory prompt word counts before and after the 65% cut alongside the first 29 hours of runtime data on Calamus: Architect fell from ~7,700 words to ~840 (-89%), Tech Lead from ~5,200 to ~370 (-93%), PM from ~4,000 to ~200 (-95%), Engineer from ~3,750 to ~220 (-94%), and _base.md from 2,861 to 55 (-98%), while Haiku turns fell 43%, Sonnet turns fell 35%, and build problem moments dropped 62%.

Cutting that much markdown only worked because we moved rules that prompts can’t reliably enforce into deterministic code:

  • Container defaults instead of shell lectures: Instead of lecturing every pod on which retry flags to pass to curl, we baked a .curlrc file directly into the pod container image.
  • Self-documenting error messages: When a merge is refused, the refusal error returned by the harness now names the exact next step in plain text, so the Tech Lead prompt doesn’t have to carry a troubleshooting manual for every refusal state. We also fixed a code bug where a retired read-only node never counted as merged and blocked its downstream dependents.
  • Direct collaboration instead of courtroom phases: The PM and the Architect now start in the planning room at the exact same time and talk directly. The PM owns what and whether (with the repository’s external wiki mounted, and without reading source code); the Architect owns how and cost. They share a single explicit goal: “a plan that delivers what the issue asks for, at the lowest cost that does it well.” The readiness, research, review, and owner-wait state machine phases are gone, deleting roughly 470 lines of ceremony from src/prd.ts.
  • Killing the prose-pinning tests: We cut src/bridge.prompts.test.ts from 1,022 lines down to 108 lines. The surviving tests only verify structured tokens that Factory’s TypeScript code actually parses.

What 29 hours on Calamus actually tells us

We deployed the pruned prompts yesterday afternoon. All 9 build runs and 10 of the 11 planning rooms in the first 29 hours ran against Calamus, which gives us a clean before-and-after comparison on a single repository against the 7 days right before the cut (97 planning rooms and 72 development runs):

Measure (Calamus)7 Days Before CutFirst 29 Hours AfterChange
Planning: Architect input per turn231k tokens130k tokens-44%
Planning: Total input per room6.98M tokens6.17M tokens-12%
Planning: Rooms ending in approved plan96 of 99 (97%)10 of 10 (100%)Held steady
Planning: Revisions per plan2.081.70-0.4 revisions
Engineer nodes planned above Class 417 of 353 (4.8%)0 of 14 (0.0%)Eliminated
Engineer on Haiku: turns per pod21.7 turns12.3 turns-43%
Engineer on Haiku: time to first edit32 seconds12 seconds-63%
Engineer on Sonnet: turns per pod38.7 turns25.3 turns-35%
Problem moments per 100 pods (Build)7930-62%
Problem moments per 100 pods (Planning)4735-26%
Tech Lead on 1-node runs: input tokens420k tokens543k tokens+29% (worse)

Look closely at the mechanism behind those engineer numbers. The token savings didn’t come from a smaller prompt on each turn; they came from the pods taking 35% to 43% fewer turns.

On Sonnet, an engineer pod’s average context per turn after the cut is almost identical to what it was before (72.5k tokens vs. 72.9k tokens), because repository files and tool output dominate the context window once a pod starts working. What changed is that the agents stopped performing all the defensive ritual work the old rules demanded: redirecting logs to /tmp/run.log, re-running unrequested checks to prove diligence, and tiptoeing around banned shell syntax. On Haiku, the median time before an engineer pod made its very first file edit dropped from 32 seconds down to 12 seconds. And with the 4,113-word noise floor gone from the Architect prompt, zero nodes have been planned above Class 4.

A few honest practitioner caveats on this dataset:

  • It’s a 29-hour sample on a single repo. Ten planning rooms, 9 build runs, and 14 engineer pods on Calamus is enough to spot a directional shift, not enough to declare victory. BrandCast, my digital signage platform, ran 244 planning rooms in the week before the cut and hasn’t run a batch since the deploy. That will be the real stress test.
  • Task shapes and model mixes shifted. Post-cut plans on Calamus averaged 1.4 nodes compared to 4.6 nodes the week before, and 43% of post-cut engineer pods ran on Haiku (Class 2) versus 23% before. That’s why the table above compares per-pod, per-turn, and same-model metrics rather than raw per-run totals (which would claim a phony 77% drop in tokens).
  • The Tech Lead went the wrong way. On comparable 1-node runs, the Tech Lead took 26% more turns (11.4 to 14.4) and 29% more input tokens (420k to 543k). We don’t know yet if that’s small-sample noise across 8 runs or a real side effect of shorter Tech Lead instructions. We’ll re-measure at 50 development runs.
  • The prune shipped its own bug on run one. When we simplified the PM’s plan approval signal to consent, our new parser extracted the revision number from the first integer in the PM’s message. In the very first live planning room after deployment, the PM wrote "calamus312 revision 2", and Factory happily parsed that as revision 312. Our unit tests had only tested "Revision 3." We fixed the parser four hours later.

Even with those caveats, cutting two-thirds of our rules made the pods faster, quieter, and less prone to self-inflicted errors.

Guarding the prompts from ourselves

The most sobering discovery during this cleanup wasn’t the word count. It was realizing that we already had a file protection guard on prompts/, and it was fencing off the wrong loop.

Back in October, I added prompts/, src/bridge.prompts.ts, and skills/ to the protect array inside .factory.json. I assumed that prevented automated loops from bloating our instructions.

It didn’t. Only our autonomous Improve loop (the background complexity-reduction loop I wrote about in the Moneyball post) checked the protect list. And Improve wrote 0 of the 170 commits that bloated prompts/. My own /leaf post-mortem sessions and the development plans generated from them wrote 153 of those 170 commits, walking right through the front door because development plans didn’t enforce protect.

Meanwhile, six secondary prompts in the directory (security.md, techwriter.md, improve.md, leadwriter.md, reader.md, and prd.md, totaling about 3,970 words) still haven’t gone through the line-by-line audit yet.

To keep the bloat from creeping right back in next week, we’re making four structural changes:

  1. Enforce protect on every plan save, not just Improve. If any node in a proposed plan touches a path listed in protect, the harness refuses to save the plan. No automated loop or /leaf-generated issue can edit a prompt file anymore; only a direct commit from me can touch prompts/.
  2. Rewrite the rule in AGENTS.md. We’re replacing “When an agent misbehaves, fix its prompt” with a new default: when an agent misbehaves, first look for a prompt rule to delete or a refusal check to move into deterministic code.
  3. Put a 1% incident gate on /leaf. When a retrospective finds a failure mode that genuinely points to a prompt change, /leaf is no longer allowed to file an issue. Instead, it has to report the finding to me alongside its historical frequency per 100 runs in factory.db.
  4. Never pin prompt prose in unit tests. src/bridge.prompts.test.ts will only ever test structured strings that code parses.

Item 1 is the real lock on the door. Items 2 through 4 are prose, and they only hold because Item 1 refuses anything they miss.

So what?

If you’re running multi-agent workflows or maintaining AGENTS.md and skill files for your team, watch out for incident-driven prompt accretion:

  • Stop treating system prompts like a post-mortem changelog. Every time you add a sentence to stop a 0.1% edge case, you dilute the 10% of instructions that keep your agents on the rails during the other 99.9% of runs.
  • Delete prose-pinning unit tests. If your test suite asserts that specific instructional sentences exist inside your markdown prompts, you’ve built a one-way ratchet that makes cleanup feel like breaking the build. Test what your code parses, not how you lecture the model.
  • Move behavioral guardrails into deterministic code. Don’t spend 50 tokens on every turn begging an LLM to pass retry flags to curl or to format a git merge a certain way. Put .curlrc in the container image, make your tool refusal errors name the exact recovery command, and let code enforce state transitions.
  • Measure turns and ritual work, not just Turn 1 prompt size. A bloated prompt doesn’t just cost you input tokens on Turn 1. It makes agents paranoid, multiplying the number of turns they spend running CYA checks instead of shipping the edit.