In early July I declared all the code of my project legacy. Not a module — everything: code, architecture, documentation. The month before that, the project — a job marketplace for blue-collar workers: mobile app, web, an AI assistant — was built by a team. Strong people, each of them had worked with LLM agents before; what we didn't have was a methodology for working with agents. An agent writes code faster than a human — and generates entropy faster too: every branch in main, decisions living only in chat, documentation that lies, personal data settling into access logs. Every contributor is locally right, and the system as a whole doesn't work. Code that is scary to touch appeared in our project earlier than the first working flow. I stopped everything and started over — alone.
The mainstream treats agent amnesia with memory: long contexts, memory features, stateful agents that "remember the project". This is expensive in the most literal sense: a long session eats tokens and answers slower, and the context in it dilutes — by the end, the model holds what it started with worse. I went the opposite way: the project's memory lives not in the model but in the repository and in the rails — rules the agent cannot break, because they are held by a pre-commit hook (the hook that physically blocks commits to main), a CI job and branch protection, not by an instruction in the context. A fresh cheap session is not a limitation you have to heroically overcome; it is the foundation of the method.
The bet here goes deeper than saving tokens. In a human team, discipline is the most expensive thing: people are lazy about writing tests and documentation, and forcing them means burning motivation. For an agent, discipline costs nothing: you require a test — it writes a test. If the rules are held by a machine, discipline becomes free — and the method gives speed and stability at once, without the usual trade of one for the other.
What this gave. Speed: a working vertical — backend, web, mobile, database, CI with gates, deployment to three environments — in a week; another week and a half later — a design system synced with Figma across 99 styles, and a full guest flow on web and mobile in four languages — from onboarding to SMS login with versioned consent. In total: 18 days, 655 commits, not a single day without a commit — and this is not full-time. Control: the stage backlog grew along the way from 28 to 48 tasks — this is how sprints usually die — but every finding became a task with an address: 41 merged within the same stage, seven carried over as explicit tails, and every tail has a reason and an address. Measurability: I measured entropy twice, with a full pass over the corpus — 47 and 93 findings, the fate of every single one is known. And the main property: the system metabolizes incidents into rules. Every incident either gives birth to a rail, or consciously goes onto the shelf with a wake-up trigger — nothing disappears silently.
Before you write the objection to the comparison "a month of a team versus two and a half weeks solo" — I will write it myself. The second attempt stood on the studied rakes of the first one, and a solo developer doesn't pay the coordination tax that any team pays. It is impossible to cleanly isolate the method's contribution from such a comparison — so there will be no productivity percentages in this text at all. There will be an argument that doesn't depend on the caveats: not a single artifact survived the first attempt, while the second one built a system that lets one person run production development and already catches real bugs — three stories below. And so that this doesn't remain just words: the gate code, the hooks, the reviewer checklist and the rules catalog are published as-is, as a separate extract repository (the extract repo itself). The product code I don't publish, for obvious reasons; what I do publish is the harness itself — the machine part of the method: gates with their tests, hooks, checklists, prompts. Don't trust the descriptions, read the job conditions (the actual job conditions, every gate in one file).
This is part 1 and a report from the middle: stage two of eight on the way to MVP is finished, the methodology is being built together with the product. What didn't work is here too.
Why instructions don't work: five observations about fresh sessions
The method has seven principles and 29 rails that enforce them; the full manifesto is for a separate part of the series. Here is the explanatory core: five observations about how fresh sessions of LLM agents behave. Everything further is derived from them.
1. The agent doesn't learn — it reassembles itself from the repository every time. The project's "experience" exists exactly to the degree it is written down: canon, docs, git history. The same situation gives the same choice — including the same bad choice — in every fresh session. A consequence that breaks the intuition "introduce a rule — the team will get used to it": a rule has to be calibrated before switching it on. "It will settle in by itself" doesn't happen with agents.
2. The repository is the shared memory of all sessions, so the quality of the history is a rail too. Fresh agents imitate merged PRs. A gate that often goes red for no reason fills the history with samples of bypassing — and dies while staying green. A gate's health is measured by the frequency of escape hatches in merged PRs, and is treated by fixing the job conditions — not by "educating" the contributors. Their reflex is a symptom, not the disease.
3. Enforcement beats persuasion — for a mechanical reason. An instruction in the context dilutes as the session grows; a hook doesn't dilute. The reverse hygiene rule: a rule pinned by machinery shrinks to one line in the agent instructions — every extra paragraph in the context is a tax on all future sessions.
4. The only one who habituates in the system is the human. A worn-out review eye is a "meat" vulnerability; a fresh review session cannot go stale — it has no yesterday. In my project, every PR passes a fresh LLM session with a fixed checklist (that very fixed checklist) before my review. Twice it caught me — in the code of the very design system that was supposed to discipline everyone else: a test that stayed green on a broken page, and an ESLint rule that promised more than it checked. The author of the rules breaks them the same way everyone does — that's why every PR is looked at by a fresh session, not by me.
5. Rules are born from incidents — or from irreversibility. An imported "best practice" without lived pain lands not in the system but on a shelf with a wake-up trigger: a rule you don't believe in yourself, you will be the first to bypass, and one optional rule teaches the repository that rules can be optional. There is one exception: irreversible risks — secrets, data loss, personal data — get a rail preventively. There may be no second time.
What the system is made of
There are 29 rails now: 12 hard canonical rules — all of them working — and 17 method rails: 12 working, two on the shelf with triggers, two moving to the next stage, one dismantled before it was born — at spec time it turned out there was nothing to enforce. The full list is not interesting (and here it is: the live catalog with statuses and an "enforcement mechanism" column), the types are:
- Silent gates — deterministic checks without a human: a CI job, a pre-commit hook, branch protection; code without tests in a PR — red CI.
- Lenses — semantic check-ins, "read the registry before you work": a task touches personal data — check against the GDPR registry before writing code.
- The reviewer — a fresh LLM session with a fixed checklist on every PR, before the human review.
- Gardeners — periodic passes over the whole corpus, not over a diff.
- Ceremonies — stage-boundary checklists: a stage doesn't close without a report, the next one doesn't open without carrying over the tails.
- Registries — SSOT reference documents read by three consumers at three points in time: the contributor before the work, the reviewer on the PR, the gardener after.
The criterion for adding a rail: the pain is lived — or the risk is irreversible — and the rail can be made silent. Ceremonies are the only source of bureaucracy; there are few of them, and each one must pay for itself many times over. Out of this cycle comes the main property: the system self-learns — not the model, the system. Every incident leaves a trace in the rules, and every next session is born into an environment already stricter than yesterday's; how well this works is visible in the two entropy measurements in the third story below.
Three stories: incident → rule
Stories like these have piled up in dozens over 18 days: the review-rules registry alone holds 37 rows, and each one carries a concrete incident or verdict in its "source" column (the universal part of it travels to the extract). These three I picked because they generalize beyond my setup.
1. An untouched PR template silenced four gates
My CI gates read the PR description: are the mandatory sections in place, are the exception markers there with a reason. What betrayed them was my own PR template: it already contained the headings of those sections and hint comments with examples of the markers. The gates found everything they were looking for in an empty description the author never touched — and the PR was green before a human wrote a single word. Four gates went out at once. The rule: a gate must check what the contributor created, not what came from the template. It generalizes far beyond my setup: if your process checks "the PR has section X" — check whether section X appears by itself. The write-up is in the extract: the fix code and the counter-case test.
2. A public endpoint served drafts — and the tests legalized it
The public API returned a record card by direct id in any status: drafts and archive were readable around the feed filter. Worse than the hole itself was the reason no test caught it: the fake storage in the tests repeated the same leaky behavior as production. The tests honestly confirmed: the hole works as designed. It wasn't found by a human — the code gardener found it, with a pass over the whole corpus, not over a diff. The rule: a fake in tests must not legalize the behavior of production code. The write-up is in the extract: the rules born from the incident.
3. Entropy retreats to where nobody looks
The PR-time mechanisms see only the diff, by construction; entropy accumulates between the diffs. There is exactly one way to see it — periodically walk the whole corpus; that is what the gardeners exist for. There were two walks. The first, at the close of stage one: two gardeners, 47 findings — zero violations of module boundaries, but duplicates and drifted wording had already piled up. The second, eleven days later: four gardeners by now, 93 findings — ninety fixed by fix-agents inside the ceremony itself, three left as tails. Comparing the two measurements head-on is not allowed — the corpus had grown almost fourfold, and the search was now done by four gardeners instead of two — but the direction is visible even through the caveats: only twice as many findings on a corpus four times bigger, with twice as many searchers. The density of entropy is falling — the system that metabolizes incidents into rules got stricter between the measurements. Tests and module boundaries are honest, security — zero findings. Entropy didn't disappear — it retreated into the routing of the guards: the rules about which checks run on which PR.
The only blocker of the close came exactly from there. A PR changing only database migrations didn't run a single database test: the invariant "every table under RLS" — born from an incident, pinned by a test — was not checked on the only class of PRs capable of breaking it. The rule existed. The test existed. There was no route from one to the other. The fix — one line in the CI config. If you have a monorepo with path filters — check today which classes of PR slip past exactly their own tests. In my case, that class was found not by a human, but by the scheduled pass over the whole. The write-up is in the extract: that very area-detector line.
"And won't 130 thousand words of documentation rot?"
The knowledge base at the close of stage two — 60 documents, around 130 thousand words in 18 days. For me this is not a byproduct, it is the heart of the method: I run the project through documentation, which is why it appears before the code. Who reads all this, and when does it start lying? Agents don't read it whole — they enter through pointers, which are generated by a script from the canon and never edited by hand; pointer drift is caught by CI. Divergence of docs from code is caught twice: by a silent gate on the PR — "architecturally significant code touched, docs not — red CI" — and by the gardener at the stage boundary. And the journal of "what changed and when" is kept by git; the docs hold decisions and the "why" — the duplication that rots first simply doesn't exist, by rule. An honest caveat: the corpus is 18 days old; whether the loop survives further growth — that will be shown by the continued work, not by my assurances now.
What didn't work and what surprised me
The most expensive rail is pixel-perfect layout: numeric comparison against Figma, screenshot triples, the rule "after two failed patches the block is rebuilt". It works, but it is the most ceremonial part of the system, and it is held by discipline, not by hooks. Honest status: tolerable solo, unproven on a team.
A separate surprise — a guard reading yesterday's newspaper. My gates judge a PR by its description, and twice it turned out that the check sees a different text than the human does. Once the API handed the review session a stale PR body — the verdict was passed on a text that no longer existed. Another time it turned out that re-running a CI job doesn't re-read the PR: it works with a snapshot of the event taken at push time, so an exception marker added to the description later stays invisible to the gate no matter how many times you re-run it — only a new commit brings a new snapshot. The moral generalizes to any CI that judges by metadata: find out which snapshot of reality your guard sees, and at what moment it was taken.
The rails needed rails themselves: one rail lived as a line in the catalog, checklists referenced it — and the document didn't exist. The method that cures "decisions live only in chat" got caught on "a rule lives only as a table row". A gate was born: "a rail without a document — red" (this gate's code, its test next to it). And the self-check ceremony dropped the deploy: the invariant "web builds" lived in two places, and nobody held the second one — the same class of hole as the path-filter blocker, the second time within one close. The guard exists, but doesn't stand at every door; the method caught even itself in the moment of self-checking — though after the fact: with a deploy, not with a gate.
And the main thing that didn't work is the whole first attempt. A month of team development declared legacy is not somebody else's story, it is mine. The cheapest way with this text would be to not write it; I pay for it with a month.
Where this goes
For now everything is on manual control: I write the canon by hand, I assemble the rails by hand; there is exactly one piece of automation — the script that generates the agent pointers from the canon. The obvious next step is a machine manifest of the methodology, from which the whole harness is generated — roughly, "Terraform for a development methodology" — but that is an idea, not an announcement; the details are for the final part of the series. Meanwhile, everything listed here can be touched with your hands in the harness extract: the gates with their tests, the hooks, the PR template, the reviewer checklist and the rules catalog.
To be continued
The next stage is the first one where an LLM core appears in production, together with imported third-party content: listings will start arriving from other platforms and being normalized in batches. Part 2 — after it closes: will the rails survive a stage with a non-deterministic core, what will the third gardener measurement find, how many escape hatches will appear in merged PRs. And in parallel — a portability experiment: I will start pulling these same rails onto another live project of mine, one that was written with vibe-coding before any of this methodology existed. What a foreign corpus digests and what it rejects — that is also coming in the series. If the format is interesting — say so; and I am genuinely curious: what gates would you set for your agents, if CI could redden any decision of theirs?
Top comments (0)