An agent opening your repo for the first time is a new hire on day one, except it forgets everything by tomorrow. Give it nothing and you get the same three problems every session:
- It does not understand the codebase. It ignores an existing component or writes a new class when one already owns that job.
- It makes your decisions. It chooses architecture during the exploration you should have owned.
- It does not understand the team. It lacks the customer context and daily decisions surrounding the code.
Table of contents
- Orientation: where am I?
- Capability: what can I do?
- Enforcement: what happens whether I remember it or not?
- Self-improvement: what should I do better next time?
- Decision ownership: who decides?
- Start from the template
The first four sections address the first problem. The fifth addresses the second, because no amount of context stops an agent from deciding something that was yours to decide. The third belongs to the shared AI Harness teammate.
We found a concrete example of the first problem in our pull-request guardrail. The coding agent was working in a Git worktree, but the hook ran its checks against a different checkout. A PR could open even though the files changed by the agent had not been validated.
We fixed the hook so it first reads the agent’s working directory and runs the checks there. This catches problems before they consume CI and E2E capacity or move further through the pipeline. The guardrail had been missing an important piece of context: where the current task was actually running.
An AI-native codebase provides that context inside the repository, so it survives one model, one harness, and one session. We could see the change in agents’ tool calls: they selected more relevant context, followed the right references, acted on the right files, and followed repository conventions with less guidance.
It takes four layers. The first three shape what the agent can do now. The fourth makes the repository improve between sessions. A fifth, which the diagram below does not cover, decides what the agent is not allowed to settle on its own.

Every example below is real, lifted from a repo I work in every day. Paths and names are changed. The shape is not.
1. Orientation: where am I?
The map the agent reads before touching anything. CLAUDE.md at the root, a
/docs/ folder with the architecture and the starting points. This is what
stops it rediscovering your repo from scratch every time.
The part that earns its place is not the architecture written out in prose. It is the short list of things that are true and surprising:
## Frontend note
`webapp/` is the **production** frontend - treat it as the live user-facing UI
when answering questions or making changes. `legacy-ext/` is **dead**: the
admin app inside it has been replaced by `webapp/`. Do not add features there.
Route changes, env injection and favicon assets all belong in `webapp/`.
## Where to look first
- **Working in a component** -> its own `CLAUDE.md` (tables above).
- **Recurring lessons, by topic** -> `docs/lessons/README.md`. Its table says
which to read when - read the matching one **before** starting, not after
getting stuck.
- **Closing out a change** -> `docs/AGENT_CHECKLIST.md` gates every PR.
Every line there is a mistake somebody made first. That is the test for what
belongs in a CLAUDE.md. Not what is true about your repo, what is expensively
true.
Build checkpoint
- Map each top-level area and name which component owns what.
- Record the expensive, surprising facts that repeatedly cause mistakes.
- Link to detailed documentation instead of injecting it all at startup.
- Give an agent a cold task and inspect whether its first file reads are the right ones.
2. Capability: what can I do?
Recipes for the tasks that repeat. Releasing a version, writing tests in your
conventions, the workflow you explain to every new hire. .claude/skills/ for
the recipes, .claude/agents/ for focused sub-agents.
A skill is two things: a body of instructions, and a description that decides when the agent loads it. People spend all their effort on the body. The description is the part that fails, because it is not a summary, it is a router.
---
name: python-tests
description: >-
Load BEFORE writing or running any Python tests - required by root CLAUDE.md.
Trigger phrases: "write tests for X", "add a unit test", "cover this with
tests", "fix this failing test", "run pytest". Covers running pytest from the
repo root, test placement and naming, and the project's hard rules -
patch.object with __name__ (never patch("string.path")), no MagicMock for
data models, typed fixtures, no caplog assertions - plus the mandatory
post-test steps (coverage, format, typecheck).
---
Trigger phrases in the words a person would actually type, not yours. The hard rules named right there in the description, so the agent knows the skill has an opinion before it decides whether to open it.
Build checkpoint
- Find three tasks you repeatedly explain to an agent.
- Write one skill for each, including when to use it, the exact steps, and the traps specific to your repository.
- Put realistic trigger phrases in the description.
- Test whether the agent loads the skill without being explicitly told to.
3. Enforcement: what happens whether I remember or not?
Orientation and capability only work if the agent reads them. Enforcement runs
regardless. Hooks are declared in .claude/settings.json, fire on events, and
do not care what the agent read: block the thing you never want, run the check
you always forget.
Every hook answers three questions: when it fires, what it fires for, and what it runs.
"hooks": {
"PostToolUse": [ // WHEN: right after a tool runs
{
"matcher": "Edit|MultiEdit|Write", // FOR WHAT: file-writing tools
"hooks": [
{ "type": "command", "command": ".../auto_black.sh" } // RUN WHAT
]
}
],
"PreToolUse": [ // WHEN: before a tool runs, can block it
{
"matcher": "Bash",
"hooks": [
{ "type": "command",
"if": "Bash(gh pr create*)", // extra filter: only this command
"command": ".../gate_pr_create.sh" }
]
}
],
"SessionStart": [ // WHEN: a session begins
{
"matcher": "startup|resume", // not on /clear or /compact
"hooks": [
{ "type": "command", "command": ".../inject_agent_checklist.sh" }
]
}
]
}
Read the three by what they can do. PostToolUse runs after the fact, so it is
for fixing: format the file the agent just wrote, whether or not it remembered
the formatter. PreToolUse runs before, which makes it the only one that can
say no. SessionStart is the one people miss - it puts the checklist in front
of the agent before it has done anything, on startup and resume but not on
/clear, so it seeds a session instead of fighting one.
The gate itself is short, because the config already decided when it runs.
#!/usr/bin/env bash
# Runs before `gh pr create`, because settings.json said so. Exit 2 blocks it.
if ! npm run lint --silent; then
echo "Lint failed. Fix it, then open the PR." >&2
exit 2
fi
Exit 2 is the whole mechanism: the command never runs, and the agent is handed the reason on stderr, so it fixes the lint instead of retrying blind. No step of that depended on it remembering a rule.
Build checkpoint
- Format or validate files immediately after the agent edits them.
- Block a pull request when mandatory checks fail.
- Pass the agent’s actual working directory into every hook.
- Test hooks from the main checkout and from a Git worktree.
- Make failures visible to both the agent and the human reviewer.
4. Self-improvement: what should I do better next time?
The one people skip, and the one that compounds. When something goes wrong, the lesson goes back into the repo so it stops recurring. Suffer once, not twice.
Two moving parts: somewhere for lessons to live, and a step that puts them there. The place is a topical library, one doc per subject, indexed by when to read it.
| Doc | Read when... |
|---|---|
| webapp-dev-environment.md | starting a frontend task (lockfile, env files) |
| backend-async-caching.md | event loop, redis, caching, connection pooling |
| git-worktrees-multiagent.md | worktrees, parallel subagent orchestration |
The “read when” column is the entire design. An agent never wonders whether a
lesson exists and goes browsing for it. It finds the doc because the words
already in its task are sitting in a line it has already loaded. That is also
why these are linked and not @-included: they cost nothing until the moment
someone needs them.
The best entry in that library came from the guardrail bug above. The hook checked the checkout where its script lived instead of the worktree where the agent had changed code. We changed its flow to:
read the agent's working directory
-> move into that directory
-> run lint against the changed files
-> block the PR if lint fails
The exact shell code matters less than the promoted lesson: every check must run against the agent’s current worktree. We recorded that next to the hook, where the next person changing it would see it, rather than only in a postmortem.
Lessons also do not have to start as prose somebody remembered to write. Most teams already have years of them sitting in PR comments nobody ever read twice. A review skill can mine that: pull the line comments and the argument threads, cluster them by theme, count each one, and keep what recurs. A note left once is somebody’s preference. A note left five times is a rule you never wrote down.
Cache that as a file and the next review has a rubric built from your own history instead of a style guide, which also makes it arguable: “this was flagged in six previous PRs” lands differently from “this looks wrong”. Then close the loop the other way. A finding that keeps recurring and is still not in the lessons library is the next thing to promote.
Build checkpoint
- End significant tasks by recording what failed and what was learned.
- Decide whether each lesson belongs in orientation, a skill, or enforcement.
- Require human review before promoting a lesson into shared instructions.
- Verify in a fresh session that the agent can discover and apply it.
5. Decision ownership: who decides?
Go back to the second problem at the top: it makes your decisions. None of the first four layers touch it. Orientation tells the agent where things are, capability tells it how you do things here, enforcement blocks the edits you banned, and self-improvement stops the repeats. An agent can be perfect on all four and still choose your auth model at 2am, inside a diff you skim.
Ours did something more expensive than that. A customer asked, in a shared channel, for a way to trigger a scheduled run. The agent researched it and recommended a new permissions object. We built that. Five days later we reverted the whole thing, and the revert shipped a tenant-isolation bug of its own.
The answer had been available on day one. A teammate had already named the existing object to extend, and when the question was put to the customer in their own thread, they said the same thing in plainer words: they wanted the simplest possible scheduled trigger, and were not convinced a new permissions object was what they needed. Both answers landed in an early cycle of the document. Neither was carried into the next one. Five agent-days went into converging on a design that had been ruled out before it started.
Nothing was wrong with the research. What was wrong is that the decisions lived in prose. Prose is append-only, so the document grew into a record of every position anyone had ever held, and the one answer that mattered sank into it. By the time the agent was writing implementation phases, the body had already frozen around its own recommendation.
GitHub Spec Kit and architecture decision records both make decisions visible. Neither says who owns them. So we stopped treating the decisions as content in a document and started treating the document as a rendering of the decisions.
An RFC here is a directory, one file per section, in the repo next to the code it proposes.
rfcs/TICKET-24__scheduled-triggers/
000_meta.md status, appetite, and the human who approves
001_tldr.md
002_decisions.md the ledger - everything else renders from it
003_existing-surfaces.md what already exists, with file:line citations
005_proposals.md
006_sequencing-cost.md
Two rules make the split worth the ceremony. The ledger is re-emitted every
cycle, never appended to: a resolved decision stops rendering as an open block
and becomes a one-line row, so the file shrinks as the RFC converges instead of
growing into a transcript. And no proposal may be drafted around a decision
that is still open. The sections it affects render LOCKED - pending D4 until
a human answers, so there is no frozen body to rewrite, because the body was
never written.
003_existing-surfaces.md is where this layer reaches back into the first one.
Before drafting a single option the agent has to enumerate what already exists,
with citations. Then every option that proposes a new table, endpoint or model
has to carry a sibling option that extends the nearest existing one. The
options in front of the human end up looking like this, each tagged with what
it does to the codebase:
Q3 TECHNICAL Which ETL generation is the target?
A ship against today's full-rebuild writer (existing-surface, extend-existing)
B build against the v2 branch (existing-surface, extend-existing)
C both, in the same ticket [Recommended] (existing-surface, extend-existing)
Other write your own answer
That is the rule the revert above was missing. It is also why the citations in orientation earn their keep twice: they stop the agent inventing during implementation, and they stop it offering you invented options during design.
Each decision carries a status, and only some of them let the RFC merge.
| Status | Meaning | Can it merge? |
|---|---|---|
OPEN |
nobody decided, no default applied | blocks |
DEFAULTED |
the agent picked, no human has seen it | blocks |
DELEGATED |
a human read it and waved it through | passes |
DECIDED |
a named human picked an option | passes |
OTHER |
answered off-menu, so the framing failed | blocks |
SPIKE |
a risk both unverified and irreversible | blocks until proven |
The load-bearing row is the gap between DEFAULTED and DELEGATED. Both mean
nobody argued. Only one means a human looked. Our first version of this checked
that no question was still marked open, which could not tell those two apart,
so every question the agent quietly answered for itself counted as settled.
That is the failure the whole table exists to name.
OTHER is the row worth stealing. An off-menu answer is not a decision, it is
evidence that the options were wrong, so it blocks until the question is
reframed. The customer above answered OTHER. Three carefully grounded options
and none of them was the thing they wanted.
The rest is a review cycle with the shape of a pull request, because it is one. The agent opens the RFC as a PR. Teammates answer the round’s questions, picking a letter or writing their own, and comment inline. When the round is answered a human triggers one revision, the agent rewrites the ledger against the answers, and a new round appears. Two approvals merge it, and the merged RFC is the brief the implementation session reads.
Answers do not have to come from your team. The question about the new permissions object went into the customer’s thread verbatim, and their reply came back as the answer of record. That is the practical payoff of holding decisions as data instead of prose: each one is small enough, and legible enough, to ask anybody.
Build checkpoint
- Make the agent list its decisions before it writes code: the question, the options, its recommendation, and the cost of changing later.
- Ground every option in a file that already exists, and give every option that invents something a sibling that extends something.
- Record who answered, and never let “the agent defaulted” look the same as “a human delegated”.
- Allow off-menu answers, and treat one as a failed question rather than a decision.
- Block the merge on unresolved decisions, the same way section 3 blocks a pull request on a failing check.
Start from the template
ai-native-codebase is a
copy-paste starting point. It includes a CLAUDE.md skeleton and lessons
library for orientation; five skills for planning, tests, review, handoff, and
PR descriptions; and five focused review agents. Its hooks format edits, inject
the checklist at session start, and block a PR when checks fail.
The repository README groups the map, toolbox, and rules as three structural layers. I count self-improvement as a fourth because reflections and promoted lessons change those layers between sessions. Decision ownership is the fifth, and the only one that is not really about the agent. The files are Claude Code shaped, but the five questions apply to any harness: where am I, what can I do, what runs whether I remember it or not, what should improve next time, and what is not mine to decide.
Start small:
- Copy the orientation structure and replace the stub with a real map of your repository.
- Add one skill for a task your team actually repeats.
- Add one enforced check that has caught a real mistake before.
- Run a fresh agent session and inspect its tool calls, file choices, and response to a failed check.
- On the next task worth more than a day, make the agent write its decisions down and wait for you before it writes any code.
Reference
- ai-native-codebase, the template
- How can I build a Harness?, the agent this repo is for
- GitHub Spec Kit, specify, clarify, plan, tasks, implement
- Architecture decision records, the older idea agents made urgent