Documentation
agentstow keeps one copy of every config you share and puts it where each agent expects to find it. This page is the reference: what lives in the Store, how each family reaches each agent, and what the tool will and will not touch.
Install
# prebuilt binary for macOS and Linux — no toolchain, no postinstall script, # so it installs offline and inside a sandboxed CI npm install -g agentstow # or build from source — needs Rust 1.97 or newer cargo install agentstow
The npm package is a small launcher; the real binary ships in one platform
package per target, declared as optional dependencies so npm installs exactly the one
matching your machine. On a platform with no prebuilt binary you get a message naming
what it looked for and pointing at cargo install, rather than a
missing-file crash.
Windows is not supported. v1 is macOS and Linux. The symlink fan-out that makes drift impossible needs symlink creation to be unprivileged.
First five minutes
$ agentstow init
Created the Store at ~/.agents
skills/
commands/
subagents/
Found 6 agents: claude, codex, opencode, pi, oh-my-pi, gemini
3 skills not in the Store:
claude/skills/my-workflow
claude/skills/review-loop
codex/skills/notes
take one with `agentstow adopt <path>`
4 MCP servers not in the Store: serena, xapi, node_repl, computer-use
take them all with `agentstow mcp adopt --all`
init answers the question a used machine actually poses: not what
agentstow does, but what of your existing config it could take over. Adopt what you
want shared, then sync.
$ agentstow adopt ~/.claude/skills/my-workflow adopted my-workflow from claude into the Store (skills) $ agentstow mcp adopt --all adopted serena from claude scoped to claude — remove the allowlist in agentstow.toml to share it $ agentstow sync
adopt moves the real file into the Store and leaves a link behind. If
the Store already holds that name with identical contents it collapses the duplicate
into a link; if the contents differ it refuses and explains, because choosing which
side to discard is not agentstow's call.
The Store
~/.agents/ ├── skills/<name>/ a directory per skill ├── commands/<name>.md Claude-dialect markdown ├── subagents/<name>.md Claude-dialect markdown ├── AGENTS.md your shared instructions ├── mcp.json the standard mcpServers shape └── hooks/<Event>.toml [[hook]] entries: command, matcher, timeout
The Store is fixed at ~/.agents/. It holds ecosystem-standard content
only — nothing agentstow-specific lives there, which is what lets other tools read it
directly, as opencode and oh-my-pi already do. Tool configuration lives separately in
~/.agentstow/agentstow.toml.
The six families
- Skills, commands, subagents
- Symlink fan-out. One canonical relative link per entry in each agent's directory; links of ours that dangle are pruned; anything else is left alone.
- Instructions
- Three mechanisms, because agents differ in kind. A plain symlink where
the whole file can be ours (Codex, pi, oh-my-pi, Windsurf). An import line
for Claude, whose
CLAUDE.mdholds your own content, so agentstow only ensures@~/.agents/AGENTS.mdis present — additive and idempotent. A rules-dir link for Roo, which globs a directory. - MCP servers
- Rendered into each agent's dialect and key-merged. See below.
- Hooks
- Command-hooks declared once in
hooks/<Event>.tomland merged into Claude, Codex and Gemini by command string: agentstow owns exactly the array elements whose command matches a Store hook, and other tools' hooks in the same event array survive untouched. Codex trust hashes are never written — approving code execution stays your decision.
A file another tool already owns — claude-mem's boilerplate in opencode's
AGENTS.md, say — is a Conflict: reported with the
remedy named, never overwritten.
Ownership, without a state file
Everything agentstow writes must be recognisable as its own on a later run, with no database to consult. Three identities cover every mechanism.
- Link identity
- A symlink resolving into the Store is ours — canonicalised, and pruned when it dangles. A link resolving anywhere else is Foreign and is never touched.
- Name identity
- An entry key-merged into a shared file is ours when its name appears in the
Store; for hooks the command string is the name. Unknown names in the same file are
Foreign. One consequence is deliberate:
syncnever deletes an MCP server, because a name that vanished from the Store cannot be told apart from one you added by hand. Removal isagentstow mcp remove. - Marker identity
- A wholly generated file carries one comment line saying so. That is what makes pruning safe: removing a marked file returns the machine to a state agentstow created. An unmarked file at the same path was written by somebody else.
Reading status
| State | Means |
|---|---|
| linked | A canonical link onto the right Store entry. Nothing to do. |
| missing | The Store has it; this agent does not, yet. |
| stale | Our link, but not in canonical form — it will be rewritten. |
| dangling | Our link, pointing at a Store entry that is gone. It will be pruned. |
| variant | A real file or directory shadowing a Store entry, on purpose. Preserved. |
| variant-identical | Same, but byte-identical to the Store copy — a duplicate you can collapse. |
| foreign | Not ours. Reported, never modified. |
| conflict | Another tool owns a file agentstow would otherwise write. |
0 clean, 1 error, 2
something actionable. A Variant that diverges and a Foreign entry are settled
states, not work, so neither makes the exit code 2.MCP servers
One mcp.json in the standard shape is rendered into each agent's
dialect: Codex takes TOML tables with http_headers; opencode wants
local/remote with the command flattened into one array and
env renamed environment; Gemini distinguishes SSE from
streamable HTTP by which URL key it uses; Windsurf calls it serverUrl.
# ~/.agentstow/agentstow.toml [mcp.serena] agents = ["claude", "codex"] # default: every capable agent [mcp.node_repl.tweaks.codex] startup_timeout_sec = 120 # reaches Codex alone
Secrets are written as ${env:VAR} in the Store, resolved from the
environment at sync, and redacted from every line of output — so the Store stays
committable. If a resolved secret would land in a file others can read, agentstow says
so.
agentstow mcp adopt claude/serena reverse-translates an existing
server into the Store, turning agent-specific knobs into Tweaks. It proves the
result first: if re-rendering it would not reproduce what you already have, it
refuses rather than reporting a success that the next sync would undo.
CLI
| Command | Does |
|---|---|
| init | Create the Store skeleton and report what could be adopted. |
| sync | Fan the Store out to every installed agent. --dry-run previews. |
| status | What is in sync, what is not, what is not ours. --json. |
| adopt <path> | Absorb an existing config into the Store, leaving a link. |
| doctor | Installed agents, Store usability, hygiene warnings. |
| mcp list | Store servers and their state in every agent. --json. |
| mcp adopt | <agent>/<server>, or --all. |
| mcp remove | Delete a server from the Store and from every agent. |
agentstow.toml
Optional, at ~/.agentstow/agentstow.toml. Absent means defaults. It
never lives in the Store, so the Store stays ecosystem-standard content only.
[targets] cursor = false # leave this agent alone entirely [custom.myagent] # an agent the registry does not know root = ".myagent" skills = ".myagent/skills" [mcp.heavy-server] agents = ["codex"]
Many machines
agentstow does not sync across machines, deliberately — that would mean building conflict resolution, and git already won that argument. The Store is an ordinary directory, so version it:
# as a git repo cd ~/.agents && git init && git add . && git commit -m "my agent config" # or with chezmoi chezmoi add ~/.agents ~/.agentstow
On the second machine, clone it and run agentstow sync.
Vocabulary
- Store
- The canonical directory
~/.agents/holding the single real copy of everything agentstow syncs. - Target
- One agent's config surface that receives fan-out.
- Fan-out
- One Store entry materialised into every Target as a symlink.
- Native
- An agent that reads the Store directly and therefore needs no fan-out.
- Variant
- A real file or directory in a Target that intentionally shadows the Store copy for that agent alone. First-class and preserved, never clobbered.
- Adopt
- Absorbing an existing real file or directory from a Target into the Store, leaving a link behind.
- Foreign
- A link, file or server entry in a Target that agentstow does not own. Never touched, listed by
status. - Conflict
- A Foreign file occupying a destination agentstow would otherwise write — reported with the remedy named, never overwritten.
- Render
- Translating a Store entry into one agent's native format and merging it into that agent's config file.
- Managed
- An entry whose name appears in the Store: agentstow owns it in every targeted config, and the Store wins.
- Tweak
- A per-agent addition merged into one agent's rendering, declared in
agentstow.toml, never in the Store. - Marker
- The one-line comment in every generated file, making it recognisable as agentstow's without a state file.