One Setup to Rule Them All: A Model-Agnostic AI Coding Config
A practical repo layout that keeps Claude Code, Codex, Copilot, Cursor, and OpenCode reading the same rules, with honest notes on where portability breaks.
Abstract
Teams rarely converge on a single AI coding tool; a repo that only works with one of Claude Code, Codex, Copilot, Cursor, or OpenCode loses every contributor who picked a different tool. This post shows a concrete layout that uses AGENTS.md as the single source of truth, symlinks or @-imports for every other tool's expected filename, and MCP for cross-tool tooling. It also flags where the dream breaks: skills, slash commands, and Windows symlink traps.
The Problem
A team adopts Claude Code. A new hire prefers Cursor. The CLAUDE.md at the repo root sits quiet while Cursor reads .cursor/rules/. Someone hand-copies the rules. A month later, a rule lands in AGENTS.md with slightly different wording. Three files drift. Nobody owns the sync.
Add a few more pains that show up in real repos:
- A monorepo with per-package conventions. Claude Code walks up the tree and concatenates nested
CLAUDE.mdfiles. OpenCode reads the nearestAGENTS.md. Copilot only reads.github/copilot-instructions.mdat the root. Same code, different behaviour. - MCP servers (GitHub, database, filesystem) must live in
.mcp.json(project root, Claude Code),.codex/config.toml,.vscode/mcp.json, and.cursor/mcp.json. Same URL, same auth, four formats. - Skills and slash commands live in
.claude/skills/and.claude/commands/. They do not automatically port to Codex, Copilot, or Cursor. - Windows contributors clone the repo. The symlinks arrive as plain text files reading
AGENTS.md. Their AI tool silently loads nothing.
The goal of this post: pick a canonical file, make every tool read it, and be honest about where the lowest-common-denominator wall actually is.
What Each Tool Reads (April 2026)
Before choosing a layout, know what each tool actually looks for on startup. I cross-checked each entry with the tool's April 2026 docs (links at the end).
Note: Anthropic's April 2026 memory docs describe
AGENTS.mdas a fallback whenCLAUDE.mdis absent, not as an equal peer. If both files exist, Claude Code readsCLAUDE.mdand ignoresAGENTS.md. This is the one place where different community guides phrase the answer differently, so verify with the official docs before you ship.
The table drives a simple choice: pick one file that the most tools read natively, and make sure every other tool can find it.
The Canonical Layout
Pick AGENTS.md. It is the widest-adopted name in 2026 and the one OpenAI, Copilot, OpenCode, Cursor, and others treat as canonical.
One file carries the rules. Symlinks bridge every other filename a tool expects. Tool directories stay tool-specific.
Three Ways to Keep One Source of Truth
Option A: Symlinks
The unix-native approach. Git tracks symlinks. Every editor and CLI tool follows them.
For Windows teammates, add git config --global core.symlinks true before cloning. Without that flag, git checks out the symlink as a text file whose only content is the string AGENTS.md. The tool then reads that single line and thinks it is the whole project rulebook.
Option B: @-imports
Claude Code and OpenCode both inline referenced files when they see an @ prefix. This is the cleanest option if you want a shared base plus a few tool-specific lines.
Copilot and Cursor do not understand @-imports. They read the literal text. If you go this route, keep Copilot and Cursor on symlinks or pointer files.
Option C: Pointer files
The crudest option, but the most portable. A one-line CLAUDE.md:
LLM adherence is probabilistic. The pointer gets ignored maybe five percent of the time. Fine for a solo repo; not fine for a compliance-sensitive one.
Picking a Strategy
When symlinks win: pure unix team, no Windows contributors, you want zero duplication.
When @-imports win: you want tool-specific additions on top of a shared base, and your team is on Claude Code or OpenCode.
When neither is worth it: single tool today, no plans to switch. CLAUDE.md or AGENTS.md alone is fine. Premature unification is just another source of drift.
The MCP Layer
MCP (Model Context Protocol) is the only real cross-tool contract for tools, not rules. Every serious assistant reads MCP server definitions. But each reads from a different path and format:
- Claude Code:
.mcp.jsonat project root (not.claude/mcp.json, a common trap) - Codex CLI:
.codex/config.tomlper project, or~/.codex/config.tomlglobally — most teams use the global file - Copilot (VS Code):
.vscode/mcp.json(uses theserverskey, notmcpServers) - Cursor:
.cursor/mcp.json(usesmcpServers)
Four files. Same URL, same auth token, four formats. Community tooling (chezmoi recipes, YAML-to-many generators posted to Hacker News in early 2026) can generate all four from one source. Worth knowing about. Not worth depending on until one approach clearly wins. For now, budget for four config files if your repo ships real MCP servers.
The trade-off here is ugly but honest: rules port via one file, tools port via MCP, and MCP configuration itself does not port. You live with it or you pick one tool.
Automating the Setup (projen and friends)
Three symlinks and a .mcp.json take an hour to set up. A year later, someone renames a file, Windows symlinks break, and the four MCP configs drift. Automation makes CI the enforcement layer instead of goodwill.
The options split by what your team already uses.
projen — TypeScript synth
projen treats project files as code. You subclass a project, declare the files you want generated, and npx projen regenerates them. Any drift fails the synth check.
Trade-off: projen is AWS CDK territory. If your team is not already synthesizing package.json, tsconfig, and GitHub Actions with projen, adopting it just for AI config is over-budget. The win comes from one-tool-for-all-config, not one-tool-for-AI-config.
chezmoi — templates, developer-scoped
chezmoi is a dotfile manager with Go text/template support. When most of your AI config lives in $HOME (user-scoped Claude, Cursor, Codex globals), chezmoi fits better than per-repo synth. One .chezmoitemplates/AGENTS.md, then chezmoi apply renders it to every tool's expected path. Per-developer overrides use the same template system.
Purpose-built and plain scripts
A small dedicated CLI or a thirty-line shell script plus a pre-commit hook is enough for a single repo with no other automation. Do not adopt a framework you do not already use elsewhere.
Picking the tool:
- Already on projen (AWS CDK shop)? Add an
AgentConfigcomponent. Zero new tooling. - Already on chezmoi for dotfiles? Add
.chezmoitemplates/AGENTS.md. Zero new tooling. - Neither? A shell script and a CI check clears the bar. Upgrade later if the pain shows up.
The bar is "rule drift fails CI." Each of these three clears it.
The Lowest-Common-Denominator Wall
Not everything unifies. A few things stay tool-specific, and pretending otherwise misleads your team.
Slash commands. .claude/commands/ holds Claude-specific slash commands. Codex, Copilot, and Cursor do not read them. If your team depends on /deploy as a Claude slash command, that workflow does not port.
Skills. Anthropic published the SKILL.md specification as an open standard in December 2025. By April 2026, adoption is broad: VS Code ships native Skills support, GitHub Copilot's version is still labelled experimental, and Cursor, Codex CLI, OpenCode, and Goose read the same SKILL.md format. A skill written for Claude Code typically loads in the others without changes. What still differs is where each tool looks — .claude/skills/ is Claude-specific, and Copilot, Cursor, and the rest each define their own discovery paths. The format ports. The convention does not yet.
Path-specific instructions. Copilot supports .github/instructions/*.instructions.md with glob patterns. Cursor has globs: frontmatter in .mdc files. Claude has its own path scoping. These do not port. Keep the root AGENTS.md generic. Let each tool use its own path-scoping mechanism.
This is the wall. Accept it, document it in your AGENTS.md, and move on. A team that pretends total portability exists will waste a week trying to force it.
When to Not Do This
The honest version of this post admits its own audience. If any of these describe your situation, stop reading and pick one tool.
You are a single-vendor enterprise shop. Procurement chose Copilot. Security signed off on one vendor. Onboarding docs point at one install script. In this world, symlinks and @-imports buy nothing except maintenance overhead. A single copilot-instructions.md file is the whole job.
You are in a regulated environment that audits AI access. SOC 2, ISO 27001, and HIPAA auditors want a single-vendor trail for AI-assisted code generation — who saw what, when, with what system prompt. Multi-vendor AI-at-code-time complicates that trail. Pick one, document it, move on.
You are one developer. A solo repo has no drift problem. CLAUDE.md or AGENTS.md alone is enough. Revisit when a second contributor shows up.
You just adopted your first AI coding tool. Do not build infrastructure for a fleet of tools you do not have yet. Start with one. Symlinks become interesting the day someone on your team opens Cursor while the rest are on Claude Code.
Where this post earns its keep: open source repos (maintainers cannot dictate contributor tooling), agencies and consultancies (each client repo meets a different tool stack), mid-stage teams where adoption grew organically and standardization would now be retroactive political work, and any team that consciously values tool-choice autonomy.
Single-vendor standardization is a valid answer. This post is for teams where it is not the answer.
Common Pitfalls
Checking in personal overrides. CLAUDE.local.md and .claude/settings.local.json are for personal overrides. Add them to .gitignore on day one. A committed CLAUDE.local.md with someone's private experiments will confuse every teammate.
Assuming Copilot reads AGENTS.md alone. Copilot merges AGENTS.md and .github/copilot-instructions.md. If you put the full ruleset only in AGENTS.md and leave copilot-instructions.md empty, Copilot's web PR review may miss context. The symlink fix solves this.
Nested AGENTS.md in monorepos. OpenCode and Copilot read the nearest one. Claude Code concatenates up the tree. Same repo, different rule composition. Document the nesting behaviour you rely on.
Windows symlinks without core.symlinks=true. The failure mode is silent. The file appears. It reads AGENTS.md as plain text. The AI tool thinks that single line is the whole rulebook. Fix: add a CI check (test -L CLAUDE.md) that fails if any symlink has been replaced with a text file.
Drift after month three. Without a check, someone will "fix" a broken symlink on Windows by replacing it with a real copy of AGENTS.md. Two weeks later, the copy has drifted. Add a pre-commit hook or a CI job that enforces the symlink.
Metrics Worth Tracking
Not every team needs dashboards here, but a few simple checks catch most drift:
- Number of instruction files that must change per rule update. Target: one.
- Percent of developers whose tool of choice reads the canonical file on first clone. Target: 100 percent.
- Drift incidents per quarter. Cases where tool A and tool B behaved differently on the same repo because they read different files.
- Time to onboard a new AI tool to the repo. Target: under thirty minutes (add symlink, add MCP config, done).
If those numbers stay healthy, your "one setup to rule them all" is actually ruling.
Principles from the Field
The mechanics (symlinks, @-imports, per-tool directories) solve the storage problem. Practitioners who work with coding agents every day have stronger views on the content problem — what belongs in AGENTS.md and how to keep it from bloating.
Addy Osmani argues for spec-before-code discipline: AGENTS.md holds standing conventions, while a per-feature spec.md carries intent. He cites the "Curse of Instructions" finding — as you pile requirements into one prompt, per-rule adherence drops, and even frontier models struggle with dozens of simultaneous rules. Practical cap: keep AGENTS.md under ~200 lines and push path-specific rules into .github/instructions/*.instructions.md or .cursor/rules/*.mdc.
Simon Willison frames the job as "hoarding things you know how to do" — a pattern library your agent recombines, not a rule book it obeys. AGENTS.md earns its keep when it points at known patterns, not when it re-specifies the obvious.
Geoffrey Huntley (Sourcegraph Amp) hits two notes: too many active MCP tools pollute the context window, and tool descriptions are not standardized. His fix: deploy tools to the stages that need them — Jira MCP during planning, GitHub MCP during review, off otherwise. The same discipline applies to rules: the always-loaded root file stays small; path-scoped rules carry the weight.
ruler (intellectronica/ruler) is a small CLI that applies one rules source to every agent's native file. Fits alongside projen and chezmoi when you want something purpose-built and lighter than either.
One security note. Rules files are readable by humans and the agent, but the agent reads every character. The "Rules File Backdoor" technique (SC Media, 2026) injects invisible Unicode into rules files to steer the agent. Treat AGENTS.md like executable code — add a CI check for non-ASCII or non-printable characters in rules-file diffs.
Closing
The 2026 AI coding ecosystem quietly converged on a shared pattern: a single root markdown file, a tool-specific directory, and MCP for cross-tool tooling. AGENTS.md is the widest-accepted canonical name. Symlinks and @-imports bridge to every other expected filename.
The honest version of the pattern admits the wall. Rules port. MCP servers port (with format conversion). Slash commands, skills, and path-specific instructions do not. Plan your AI-tooling strategy around what ports, and keep the non-portable pieces documented and scoped.
If your team is still hand-copying rules between CLAUDE.md and .cursor/rules/main.mdc, the fix is a one-hour afternoon. Pick AGENTS.md, run three ln commands, add a CI check, and move on to harder problems.
References
- AGENTS.md official spec - Open standard site with a current adoption list (Codex, Cursor, Copilot, Gemini CLI, Aider, OpenCode, Zed, Warp, VS Code, Devin, and more).
- Codex AGENTS.md guide (OpenAI) - OpenAI's official documentation for how Codex reads AGENTS.md.
- GitHub blog: How to write a great agents.md - Empirical patterns from a 2,500-repo analysis, including the six core sections that work.
- Claude Code memory docs - CLAUDE.md hierarchy,
@-imports, AGENTS.md fallback behaviour, and 200-line guidance. - OpenCode rules docs - sst/opencode's AGENTS.md handling, Claude Code compatibility fallback, project and global scopes.
- GitHub Docs: Adding repository custom instructions for Copilot - Official path, merge behaviour with AGENTS.md, and path-specific
.github/instructions/*.instructions.md. - Cursor Rules docs -
.cursor/rules/*.mdcformat, frontmatter (description, alwaysApply, globs), and legacy.cursorrulesdeprecation notice. - Gemini CLI GEMINI.md docs - Hierarchical loading,
@file.mdimport syntax, and/memorycommands. - Aider conventions docs - How Aider loads CONVENTIONS.md or AGENTS.md via
.aider.conf.yml. - Keeping Claude Code, Codex, and Cursor memory in sync - Three approaches (symlinks,
@-imports, pointer files) with Windows notes. - One AGENTS.md to Rule Them All (Kaushik Gopal) - A practitioner writeup of the single-source-of-truth pattern.
- Sharing AI Agent Configs with Symlinks (Rushi) - A concrete symlink recipe for Cursor and Claude.
- One MCP Configuration for Codex, Claude, Cursor, and Copilot - A practical approach to MCP config drift using chezmoi.
- projen — config as code - TypeScript-based project synthesizer from the AWS CDK team; custom
Componentsubclasses emit files and runsynthesize()on eachnpx projeninvocation. - ruler — apply the same rules to all coding agents - Small CLI that writes one rules source into every agent's native file format; a lighter alternative to projen or chezmoi for the specific problem.
- Agents.md: an open standard for AI coding agents (Tessl) - Context on the Linux Foundation and Agentic AI Foundation stewardship of the standard.