{"id":51034598,"url":"https://github.com/shanemhamilton/unify-agent-docs","last_synced_at":"2026-06-22T04:01:36.880Z","repository":{"id":364847815,"uuid":"1269439883","full_name":"shanemhamilton/unify-agent-docs","owner":"shanemhamilton","description":"One canonical agent-instruction file per directory for Claude Code, Codex, Cursor \u0026 Gemini — CLAUDE.md/AGENTS.md/GEMINI.md unified via symlinks, with a drift-proof pre-commit guard.","archived":false,"fork":false,"pushed_at":"2026-06-14T18:25:17.000Z","size":18,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-14T20:11:51.715Z","etag":null,"topics":["agents-md","ai-agents","claude-code","claude-md","codex","cursor","developer-tools","gemini-cli","monorepo","skill"],"latest_commit_sha":null,"homepage":null,"language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shanemhamilton.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-14T18:04:34.000Z","updated_at":"2026-06-14T18:25:19.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/shanemhamilton/unify-agent-docs","commit_stats":null,"previous_names":["shanemhamilton/unify-agent-docs"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/shanemhamilton/unify-agent-docs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shanemhamilton%2Funify-agent-docs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shanemhamilton%2Funify-agent-docs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shanemhamilton%2Funify-agent-docs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shanemhamilton%2Funify-agent-docs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shanemhamilton","download_url":"https://codeload.github.com/shanemhamilton/unify-agent-docs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shanemhamilton%2Funify-agent-docs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34633796,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-22T02:00:06.391Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agents-md","ai-agents","claude-code","claude-md","codex","cursor","developer-tools","gemini-cli","monorepo","skill"],"created_at":"2026-06-22T04:01:35.986Z","updated_at":"2026-06-22T04:01:36.868Z","avatar_url":"https://github.com/shanemhamilton.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# unify-agent-docs\n\n**One canonical instruction file per directory for Claude Code, Codex, Cursor, and Gemini — so your agent docs can never drift apart again.**\n\nA [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.\n\n---\n\n## The problem\n\nModern 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:\n\n- The same facts (build commands, schema enums, pricing constants, conventions) get restated in several files and quietly disagree.\n- 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.\n- Nobody notices until an agent acts on a stale fact.\n\n## The fix\n\nStructural, not vigilance-based:\n\n- **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.\n- **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.\n- **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.\n\n```\nyour-project/\n├── AGENTS.md            # the one real file (canonical)\n├── CLAUDE.md  → AGENTS.md   (symlink)\n├── GEMINI.md  → AGENTS.md   (symlink)\n└── packages/api/\n    ├── AGENTS.md        # canonical for this package\n    ├── CLAUDE.md → AGENTS.md\n    └── GEMINI.md → AGENTS.md\n```\n\n---\n\n## Install\n\n### As a Claude Code plugin (recommended)\n\n```text\n/plugin marketplace add shanemhamilton/unify-agent-docs\n/plugin install unify-agent-docs@unify-agent-docs\n```\n\nYou get the skill (and future updates) in one step. Then in any project, ask Claude to\n*\"unify the agent docs in this project\"* or invoke `/unify-agent-docs:unify-agent-docs`. The\nskill walks the full workflow: inventory the files, merge their content losslessly, set up the\nsymlinks, install the guard, and verify.\n\n### As a plain skill (clone or download)\n\n```bash\n# copy just the skill into your skills directory\ngit clone https://github.com/shanemhamilton/unify-agent-docs.git /tmp/uad \\\n  \u0026\u0026 cp -R /tmp/uad/skills/unify-agent-docs ~/.claude/skills/\n```\n\nOr grab the packaged `unify-agent-docs.skill` from the\n[latest release](https://github.com/shanemhamilton/unify-agent-docs/releases/latest) for a\ndrag-and-drop / claude.ai install.\n\n### Just the script (any agent, no skill runtime)\n\nThe engine is a single dependency-free Bash script — copy it into your repo:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/shanemhamilton/unify-agent-docs/main/skills/unify-agent-docs/scripts/agent-docs.sh \\\n  -o tools/agent-docs.sh \u0026\u0026 chmod +x tools/agent-docs.sh\n```\n\n### Use with Codex, Cursor, Gemini, and other agents\n\nNothing here is Claude-only. The `agent-docs.sh` engine and the `pre-commit` guard are\nplain Bash — drop them into any repo regardless of which agent you use. The `SKILL.md`\nworkflow is written so any agent that reads project instructions (`AGENTS.md` for Codex/Cursor,\n`GEMINI.md` for Gemini CLI) can follow it directly: point the agent at\n[`skills/unify-agent-docs/SKILL.md`](skills/unify-agent-docs/SKILL.md) and ask it to unify the\ndocs. Tools that support the [Agent Skills](https://agentskills.io) standard can install the\n`skills/unify-agent-docs/` folder the same way Claude Code does.\n\n---\n\n## Usage (the script)\n\n```bash\ntools/agent-docs.sh --sync                 # create the symlinks (+ embed shared-core if present)\ntools/agent-docs.sh --check                # verify everything is in sync (use in pre-commit)\ntools/agent-docs.sh --check-cross ../other # compare shared-core against a sibling repo\n```\n\n`--sync` and `--check` are **config-free**: the script auto-discovers every directory that\ncontains a real canonical file and manages the symlinks there. It works on single-repo,\nmonorepo, and multi-repo layouts on any stack.\n\nOverride behavior with environment variables when you need to:\n\n| Variable | Default | Purpose |\n|----------|---------|---------|\n| `AGENT_DOCS_CANONICAL` | `AGENTS.md` | Which filename is the real file (the others symlink to it). |\n| `AGENT_DOCS_LINKS` | `CLAUDE.md GEMINI.md` | Which names become symlinks. |\n| `AGENT_DOCS_SHARED` | `docs/agents/shared-core.md` | Path to the shared-core file (multi-root). |\n| `AGENT_DOCS_UPSTREAM` | _(unset)_ | A sibling repo to pull shared-core from during `--sync`. |\n\n### Enable the guard\n\n```bash\ncp scripts/pre-commit .githooks/pre-commit \u0026\u0026 chmod +x .githooks/pre-commit\ngit config core.hooksPath .githooks\n```\n\n\u003e 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.\n\n---\n\n## Multi-root / monorepo\n\nFor monorepos or sibling repos that share invariants, put the cross-cutting facts in\n`docs/agents/shared-core.md`. The script embeds it into the root canonical file between\nsentinels and stamps a content hash:\n\n```\n\u003c!-- BEGIN SHARED-CORE hash:XXXX src:docs/agents/shared-core.md ... --\u003e\n...generated copy...\n\u003c!-- END SHARED-CORE --\u003e\n```\n\n`--check` recomputes the hash and fails if the embed drifted from the source. For separate\nrepos, designate one as upstream and have the others pull it via `AGENT_DOCS_UPSTREAM`, then\nverify with `--check-cross`. See [`references/multi-root.md`](references/multi-root.md) for the\nfull pattern and a `shared-core.md` starter template.\n\n---\n\n## How merging works\n\nThe skill never deletes the richer file to \"let the source of truth win.\" It **merges** all\noperational detail into the single canonical file, de-duplicates repeated blocks, and where\nguidance is genuinely tool-specific (a `/command` for Claude vs a `$command` for Codex) keeps\none section with clearly labeled `### Claude Code` / `### Codex` / `### Gemini CLI`\nsubsections. Resolving those conflicts in plain sight is what stops the drift from returning.\n\nIt also stops and flags any plaintext secret it finds while merging — removing it from the\noutput and reminding you the leaked credential must be rotated (deleting the file doesn't\ninvalidate it).\n\n---\n\n## Compatibility\n\n| Tool | Reads | Covered by |\n|------|-------|------------|\n| Claude Code | `CLAUDE.md` | symlink → canonical |\n| Codex / Cursor | `AGENTS.md` | canonical (default) |\n| Gemini CLI | `GEMINI.md` | symlink → canonical |\n\nSymlinks are committed as git mode `120000` and resolve transparently on every platform git\nsupports. After merging a PR, confirm a squash didn't turn a symlink back into a regular file\n(the `--check` guard catches this).\n\n---\n\n## License\n\n[MIT](LICENSE) © Shane Hamilton\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshanemhamilton%2Funify-agent-docs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshanemhamilton%2Funify-agent-docs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshanemhamilton%2Funify-agent-docs/lists"}