Your repo has CLAUDE.md. It also has .cursor/rules/, and
.github/copilot-instructions.md, and someone added GEMINI.md last month,
and there is a .windsurfrules nobody has opened since March.
They were copy-pasted from each other. They have been drifting ever since.
And they are stale in a way nobody checks: they point at files that moved,
tell the agent to run scripts that were renamed, contradict themselves in two
places, and — often enough to matter — contain an API key somebody pasted into
a curl example and committed, because unlike .env, an instructions file is
meant to be checked in.
agentsync fixes both halves.
uvx agentsync adopt # merge the rules files you already have into AGENTS.md
uvx agentsync lint # find what has rotted
uvx agentsync sync # write every tool's file from that one source$ agentsync sync --targets all
created CLAUDE.md Claude Code
created .cursor/rules/agentsync.mdc Cursor
created .github/copilot-instructions.md GitHub Copilot
created .windsurf/rules/agentsync.md Windsurf
created GEMINI.md Gemini CLI
created .clinerules/agentsync.md Cline
unchanged AGENT.md Amp
...
source: AGENTS.md targets: --targets allFrontmatter, paths and per-tool quirks are handled for you — Cursor's .mdc
gets alwaysApply: true, Windsurf gets trigger: always_on, Copilot's
repo-wide file gets no frontmatter at all because it does not take any.
Put it in CI and drift stops being possible:
- run: uvx agentsync check # exit 1 if any rules file is out of date$ agentsync lint
error C005 AGENTS.md:31 GitHub personal access token found in the instructions.
curl -H "Authorization: Bearer ghp_ab********[redacted]"
error C003 AGENTS.md ~6,800 tokens (27,200 characters). Windsurf truncates
a rules file around 24,000 characters.
warning C001 AGENTS.md:14 `src/api/client.ts` does not exist in the repository.
warning C002 AGENTS.md:22 `npm run test:unit` is not defined in package.json scripts.
warning C004 AGENTS.md:9 line 9 and line 58 give opposite instructions about the
same thing ('pnpm for installs')
advisory C007 AGENTS.md:41 line 41 is repeated at line 63.An agent trusts your instructions over the code in front of it. A path that moved does not read as an error — it reads as a fact, and the agent fills the gap by guessing. That is what this linter is for.
| C001 | warning | Referenced file or directory no longer exists |
| C002 | warning | Referenced npm/make/just script is no longer defined |
| C003 | error | Instructions large enough to be truncated, or to cost real context on every request |
| C004 | warning | Two instructions contradict each other |
| C005 | error | A credential is sitting in a file designed to be committed |
| C006 | warning | Template placeholder text never filled in |
| C007 | advisory | The same instruction appears twice |
| C008 | warning | A relative markdown link points at a missing file |
Every check is one small file in src/agentsync/checks/.
Adding one is a 20-minute contribution — see CONTRIBUTING.md.
uvx agentsync --help # no install
pipx install agentsync # or install it
pip install agentsyncYou already have rules files, and they do not agree. adopt does not pretend
otherwise:
$ agentsync adopt
Found 3 instructions file(s):
1204 chars CLAUDE.md
880 chars .cursorrules
412 chars .github/copilot-instructions.md
dropped: GEMINI.md (identical to CLAUDE.md)
Wrote AGENTS.md with 3 section(s).
Read it before syncing -- where two tools disagreed, both are still in there.Each block is labelled with the file it came from. Where two tools disagreed,
both are kept — deciding which one is right is not a call a tool gets to
make. Delete the loser, then agentsync sync.
Reads AGENTS.md natively |
Generated for you |
|---|---|
| OpenAI Codex, opencode | Claude Code, Cursor, GitHub Copilot, Windsurf, Gemini CLI, Cline, Roo Code, Kilo Code, Continue, JetBrains Junie, OpenHands, Amp, Zed, Aider |
agentsync targets prints the current list with the exact path each one reads.
Legacy single-file formats (.cursorrules, .windsurfrules) are supported but
opt-in — generating both the old and new file for one tool would leave you
carrying the same instructions twice, which is the problem this tool exists to
remove.
Most instructions are the same everywhere. When one genuinely is not:
<!-- agentsync:only claude -->
Register the MCP server with `claude mcp add`.
<!-- agentsync:end -->
<!-- agentsync:except copilot -->
You can run migrations directly; Copilot's sandbox has no database.
<!-- agentsync:end -->One file with two fenced paragraphs beats two files that drift.
Zero-config, agentsync syncs the tools your repo already has files for. To
pin the list or silence a check:
# .agentsync.yml
targets: [claude, cursor, copilot]
disable: [C007]Every generated file is stamped:
<!-- Generated by agentsync from AGENTS.md. Do not edit by hand -- edit AGENTS.md and run `agentsync sync`. -->A file without that stamp is never overwritten. sync reports a conflict
and leaves it exactly as it is.
That is not politeness, it is the whole trust model. A hand-written CLAUDE.md
is often the most carefully-worded file in a repository, tuned over months of
watching an agent get things wrong. Destroying one to fix a formatting nit
would cost more than every drifted rules file this tool was installed to fix.
--force exists if you really mean it.
0 |
in sync / lint passed |
1 |
drift, a conflict, or a lint error |
2 |
could not run (no AGENTS.md, bad config, unknown target) |
name: agents
on: [push, pull_request]
jobs:
agentsync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
- run: uvx agentsync check # rules files match AGENTS.md
- run: uvx agentsync lint # nothing has rottedAs a pre-commit hook:
repos:
- repo: local
hooks:
- id: agentsync
name: agentsync
entry: uvx agentsync check
language: system
pass_filenames: falseA new tool is a 3-line class. A new lint check is one small file with one test. Both are auto-discovered — nothing to register. See CONTRIBUTING.md, and good first issues for what is currently open.
MIT — see LICENSE.