# Agentstow: Canonical configs, fanned out to all your AI coding agents

> Source: <https://agentstow.dev/>
> Published: 2026-08-14 02:20:16+00:00

# Canonical configs (skills, MCP, memory, etc.), fanned out to all your AI coding agents.

**One Store at ~/.agents/ holds the single real
copy of every config you share** — skills, instructions, MCP servers, slash
commands, subagents, hooks.

`agentstow sync`

fans it out to all ten agents
you have installed: symlinks where the bytes can be identical, a rendered key-merge
where they can't. There is no state file, and there never will be.

```
# the Store — one real copy of everything you share
~/.agents/
├── skills/          research/  tdd/  code-review/
├── commands/        ship.md  triage.md
├── subagents/       reviewer.md
├── AGENTS.md        your instructions, once
├── mcp.json         standard mcpServers shape
└── hooks/           SessionStart.toml  PreToolUse.toml
```

Fan-out

## Edit one file. Every agent sees it.

``` php
$ ls -l ~/.claude/skills/
research    -> ../../.agents/skills/research
tdd         -> ../../.agents/skills/tdd
code-review -> ../../.agents/skills/code-review

$ ls -l ~/.codex/skills/
research    -> ../../.agents/skills/research
tdd         -> ../../.agents/skills/tdd
code-review -> ../../.agents/skills/code-review
```

A skill added to the Store appears in Claude Code, Codex, Cursor and pi as a relative symlink — computed, not hand-typed, so the tree survives being moved or restored somewhere else.

opencode and oh-my-pi already read `~/.agents/`

themselves, so
agentstow deliberately writes nothing for them. A link of ours that dangles gets
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 they are one file seen from ten places — drift is impossible by construction. MCP servers and hooks live inside files the agent also owns, in formats no two agents share, so those are rendered and key-merged: your other keys are preserved, and only the entries named in the Store are rewritten.

```
# ~/.agents/mcp.json — you write this once
{
  "mcpServers": {
    "serena": {
      "type": "stdio",
      "command": "uvx",
      "args": ["--from", "serena-agent", "serena"]
    }
  }
}
# ~/.codex/config.toml — merged, not replaced
model = "gpt-5.3-codex"        # untouched

[mcp_servers.serena]
command = "uvx"
args = ["--from", "serena-agent", "serena"]

[projects."/Users/you/work"]   # untouched
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 beside your configs. When that record disagrees with the disk, your hand-edits lose. agentstow keeps no record at all, because ownership is legible from the disk itself.

- Link identity
- A symlink that resolves into the Store is ours. It gets canonicalised, and pruned when it dangles.
- Name identity
- An MCP server, or a hook whose command appears in the Store, is ours. Every other name in the same file is Foreign and survives untouched.
- Marker identity
- A wholly generated file carries one comment line saying so. Marked is ours; unmarked was written by somebody else.

Restraint

## Variants are a feature, not a conflict.

``` bash
$ agentstow status
claude (.claude/skills)  12 linked
  variant           plannotator — left alone
  variant-identical old-notes — identical to the
                    Store, could be re-linked
  foreign           vendor-thing — not ours

mcp (mcp.json)
  managed           serena → claude
  foreign           xapi → claude — not in the
                    Store — left alone

2 items need attention — run `agentstow sync`.
```

A real directory shadowing a Store entry is a **Variant**:
deliberate, preserved forever, and flagged only when its contents are identical
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
codes are the contract: `0`

clean, `1`

error,
`2`

something to do.

Coverage

## Ten agents, six families.

| Agent | Skills | Instructions | MCP | Commands | Subagents | Hooks |
|---|---|---|---|---|---|---|
| Claude Code | fan-out | import-line | key-merge | fan-out | fan-out | key-merge |
| Codex | fan-out | symlink | key-merge (TOML) | fan-out | none | key-merge |
| opencode | native | symlink | key-merge | fan-out | fan-out | none |
| pi | fan-out | symlink | none | none | none | none |
| oh-my-pi | native | symlink | native | native | none | none |
| Gemini CLI | none | symlink | key-merge | render | none | key-merge |
| Cursor | fan-out | none | key-merge | fan-out | none | none |
| Windsurf | none | symlink | key-merge | fan-out | none | none |
| Roo | none | rules-dir link | none | fan-out | none | none |
| Cline | none | none | key-merge | none | none | none |

*none*means that agent has no such config surface — not that agentstow skipped it.

*native*means the agent reads the Store itself, so writing anything would only duplicate it.

Safety

## Safe to run before you trust it.

``` bash
$ agentstow sync --dry-run
dry run — no changes will be made

claude (.claude/skills)
  missing   research
  missing   tdd
mcp (mcp.json)
  missing   serena → codex — not in this agent's config yet

3 changes would be made.
```

- A second sync is a no-op
- Run it twice and the second run reports
*Everything is up to date*with the files byte-identical. - Every write is atomic
- A private temp file, fsync, then an atomic rename — resolved through a symlinked destination, so dotfiles wiring survives.
- Secrets stay out of the Store and out of your terminal
`${env:VAR}`

is resolved at sync and redacted from every line of output, so the Store stays committable.- It reports to CI
`status --json`

and`mcp list --json`

, with exit code`2`

reserved for “there is something to do”.

Install

## macOS and Linux.

```
# prebuilt binary — no toolchain, no postinstall script
npm install -g agentstow

# or from source, needs Rust 1.97+
cargo install agentstow

# then, on a machine you have already been using
agentstow init
```

`init`

creates the Store and then tells you what of your existing
config it could take over — per family, with the command that would do it.

Limits

## What it does not do.

**No cross-machine sync.** The Store is an ordinary directory —
version it with git or chezmoi. Building sync would mean building conflict
resolution, and git already won that.

**No memory sync.** Agent memory is not a defined artifact, and
agentstow will not pretend otherwise.

**No Windows**, no GUI, no daemon, no file watcher. It does not
install skills — it fans out whatever is in the Store, whoever put it there. There
is no `mcp add`

, because adding a server is editing a documented
standard file.
