Make a repository explain itself to an agent. One command lays a Markdown structure into an existing repository, so that an agent opening it knows how the project works before it writes a line.
python3 ai_setup.py init /path/to/repoThen open the repository with your agent and say:
read ai/BOOTSTRAP.md and do it
Python 3.8 or later. No dependencies. Nothing leaves your machine.
An agent can find and open any file in a large repository in under a second. Nothing it finds there tells it how to work with what it has just opened: which document explains that code, which rule it is about to break, or which test would catch it if it gets that wrong.
That knowledge exists. It lives in a wiki nobody updates, in a handful of review comments, and in the maintainer's head. A new developer absorbs it over weeks. An agent arrives with none of it, cannot ask for it, and starts again from nothing in every session.
Most repositories are well organised. The reasoning behind the organisation was never written into the tree, because the people carried it instead. Plenty of ecosystems ship a command that lays out a new project, and what those commands generate is aimed at the compiler, the package manager and the human reader. Not one of them puts anything in the tree for an agent.
This tool is one attempt at that missing part.
It copies a set of rules, indexes and templates into your repository, asks one
question about where your documentation lives, and leaves behind
ai/BOOTSTRAP.md: an ordered list of what an agent should build next, from
what it finds in your tree. The tool ships almost no code, because checks,
hooks and generators depend on your language, your build system and your
conventions. A generated check that fits the project beats a copied one that
does not.
There is one exception, and it is deliberate: scripts/ai-commit.py. Git
behaves the same in every repository, so the commit path is the one piece of
machinery that transfers intact. See The commit path.
python3 ai_setup.py init [PATH] # copy the structure in
python3 ai_setup.py check [PATH] # check the structure is consistent
python3 ai_setup.py list # print what init writes| Flag | Effect |
|---|---|
--name NAME |
Project name in the templates (default: the directory name) |
--docs LIST |
in-repo,wiki,site,external or none, instead of the question |
--no-connect |
Do not wire documentation to the code |
--force |
Overwrite files that exist, named individually before it asks |
--dry-run |
Print the plan and the disclaimer, write nothing, ask nothing |
--yes |
Accept the disclaimer and the detected defaults, ask nothing |
init prints every file it will write, then a disclaimer, then waits for you
to type yes. The disclaimer says what changes, what it does not touch
(nothing outside the directory, no git command, no network), and that
CLAUDE.md and AGENTS.md will govern every agent session opened in the
repository from then on. A run that is not a terminal refuses rather than
proceeding unattended.
An existing file is never overwritten without --force, so the tool is safe
in a repository that already has a CLAUDE.md. When it keeps yours, it prints
the one line to add to it.
Safe, and useful. Three cases:
| You run | It does |
|---|---|
| The same command twice | Nothing. Every file exists, so it reports nothing to do and writes zero bytes |
| A newer ai-setup that ships new rules | Writes only the new files, then inserts each new rule into ai/rules/INDEX.md in alphabetical position, so a rule can never reach the tree without reaching the index |
--docs <surfaces> after declining at install |
Writes the documentation rule and surface list, then inserts the missing row into ai/rules/INDEX.md, AGENTS.md, CLAUDE.md and ai/INDEX.md |
Reconciliation is idempotent: a row already present is never added twice. If an anchor line has been edited away, the tool prints the row for you to place by hand rather than guessing.
--force is the exception. It overwrites, and it names every file first,
marking the ones you have edited since install:
OVERWRITES 34 existing file(s), losing their content:
ai/INSTRUCTIONS.md <-- EDITED SINCE INSTALL, your answers are lost
Where does this project's documentation live?
* 1 in-repo docs/ Markdown inside this repository
2 GitHub wiki a separate <repo>.wiki.git checkout
3 published site GitHub Pages branch, or a sibling worktree
4 external service Notion, Confluence, a hosted docs service
0 none
Connect the documentation to the code?
Source files point at the document that explains them, documents point back,
the index between them is generated, and a stale link fails verification.
Answering yes adds ai/rules/documentation.md and ai/DOC-SURFACES.md, with
one section per surface saying what that surface owes. A wiki is treated as an
output, not a source, because nothing there can be gated. A published site is
checked out as a worktree beside the code so one session can read both, and
every page carrying a factual claim is generated from the code rather than
transcribed. A surface outside the repository also gets ai/DOC-SURFACE-AI.md,
the entry file to copy to its root.
Answer 0 and none of it is written. There are no empty sections left behind.
CLAUDE.md entry point, a copy of AGENTS.md
AGENTS.md the always-on rules and the dispatch table
ai/
INSTRUCTIONS.md canonical source of the two entry points
BOOTSTRAP.md what the agent builds next, in order (delete when done)
INDEX.md task to document routing: "I want to X, read Y"
rules/ 17 rules, plus documentation.md when connected
patterns/ the approved shape of each repeated concern
workflows/ the procedure for each repeated multi-step job
DOC-SURFACES.md where documentation lives (when connected)
DOC-SURFACE-AI.md entry file for a surface outside this repository
plan/
README.md spec lifecycle
TEMPLATE.md the spec format
journal/ one file per problem class, one row per occurrence
learned/ why the design is this shape, and what recurs
scripts/
ai-commit.py the one piece of machinery that transfers
scripts/ai-commit.py is a small, dependency-free version of the commit
helper Ze uses. It exists because three failures are silent and expensive:
| Failure | What the helper does |
|---|---|
| A commit carries a file nobody intended, because several sessions share one working tree and one index | Stages an explicit list, and aborts if anything else was already staged or if staging picks up more |
| Verification passed against a different tree | Refuses unless a stamp matches a fingerprint of this exact tree, tracked and untracked |
| A check was bypassed to get green | No bypass flag for a red run. --no-verify-stamp is for a commit no verification covers, and the reason belongs in the message |
make verify && python3 scripts/ai-commit.py verified # stamp this tree
python3 scripts/ai-commit.py status # FRESH or STALE
python3 scripts/ai-commit.py commit -m "message" a.py b.pyThe stamp lives in .git/, so it is never committed and never shared. A
commit clears it, because HEAD moved and the evidence no longer describes the
tree. The helper never pushes: pushing stays a separate, deliberate act.
Delete it if your project already has an equivalent, and name the real one in
ai/rules/change-control.md.
Each file opens with a trigger (**When:**) and a severity. The trigger is a
routing key: an agent matches it against the task in hand, then opens one file.
| Rule | Says |
|---|---|
discoverability.md |
The tree explains itself, and the links are checked |
documentation.md |
Code points at its document, the document points back, the index is generated |
architecture.md |
Search the repository before proposing; placement follows dependency direction |
simplicity.md |
The simplest FULLY CORRECT answer. Simplicity cuts machinery, never correctness |
evidence.md |
Read the producer before claiming what code does. A coherent story is a hypothesis |
testing.md |
The change decides the test it owes. Break a new test on purpose before trusting it |
proof.md |
Name every obligation. A tag in a file nothing runs is no evidence |
completion.md |
Deferred is not done. Recording a problem is not addressing it |
verification.md |
One entry point, cheap failures first, every message teaches |
change-control.md |
A commit carries evidence that this exact tree was checked |
planning.md |
Spec before code. Review is independent of the author |
sessions.md |
Enumerate a handoff before planning. Write state down, do not hold it |
context-economy.md |
Batch independent calls, read ranges not files, size the work to one agent |
agent-interface.md |
Your program's errors are the agent's next prompt. Make them say what to do |
writing.md |
Say it once, say it short. No hedging, no marketing adjectives, no stale comments |
repo-maintenance.md |
A change updates its discovery path in the same change |
rule-format.md |
A trigger routes. A directive states a level. An unenforced rule is deleted |
rule-precedence.md |
One ladder for deciding whether to stop, ask or continue |
Every rule carries <!-- ADAPT: ... --> markers where a project fact is
missing: the layers of your architecture, the table of which change owes which
test, the commands that verify.
Delete the rules that do not apply. An unenforced rule teaches the next
agent that rules here are decorative, and that costs more than the rule was
worth. proof.md says so about itself: a project making no external claim
should remove it.
ai/BOOTSTRAP.md is the handover. Ten steps, in the order that makes each one
pay for itself alone, so you can stop after any of them:
- Make the project folder runnable. Predictable places for configuration, fixtures and data. One table an agent reads to start the program.
- Write the architecture map. One row per directory, what belongs in it, which way its dependencies run.
- Create the task index. Read the twenty most recent changes and ask what each one needed to know before it started. Each answer is a row.
- Link source to design, and back. A marker in the file, a marker in the document, the reverse index generated, a stale link failing the build.
- Record the approved patterns. One file per repeated concern, written from the code that already exists.
- Turn repeated mistakes into checks. Explanation, example, mechanical check, behavioural test. The check fires as early as it can.
- Decide which change owes which test. Fill the lookup table, list the exceptions, so the choice is looked up and not improvised.
- Provide one verification command. Cheap failures first, continuing far enough to report every useful failure. The same command in CI.
- Make the proof traceable. Only if the project claims something publicly: stable names for obligations, tagged tests, published gaps.
- Sync the entry points, then delete the bootstrap file.
Then it reports which steps it completed, which ADAPT markers are still open, which rules it deleted as inapplicable, and what it could not decide without you.
python3 ai_setup.py check .It is deliberately small, and it is the only check the tool contributes to your quality gates. It fails on:
- a rule file missing from
ai/rules/INDEX.md, or listed there and absent - a rule with no
**When:**trigger or no**Severity:** - a rule declaring
advisorywhile its body statesMUST - a scaffold file that has gone missing, which is how a half install reads
AGENTS.mdandCLAUDE.mdhaving drifted apart- a dead relative link in
ai/,plan/,AGENTS.mdorCLAUDE.md - an unfilled
{{...}}placeholder
It reports, without failing, every open <!-- ADAPT --> marker. That keeps it
green from the first day and useful as a progress meter afterwards. Wire it
into CI once the structure settles.
python3 -m unittest discover -s tests30 tests, no dependencies. Each one names the failure it prevents rather than the function it exercises, and the two that guard the worst bugs (a template error leaving a half install, an upgrade leaving a rule unindexed) were checked by breaking the fix and confirming they go red.
Why rules and not code. A check that does not fit the project is worse than no check: it fires on correct code, somebody switches it off, and everything it protected goes with it. The rules are portable because they are about how to work. The enforcement is not, so the agent writes it.
Why Markdown. It is what the agent reads, what the editor opens, what the diff shows and what review already covers. Karpathy's LLM Wiki gist reached the same answer, and so did several other people independently, which is a reasonable sign that it is the right level.
Why boring file names. ai/INDEX.md, CODE-TO-DOCS.md, DOCS-TO-CODE.md.
An agent can guess a boring name. It cannot guess a product name invented for
a simple idea.
Why one question and not twelve. Everything else can be read from the tree by an agent that is already sitting in it. Where the documentation lives, and whether you want it wired to the code, is a decision about your project that no amount of reading answers.
Why it asks for consent. It writes into your repository, and then hands an agent a list of machinery to build that can refuse edits and fail your build. That deserves a yes.
Why ai-setup does not run on itself. The obvious credibility move is to
install the scaffold here. It was considered and rejected: this repository
would then hold two near-copies of every rule, templates/ai/rules/x.md as
the product and ai/rules/x.md as its own instance, and the wrong one would
get edited. They are meant to differ, since an instance has its ADAPT markers
filled in, so no check can demand they match. The rules that govern this tool
live in templates/, and what proves the tool behaves is tests/, not a
second copy of its own documentation.
This tool came out of the Ze blog, where the practice behind these rules is written up as it was built. The two that matter most here:
They describe the machinery built for Ze, a network operating system of 623 Go packages where most of the code is written by Claude and none of it is trusted until it earns its place. Ze runs 28 rules, around 6,000 cross-reference comments, 1,600 functional scenarios, a 25-stage verification command and an RFC requirement ledger.
That is more than most projects need, and it was built over a year of finding out which parts pay for themselves. What is here is the part that transfers, in the order the first article recommends building it.
Cloudflare arrived at a similar shape from the other end, across a large engineering organisation, in How Cloudflare enforces engineering standards using AI. Two efforts that different converging on the same answer is useful evidence.
The rules are a starting point, not a description of your project, and they are worth very little until the ADAPT markers are filled and the checks exist. Step 6 of the bootstrap is where the value actually appears, and it is the step that takes real work. Until then the repository holds rules nothing enforces, which the rules themselves call a failure state.
Everything here was derived from one project: a large Go network operating
system with a single maintainer, in a domain where published standards supply
the requirements. The reasoning transfers better than the specifics. Two rules
in particular, sessions.md and context-economy.md, govern how an agent
works rather than what your project is, and both say to delete them when your
harness already carries an equivalent. context-economy.md also inherits its
conclusions from measurements taken elsewhere, and says so: measure them in
your own repository before quoting any of them.
Model releases arrive almost every month, and each one moves the boundary. A more capable model may make some of this unnecessary, or may use a richer structure correctly and justify more. If you are reading this a year from now, check which of these problems have already been solved before copying anything.
BSD 3-Clause. See LICENSE.
Ze itself is AGPL. This part is deliberately permissive, because a convention nobody may copy is not a convention.