Every repository in the project has an instruction file that the agent reads at the start of every session: CLAUDE.md for Claude Code, an AGENTS.md that mirrors it for other agents, and path-scoped instruction files for GitHub Copilot.
Ours started from a template. Seven months later, the most useful parts are rules we didn't know we needed until something went wrong.
Start with boundaries, not descriptions
Our most mature file belongs to the web portal and runs to about 250 lines. It is organised around three tiers:
- Always: things the agent does without asking, such as running the check, updating the module's sitemap and writing a session note.
- Ask: things where the agent stops and confirms first, such as touching shared environments, adding dependencies or deleting anything.
- Never: things the agent must not do even when it looks helpful, such as skipping pre-commit hooks, hardcoding the path to the API collection repository, or hand-editing mirrored ticket files.
Around those tiers sit a map of the apps, the worktree workflow, and the fixed pipeline every API change follows: spec, backend types, transformer, front-end types, data hook, component. Describing the codebase helps. Telling the agent where its judgement ends helps more.
The standing order
Need Help Implementing This?
Our team can help you put these ideas into action. Get in touch for a free consultation.
The file has a "harness maintenance" section with seven standing orders. Some are routine: check for drift against the app config when a session starts, write a session note before editing, update the module's sitemap after touching a module, write an architecture decision record after an architectural decision. One matters more than all the others:
After an agent mistake, add a rule to the appropriate Boundaries tier.
That single line is why the file keeps getting better rather than going stale.
Rules that carry their incident
Each rule says what happened. A rule with its story attached gets followed, while a bare "don't" gets argued with. Some examples, paraphrased:
- "Before saying the portal has no hint, limit or message on a field, open the component that renders it. A grep that finds nothing proves nothing." A confident false claim had reached a pull request description.
- "A status value the API has not been seen to return is a guess. Make the code refuse an unknown value." A guessed status had opened a submitted record as an editable draft.
- "Type-check with the build-mode command, never the single-project one. Five 'clean' runs hid a file-name clash."
- "Before concluding the admin side lacks an endpoint, probe the business path with an admin token." The developer's correction, "there is no admin path, it's the same path", went into the file the same day.
- "This feature flag stays on in the test environment. A plan proposed turning it off; only the test caught it."
- "Every pull request bumps the app version", so anyone can tell the deployed build from the previous one.
- "The verify script reports about 41 known false failures. Read the output; do not trust the exit code."
- "A fresh worktree has no git hooks until you install dependencies. Git then runs no pre-commit hooks and says nothing."
None of these came from a best-practice list. Each one cost us something once.
The loud banner
The consumer app's file opens with a line that is deliberately blunt:
SESSION WILL BE KILLED IMMEDIATELY ONCE THE MODEL STARTS HALLUCINATING. State only what you have verified.
Its AGENTS.md says the same thing for other tools: "Do not hallucinate. Ask to confirm to clear any doubt."
It's crude, but it set the tone for everything that followed: reports that end with "Checked" and "Not checked" lists, and API documents that say "verified live on" a given date. Part 6 covers how that works in practice.
Gotchas as an incident log
The mobile app's Gotchas section reads like an archive of postmortems:
- never conclude a server's certificate chain is healthy from a passing
curlon macOS - never add a plaintext fallback when secure storage throws an error
- the new OS version's scene lifecycle requirement, which crashed the app on launch
- the rules for installing signing keys
These are exactly the things a fresh session would otherwise rediscover the hard way, usually in production.
One paragraph, every repository
Some concerns are shared, so they get identical text in every repository. The paragraph on the ticket mirror is one: read a ticket before copying any of it into a repository, pull request or chat; never hand-edit ticket files; and fix any missed redaction pattern in the scraper, with a test, instead.
Shared text means an agent in any repository behaves the same way about the same risk.
Personal lessons get promoted
Not every lesson starts in the instruction file. Most start as a note in the agent's memory (Part 4). When a lesson turns out to apply to everyone, it gets promoted into the shared file through a small docs(harness) commit. "Every PR bumps the app version" and "treat a value you haven't seen the API return as a guess" both travelled that way.
Global rules, project rules
Project files hold product rules. A short global file holds how-we-work rules that apply to every project. Ours contains one opinion that changed our whole process: "Skills are tools, not obligations." Part 3 tells that story.
What to copy
- Organise the file around Always, Ask and Never tiers, not just a description of the codebase.
- Add a standing order: every agent mistake becomes a rule.
- Attach the incident to each rule, in one line.
- Write shared risks as identical paragraphs in every repository.
- Keep one source of truth and mirror it for the other tools your team uses.