agentstow — Canonical configs, fanned out to all your AI coding agents
Skip to content
Canonical configs (skills, MCP, memory, etc.), fanned out to all your AI coding agents.
One Store at ~/.agents/ holds the single real<br>copy of every config you share — skills, instructions, MCP servers, slash<br>commands, subagents, hooks. agentstow sync fans it out to all ten agents<br>you have installed: symlinks where the bytes can be identical, a rendered key-merge<br>where they can't. There is no state file, and there never will be.
# the Store — one real copy of everything you share<br>~/.agents/<br>├── skills/ research/ tdd/ code-review/<br>├── commands/ ship.md triage.md<br>├── subagents/ reviewer.md<br>├── AGENTS.md your instructions, once<br>├── mcp.json standard mcpServers shape<br>└── hooks/ SessionStart.toml PreToolUse.toml
Read the docs<br>View on GitHub
Fan-out
Edit one file. Every agent sees it.
$ ls -l ~/.claude/skills/<br>research -> ../../.agents/skills/research<br>tdd -> ../../.agents/skills/tdd<br>code-review -> ../../.agents/skills/code-review
$ ls -l ~/.codex/skills/<br>research -> ../../.agents/skills/research<br>tdd -> ../../.agents/skills/tdd<br>code-review -> ../../.agents/skills/code-review
A skill added to the Store appears in Claude Code, Codex, Cursor and pi as a<br>relative symlink — computed, not hand-typed, so the tree survives being moved or<br>restored somewhere else.
opencode and oh-my-pi already read ~/.agents/ themselves, so<br>agentstow deliberately writes nothing for them. A link of ours that dangles gets<br>pruned; a link pointing anywhere else is Foreign and is left alone.
Two mechanisms
Symlinked where it can be, rendered where it can't.
Skills, instructions, commands and subagents can be byte-identical everywhere, so<br>they are one file seen from ten places — drift is impossible by construction. MCP<br>servers and hooks live inside files the agent also owns, in formats no two agents<br>share, so those are rendered and key-merged: your other keys are preserved, and only<br>the entries named in the Store are rewritten.
# ~/.agents/mcp.json — you write this once<br>"mcpServers": {<br>"serena": {<br>"type": "stdio",<br>"command": "uvx",<br>"args": ["--from", "serena-agent", "serena"]<br># ~/.codex/config.toml — merged, not replaced<br>model = "gpt-5.3-codex" # untouched
[mcp_servers.serena]<br>command = "uvx"<br>args = ["--from", "serena-agent", "serena"]
[projects."/Users/you/work"] # untouched<br>trust_level = "trusted"
No state
The filesystem is the state.
Other tools in this space copy, render, and remember what they own in a record<br>beside your configs. When that record disagrees with the disk, your hand-edits lose.<br>agentstow keeps no record at all, because ownership is legible from the disk<br>itself.
Link identity<br>A symlink that resolves into the Store is ours. It gets canonicalised, and<br>pruned when it dangles.
Name identity<br>An MCP server, or a hook whose command appears in the Store, is ours. Every<br>other name in the same file is Foreign and survives untouched.
Marker identity<br>A wholly generated file carries one comment line saying so. Marked is ours;<br>unmarked was written by somebody else.
Restraint
Variants are a feature, not a conflict.
$ agentstow status<br>claude (.claude/skills) 12 linked<br>variant plannotator — left alone<br>variant-identical old-notes — identical to the<br>Store, could be re-linked<br>foreign vendor-thing — not ours
mcp (mcp.json)<br>managed serena → claude<br>foreign xapi → claude — not in the<br>Store — left alone
2 items need attention — run `agentstow sync`.
A real directory shadowing a Store entry is a Variant :<br>deliberate, preserved forever, and flagged only when its contents are identical<br>to the Store copy, so you can dedupe on purpose rather than by accident.
Anything agentstow did not write is Foreign — reported, never modified. Exit<br>codes are the contract: 0 clean, 1 error,<br>2 something to do.
Coverage
Ten agents, six families.
AgentSkills<br>InstructionsMCP<br>CommandsSubagents<br>Hooks
Claude Codefan-outimport-linekey-mergefan-outfan-outkey-merge<br>Codexfan-outsymlinkkey-merge (TOML)fan-outnonekey-merge<br>opencodenativesymlinkkey-mergefan-outfan-outnone<br>pifan-outsymlinknonenonenonenone<br>oh-my-pinativesymlinknativenativenonenone<br>Gemini CLInonesymlinkkey-mergerendernonekey-merge<br>Cursorfan-outnonekey-mergefan-outnonenone<br>Windsurfnonesymlinkkey-mergefan-outnonenone<br>Roononerules-dir linknonefan-outnonenone<br>Clinenonenonekey-mergenonenonenone
What each agent supports, and by which mechanism. none means that<br>agent has no such config surface — not that agentstow skipped it. native<br>means the agent reads the Store itself, so writing anything would only duplicate<br>it.
Safety
Safe to run before you trust it.
$ agentstow sync --dry-run<br>dry run — no changes will be made
claude (.claude/skills)<br>missing research<br>missing tdd<br>mcp (mcp.json)<br>missing serena → codex — not in this agent's config yet
3 changes would be made.
A second sync is a no-op<br>Run it twice and the second run reports Everything is up to date<br>with the files byte-identical.
Every write is...