repoagents
Repo-only agent config for Claude Code, Codex, Grok and Cursor. One AGENTS.md, one .mcp.json, vendored skills
with provenance — committed in the repository, checked in CI, nothing installed on the machine.
bunx repoagents # create/repair links, regenerate MCP files
bunx repoagents check # fail on drift (CI, pre-commit)
bunx repoagents status # what each harness really loads here, and from where
bunx repoagents doctor # explain what each harness loads here
The problem
Every coding agent reads its config from different places:
So a repository that wants all four ends up with copies that drift. Three more problems show up in practice:
- Vendored skills lose their origin. You copy a skill from GitHub, tweak a sentence, and a month later nobody knows which upstream version it was, whether it was edited, or under which license.
- Machine-level config leaks in. Skills and MCP servers installed in
~/.claude,~/.codexor~/.grokapply to every repo (Grok even loads Claude's), so behaviour differs per machine and per person. - Nothing tells you when it broke. A hand edit to a generated file, a dangling link or an unrecorded skill edit goes unnoticed until an agent behaves oddly.
How repoagents solves it
You edit three masters; repoagents derives the rest and fails CI when they disagree.
AGENTS.md ──► CLAUDE.md -> AGENTS.md (symlink, also next to every nested AGENTS.md)
.agents/skills/<name>/ ──► .claude/skills/<name> -> ../../.agents/skills/<name>
.agents/skills/sources.json provenance for vendored skills (see below)
.mcp.json ──► .codex/config.toml (TOML, secrets by env var name)
──► .cursor/mcp.json (${VAR} → ${env:VAR})
CLAUDE.mdis a symlink, not an@AGENTS.mdimport, because Grok sends the import line verbatim. Put a line at the top ofAGENTS.mdsaying it is the master, so agents edit it rather than the link.- Every MCP server is written as a full entry (Codex merges a project file field by field over the user's global
config). Inline secrets,
${VAR:-default}andsseservers are rejected because one of the targets cannot express them. OAuth servers are just a URL; each harness keeps its own login, so the MCP server still sees which client acted. - repoagents never writes through a symlink and never overwrites a hand-written
.codex/config.tomlor aCLAUDE.mdwith its own content without--force.
Vendored skills with provenance
Skills are copied as real files (not symlinks, not gitignored), so a fresh clone, a worktree or a read-only sandbox
works without an install step. Each one is pinned in .agents/skills/sources.json:
{
"version": 2,
"skills": {
"shadcn": {
"repository": "shadcn-ui/ui",
"commit": "2d3f1cd…",
"path": "skills/shadcn",
"license": "MIT",
"licenses": ["LICENSE.md"],
"treeSha256": "baa5d621…", // the files as copied from upstream
"localTreeSha256": "baa5d621…", // the directory as committed
"unchanged": true,
},
"mobile-native": {
"repository": "emilkowalski/skills",
"commit": "e8a175d…",
"path": "skills/mobile-native",
"license": "MIT",
"licenses": ["LICENSE"],
"treeSha256": "e09d6a58…",
"localTreeSha256": "1f4c1833…", // differs: we edited it…
"unchanged": false,
"adaptation": "Description narrowed to touch/mobile web; Apple specifics deferred to apple-web-app.",
"baseCommit": "e8a175d…", // …on top of this upstream version
},
},
}
The tree hash covers every file (sorted paths + bytes), not just SKILL.md. The workflow:
repoagents skills add emilkowalski/skills skills/mobile-native # fetch one dir (sparse, shallow) + its license
# edit .agents/skills/mobile-native/SKILL.md → `check` now fails: "edited since it was recorded"
repoagents skills rehash mobile-native "why it differs" # record the adaptation
repoagents skills update --check # which pins are behind upstream?
repoagents skills update # re-vendor unchanged skills; adapted ones are reported
repoagents skills fanout mobile-native --to ../other-repo # same files + same record elsewhere
repoagents skills audit # prompt injection, piped scripts, keys, hidden Unicode
Licenses are found next to the skill, or in the nearest ancestor directory (plugin repos keep LICENSE beside the
plugin), and recorded as SPDX ids.
What a repository can and cannot switch off
The repository adds config; every harness still merges the user's own on top. What status shows and --isolate
writes, verified 2026-10-10 with temporary home directories:
Without --isolate, a user's Grok server named like a repository server silently wins, and a machine-local Claude
entry for the project path shadows .mcp.json; status marks both with !. Grok 1.0.46 reports servers from the
project .cursor/mcp.json as coming from ~/.cursor/mcp.json; repoagents accounts for that.
Install
Commands
Global flags: --cwd <dir>, --force, --json, --quiet. Exit codes: 0 ok, 1 issues/drift, 2 usage, 3 upstream
(git/network), 4 invalid file, 5 unsafe write.
Trust is per machine and cannot be committed: approve the repository once in each harness (Claude's trust
dialog, Codex's trust prompt, grok --trust, cursor-agent --trust) and log in to OAuth MCP servers once per tool.
Compared with other tools
When to use something else:
- rulesync if you want one generator for many harnesses and are fine with
.rulesync/as the source instead ofAGENTS.md. - skillshare if you want one personal skill library synced to many tools across machines (global first), with a UI.
- apm for organisation-wide package management with governance and SBOMs.
npx skillsto install a skill quickly where provenance does not matter.
repoagents is for the narrower case: everything in the repository, the same result on every machine and in CI, and an honest record of which upstream skill you copied and how you changed it.
Limitations
statusreads config files;--livecross-checks Grok and Codex only (Claude and Cursor print text with slow health checks). Skill precedence between directories is not verified, sostatuslists every copy.- Four harnesses, each verified on the version in the table; behaviour changes upstream (it moves fast) and the
table is updated when re-verified. Cursor's handling of a skill present in both
.agents/skillsand.claude/skillsis not verified yet (doctormentions it). - Bun is required for
bunx; the release binaries include it. - Adapted skills are never merged automatically:
skills updatereports them and you re-apply upstream changes.
Development
bun install
bun run check # format, type-aware lint (oxlint + anti-slop), typecheck, Effect diagnostics, knip, tests, build, self-check
Effect v4 (effect/cli), Bun, Vitest with @effect/vitest. See AGENTS.md.
MIT © Kristjan Grm