Make any repo Day-0 onboardable: a new developer + a coding agent can build, test, and ship a PR on their first day — with nobody teaching them anything.
This playbook was distilled from a production project (an ESP32 device fleet with two firmware lines, three servers, OTA releases, and a rotating team of contributors) where the mechanism has been running for months. Everything here is field-tested; the anti-patterns in §4 are things we actually did wrong first.
It is deliberately portable: no framework, no vendor lock-in, no tooling to install. It is a set of conventions plus a handful of scripts you can rebuild in an afternoon.
Day-0 onboardable means: a new team member — or a brand-new agent session — clones the repo and, without anyone explaining anything, can correctly build, run, test, and open a PR, and cannot stumble into anything irreversible.
In a traditional project, the knowledge that makes this possible lives in senior engineers' heads. When they leave, it leaves. The agent-first answer:
The real maintainer is the repository itself. Humans are rotating operators.
All tacit knowledge is externalized into exactly two forms:
- Context an agent auto-loads on every session — the core prompt (§1);
- Gates enforced by machines — CI, hooks, validators (§2, M4).
Onboarding then stops being person-to-person teaching. A newcomer brings any coding agent; the agent loads the full rules and map from the repo; the human's job reduces to reviewing diffs and providing acceptance evidence. Whoever leaves, whoever joins — the repo + agent layer of memory does not move.
So what is the core prompt? A single file at the repo root: AGENTS.md
(with CLAUDE.md symlinked to it — see §1.1). But note carefully:
What sustains Day-0 performance is not the prompt itself. It is the closed loop around it: single source of truth → machine gates → lesson reflow. The prompt is merely the visible face of that loop. A prompt without the loop rots into an unread README within weeks.
- The one and only home of agent rules is
AGENTS.mdat the repo root — the cross-vendor convention that Codex, Cursor, Copilot, and Gemini CLI read natively.CLAUDE.mdis a symlink to it (Claude Code loads from there); editor-specific stubs (e.g..cursor/rules/agents.mdc) just point at it. Any agent that clones the repo auto-loads the rules. No prompt-feeding. - Never fork per-agent copies of the rules. Symlinks and pointer stubs may
be many; the source is one. (Our own
.cursorrulesonce drifted a full month behind the main rules while still steering one editor — see §4.)
Keep AGENTS.md scannable in one sitting; push details out through links.
Six mandatory sections:
| Section | What it does |
|---|---|
| Identity & creed | 4–6 team principles, shared by humans and agents. They are the underlying why for every hard rule — an agent that understands why complies; one that only sees an instruction routes around it at the edges. |
| System map | Product lines / repo layout / end-to-end data flow, in tables. A 10-minute mental model. |
| Single entrypoint | One command surface for everything (§2, M2). |
| NEVER list | Hard constraints — each with the incident that created it, or the concrete consequence. |
| Irreversibility boundary | The operations an agent must never perform and must hand back to a human (§2, M5). |
| Context index | A table pointing to each authoritative doc. Points, never copies. |
The prompt is read on every session; tokens are finite, attention more so.
Rule of thumb: AGENTS.md holds only what is needed every time; everything
needed on demand lives in docs/ and gets one row in the context index.
To decide where a fact lives, ask: would an agent that doesn't know this make
a mistake on the spot? Yes → it stays in AGENTS.md. No → link it out.
Every category of information has exactly one home: agent rules →
AGENTS.md; design tokens → one shared CSS/token package; the PR checklist →
.github/pull_request_template.md; doc metadata → frontmatter. Every other
location may only link (or symlink) to it.
A copy is a corpse that hasn't started smelling yet. Every forked copy in our history — the per-editor rules file, the checklist duplicated into two guides — measurably drifted. So "never fork X" entries belong on the NEVER list itself.
One dev.sh (or Makefile / justfile) wraps every build / run / test / check,
so "how do I do X?" has exactly one answer, and the answer is verifiable:
- Builds run in a pinned container image — the same image CI uses — killing "works on my machine" at the root;
- CI runs literally
dev.sh check, so a red CI always reproduces locally with one command; - The agent-onboarding test: ask a freshly installed agent "how do I
build this project?" If the answer isn't the
dev.shcommand, the agent didn't load the rules — fix that before writing any code. This question is a step in the Day-0 checklist.
Every managed doc starts with machine-readable YAML frontmatter:
---
title: OTA design & safety model # must equal the H1
status: current # draft | current | superseded | archived
owner: Jane Doe # a real person from a whitelist — no teams, no "AI"
updated: 2026-08-27 # a date, not a version
code_paths: # the code this doc claims responsibility for
- server/ota/**
- firmware/components/ota/**
---A ~300-line validator script gives you three superpowers:
- Bidirectional lookup — before and after touching code, run
dev.sh docs affected --paths <files>to find every doc that claims those paths. The hits may contain constraints that change your implementation (e.g. "this path requires senior review"). - Machine-evidenced staleness — a
code_pathsglob matching nothing is proof the doc is stale;dev.sh docs checkfails on it. No human archaeology. - Named ownership —
ownermust be a real person on a whitelist. No specific person = no owner = not trustworthy.
A written rule alone stops nothing. We proved this experimentally: three copies of a PR checklist each drifted independently until only the template-managed one was kept. Every rule that matters gets up to three layers:
- Local hook (
pre-push) — seconds of feedback, runs only checks for the changed area, skippable. It is a fast preview, not the gate. - CI — the unskippable authority, running the same command as the hook.
- Tests that guard the rules themselves — e.g. a small pytest that asserts
the entire CI-trigger routing table on every PR that edits a workflow file,
so a glob can never silently widen. (War story: an OTA-publish trigger glob
of
'v2*'also matched our ordinary three-segment release tags — one routine tag push rolled the entire device fleet.)
The other half is equally critical: every NEVER entry carries its why and its incident story. For humans that's persuasion; for agents it's decisive — a bare instruction gets "reasonably" bypassed in edge cases; a rule with its causal story does not.
Principle: be bold where mistakes are cheap; ask where they are not. Three explicit lists:
- Agent-independent work — endpoints, types, tests, docs, frontend, non-critical bug fixes. Agents proceed without asking. This is what makes Day-0 fast.
- Senior-review-required — the paths where a bug hurts real users (in our case: fall-detection logic, safety timeouts, alert routing). AI must not merge these independently.
- Agents never, at all — the genuinely irreversible actions. In our repo there is exactly one: pushing the four-segment release tag that OTA-updates the whole fleet. The rule is backed by a machine: the pre-push hook prompts a human interactively and fails closed for non-interactive (i.e. agent) pushes.
A crisp boundary is what makes delegation safe; safe delegation is what makes Day-0 real.
Agents produce code several times faster than humans — and without governance, they turn a repo into a landfill at the same multiple. The fix is a short architecture constitution: any new top-level module / product line / page / persistent store / event schema requires a lightweight registration flow first (proposal issue → recorded discussion → named owner → constitution update). Unregistered additions get rejected in review — by rule, not by mood.
Pair it with a freeze document: the authoritative registry of what exists right now — and define the authority chain explicitly (constitution > freeze
per-decision ADRs > any tour/overview doc, which has no authority and may not duplicate lists). Conflicts get resolved by lookup, not by argument.
Day-0 performance = "every lesson learned up to yesterday is already in the context that auto-loads today."
Concretely:
- Team creed: every lesson lands back in
docs/or a skill — never only in a chat log; - Run the docs-affected lookup before and after each change; bump the hit
docs'
updated:dates, or stateDocs-Impact: none — <reason>in the PR (a warn-only CI job posts the candidate list as a reminder); - Project-specific operational skills (fleet debugging, release announcements, weekly reports) are versioned in the repo and evolve with the code; general-purpose skills are installed and lock-pinned, and lessons about them are PR'd upstream, not patched into local copies;
- Every incident becomes: one NEVER entry with its story + one machine gate (M4).
M7 is the only mechanism sustained by habit rather than by files — and the easiest to break. When it breaks, the prompt stops updating and Day-0 performance decays week by week.
One standalone onboarding-101.md, five rules:
- Entry and threading only — never duplicate rules. Authority always
stays with
AGENTS.mdand the docs it links. The doc's header declares the owner's sync obligation: whoever changes a process must update this doc. - Every Day-0 checklist step ships with its verification. A checklist is not a todo list; it is a test suite ("install Docker" verifies as "this build command completes").
- Include the agent-onboarding test — one question only a rules-loaded agent answers correctly (M2).
- The first-week task is one full trip through the pipeline on a deliberately tiny change: claim an issue → agent branches and implements → human reviews the diff → PR with acceptance evidence → reviewer merges → ship announcement. The goal is validating the pipeline, not the output.
- Graduation = a handful of questions answerable from memory. (How do you build? Where do branches come from and where do PRs go? What requires senior review? How do you check what version a device is running? What does a release tag do, and who may push one?)
| Anti-pattern | What actually happened | Mechanism |
|---|---|---|
| Per-agent forks of the rules file | An editor-specific copy lagged the main rules by a month, still steering that editor | M1 |
| Rules without machines | Three PR-checklist copies drifted independently | M4 |
| Rules without a why | "Reasonably" bypassed by agents in edge cases | M4 |
| Lessons left in chat logs | The next session / next person re-stepped on the same rake | M7 |
| Docs without owner / date / code_paths | Nobody responsible = not trusted = not read | M3 |
| Over-wide gate globs | 'v2*' matched an ordinary release tag and OTA-rolled the whole fleet |
M4, layer 3 |
| Duplicated expensive CI checks | The firmware build was once paid for on three separate paths | M2 (tier checks by cost) |
- Write
AGENTS.mdwith the six sections of §1.2, each in minimal form, thenln -s AGENTS.md CLAUDE.md. Start the NEVER list with just the 3 rules whose violation genuinely hurts, each with its consequence. - Create the single entrypoint (
tools/dev.shor a Makefile) — even if it wraps only three commands:build,run,check. - Write a 3-step Day-0 checklist (clone →
checkpasses → the agent-onboarding question) — inline inAGENTS.mduntil it outgrows it.
- Make CI run the exact same
checkcommand as local. Add the pre-push hook if you like (it's a preview, not the gate). - Add doc frontmatter + the validator (a single Python file: parse YAML
headers, check owner whitelist / dates / that
code_pathsglobs match something, and answeraffected --paths ...reverse lookups). - Split out
onboarding-101.mdper §3, with the first-week task and the graduation questions.
- Every incident → a NEVER entry with its story + a machine gate (write it as a test whenever possible).
- Every lesson → reflowed into docs/skills the same day. Never "later".
- When the second module / page / store appears → adopt the constitution + governance flow (M6). Not before.
- Periodically sweep for exactly three smells: dangling
code_paths, unregistered new pages/modules, and a second copy of any source of truth.
| # | Mechanism | One line | Defends against |
|---|---|---|---|
| — | Core prompt | AGENTS.md, single source, auto-loaded by every agent with zero config |
Person-to-person teaching |
| M1 | Anti-fork | Each fact has one home; everywhere else links | Copy drift |
| M2 | Single entrypoint | "How do I do X" has one verifiable answer | Environment drift, wrong paths |
| M3 | Docs as database | Frontmatter + code_paths reverse lookup |
Silently stale docs |
| M4 | Machines behind rules | Hook + CI + tests guarding the rules; NEVERs carry their why | Rules bypassed or widened |
| M5 | Irreversibility boundary | Bold zone delegated; humans-only zone fails closed | The mistake you can't undo |
| M6 | Governance | New entities register first; a freeze doc holds the truth | Agent-speed entropy |
| M7 | Lesson reflow | Every lesson lands in auto-loaded context | Week-by-week decay |
Does this require any specific coding agent?
No. AGENTS.md is a cross-vendor convention; the symlink/stub trick covers
agents with their own filename conventions. The mechanisms are tool-agnostic.
Is this only for firmware/hardware projects? No — that's just where it was distilled. The mechanisms assume nothing beyond "a repo, CI, and humans who rotate".
Where's the code?
Deliberately minimal: a dev.sh, a docs validator (~300 lines of Python), a
pre-push hook, and one CI workflow that calls dev.sh check. Rebuild them in
your own stack in an afternoon — the value is the conventions, not the code.
MIT © ToyWorks