Skip to main content

Coupling map

CLAUDE.md tells Claude Code to keep pipeline.md and llms.txt honest, but that rule only covers those two files. It grew to cover both because llms.txt drifted once and got folded in after the fact (see "A baseline is not a fact"), not because anyone planned for it. Writing a new rule for every future pair wouldn't scale. A reminder that depends on a future session recalling each one adds recall surface with every pair it covers.

The coupling map replaces "remember to check this" with two things instead: a small, explicit list of known pairs, and two automated checks that read it. Neither one discovers a new coupling on its own. Both only ever confirm or flag a relationship someone already wrote down.

The map itself​

scripts/coupling-map.json is a plain array. Each entry names a fact and the files that state it. For example:

{
"description": "Pipeline facts (workflow count, Vale rule count and names, tool names) stated in both the docs page and the agent-facing index file",
"files": [
"website/docs/pipeline.md",
"website/static/llms.txt"
]
}

Four pairs are tracked as of this writing:

  • CLAUDE.md and its own write-up on this page's sibling
  • pipeline.md and llms.txt
  • the /check command's shell invocations, quoted verbatim in the skills write-up
  • pipeline.md's tool table, duplicated independently in README.md

The deterministic check​

coupling-check.yml runs on every pull request. It diffs the PR's changed files against the map, and if one side of a pair changed without the other, it comments asking for confirmation. It does not block the build from merging. A partial change to a coupled pair is often correct. For example, a typo fix on one side doesn't always need a matching edit on the other, so the check only ever asks, the same way coupling-map-review.yml does one level up.

This half is a plain script: git diff against a JSON file, no model involved. It can't be wrong about whether a pair is in the map. It can only be wrong about whether the map itself is still complete, which is the other half's job.

The agent​

The map needs its own periodic check too, and that check can't be a script the same way. "Does this file still exist" is mechanical. "Does this description still accurately describe what these two files have in common" and "is there a new pair worth adding" both require reading the actual content and making a judgment call.

coupling-map-review.yml runs on the first of every month, via anthropics/claude-code-action. Each run:

  1. Reads every file path in the map and confirms it still exists.
  2. Reads each pair and judges whether its description still holds, given what the files currently say.
  3. Looks for new candidate pairs elsewhere in the repo, citing the specific overlapping fact rather than proposing anything speculative.
  4. Reports all of it by opening or commenting on a GitHub issue titled "Monthly coupling-map review." It's the same gh issue create mechanism api-reference.yml and doodle.yml already use for their own drift alerts.

It never edits the map. It reports, the same way the PR check reports, and a human decides what to do with what it finds. The first real run found something: two new pairs worth adding, and a stale name, skill.md, that had been sitting in three files since a rename weeks earlier. Getting the workflow itself running took three wrong guesses first. Both are covered in the blog post The reviewer's first catch was its own builder.

See also​