October 13, 2026

Taproot gets worked on by more than one AI coding assistant. I use Claude and OpenAI Codex, and the two have been used interchangeably. I decide what work to give to which depending on which model release is currently better for the task at hand. Whichever assistant codes it then has the other review the work. GitHub Copilot reads instructions from the repository too, but these days I don't use GitHub Copilot at all. It's too expensive.

I started using two models for a practical reason: I kept burning through my entire Claude usage, so I started paying for OpenAI's models as well. Codex did a good job, and I've used both ever since. The bigger reason I kept both is that the models are different. When they review each other's work, each one catches things the other missed, and the quality of what we ship goes up. If you care about quality, I'd recommend building with at least two models.

Retro Bot.png

Two models means two tools looking for instructions, and each tool has a file of its own: CLAUDE.md for Claude Code, AGENTS.md for Codex, and .github/copilot-instructions.md for Copilot. If each file carries its own copy of the rules, the copies start to disagree, and a review turns into an argument about which copy the reviewer happened to read.

Our answer is one canonical file, AGENTS.md, that every tool reads. Keeping agent instructions DRY matters just as much as keeping code DRY, and for the same reason: a rule that lives in two places eventually says two different things.

How do Claude Code, Codex and Copilot share one file?

Each tool gets to AGENTS.md a slightly different way.

Codex reads AGENTS.md natively, from the project root down to the current directory. Nothing extra is needed.

Claude Code reads CLAUDE.md, so ours imports the shared guide on its first line. Claude Code's memory docs support @path imports, and an imported file loads at the start of every session, exactly as if it were written inline. Below the import, CLAUDE.md holds the only instructions that belong to Claude Code alone, about which models and how much reasoning effort to use when it hands out work:

@AGENTS.md

## Claude Code only
...

Copilot also reads AGENTS.md files, and our .github/copilot-instructions.md is a short note that names AGENTS.md as the canonical guide. Copilot doesn't support imports, so that file stays a pointer, and it doesn't repeat rules that live in the main guide.

AGENTS.md states the arrangement from its side at the top: it's the canonical guide for people and AI assistants, the tool-specific files only add what belongs to their tool, and if anything conflicts, AGENTS.md wins.

What goes in AGENTS.md?

The top-level outline of Taproot's guide:

  • What Taproot is

  • How to work in this repo: backlog tasks, verifying before handing off, the Tilt dev environment, writing tests, coverage, the Git workflow with verified pull requests, task tracking, and the code review format

  • Architectural principles: contracts first, the command pipeline for all mutations, one authorization point per endpoint, client-first processing, shared code, typed outbox messages, and bounded contexts

  • C# and API conventions

  • TypeScript and frontend conventions

  • Protobuf conventions

  • Dependency philosophy

  • Further reading, which links to longer area-specific documents in docs/

It leans on the reader's ability to read code. It states rules that catch real failure modes and points at one example of each, and the long explanations live in linked documents that an assistant reads when the work calls for them. That's the same habit I wrote about in why documentation-first development helped us build with AI: the guide is useful because it's specific.

It also defines the code review output format, a JSON array of findings with a file, line, severity and suggestion. Every reviewer, human or tool, ends with that array, so findings from Claude Code and Codex can be compared and tracked the same way.

Per-language Copilot instructions with applyTo

Copilot supports path-specific instruction files in .github/instructions/, each with an applyTo glob in its front matter. We have three: C#, TypeScript and protobuf.

---
applyTo: "**/*.proto"
---

# Protobuf Review Deltas

`/AGENTS.md` is the canonical repo-wide guide. This file only captures
protobuf-specific reminders that are useful to surface when reviewing `.proto`
files.

GitHub's docs say that when a path-specific file and the repository-wide file both apply, Copilot uses both. These files are deltas: short reminders for one file type that must never contradict the main guide. Keeping that promise takes regular checking, which I come back to below.

Why both models need to read the same rules

Cross-model review is where the single file pays off. When Claude Code finishes a task, it runs an internal review in a fresh, review-only context. Then the same change goes to Codex for an external review in a read-only sandbox, through a small file-based exchange in the repository. When Codex wrote the code, Claude Code (claude -p) does the external review instead. The external round can repeat up to ten times in one direction and five in the other before the workflow stops and reports that the reviewers didn't converge.

Using two different models works because they notice different things. That's only useful if they're judging the change against the same rules, so the review prompt names the file explicitly:

Read AGENTS.md,
docs/tasks/active/{{TASK}}.md, the full diff (`git diff {{BASE_SHA}}` plus the
untracked files listed below), relevant callers and callees, and matching
.github/instructions files.

The shared playbook that drives our backlog tasks does the same for both assistants. Those tasks live as Markdown in the repository too, which I covered in we put our backlog in Git.

Rules that can be checked move into code

Wherever a rule can be checked mechanically, we move it out of prose and into a guard. The rule against raw fetch() calls in the frontend has a script that parses the TypeScript and fails lint. Test antipatterns, coverage thresholds, the backlog index and parts of the .NET architecture have their own checks. A script also verifies that relative links in AGENTS.md, CLAUDE.md and the docs resolve. Once a rule has a guard, the prose can stay short, because the check enforces the detail. I went into more detail in how we enforce coding standards.

Should you use an import, a symlink, or a pointer?

AGENTS.md is an open format for coding agent instructions, now maintained under the Linux Foundation's Agentic AI Foundation, and many tools read it directly. For tools that look for their own file, you have three ways to share it.

An import is what we use for Claude Code. It keeps one file, leaves room for tool-specific notes underneath, and loads the shared guide every session without the assistant having to decide to open it.

A symlink also works. Claude Code's docs advise against it if anyone works on Windows, since Git may check the link out as a one-line text file.

A pointer, a file that tells the tool in words to go read AGENTS.md, is the weakest option. Anthropic's docs are direct about it: Claude sees the file only if it decides to open it. Use a pointer only for tools that support nothing better, the way we do for Copilot's repository-wide file.

Audit your agent instructions periodically

An instruction file is code that nobody runs a test suite against. It grows one reasonable rule at a time, and it rots the same way documentation does. Our last audit, done while I was writing this post, turned up three problems that had been sitting there for months:

  • The protobuf delta said every RPC must have a google.api.http annotation. AGENTS.md says internal-only RPCs omit it, so JSON transcoding doesn't expose them as REST endpoints. Taproot depends on that: the site generator calls an internal RPC for legal document history that the browser should never reach. (I walk through that example in from .proto to a typed TypeScript client.) A reviewer reading a .proto change got both versions of the rule.

  • AGENTS.md had grown to about 98 KB. Codex stops reading project instruction files at 32 KiB combined by default, so most of the guide was never loaded. Claude Code's docs make the related point that every line costs context in every session.

  • A lot of it was wordy. Rules were restated several ways, explanations covered things the code already made obvious, and some instructions described workflows we no longer use.

We fixed all three. The protobuf delta now matches the main guide. AGENTS.md was rewritten in concise language until it fit under the limit, with long area-specific material moved into linked documents. And CLAUDE.md moved to the import.

Put a recurring audit on the calendar, the same way you'd schedule dependency updates. Each time, check:

  • Size against each tool's limits. Know how much your assistants load by default, and trim to fit. Verbose instructions cost context on every session.

  • Contradictions between files. Read the canonical file next to every tool-specific and delta file, and search for rules that changed in one place and not the other.

  • Stale rules. Delete instructions for code, tools or workflows that no longer exist.

  • Wordiness. Cut filler, repeated explanations, and paragraphs that say the same rule three ways. Concise language is easier for the assistant to follow and easier for you to keep accurate.

  • Rules that should be guards. If a rule can be checked mechanically, write the check and shorten the prose.

The same pattern under a different name

taproot-controls, the repository for our Espalier design system and the WTFM documentation tooling, does the same thing with a different canonical file. Its shared guide is AI_GUIDELINES.md, its CLAUDE.md imports it, and AGENTS.md and the Copilot file point to it. Its AGENTS.md also carries a generated block for Trellis, our backlog toolkit, which gives that file a job of its own.

The name matters less than the rule: one file holds the shared guidance, and every tool-specific file either loads it or adds only what belongs to that tool.

Setting this up in your own repository

  1. Pick one canonical file. AGENTS.md is the name that the most tools read without extra setup.

  2. Move everything shared into it. Compare it section by section with any existing CLAUDE.md or Copilot file before you delete those copies.

  3. Have the other files load it with an import where the tool supports one, and a short pointer where it doesn't. Keep only tool-specific instructions in them.

  4. If you add per-language files, keep them to reminders. When a rule changes in the main file, search the delta files for the old wording.

  5. Turn the rules you can check into scripts, so a drifted sentence fails a build instead of a review.

  6. Use at least two models, and name the canonical file in every review prompt so they judge the work against the same rules.

  7. Audit the files on a schedule: size, contradictions, stale rules and wordiness.