Repository navigation
Working with AI
The template assumes most code is written by an AI assistant and every change is approved by a human. It gives the assistant precise rails, and gives the reviewer a checklist and checks they can rely on.
AGENTS.md is the single source of instructions: the stack and exact commands, the repository map with owners, conventions, boundaries ("never do these"), the Definition of done, and the docs map. Each tool's own file points to it, so the instructions can't diverge:
| Assistant | Entry point | How it reaches AGENTS.md |
|---|---|---|
| Claude Code | CLAUDE.md |
@AGENTS.md import, plus .claude/settings.json: check commands pre-allowed; edits to CHANGELOG, the manifest and the answers file denied; pushes to feature branches allowed (asked each time), but pushes naming main, force pushes, git tag and gh release denied (the main ruleset is the real guard); .env/secrets/ unreadable; a hook blocks edits outside the repository, and the dependency directories and gh pr create -R are denied |
| OpenAI Codex, ChatGPT with repo access | AGENTS.md |
native |
| ChatGPT / Claude.ai chat, no repo access | docs/ai/prompts.md |
the "Context for a chat assistant" prompt, then paste AGENTS.md |
| GitHub Copilot | .github/copilot-instructions.md |
a pointer plus three critical rules; the coding agent reads AGENTS.md natively |
| Gemini CLI | GEMINI.md |
@./AGENTS.md import |
| Cursor | AGENTS.md | native; .cursor/rules/project.mdc is a one-line pointer (no @ import, so nothing loads twice) |
A brain's AGENTS.md (language: obsidian) is shorter: read the vault's π Home.md first and then only the notes the task needs, write by π Conventions, link notes by name, record a decision about the repository as a design record from the template and stop for approval, never edit .obsidian/ beyond its two shared files, never commit what .gitignore keeps out. Its Definition of done is uv run scripts/check-vault.py (which includes the context budget), scripts/check.sh and the secret scan.
The README's "For AI assistants" section lists the same table for humans. Personal tweaks go in git-ignored files (CLAUDE.local.md, .claude/settings.local.json), never in the shared ones.
-
Design: prompt 1 in
docs/ai/prompts.md. The assistant writes adocs/design/record and stops. A human approves or corrects it. Rejected ideas go intoTODO.md"Decided against", so they aren't proposed again. -
Build: in small Conventional Commits, each passing the Definition of done (
ruff,mypy,pytest,gen-wiki --check,check-wiki,check-manifests, andcheck-docs-secretswhere Docker is available). - Document: the same PR updates the pages the docs map names, and replaces skeleton guidance with real text (prompt 4 audits the whole wiki).
- Review: the PR template records how much was generated. A code owner reviews with the Human Review Checklist. Optionally, a second assistant reviews first (prompt 5). Prompt 6 works through the open issues with one sub-agent each, merging only green bug fixes.
- Release: release-please's Release PR, also reviewed, is blocked until the wiki is complete.
Every assistant session pays for what it reads, so the AI-facing files are kept lean (design records 0002 and 0006):
| Measure | Effect |
|---|---|
| AGENTS.md is terse: imperative rules and tables, the reasons in the wiki | ~1,500 tokens per session, for every tool |
A "Don't read" list (lock file, CHANGELOG, caches, generated blocks), plus Read denies in .claude/settings.json
|
avoids one-off reads of 10kβ40k tokens (uv.lock alone is ~37k) |
docs/design/README.md indexes every record (CI-checked) |
the assistant reads the index, not every record |
| Pointer files only point; the README's AI section is a table of entry points | no double loading in Cursor or Copilot |
| Template-owned wiki pages tell assistants whether to read on | fewer whole-page reads |
[context_budget] in each project's docs/wiki/.standard.toml, enforced by check-wiki.py in project CI |
AGENTS.md β€ 9,000 characters, the pointer files 300β700. The template's own tests require the skeleton to use at most 75%, leaving room for the project |
| AGENTS.md, the review checklist and the Contributing page tell assistants and reviewers to keep it that way | the method carries on after the first commit |
The budget covers what an assistant reads first. Most of a session's tokens come later: command output, and the conversation itself, which is sent again with every turn (design record 0007).
-
Quiet checks: every Definition of done command prints one line when it passes, and its detail only when it fails.
check-wiki.py --verboselists the warnings it counts. A passing run of a fresh project's Definition of done prints about 6,450 characters without this. The template's tests fail if a template-owned check prints more than one line on a pass. - Terse replies: AGENTS.md tells the assistant to give the result, then what it needs from the user, with no preamble, recaps or restated plans. That cuts form, not content: recommendations, reasons for non-obvious choices and what was skipped stay.
-
One task per session: when a task is done and the next is unrelated, the assistant checks that the PR,
TODO.mdor a design record holds what the next session needs, then suggests starting one. It suggests this once, at the boundary, never mid-task. In Claude Code,/clearstarts afresh and/compactsummarises; other tools have their own equivalents. -
Tidy up, with the user's say-so: before suggesting a new session (or, in a brain, when a session ends), the assistant lists what it left: worktrees, local and remote branches, temp files, processes and containers. For each it says whether it is safe to remove and why (merged as #N, already in
main, unpushed work), and it removes only what the user approves, so unmerged or unpushed work is never lost. Sessions that run one sub-agent per issue leave a worktree and a branch for each; without the list they pile up, and a worktree removed while its agent still runs breaks that run. The tool's own per-session scratch directory isn't listed: it lives outside the repository and the tool manages it. - Point, don't paste: give the assistant a path or the failing check's name, not the log. It can read the file or rerun the check, and only reads what it needs.
- Checks the assistant can't talk its way past: blocking CI, the coverage floor, mypy strict, the wiki standard, docs-touched, and PR-title linting.
-
One repository per session: another codebase (a sibling repository, a submodule, an installed dependency) is changed by an issue in its own repository, never from here, even when the user asks: they open a session there instead. The assistant searches that repository's issues, comments or drafts a new one for the user to confirm in that repository's own issue form (hand-written only when there is none, with the user's yes: see Use the repository's own issue form), and keeps any workaround minimal and linked to it. Generated projects receive such requests through their Change request from another repository issue form. In Claude Code,
scripts/repo-boundary.pyruns as aPreToolUsehook and blocks Edit, Write and NotebookEdit outside the repository, in every permission mode (the temp directory and~/.claudestay writable). Bash isn't checked: Claude Code's sandbox would confine it, but it also blocks theuvcache, Docker andghlogin, so it is left for users to turn on in.claude/settings.local.json(design record 0013). -
Boundaries in AGENTS.md: never edit release-owned or template-owned files, never weaken a check (no unexplained
noqaortype: ignore, no skipped tests, no loosened sandbox), never commit secrets, never push to main or tag. - Supply chain: dependencies must be justified, and checked to exist under exactly that name (typosquatting). The lock file pins them, and Dependabot updates them.
- Honesty: the assistant must say what it didn't run or isn't sure of. A claimed green check must have been run.
- A recommendation with every question: when the assistant asks the user something, including a design record's open questions, it says what it would choose and why. The user can then answer "yes" instead of asking for a recommendation first, and a weak reason is visible before it becomes a decision. The assistant still stops for the answer.
- Lessons from every fix: finishing a bug or enhancement, the assistant says what let it happen and what should change so it can't again (a test, a check, AGENTS.md, the template), or "none". The PR template's Lessons section asks human authors the same. A real lesson ends as an issue or a PR, not only prose. "None" is a fine answer: the point is to ask, not to invent one.
-
Human ownership: CODEOWNERS plus a required review.
no-docs-neededis a reviewer's label, and the assistant never adds it. -
No AI credit in history: the person who opens the PR is its author.
.claude/settings.jsonsets"attribution": {"commit": "", "pr": "", "sessionUrl": false}, so Claude Code adds noCo-authored-bytrailer, PR byline or session link, and AGENTS.md tells every other assistant the same. Set it in your user settings (~/.claude/settings.json) too, for repositories not made from the template; the oldincludeCoAuthoredBysetting is deprecated and ignored.
project-template | The metalayerlab project template
GitHub β’ Releases β’ Changelog β’ Contributing
This wiki is generated from docs/wiki/ on every push to main: edits made here are overwritten. Change it with a pull request.
- π
copier updatekeeps every project in step - π·οΈ release-please: reviewed Release PRs and generated changelogs
- π A standardised, CI-checked wiki in every repo
- π€ One
AGENTS.mdfor Claude, Codex, Copilot, Gemini and Cursor - π³ Hardened Docker, Kubernetes and systemd manifests