Govern: one way of working for your team's AI agents

Make every agent read one file

Check exactly what each agent loads with /context, then turn a long shared file into one short AGENTS.md that every machine loads.

Parcialmente em inglês
Algumas partes desta página ainda não estão traduzidas para português, por isso são apresentadas em inglês.

Before you start

You need four things on your machine: Claude Code, git, Python 3.12 with pytest, and a clone of the course's practice repo.

Claude Code is Anthropic's coding agent. It runs in your terminal, reads your repo, and edits files and runs commands when you ask it to. Install it with the command for your system (official quickstart: https://code.claude.com/docs/en/quickstart(abre num novo separador); system requirements and other install methods: https://code.claude.com/docs/en/setup(abre num novo separador)):

# macOS, Linux, WSL
curl -fsSL https://claude.ai/install.sh | bash
# or with Homebrew
brew install --cask claude-code
# Windows PowerShell
irm https://claude.ai/install.ps1 | iex
# or with WinGet
winget install Anthropic.ClaudeCode

Open a new terminal and check it: claude --version prints a version number followed by (Claude Code). Claude Code needs an account: a Claude Pro, Max, Team or Enterprise plan, a Claude Console account, or a supported cloud provider. The free claude.ai plan does not include it. You log in the first time you run claude.

Python 3.12 and pytest run the practice repo's tests. Python: https://www.python.org/downloads/(abre num novo separador). pytest: pip install -U pytest (https://docs.pytest.org/en/stable/getting-started.html(abre num novo separador)).

git clones the repo and moves between lessons: https://git-scm.com/install/(abre num novo separador).

The practice repo is public: https://github.com/neomanexlabs/govern-course(abre num novo separador). It has one git tag per lesson: l0 is the repo before lesson 1 (the long file), l1 is the repo after it, and so on. Clone it, start from l0 on a branch of your own, run the tests, then start Claude Code in the clone:

git clone https://github.com/neomanexlabs/govern-course.git
cd govern-course
git checkout -b my-l1 l0
python -m pytest -q   # 2 passed
claude                # the first time, it asks you to log in

What loads when a session starts

Claude Code loads these files before you type a word:

FileWhoseShared in git
~/.claude/CLAUDE.mdyours, for every project on this machineno
CLAUDE.md or AGENTS.mdthe project'syes
CLAUDE.local.mdyours, for this project onlyno (gitignored)

The catch: Claude Code reads AGENTS.md by itself only when the project has no CLAUDE.md and no CLAUDE.local.md. Claude Code treats AGENTS.md as a fallback, for a project with no Claude file of its own: a personal CLAUDE.local.md counts as one, so it switches the team file off. Source: https://code.claude.com/docs/en/memory#agents-md(abre num novo separador). Reading AGENTS.md directly needs Claude Code v2.1.277 or later.

Cursor, Codex, Copilot and OpenCode read AGENTS.md too. When both files exist, OpenCode picks AGENTS.md and Claude Code picks CLAUDE.md. One CLAUDE.md that imports AGENTS.md serves them all.

Before: same repo, same prompt, two processes

Priya and Sam gave their agents the same prompt, word for word:

Customers say invoice INV-2040 shows the wrong total. Fix it and commit.

Priya keeps personal notes in CLAUDE.local.md: "Bug fix: write a test that fails first, then fix, then run the whole suite." Her agent wrote the test, ran it (1 failed, 2 passed), fixed the bug, ran the suite (3 passed), and committed. Sam has no notes. His agent fixed first, then wrote a test and ran it once (3 passed). Both commits carry a test. Only Priya's test was ever seen failing, and a test you never saw fail may not catch the bug.

The team's answer was a shared AGENTS.md everyone adds to. It grew to 19 sections and 1,315 words. No one deletes a rule a teammate once needed, so a shared file only grows. Anthropic's own docs warn: "Bloated CLAUDE.md files cause Claude to ignore your actual instructions." (Best practices for Claude Code: https://code.claude.com/docs/en/best-practices(abre num novo separador))

Check your own machine

In Claude Code, type:

/context all

/context shows what fills the session's context; all expands the full list (commands reference: https://code.claude.com/docs/en/commands(abre num novo separador)). The Memory files list shows every instruction file that loaded, with its size in tokens (a token is a short piece of text, about three quarters of a word; it is how the model counts what it reads). What five machines showed on the Acme Billing repo:

Machine and stateMemory files
Sam, long AGENTS.md~/.claude/CLAUDE.md 27, AGENTS.md 2.7k
Priya, long AGENTS.md + her notes~/.claude/CLAUDE.md 27, CLAUDE.local.md 79. No AGENTS.md
a CLAUDE.md without the import~/.claude/CLAUDE.md 27, CLAUDE.md 22. No AGENTS.md
Sam, after the change~/.claude/CLAUDE.md 27, CLAUDE.md 16, AGENTS.md 340
Priya, after the change~/.claude/CLAUDE.md 27, CLAUDE.md 16, AGENTS.md 340, CLAUDE.local.md 79

Two things to read in that table:

  • Your personal file travels. ~/.claude/CLAUDE.md loaded on every machine, in every state. Whatever you put there reaches every team repo you open.
  • A personal file can hide the team's. Priya's CLAUDE.local.md is gitignored, so nobody on the team can see it, yet it changed what her agent did and stopped the team file from loading. Team rules never live in a personal file.

Ask every teammate to run /context all. Every list should show AGENTS.md. Ask each new developer for that list, and again after any setup change; look first for a personal file that was not there before. A list without AGENTS.md is a machine on its own rules.

When a teammate's agent works oddly, read their Memory files list first, before you suspect the prompt or the model. A gitignored personal file shows up in no review; this list is the one place it shows.

What the change fixes, and how

Two problems, both seen above:

ProblemWhat the agent gets
The team file only grows: everyone adds to it, nobody deletes a rule a teammate once needed, and every session loads all of itfor a wrong total, every rule the team ever added (2.7k tokens in Sam's list); the one rule this bug needs, test first, is one line deep in the Testing section, worded as a result ("ships with a test that fails before the fix"), which Sam's test also meets: it fails on the old code, but was only ever run after the fix
Priya's personal notes file switches the team file offher notes, and none of the team's rules

The fix is one short file every agent loads. It routes, it never collects:

  • Short: AGENTS.md keeps only the rules every change must follow.
  • Routes: for each other kind of work, a table row names the file to read.
  • Never collects: the rest lives in those files, not in AGENTS.md.
  • Every agent loads it: a one-line CLAUDE.md imports it, so no personal file can switch it off.

On this bug: test first applies to every change, so it stays in AGENTS.md. The other money rules apply only to money work, so they move to standards/money.md ("Totals are subtotal plus tax." is one of them), and the money, totals, tax row points there. The four steps below make that change, and each one says why, what changes, and what the agent does differently afterwards.

The change, step by step

Work in the clone from "Before you start", on your my-l1 branch at l0. Count the long file first:

wc -w AGENTS.md          # 1315 AGENTS.md
grep -c '^## ' AGENTS.md # 19

You never write these files by hand. Each step is one request to Claude Code in the clone; you read what comes back and decide whether it stays.

Step 1. Check what each agent loads.

  • Why: an agent follows what its session loads, and a gitignored personal file shows up in no review.
  • What changes: nothing yet. You get the list to compare against after step 4.

In Claude Code, type /context all on your machine (and on each teammate's, as in the section above) and keep the Memory files list. At l0 it shows the long AGENTS.md, or no AGENTS.md at all on a machine with a personal notes file.

Step 2. Sections move out.

  • Why: every section in AGENTS.md loads into every session, on every machine, whether the task needs it or not.
  • What changes: each section that only some work needs moves into a file named for that work: how the team works in standards/, what the system is in docs/. Nothing is deleted.
  • What the agent does now: a moved section no longer loads when the session starts. The agent reads it when it opens that file, and the table from step 3 says which file to open.

This one request does steps 2 and 3: it moves the sections out and gives back the new AGENTS.md. Ask Claude Code:

AGENTS.md has grown too long for an agent to follow. Split it: keep only the rules every change must follow, then a table that points to the file to read for each kind of work. Move every other section into standards/ (how we work) or docs/ (what the system is), one file per kind of work. Delete nothing.

What comes back: two new folders and each section moved into a file named for the work that needs it. Nothing is deleted. Sections on one topic share a file, which is why 19 sections become 12 files in the reference at l1:

Sections at l0File at l1
Testingstandards/testing.md
Moneystandards/money.md
Code stylestandards/code-style.md
Git, Pull requestsstandards/git.md
Errors and loggingstandards/logging.md
Securitystandards/security.md
Performancestandards/performance.md
About the product, Invoices, Customers, Email, CSV import, Reportsdocs/product.md
Setupdocs/setup.md
Deploysdocs/deploys.md
Incidents we learned fromdocs/incidents.md
Working with the agent, Miscdocs/team.md

Check that every section landed somewhere: a section missing from the diff is a rule deleted, and the request said delete nothing.

Step 3. AGENTS.md keeps rules and routes.

  • Why: AGENTS.md is the one file every session loads, so it holds only what no change may skip.
  • What changes: AGENTS.md keeps the rules for every change (the test rule as steps in order) and gains a "Before you work on it, read" table: one row per kind of work, in the words a task uses.
  • What the agent does now: it gets the every-change rules in every session, so it writes the failing test and watches it fail before the fix. For a wrong total, the money, totals, tax row names standards/money.md.

The same request also gives back a new AGENTS.md. Read it as if it were written from empty, not trimmed: a trim keeps a section because it is already there. It should hold only what every change must follow, then a table that says what to read for each kind of work, each row in the words a task uses (the bug report says "wrong total", so the money row names totals); a row that names only the file matches nothing a task says. If a section stayed only because it was there, or the test rule came back as a result instead of steps, ask Claude to fix that line. When an agent later misses a rule behind a pointer, ask Claude to reword the row before you move the rule back into AGENTS.md. The reference file at l1:

# Acme Billing

Invoicing for small shops. Python 3.12, pytest. Run the tests: `python -m pytest -q`

## Every change

- Bug fix: first write a test that shows the bug. Run it and see it fail. Then fix, then run the whole suite.
- Money is `Decimal`, never `float`.
- Never commit with a failing test.
- Never commit secrets or customer data.

## Before you work on it, read

| Work on | Read |
|---|---|
| tests | `standards/testing.md` |
| money, totals, tax | `standards/money.md` |
| any code | `standards/code-style.md` |
| commits, branches, pull requests | `standards/git.md` |
| logs and errors | `standards/logging.md` |
| security, customer data | `standards/security.md` |
| speed | `standards/performance.md` |
| invoices, customers, email, CSV, reports | `docs/product.md` |
| setup, deploys, past incidents, team notes | `docs/` |

Step 4. CLAUDE.md imports AGENTS.md.

  • Why: on Priya's machine, her CLAUDE.local.md switches the automatic AGENTS.md read off.
  • What changes: a CLAUDE.md with one line, @AGENTS.md, which pulls AGENTS.md in whole.
  • What the agent does now: every session loads AGENTS.md through the import, personal notes or not. On Priya's machine her notes still load beside it.

In the same session, ask:

Add a CLAUDE.md that imports AGENTS.md, so Claude Code loads it.

What comes back: a CLAUDE.md with one line, @AGENTS.md (the @ import: https://code.claude.com/docs/en/memory#import-additional-files(abre num novo separador)). If it adds anything else, ask Claude to cut it to that line.

Keep this file even though Claude Code reads AGENTS.md by itself when there is no CLAUDE.md. That automatic read comes from your user settings. A scripted or CI run that leaves user settings out (for example claude -p --setting-sources project,local; flags: https://code.claude.com/docs/en/cli-reference(abre num novo separador)) loads AGENTS.md only through this import.

Keep CLAUDE.md to that one line. A rule written there reaches Claude Code alone: Cursor, Codex, Copilot and OpenCode read AGENTS.md and never see it.

Then check and commit. Run /context all again: the Memory files list now shows CLAUDE.md and AGENTS.md. Then count, test and commit:

wc -w AGENTS.md CLAUDE.md   # reference: 142 AGENTS.md, 1 CLAUDE.md, 143 total
python -m pytest -q         # 2 passed
git add AGENTS.md CLAUDE.md standards docs
git commit -q -m 'Route AGENTS.md: keep the must-follow rules, move the rest to standards/ and docs/'

In the course clone the tag l1 already exists, so compare with it: git diff l1 ':!README.md'. Claude's wording will differ from the reference; what must match is the shape: every section moved and none deleted, the four rules for every change in AGENTS.md, a route row for each kind of work, and CLAUDE.md as the one import line. The film shows the reference change on a fresh clone of the course repo.

The check that proves it: /context all on each machine lists CLAUDE.md and AGENTS.md (340 tokens where it was 2.7k: about a tenth of the words and an eighth of the tokens). Then Sam ran the same INV-2040 prompt at l1, still with no personal notes. His agent wrote the test first, saw it fail (15.00 where it should be 45.00), fixed the bug, saw 3 passed, and committed. In both runs the new test failed first.

Why the test rule stays in AGENTS.md

AGENTS.md always loads. A standard loads only when the agent opens it. So a rule no change may skip lives in AGENTS.md, and a rule for one kind of work lives in its standard.

That is why the test rule is written twice. standards/testing.md holds the full testing standard ("Every bug fix ships with a test that fails before the fix and passes after it", plus how tests are named and run). AGENTS.md keeps the short, must-follow version, written the way you want it done: test first, see it fail, fix, run the whole suite. If it lived only in the standard, an agent that never opened the standard would never see it.

Write it as steps in order, not as a result. "A test that fails before the fix" is true of Sam's test too: it would fail on the old code, but it was only ever run after the fix. A result can be checked off after the fix; an order makes the agent watch the test fail first.

Habits the runs taught

  • Put the test command in AGENTS.md and in your permission allowlist, word for word. In an earlier run the allowlist allowed python3 and the agents called python -m pytest. It was blocked. Priya's agent stopped and did not commit. Sam's agent committed without running any test. Permissions shape what an agent does as much as the rules file (allow rules: https://code.claude.com/docs/en/permissions(abre num novo separador)).
  • Read the agent's last reply before you trust a commit. Sam's agent said it plainly: "I haven't run the tests." It tells you when it skipped a step, if you read it.
  • Do not count on the agent choosing to read. In one run, the agent followed the long file's rules because it chose to open the file with cat. The file was never loaded. What loads every time is what counts.
  • A pointer is not a read. The table only points to the standards. Sam's agent chose to open them, and named its branch from standards/git.md. Nothing in the file makes it do that.

What the lead decides

Which rules make the cut into AGENTS.md. Every line there is read in every session, on every machine, before anyone types a word. A rule that earns that cost stays; everything else becomes a pointer to its standard or doc. Move a rule, never cut it: a move is a change a team agrees to; a cut rarely is. Personal notes can stay personal (Priya's still load at l1), as long as no team rule lives only there.

To sort a personal note, ask: would a review send back a change that broke it? If yes, it was a team rule all along and it moves into AGENTS.md. Two of Priya's three notes pass that test (write the failing test first; money is Decimal) and are in the l1 file. Small commits stays hers.

This week, on your own repo

Run /context all on each machine. No AGENTS.md in the list? Ask Claude for a one-line CLAUDE.md that imports it:

Add a CLAUDE.md that imports AGENTS.md, so Claude Code loads it.

Read what comes back: one line, @AGENTS.md. Do the machines first, before you shorten the file: a short file that never loads changes nothing.

Next lesson

Lesson 2: Review against a locked standards list.