I first published this post on 2026-10-13 and revised it on 2026-10-20. The first version introduced more rules up front. I spent too much time establishing additional rules before demonstrating a feature. That made the introduction feel heavier than necessary, including for me. The series now adds rules when a concrete need arises. The companion repository has started over; this post links to its tag part-1.
In my previous post, When Agile Is Not Enough, I described an agent team that produced pull requests faster than I could review them. I could get code written quickly enough. Keeping up with what I was approving was another matter.
Part of that was my own doing. I hadn't written down the expected behavior in enough detail. The agent made the missing decisions, and I had to find them in the diff. By then, I was reviewing both the implementation and decisions I hadn't realized needed making. I'd rather agree on the intent before the code exists. Then I have something to review the result against.
The method
This series follows the method Anatoly Volkhover describes in his book Agentic Spec-Driven Development. In his method, the spec is the source of truth. Code is generated from it and never edited by hand. The coding agent keeps persistent rules that change only through analysis and my approval.
My goal is to develop a specification together with the agent, implement it, inspect the result, and evolve the specification when requirements change. You can follow the repository tag by tag and apply the approach to your own projects.
Other approaches share the name, GitHub's Spec Kit among them; this series follows one, with my own changes. Anatoly allowed me to publish my adapted files with attribution. I'm not affiliated with him.
What I'm building
I'm a platform engineer with a security background. I'm building recon-mcp, an MCP (Model Context Protocol) server for authorized penetration tests. It exposes tools an AI agent can call, in this case to run reconnaissance against targets the tester is authorized to scan. The first tool scans a target for open TCP ports. At this checkpoint there is no implementation yet, only the rules for the work ahead.
That intent starts AGENTS.md. I replaced Volkhover's example, his companion website agentic-spec.com, with this project in the first commit.
Four files to start
Four files come from Volkhover's bootstrap downloads. I added README.md for human readers: the project description and attribution, shown on the repository's front page.
.
├── AGENTS.md # intent, rules and file registry
├── README.md # project description and attribution
└── .ai/
├── rule-analysis.md # checks before a rule changes
├── rule-conflict-protocol.md # procedure when rules collide
└── logs/
└── rule-conflict-log.md # append-only conflict record
AGENTS.md travels with every prompt. It tells the agent to read rule-analysis.md when adding, editing or removing a rule. When two rules collide at runtime, the agent reads rule-conflict-protocol.md, which has it append to rule-conflict-log.md.
For example, rule-analysis.md holds about 600 words, six formatting conventions and six analysis steps. Putting it inside AGENTS.md, already about 3000 words, would send it with every unrelated request too.
Volkhover advises keeping the main file short: longer rule sets take up more space in each model call and are harder to follow. It holds the rules that always apply and says when to load the rest; too many triggers defeat that saving. I keep the procedures in their own files so they aren't hardcoded into AGENTS.md.
What the agent sees
Volkhover explains that the agent calls the model repeatedly while working. Each call and response is a turn. Every turn sends the conversation, standing rules, files read and tool results: together, the context. The model has no memory between calls. Reading a procedure doesn't remove it afterwards; it stays in the session's context.
The context window is the maximum text the model can process at once. Volkhover describes quality dropping before it fills: the middle gets less attention than the beginning and end, where agents place the rules and latest request. He calls this context rot. As the window fills, agents either drop old messages or compact them into a summary that loses detail. He treats compaction as a sign to have ended the session earlier.
His illustration shows why leftovers matter: after a session about a public marketing page, an admin interface inherits the open-access assumption and lacks a login check; a fresh session adds authentication. His advice is one topic per session. I want each new task to start without that leftover context. A fresh session also forgets decisions, which is why the rules, registry and log live in the repository.
The main file: AGENTS.md
The intent comes first because the agent compares every request against it. If a request doesn't fit, it asks how it relates. Volkhover's reason is practical: a prompt pasted into the wrong project's session otherwise gets done there. Keeping the intent in the main file puts it in context before the request arrives.
Next come the rules. Durable rules live here or in rules files this file references, never in a user-global or nested instruction file. They change only after analysis and approval. This fixes where new rules belong when an agent reads instructions from several places. A missing file or undefined reference makes it stop and ask. Throwaway scripts and output go into .tmp/, exempt from the registry and never committed.
The registry at the bottom gives each file a type and a protocol. Types say what it is: rules, log or docs. Protocols say what the agent may do: read-only forbids changes, append-only allows new entries, and editable allows content changes. Both sets are closed; adding a category needs my approval, so the labels keep their meaning.
| Subfolder | File | Type | Protocol | Dependencies | Instructions | Description |
|---|---|---|---|---|---|---|
.ai/logs |
rule-conflict-log.md |
log | append-only | Audit log of runtime rule conflicts and their resolutions |
Dependencies and Instructions are empty at part-1, as all three protocols require; Volkhover reserves them for a later protocol. Creating, moving, renaming or deleting a file needs an approved registry change first. Even editable doesn't allow an unapproved cleanup deletion.
Changing a rule
Before adding or changing a rule, the agent reads rule-analysis.md. It lists what the rule requires, allows and forbids, checks conflicts with existing rules, checks the wording and resolves file references. It presents the result and waits for my approval before writing anything.
Volkhover's aim is that I approve the rule actually written, including its implications. A conflict caught now needs a wording change; found later, it may have affected weeks of work. Removing a rule checks what behavior disappears and blocks removal while other rules still reference it.
In his method, the bootstrap files aren't edited by hand after installation. Every rule change goes through a prompt, placing the analysis between me and the change. The git rule below shows one finding.
When rules collide
Analysis catches conflicts visible when a rule is written. Volkhover keeps a runtime procedure because other conflicts appear only when a particular request triggers two rules together.
rule-conflict-protocol.md has the agent stop and log the conflict first. It then quotes the rules and their sources, offers at least three options (drop a rule, resolve this request only, or stop), and waits for me. It mustn't silently choose which rule wins. A decision for one request doesn't become a durable rule unless I say so.
rule-conflict-log.md keeps that record, append-only: an ID such as RC001, the triggering input verbatim, the operation, the rules, the options and my decision. Earlier entries stay unchanged; corrections are new entries that reference them. At part-1, it holds only the entry template. Future entries let me reconstruct what happened.
These are instructions, not enforcement. I still check the agent's work.
Two changes to the layout
My setup differs from Volkhover's in three places, two in the layout. I use AGENTS.md instead of CLAUDE.md so the name isn't tied to one tool, replacing its references throughout as Volkhover advises. Claude Code reads it from v2.1.277, by default when no CLAUDE.md or CLAUDE.local.md takes precedence in the working directory or above it. I also moved the supporting files into .ai/, leaving AGENTS.md and README.md at the top.
Volkhover's naming rule banned dotted folder names, so a leading-dot rule went through analysis and was committed before the move. The README needed the docs type and a naming exemption; both went through analysis too. Each rule answered a concrete need.
Letting the agent commit
The third change concerns git. Volkhover keeps it away from the AI. I found that strange: git tracks every change, so once I've approved one, the agent may as well commit it within my rules.
It commits only approved, fully written changes, including the registry update, one logical step per commit, using Conventional Commits without AI attribution. It never commits to main; there, it asks for a branch name. Push, force-push, merge into main, rebase, reset, amend, branch deletion and switching to an existing branch stay with me: the agent names the command, and I run it. Corrections to commits not yet on main become fixup commits; discarding uncommitted work requires asking first.
The analysis raised six points; one was that switching to an existing branch would overwrite the append-only conflict log's working copy, so that operation stays with me.
Next: the first tool
You can check out tag part-1 for this scaffold. In part 2, I specify the first tool with the coding agent, including how scans stay within authorized targets, then implement it. The next rule waits until the tool needs it.

Top comments (1)
I wrote this piece because I found myself drowning in agent-generated PRs faster than I could manually review them. Letting the AI make undocumented design choices behind the scenes just created a bigger review burden for me later.
I’m really curious; how are you all handling code generation safety and review bottlenecks in your current workflows? Has anyone else experimented with putting specs before the code? Let me know what you think!