Most of your coding agents can't read CLAUDE.md

We have three repositories that all get worked on by coding agents, and until this week they had three different answers to the same question: where do the instructions live?

repo AGENTS.md CLAUDE.md
this site 196 lines one line: @AGENTS.md
jobwolverine 353 lines a 15-line hand-written pointer
pkanban 387 lines didn't exist

The interesting part is that the middle one — the one we'd put actual thought into, the one with a hand-written pointer explaining which sections matter most — was the broken one. It was broken in a way that produces no error, no failing check, and no visible symptom. It just quietly did nothing for three quarters of the agents that read it.

Two files, two audiences

CLAUDE.md is Claude Code's convention. AGENTS.md is the cross-tool one, read by opencode, Codex, Cursor and a list that keeps growing — which is itself the argument for treating it as the real file, since you don't want your instructions pinned to whichever tool you happened to start with.

So you write AGENTS.md and you need CLAUDE.md to point at it. The mechanical problem is obvious and everybody hits it: two files that are supposed to say the same thing, kept in sync by somebody remembering. Copy the guidance into both and they agree for about a week.

That problem has a clean fix. Claude Code supports an import:

Instructions for this repo live in AGENTS.md, imported below -- one file, so
the two can never drift. Edit AGENTS.md, never this file.

@AGENTS.md

Four lines, and the whole of AGENTS.md gets pulled in at load time. There is no second copy, so there is nothing to drift. The @ syntax is Claude Code-specific and would render as literal text anywhere else, which is fine — that file is Claude Code's, and it's the only thing reading it.

Not a symlink, incidentally, though that's the first thing people reach for. We're on Windows, where git symlinks need core.symlinks enabled per clone; a checkout without it gets a text file containing the word AGENTS.md and no indication anything is wrong.

The bug that isn't about drift

Here's what we'd actually done in jobwolverine. CLAUDE.md there wasn't a copy of anything — it was a genuinely useful document, and it looked like this:

The guidelines for this repo live in AGENTS.md. Two sections are the ones most often skipped and most often needed:

  • Roadmap and issue tracking — work is tracked on kanban boards, not in a file here. Check the board before starting.
  • Production deployment — deploys go through the GitHub Actions workflow, never by hand.

That's a good document. It solves a real problem: AGENTS.md is 353 lines, and in 353 lines of flat markdown, "never deploy by hand" and "here is what the /data/ route prefix does" carry exactly the same weight. Somebody had noticed that and built a priority layer on top.

They'd built it in the file that opencode does not read.

Every agent except Claude Code got the flat 353 lines with no signal about which parts were load-bearing. The care that went into identifying the two most-skipped sections reached exactly one of the four tools working in that repo. And nothing anywhere reports this — you find out when an agent deploys by hand, or spends a session on work that was already a card on the board.

The fix is not subtle once you see it. The emphasis layer has to be in the file everyone reads. It goes in AGENTS.md, above the project overview, and CLAUDE.md goes back to being four lines that import it.

Which means the arrangement we'd been treating as the unfinished one — this site's bare one-line import — was already right, and the sophisticated version was wrong. The one-line import isn't a stub. It's the whole design.

What earns a place at the top

A priority section only works if it's short, and it stays short only if you have a rule for what goes in it. Ours:

A rule earns the top slot if breaking it fails silently.

No error, no failing test, no red anywhere — just work that quietly did nothing. That's it. Here's what that selected for on this site:

  • web/dist is the only thing the server serves. Editing web/src changes nothing until you run npm run build. An agent can make a correct change, verify the file on disk, and report success, having altered nothing about the running site.
  • The kanban board is the only roadmap. Not checking it means re-deriving something that's already a card. Re-introducing a checked-in TODO.txt means starting the drift over.
  • Tests need a build first, and the repo root. Handler paths are relative to the working directory, so running from anywhere else fails in a way that looks convincingly like a code bug.

Three. Not the ten most important rules in the repo — the three that punish you without telling you.

The rule also says what doesn't go up there, which is the half that keeps the section from growing. This repository vendors a copy of a library from another repository, and editing it in place is a genuine mistake an agent would plausibly make. It's not in the top section, because a CI check already catches it. A guarded rule doesn't need the scarce space. It'll announce itself.

That distinction is worth stating explicitly in the file, because otherwise the next person to add something reasonable adds it, and six months later the "read this first" section is forty lines and reads first no better than line 200 does.

The small mechanical thing

One reason this site's CLAUDE.md had stayed a bare import is that there was nothing stable to point at. The sections were numbered:

### 9. Planning (pkanban)

which anchors as #9-planning-pkanban. Insert a section anywhere above it and every link into it breaks, silently, in the usual way of markdown anchors. So nobody wrote links, so there was no way to build a pointer layer even if you wanted one.

Dropping the numbers costs nothing and gives you #roadmap-and-issue-tracking, which survives anything except renaming the section. Then the top section can link into the body, prose can cross-reference other sections, and the file becomes navigable rather than sequential. Two of ours had already drifted into referring to "section 3" and "section 9" by number — which had been correct when written.

While we were in there, the roadmap section moved from dead last to second, directly after the project overview. It had been sitting below the section titled "Orphaned by the SPA rewrite," which is a good description of where it ranked in practice.

The same shape, resolved the other way

We've written before about a file in this repo that's a copy of a file in a different repo, and the CI check that exists because a comment cannot notice it has become false. That's the same shape as this: two things that are supposed to agree, with nothing but memory enforcing it.

The resolutions are opposites, and the difference is worth naming. There, the duplication was forced — the library's whole premise requires a copy that can be served directly — so the answer was to build machinery that watches the copy and files a pull request when it drifts. Here the duplication is optional, so the answer is to not have a second copy at all.

Machinery that watches a duplicate is what you build when you've already lost the argument for having one. Check whether you've actually lost it first. We had two files that must never disagree and reached for a careful hand-maintained pointer, when four lines of import made disagreement impossible.

What it cost

An afternoon, mostly spent reading three files and noticing that the best one was wrong. The edits themselves are small: promote a section, drop some numbers from headings, move a callout between files, add a note at the top of AGENTS.md saying this is the file you edit, and anything living only in CLAUDE.md is invisible to every agent but one.

That last line is the one that does the work long-term. The failure mode isn't a person deciding to duplicate instructions — it's an agent opening a four-line CLAUDE.md, correctly observing that it looks unfinished, and helpfully filling it in.