Shared agent rules — one core, tested adapters
Shared agent rules are one versioned instruction core (a root AGENTS.md), the thinnest per-tool adapter that makes Claude Code, Codex and Cursor load it, and a test proving each tool did. Rules steer the model; anything that must never happen belongs in permissions, sandboxes, CI and branch protection.
Your repository has a 400-line CLAUDE.md written in March, an AGENTS.md that the Codex users added in July, and a Cursor rule that still says npm test after the move to pnpm. Three agents read three versions of the truth, and nobody can say which one a given session loaded. This page is for the tech lead who owns the shared harness and the CTO answering question 5 of the CTO Scorecard.
What a tested shared-rules setup gives you
Section titled “What a tested shared-rules setup gives you”- A file layout and an
AGENTS.mdcore template you can commit today. - The adapter each tool needs, based on how it discovers instruction files (checked 2026-09-26 against Claude Code 2.1.283 and Codex 0.157.1).
- A written precedence table that settles conflicts by rule, not by load order.
- A deterministic CI check and a fresh-session probe that prove each agent loaded the rules, so nobody has to read transcripts.
- The failure modes that make an agent silently ignore the rules, and how to recover from each.
How does the CTO Scorecard grade shared rules?
Section titled “How does the CTO Scorecard grade shared rules?”Question 5 asks: “Does the team share agent rules (CLAUDE.md / AGENTS.md / managed policy)?” Use the table to place the team honestly, then close the gap to the next row.
| Points | Answer | Evidence a reviewer asks for |
|---|---|---|
| 0 | Everyone authors their own, no sharing | none |
| 1 | A “recommended” CLAUDE.md in the README | a copy-paste snippet, no enforcement |
| 2 | Per-repo CLAUDE.md/AGENTS.md committed to main | the file exists; nobody knows whether every tool loads it |
| 3 | Versioned shared core plus tested tool adapters, owners, precedence, change review and external enforcement for hard requirements | CODEOWNERS entry, the CI check below, probe results per tool, a list mapping each hard rule to its control |
The jump from 2 to 3 is almost entirely verification. The file is the easy part.
Split durable truth from tool adapters
Section titled “Split durable truth from tool adapters”Each layer has one job. When a sentence could live in two layers, it belongs in the lower one.
| Layer | Holds | Lives in |
|---|---|---|
| Shared core | repository map, commands, definition of done, protected paths, human gates, owners | root AGENTS.md |
| Directory scope | rules for one package, service, language or risk area | services/billing/AGENTS.md and similar |
| Tool adapter | discovery glue and genuinely tool-specific behaviour, nothing else | CLAUDE.md, a Cursor project rule |
| External enforcement | what must hold even when the model ignores every file above | sandbox, permission rules, CI, branch protection, deploy approval |
The core goes in AGENTS.md because it is the format the tools converge on: an open format stewarded by the Agentic AI Foundation under the Linux Foundation, which its site describes as “used by over 60k open-source projects” (agents.md, September 2026). How to write the content itself (what to include, and what to leave out) is covered in AGENTS.md and CLAUDE.md: concise repository context.
A layout that works for a monorepo:
AGENTS.md # shared core, target under 200 linesCLAUDE.md # adapter: "@AGENTS.md" + Claude-only linesservices/billing/AGENTS.md # directory scopeservices/billing/CLAUDE.md # adapter: "@AGENTS.md".claude/rules/ # optional Claude path-scoped rules (paths: frontmatter).github/CODEOWNERS # rule files owned by the harness ownerscripts/check-agent-rules.sh # deterministic CI check (below)tests/agent-rules/probe.sh # fresh-session probe (below)The shared core template, ready to adapt:
Rules version: 2026-09-26.1
## Commands- Install: `pnpm install --frozen-lockfile`- Unit tests: `pnpm test`- Types and lint: `pnpm typecheck && pnpm lint`
## Definition of done- Tests, types and lint pass locally before you open a pull request.- New behaviour has a test that fails without the change.
## Protected paths (ask a human first)- `services/billing/migrations/`- `infra/` and anything that changes production access
## Human gates- Merging to `main` and deploying are human decisions. Never push to `main`.
## Precedence- A directory `AGENTS.md` may add constraints. It may not relax a rule in this file.- If two rules conflict, stop and ask; do not pick one.
## Owners- This file: @acme/agent-platform. Change it through a pull request.The Rules version: line is a canary: every test on this page checks that an agent can quote it.
How each agent discovers instruction files
Section titled “How each agent discovers instruction files”Discovery is where shared rules fail, and it differs per tool, so the adapters differ too.
Checked against the memory documentation and Claude Code 2.1.283 on 2026-09-26.
- Launch: Claude Code loads
CLAUDE.md,.claude/CLAUDE.mdandCLAUDE.local.mdfrom the working directory and every directory above it. Files in subdirectories load when Claude reads files there. Everything is concatenated, root first; nothing overrides anything. AGENTS.md: read directly from v2.1.277 (v2.1.281 on Bedrock, Google Cloud, Foundry, gateways and telemetry-off sessions), and by default only when there is noCLAUDE.md,.claude/CLAUDE.mdorCLAUDE.local.mdin the working directory or above. On 2026-09-26 that is thelatestchannel only; thestablechannel is 2.1.274 and readsCLAUDE.mdfiles only.- Also read, by Claude Code only:
.claude/AGENTS.mdin the working directory and above. Codex ignores it, so it is another way for the two tools to diverge; the CI check below fails on it. - Not read:
AGENTS.override.md,AGENTS.local.md, and anything under.agents/. - Adapter: a
CLAUDE.mdnext to eachAGENTS.mdwhose first line is@AGENTS.md. The import works on every version and channel, and a version that also readsAGENTS.mddirectly never loads it twice. - Alternative: in
/config, set Project instructions toclaude-md-and-agents-mdto readCLAUDE.mdandAGENTS.mdtogether, deduplicated. It is honoured only in user or managed settings, never in project settings. It also lets aCLAUDE.local.mdcoexist withAGENTS.md; under the default, aCLAUDE.local.mdcounts as aCLAUDE.mdand suppressesAGENTS.md. Keep the import adapter anyway, because it works on every channel.
@AGENTS.md
## Claude Code only- Use plan mode for changes under `services/billing/`.- Check: run
/contextand confirm the files appear under Memory files;/memoryopens the loaded CLAUDE.md files for editing.
Checked against the agents_md.rs and config_toml.rs sources at rust-v0.157.1 and the installed Codex 0.157.1 on 2026-09-26.
- Launch: Codex finds the project root (the nearest directory with
.git, configurable withproject_root_markers) and collects instructions from the root down to the working directory, root first. It never walks above the root. - Per directory: Codex takes the first file that exists from
AGENTS.override.md,AGENTS.md, then any names inproject_doc_fallback_filenames. An override therefore replaces that directory’sAGENTS.mdfor Codex only. - Budget:
project_doc_max_bytescaps the whole chain at 32 KiB by default. Past the cap Codex truncates, and the deepest files go first. - Trust: since 0.150.0, a project marked untrusted does not supply project-level
AGENTS.md. A project with no trust entry yet still loads it. - Adapter: none. Codex reads
AGENTS.mdnatively. - Check:
codex debug prompt-inputprints the model-visible input as JSON, so you can grep it for the canary without running a task.
# Terminal, from the directory where engineers start Codexcodex debug prompt-input "noop" | grep -c "Rules version: 2026-09-26.1"Cursor applies instructions through Rules (cursor.com/docs/rules, verified 2026-08-28). On 2026-09-26 cursor.com could not be reached from our verification environment. The current rule file format is unverified here, so the probe below decides whether Cursor needs a pointer rule.
- Adapter: if the fresh-session probe below shows your build loads
AGENTS.md, add nothing. Otherwise add one always-applied project rule that points the agent atAGENTS.mdand holds only Cursor-specific lines, in the format the Rules page specifies today. - Do not paste the core into the rule. A copy is how the
npm testline in the opening example survived the move to pnpm. - Check: open a new Agent chat and paste the probe prompt from the next section. A pointer rule relies on the model choosing to open
AGENTS.md, so repeat the probe after every Cursor update.
Write the precedence down
Section titled “Write the precedence down”Neither Claude Code nor Codex resolves conflicts for you. Both concatenate files, and Anthropic’s memory page warns that if two rules contradict each other, “Claude may pick one arbitrarily”. So precedence is a rule you write, review and test, not a load order you hope for.
| Situation | What wins | How it is enforced |
|---|---|---|
| Directory file contradicts the root | the stricter rule; a directory may add constraints, never relax them | stated in the core; conflict audit in review |
AGENTS.override.md exists | Codex reads it instead of that directory’s AGENTS.md; Claude Code ignores it | never committed; the CI check fails on it |
| Personal preferences | CLAUDE.local.md or user-level files, gitignored | a personal file cannot weaken a hard rule, because hard rules are not in files |
| Organisation-wide rules | managed instructions deployed by IT, such as Claude Code’s managed CLAUDE.md, which loads before project files | managed policy across every agent |
| A rule and a control disagree | the control; fix the rule’s wording | the map from each hard rule to its control, reviewed quarterly |
Roll out shared rules without a big-bang rewrite
Section titled “Roll out shared rules without a big-bang rewrite”- Inventory every source. List each
AGENTS.md,CLAUDE.md,.claude/rules/file, Cursor rule and personal default in use, with its scope and owner. The first prompt below does the reading; on the Claude side,/doctor prompt-audit(v2.1.283,latestchannel) also flags contradictingCLAUDE.mdandAGENTS.mdfiles. - Choose the canonical core. Move durable rules into the root
AGENTS.md, keep it under 200 lines (the size Anthropic’s memory page recommends per file), and link to architecture docs instead of pasting them. Use the ablation protocol to decide what earns a line. - Replace copies with adapters. Each
CLAUDE.mdbecomes@AGENTS.mdplus Claude-only lines. Delete the duplicated text in the same pull request, so there is never a period with two live copies. - Map hard rules to controls. For every “never” in the core, name the control that enforces it: a permission rule, a sandbox mode, a CI job, branch protection. A rule with no control is advice, and the core should say so.
- Add the CI check and the probe. Both are below. The CI check runs on every pull request; the probe runs on rule changes and after tool upgrades.
- Assign ownership. Put the rule files under a
CODEOWNERSentry, and require every rule change to cite what prompted it: an incident, a review comment, an onboarding failure.
Prove every agent loaded the rules without reading transcripts
Section titled “Prove every agent loaded the rules without reading transcripts”Verification has two layers. The deterministic layer checks files and needs no model. The probe layer asks each agent what it loaded and compares the answer with the canary.
Layer 1: a CI check on every pull request. It fails when an adapter is missing, when a Codex-only override or a Claude-only .claude/AGENTS.md is committed, or when a directory’s chain exceeds Codex’s default budget. Tested with bash on 2026-09-26.
#!/usr/bin/env bash# scripts/check-agent-rules.sh: deterministic, no model calls. Run from the repository root.set -euo pipefailfail=0files=$(find . -name 'AGENTS*.md' -not -path './node_modules/*' -not -path './.git/*')
for f in $files; do d=$(dirname "$f") case "$f" in */AGENTS.override.md) echo "$f: Codex-only override is committed"; fail=1; continue ;; */.claude/AGENTS.md) echo "$f: read by Claude Code only; merge it into AGENTS.md"; fail=1; continue ;; */AGENTS.md) ;; *) continue ;; esac # Claude Code adapter: a CLAUDE.md next to every AGENTS.md whose first line imports it if [ "$(head -n 1 "$d/CLAUDE.md" 2>/dev/null)" != "@AGENTS.md" ]; then echo "$d: needs a CLAUDE.md whose first line is @AGENTS.md"; fail=1 fi # Codex budget: every AGENTS.md from the root down to this directory total=0; p="$d" while :; do [ -f "$p/AGENTS.md" ] && total=$(( total + $(wc -c < "$p/AGENTS.md") )) [ "$p" = "." ] && break p=$(dirname "$p") done if [ "$total" -gt 32768 ]; then echo "$d: AGENTS.md chain is $total bytes, over Codex's 32 KiB default"; fail=1 fidoneexit "$fail"Layer 2: a fresh-session probe per tool. Run it when a rule file changes and after every tool upgrade. The canary grep is the pass/fail signal; the other three answers are for the owner to skim.
#!/usr/bin/env bash# tests/agent-rules/probe.sh: run from the repository root on a trusted checkoutset -euo pipefailCANARY=$(grep -m1 '^Rules version:' AGENTS.md)PROBE=$(cat tests/agent-rules/probe-prompt.txt) # the probe prompt above
codex debug prompt-input "noop" | grep -qF "$CANARY" || { echo "Codex: core not in prompt"; exit 1; }claude -p "$PROBE" --permission-mode plan > claude.outcodex exec --sandbox read-only --ephemeral -o codex.out "$PROBE"for out in claude.out codex.out; do grep -qF "$CANARY" "$out" || { echo "$out: canary missing"; exit 1; }doneCursor has no line in the script because its CLI was not verifiable on 2026-09-26; paste the same probe into a new Agent chat and record the result in the pull request.
Sign-off. The harness owner in CODEOWNERS approves every rule change. The pull request carries the CI check result, the probe output per tool, and the incident or review comment that motivated the change. A reviewer checks those artefacts, not the full diff of every transcript. Report the same three items when you answer question 5.
What breaks when teams share agent rules?
Section titled “What breaks when teams share agent rules?”Claude Code ignores AGENTS.md. Symptom: the probe returns no canary in Claude Code while Codex passes. Cause: someone has a CLAUDE.md or CLAUDE.local.md in the working directory or above, is on the stable channel (2.1.274 on 2026-09-26), or, in some cases, is in the first session after upgrading from 2.1.276 or earlier. Recovery: add the @AGENTS.md adapter; it works in all three cases.
Codex drops the package rules. Symptom: a rule from services/billing/AGENTS.md is followed when Codex starts in services/billing/ and ignored when it starts at the root. Cause: Codex builds its startup chain only from the root down to the working directory. Recovery: move rules that every session needs into the root core, and tell engineers to start Codex in the package they are changing.
Codex truncates the chain. Symptom: the canary is present but a directory rule is missing from codex debug prompt-input. Cause: the chain passed 32 KiB and Codex truncated it, logging only a warning. Recovery: cut the core, starting with anything the ablation protocol cannot justify. Raise project_doc_max_bytes only after the cut, and only with a written reason.
Codex and Claude Code disagree on one directory. Symptom: behaviour differs by tool in one directory only. Cause: an AGENTS.override.md that Codex reads and Claude Code ignores. Recovery: delete it, move the content into AGENTS.md, and keep the CI check that fails on it.
Codex loads no project rules at all. Symptom: an empty instructions block in codex debug prompt-input on one machine. Cause: that project is marked untrusted there, because someone declined the trust prompt or ~/.codex/config.toml sets trust_level = "untrusted" for it; since 0.150.0 an untrusted project does not supply project-level AGENTS.md. Recovery: set the project to trusted on that machine, and keep the canary check in the onboarding fixture.
The core loads twice. Symptom: context grows and the fresh-session probe (or asking the session to quote its instructions) shows the core twice: once from the SessionStart hook output and once from the loaded file. Cause: a SessionStart hook that prints AGENTS.md still runs after Claude Code learned to read the file. Recovery: remove the hook; the @AGENTS.md import never duplicates.
A rule is treated as a security control. Symptom: an agent reads .env although the core says “never read .env”. Cause: instructions steer the model; they do not bind it. Recovery: enforce with permission rules or a sandbox, reviewed as code in shared hooks governance, and keep the sentence in the core only as an explanation of the control.
Policy by duplication creeps back. Symptom: the inventory prompt finds the same rule in three files. Cause: a migration command or a well-meaning engineer copied text instead of importing it. Both Claude Code and Codex offer /import for another tool’s configuration; run it once during migration, then run the inventory prompt and delete the copies.
Where to go next after shared agent rules
Section titled “Where to go next after shared agent rules”Before this page: make the codebase agent-ready and read how teams share context and rules. After it, package procedures that do not belong in always-loaded rules as skills, and move hard requirements into reviewed controls.