Skip to content

ADR 0032: The Claude Code mirror imports AGENTS.md instead of duplicating it

Consolidated into ADR 0034. Its tracking premise was superseded there; the surviving @AGENTS.md pointer mechanism is described there. Kept for history.

Status: accepted; extends ADR 0031 (the provider registry this adds a capability to). The tracking premise here ("AGENTS.md is the one tracked file") is superseded by ADR 0034, which makes AGENTS.md an untracked artifact; the pointer mechanism this ADR introduces is unchanged.

Context

§

discern refresh compiles one body — [built-in base] + [a section per enabled feature] + [your sources] — and writes it to every provider file named in [guidance].agents (default claude_codeCLAUDE.md, codexAGENTS.md). AGENTS.md is the one tracked file (so guidance changes show in review); CLAUDE.md/GEMINI.md are gitignored mirrors.

Until now every provider file held a byte-for-byte copy of the compiled body. For a project that emits both claude_code and codex that means two identical multi-kilobyte files in the tree — AGENTS.md and CLAUDE.md — differing only in name. The duplication is harmless to correctness (both are regenerated) but genuinely confusing: a reader opening CLAUDE.md next to AGENTS.md can't tell which is authoritative, and the redundancy invites the question "why two copies?".

Claude Code already supports an @<path> import in CLAUDE.md (and in ~/.claude/CLAUDE.md): the referenced file's content is expanded in place at load time. So a CLAUDE.md that is just @AGENTS.md is, to the agent, identical to the full copy — without the second copy on disk.

Decision

§

A provider's guidance file can be a pointer to the canonical tracked file rather than a duplicate. The Provider.guidanceFile record gains an optional pointer(canonicalPath) → body; Claude Code's sets it to emit a do-not-edit banner plus an @<canonicalPath> import line.

compileGuidelines resolves the canonical file — the tracked provider in the current run (codexAGENTS.md) — and, for each provider that declares a pointer, writes the pointer body when that canonical file is also being emitted (and isn't the file itself). Otherwise it writes the full compiled body. So:

  • AGENTS.md (tracked) — the full compiled body, the single source.
  • CLAUDE.md@AGENTS.md, expanded by Claude Code at load time.
  • GEMINI.md — still a full copy; Gemini's include syntax isn't wired, so it has no pointer and falls through to the full body.
  • A project emitting only claude_code (no tracked AGENTS.md) — CLAUDE.md falls back to the full body, since there is nothing to point at.

Consequences

§
  • One source of truth on disk, visibly. The guidance lives in AGENTS.md; the Claude mirror imports it, so the two can never drift and it is obvious which is authoritative. The confusing identical-twin files are gone.
  • No behaviour change for the agent. Claude Code expands @AGENTS.md to the same bytes it used to read inline.
  • The pointer is a typed provider capability, not a Claude-Code special case — a future agent with its own include syntax sets its own pointer, and the fallback keeps any single-provider or tracked-file-absent setup correct.
  • A stale AGENTS.md still fails CI (git diff --exit-code); the gitignored CLAUDE.md pointer is stable text that doesn't change with the guidance, so it doesn't churn.

Alternatives considered

§
  • Keep the byte-for-byte copy. Rejected: it's the confusion this removes, and it duplicates a growing body in the tree for no benefit.
  • Make CLAUDE.md the tracked canonical and have AGENTS.md point at it. Rejected: AGENTS.md is the cross-agent standard and the one we already track for review; Codex reads it literally and has no import syntax to rely on, so the full body must live there.
  • Also convert GEMINI.md to a pointer now. Deferred: the @-import is Claude Code's mechanism; emitting it into GEMINI.md without confirming Gemini expands it would risk a broken guidance file. A full copy is safe until its syntax is wired (then it sets a pointer like Claude Code).
choose openEsc close