https://github.com/shanemhamilton/unify-agent-docs
One canonical agent-instruction file per directory for Claude Code, Codex, Cursor & Gemini — CLAUDE.md/AGENTS.md/GEMINI.md unified via symlinks, with a drift-proof pre-commit guard.
https://github.com/shanemhamilton/unify-agent-docs
agents-md ai-agents claude-code claude-md codex cursor developer-tools gemini-cli monorepo skill
Last synced: 8 days ago
JSON representation
One canonical agent-instruction file per directory for Claude Code, Codex, Cursor & Gemini — CLAUDE.md/AGENTS.md/GEMINI.md unified via symlinks, with a drift-proof pre-commit guard.
- Host: GitHub
- URL: https://github.com/shanemhamilton/unify-agent-docs
- Owner: shanemhamilton
- License: mit
- Created: 2026-06-14T18:04:34.000Z (15 days ago)
- Default Branch: main
- Last Pushed: 2026-06-14T18:25:17.000Z (15 days ago)
- Last Synced: 2026-06-14T20:11:51.715Z (15 days ago)
- Topics: agents-md, ai-agents, claude-code, claude-md, codex, cursor, developer-tools, gemini-cli, monorepo, skill
- Language: Shell
- Size: 17.6 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# unify-agent-docs
**One canonical instruction file per directory for Claude Code, Codex, Cursor, and Gemini — so your agent docs can never drift apart again.**
A [Claude Code skill](https://docs.claude.com/en/docs/claude-code) (and a standalone shell script) that consolidates a project's `CLAUDE.md`, `AGENTS.md`, and `GEMINI.md` files behind a single source of truth, then guards against drift with a pre-commit hook.
---
## The problem
Modern projects collect a pile of AI-agent instruction files — `CLAUDE.md` for Claude Code, `AGENTS.md` for Codex and Cursor, `GEMINI.md` for Gemini CLI — at multiple directory levels. They drift:
- The same facts (build commands, schema enums, pricing constants, conventions) get restated in several files and quietly disagree.
- The `CLAUDE.md` and `AGENTS.md` in the **same directory** end up with different rules, so switching tools silently changes the instructions your agent follows.
- Nobody notices until an agent acts on a stale fact.
## The fix
Structural, not vigilance-based:
- **One real file per directory.** `AGENTS.md` holds the content; `CLAUDE.md` and `GEMINI.md` become **symlinks** to it. Every tool reads identical bytes — drift between the names is impossible by construction.
- **One home for cross-cutting facts.** In a monorepo or multi-repo setup, invariants (enums, constants, ownership tables, agent/skill names, anti-hallucination rules) live once in `docs/agents/shared-core.md` and are embedded into the root file between hash-stamped sentinels.
- **A guard that fails loudly.** A `pre-commit` hook runs a `--check` that fails the commit if a symlink was replaced by a real file (e.g. a tool overwrote `CLAUDE.md`) or the embedded shared block drifted from its source.
```
your-project/
├── AGENTS.md # the one real file (canonical)
├── CLAUDE.md → AGENTS.md (symlink)
├── GEMINI.md → AGENTS.md (symlink)
└── packages/api/
├── AGENTS.md # canonical for this package
├── CLAUDE.md → AGENTS.md
└── GEMINI.md → AGENTS.md
```
---
## Install
### As a Claude Code plugin (recommended)
```text
/plugin marketplace add shanemhamilton/unify-agent-docs
/plugin install unify-agent-docs@unify-agent-docs
```
You get the skill (and future updates) in one step. Then in any project, ask Claude to
*"unify the agent docs in this project"* or invoke `/unify-agent-docs:unify-agent-docs`. The
skill walks the full workflow: inventory the files, merge their content losslessly, set up the
symlinks, install the guard, and verify.
### As a plain skill (clone or download)
```bash
# copy just the skill into your skills directory
git clone https://github.com/shanemhamilton/unify-agent-docs.git /tmp/uad \
&& cp -R /tmp/uad/skills/unify-agent-docs ~/.claude/skills/
```
Or grab the packaged `unify-agent-docs.skill` from the
[latest release](https://github.com/shanemhamilton/unify-agent-docs/releases/latest) for a
drag-and-drop / claude.ai install.
### Just the script (any agent, no skill runtime)
The engine is a single dependency-free Bash script — copy it into your repo:
```bash
curl -fsSL https://raw.githubusercontent.com/shanemhamilton/unify-agent-docs/main/skills/unify-agent-docs/scripts/agent-docs.sh \
-o tools/agent-docs.sh && chmod +x tools/agent-docs.sh
```
### Use with Codex, Cursor, Gemini, and other agents
Nothing here is Claude-only. The `agent-docs.sh` engine and the `pre-commit` guard are
plain Bash — drop them into any repo regardless of which agent you use. The `SKILL.md`
workflow is written so any agent that reads project instructions (`AGENTS.md` for Codex/Cursor,
`GEMINI.md` for Gemini CLI) can follow it directly: point the agent at
[`skills/unify-agent-docs/SKILL.md`](skills/unify-agent-docs/SKILL.md) and ask it to unify the
docs. Tools that support the [Agent Skills](https://agentskills.io) standard can install the
`skills/unify-agent-docs/` folder the same way Claude Code does.
---
## Usage (the script)
```bash
tools/agent-docs.sh --sync # create the symlinks (+ embed shared-core if present)
tools/agent-docs.sh --check # verify everything is in sync (use in pre-commit)
tools/agent-docs.sh --check-cross ../other # compare shared-core against a sibling repo
```
`--sync` and `--check` are **config-free**: the script auto-discovers every directory that
contains a real canonical file and manages the symlinks there. It works on single-repo,
monorepo, and multi-repo layouts on any stack.
Override behavior with environment variables when you need to:
| Variable | Default | Purpose |
|----------|---------|---------|
| `AGENT_DOCS_CANONICAL` | `AGENTS.md` | Which filename is the real file (the others symlink to it). |
| `AGENT_DOCS_LINKS` | `CLAUDE.md GEMINI.md` | Which names become symlinks. |
| `AGENT_DOCS_SHARED` | `docs/agents/shared-core.md` | Path to the shared-core file (multi-root). |
| `AGENT_DOCS_UPSTREAM` | _(unset)_ | A sibling repo to pull shared-core from during `--sync`. |
### Enable the guard
```bash
cp scripts/pre-commit .githooks/pre-commit && chmod +x .githooks/pre-commit
git config core.hooksPath .githooks
```
> Git deliberately won't auto-activate a repo's own hooks on clone (a security boundary), so each fresh clone runs `git config core.hooksPath .githooks` once.
---
## Multi-root / monorepo
For monorepos or sibling repos that share invariants, put the cross-cutting facts in
`docs/agents/shared-core.md`. The script embeds it into the root canonical file between
sentinels and stamps a content hash:
```
...generated copy...
```
`--check` recomputes the hash and fails if the embed drifted from the source. For separate
repos, designate one as upstream and have the others pull it via `AGENT_DOCS_UPSTREAM`, then
verify with `--check-cross`. See [`references/multi-root.md`](references/multi-root.md) for the
full pattern and a `shared-core.md` starter template.
---
## How merging works
The skill never deletes the richer file to "let the source of truth win." It **merges** all
operational detail into the single canonical file, de-duplicates repeated blocks, and where
guidance is genuinely tool-specific (a `/command` for Claude vs a `$command` for Codex) keeps
one section with clearly labeled `### Claude Code` / `### Codex` / `### Gemini CLI`
subsections. Resolving those conflicts in plain sight is what stops the drift from returning.
It also stops and flags any plaintext secret it finds while merging — removing it from the
output and reminding you the leaked credential must be rotated (deleting the file doesn't
invalidate it).
---
## Compatibility
| Tool | Reads | Covered by |
|------|-------|------------|
| Claude Code | `CLAUDE.md` | symlink → canonical |
| Codex / Cursor | `AGENTS.md` | canonical (default) |
| Gemini CLI | `GEMINI.md` | symlink → canonical |
Symlinks are committed as git mode `120000` and resolve transparently on every platform git
supports. After merging a PR, confirm a squash didn't turn a symlink back into a regular file
(the `--check` guard catches this).
---
## License
[MIT](LICENSE) © Shane Hamilton