Skip to content

CLI commands

CommandPurposeKey flags / args
init [<git-url>]Create ~/.agentsync/; optionally clone a bootstrap repo. --scope project / --project <path> scaffolds a project tree instead.--scope --project
doctorDiagnose setup: PATH, home/state writability, schema, secrets backend, destination-git-backup mode + per-dir repo status.
checkValidate the config: schema lint + unresolved ${secret:} / ${env:} refs. --scope project / --project <path> lints the project tree instead. (Renamed from verify.)--scope --project
agent add|remove|list|enable|disable <name>Manage the agent registry — the user’s, or a project tree’s own [agents] declaration with --scope project / --project <path>.disable --purge --scope --project
skill|subagent|command|hook|lsp listList that component in the canonical source (read-side only — none of these is flag-authorable).--scope --project
migrate subagentsOne-shot move of the retired canonical agents/ directory to subagents/ (rewrites that tree’s recorded source_id values).--scope --project
mcp add|remove|list|enable|disable <name>Manage MCP servers. enable/disable flip the enabled bit (keep the definition, stop rendering). --header "Name: Value" (repeatable, http/sse only) sets request headers — the usual remote-auth secret site.--type --command --args --url --env --agents --header
marketplace add|remove|list <url-or-name>Manage marketplaces.
plugin add|upgrade|enable|disable|remove <id[@marketplace]> / list / outdated / explainManage plugins (the lifecycle subcommands all accept the same id[@marketplace] ref add accepts; the bare id also works, and a qualifier naming a different marketplace than the one the plugin was installed from is refused).add <id[@marketplace]>
secret set|get|list|remove <key> / secret editManage age-encrypted secrets (list prints KEYS only; edit opens the whole vault, no <key>; set refuses an empty value unless --allow-empty).set --stdin
plugin outdated / plugin upgrade [<id>](network) Poll marketplaces and report pending bumps / re-fetch a plugin (or --all pending bumps) and run apply.upgrade --all --lossless --scope --project
applyRender source → write agent configs (offline). Git-versions each destination dir (opt-out).--agents --dry-run --scope --project --no-git-backup
revert <agent>Roll a destination dir back to a prior apply checkpoint (local-only git history).--agents --to --all --dry-run
statusSummarize drift / pending across agents (skill dirs collapse by default; converged displays as clean, --json keeps them distinct). --legend prints the nine-class glossary and exits. --exit-code → exit 2 on any drift, 0 when clean (CI gate).--agents --verbose --legend --json --exit-code --scope --project
diff [<path>]Show pending / drift changes; secrets redacted. --exit-code → exit 2 on any hunk, 0 when clean.--agents --json --exit-code --scope --project
reconcileInteractively merge drift back into source.--agents --auto-writeback --auto-override --auto-safe --scope --project
import <agent>[:<component>[:<name>]]Capture native config into source. --scope project captures the agent’s native project-scope config into the project tree.--dry-run --scope --project
plugin explain [<plugin>...]Show per-agent translation coverage for one or more plugins.--all --json
explain <path>[#<pointer>]Show what produced a destination file (or one merged key). Metadata only — never file content.--pointer --scope --project --json
versionPrint version information (alias for --version).

Creates the ~/.agentsync/ directory and its layout (user scope). Pass a git URL to clone an existing bootstrap config instead of starting empty (user scope only).

--scope project scaffolds a project source tree at <cwd>/.agentsync/ instead — the same on-disk layout as the user tree (agentsync.toml plus mcp/, lsp/, skills/, subagents/, commands/, hooks/, memory/ with fragments/, plugins/, secrets/), but no .state/ (apply records state centrally under ~/.agentsync/.state/, keyed by project root). --project <path> targets <path>/.agentsync/ and implies project scope; --scope user together with --project is an error. Commit the .agentsync/ tree to share project agent config with collaborators. Full guide: Project-local config.

A one-shot migration for a retired canonical layout. agentsync used to spell the canonical subagent directory agents/, one directory away from the [agents] harness registry in agentsync.toml — the same word naming two different types. The subagent side moved to subagents/; the harness side did not ([agents], --agents, and the agent command group are unchanged).

Until a tree is migrated, every command that loads the source refuses with a distinguishable error naming this command, and doctor reports it as a failing check. That refusal is deliberate: an unmigrated tree loads with zero subagents, and one apply would then delete every subagent it had already rendered.

Terminal window
agentsync migrate subagents # the user tree
agentsync migrate subagents --project ~/code/x # a project's committed tree

Interactively, the refusal offers to run the move for you. The move never overwrites: if a file exists under both agents/ and subagents/, it refuses with the colliding names and moves nothing. After a user-scope move, commit the rename — ~/.agentsync is usually a dotfiles repo.

A health check: verifies your PATH, that home and state directories are writable, that the config schema parses, and that the secrets backend is reachable. It also lists plugins installed natively in an agent (Claude and Codex) that aren’t in your source yet — run import <agent>:plugin to capture them. A Destination git backup section reports the configured [destination_directory_git_backup] mode (prompt/on/off) and, per versioned destination dir on disk, whether it is agentsync-versioned, under foreign source control, or untracked. An untracked candidate dir that contains a nested git repo below it is flagged as a warning, since apply refuses to init a repo inside a repo and skips git backup there. Run it first when something feels off.

Validates your config — the sibling of doctor, which validates your machine. Reach for doctor when something is set up wrong, and check when something is written wrong. (This command was named verify before v0.11.0; folding it into doctor --config was considered and declined, because check is scope-aware and doctor is not.)

It schema-lints the canonical source and surfaces every unresolved ${secret:…} / ${env:…} reference. Ideal for CI — see Verify config in CI. Pair with AGENTSYNC_ALLOW_OFFLINE_VERIFY=1 on runners without an age key: offline mode validates reference shape (a malformed ${secret:} still fails) but skips resolution, so a well-formed-but-unresolvable name only surfaces on a run without the flag.

Defaults to user scope. --scope project (walks up from cwd to the .agentsync/ tree) or --project <path> schema-lints the project source tree and validates its references — resolving ${secret:…} against the inherited user secrets backend, exactly as apply does, so the two never disagree. With no scope flag inside a project tree the choice is ambiguous: verify prompts project-vs-user, or fails closed under --no-input / a non-TTY stdin.


Manage which agents agentsync applies to.

Terminal window
agentsync agent add claude # register
agentsync agent list # registry + enabled state
agentsync agent list --all # every supported agent (registered or not)
agentsync agent disable opencode # stop applying (keeps source)
agentsync agent disable opencode --purge # also remove what it wrote

Every subcommand also takes --scope project / --project <path> to manage the project’s own [agents] declaration in <root>/.agentsync/agentsync.toml — the set project scope renders to (user-scope agents are never inherited; see Project-local config):

Terminal window
agentsync agent add claude --scope project # declare a project agent
agentsync agent list --project ~/code/myrepo # read a project's declaration
agentsync agent disable claude --purge --scope project # purge only this project's rendered files

Manage MCP servers. Full guide: MCP servers.

Terminal window
agentsync mcp add github --command npx --args "-y,@modelcontextprotocol/server-github"
agentsync mcp add linear --type http --url https://mcp.linear.app/sse \
--header "Authorization: Bearer ${secret:LINEAR_TOKEN}"
agentsync mcp list
agentsync mcp enable github
agentsync mcp disable github
agentsync mcp remove github

enable / disable flip the server’s enabled bit: the definition stays in the canonical source, but a disabled server stops rendering to every agent (the next apply removes what it had written). That is the difference from remove, which deletes mcp/<id>.toml outright. The enabled field and the loader that reads it both predate these verbs — until #200 F4 the only way to flip it was to hand-edit the TOML.

Flags: --type (stdio|http|sse), --command, --args, --url, --env, --agents, --header. --header "Name: Value" is repeatable and http/sse only (rejected for stdio); it sets request headers, the usual remote-auth secret site. A header value may reference a secret (--header "Authorization: Bearer ${secret:TOKEN}") — headers is an existing secret-resolving field, so the reference resolves at apply and re-references on capture, never landing in the canonical source as cleartext.

Manage plugin registries and the plugins drawn from them. Full guide: Marketplaces & plugins.

Terminal window
agentsync marketplace add github:anthropics/claude-plugins-official
agentsync plugin add atlassian@anthropic
agentsync plugin list

Manage the age-encrypted vault. Full guide: Secrets.

Terminal window
agentsync secret set github.token --stdin
agentsync secret get github.token
agentsync secret list
agentsync secret remove github.token
agentsync secret edit

secret set refuses an empty (or whitespace-only) value by default; pass --allow-empty to store one deliberately.

secret list prints keys only, never values, which is what lets it exist alongside secret editedit decrypts the whole vault into $EDITOR, and before list/remove it was the only way to see or delete a key.

secret get writes the raw value to stdout for piping. When stdout is a terminal it prints a caution first, since a bare secret get puts a live credential in your scrollback.


Renders the source and writes each agent’s native config. Offline — it never touches the network. --dry-run runs the full pipeline and prints the plan and translation report without writing a byte; each planned destination is labeled ✓ synced (already holds our exact bytes) or → write (would be created or changed), with a — N to write, M already synced tally, so an in-sync tree reads as a no-op rather than a list of pending writes.

Terminal window
agentsync apply --dry-run
agentsync apply

Destination git backup. After a successful user-scope apply that changes managed files, apply keeps each agent’s destination dir (~/.claude, ~/.codex, …) in its own local-only git repo and records a checkpoint commit, so a bad apply is one agentsync revert away — including the first apply: before the first apply overwrites a dir, agentsync records a pre-apply baseline commit of the prior content of the files it manages, so the apply checkpoint’s parent is the genuine pre-apply state and revert right after a first apply restores it. Pre-existing files agentsync did not write (credentials, transcripts, your own files) are left out of the history — untracked, so a revert leaves them untouched. They are preserved, not versioned: a revert never deletes them, but the history cannot restore one you delete. The first apply to an untracked dir prompts to enable this (opt-out); answer once and it’s remembered in [destination_directory_git_backup]. These repos are never pushed (the history may hold cleartext secrets, like the files it versions — which is why it stays local). A dir already under your own source control is left untouched. Pass --no-git-backup to skip it for one run (CI/scripting) without touching config. The [destination_directory_git_backup] table (mode = "prompt" | "on" | "off", optional author_name/author_email) controls the default; agentsync doctor shows the current mode and per-dir status. mode is validated at load — it must be exactly prompt, on, or off (case-sensitive; omit it for the prompt default). Any other value now errors at load with a path-prefixed message, rather than being silently ignored. See agentsync revert below.

Rolls an agent’s destination dir back to a prior apply checkpoint from its local-only git history — recovering from a bad apply. It is append-only: it records a new commit, so the history is never rewritten and the revert is itself revertible. Untracked files you dropped into the dir (and gitignored files) are left untouched — revert only rewinds the files agentsync versions, so your own scratch files are never deleted. By default it undoes the most recent apply (restores the previous checkpoint); --to <ref> picks a specific one (a commit hash or HEAD~2) and must name one of the dir’s own checkpoints — the current one or an ancestor; any other resolvable commit is refused. --all reverts every managed dir, and --dry-run previews the file changes without writing (noting when untracked files are present). Because the first apply records a pre-apply baseline (see apply above), even reverting a brand-new dir’s first apply works — it rolls back to that baseline rather than refusing with a “only one checkpoint” message.

revert moves only the destination. The next apply re-renders from the canonical source and would overwrite the reverted state, so revert prints a notice telling you to reconcile (agentsync reconcile / import) or fix the canonical source first. Only agentsync-managed (git-backed) user-scope dirs can be reverted.

Terminal window
agentsync revert claude # undo the most recent apply to ~/.claude
agentsync revert claude --to HEAD~3 # roll back further
agentsync revert --all --dry-run # preview reverting every managed dir

Full guide: Rolling back a bad apply.

Summarizes what’s out of sync across all agents — pending source changes and destination drift. To stay readable, each skill directory collapses to one row by default (the skill dir, its most-severe drift class, and a faint SKILL.md + N files count — with a per-class breakdown when the bundled files don’t all share one class), so a skill shipping hundreds of assets no longer floods the report. Pass -v/--verbose to expand every skill back to one row per bundled file. A one-line summary footer tallies items by drift class, and a brief “What apply will do:” legend follows it, explaining each class present (new will be created, pending will be updated to match source, drift will be overwritten — use reconcile to keep the edit, etc.). Clean items are tallied but never glossed.

Use --agents <list> (a comma-separated allowlist, matching mcp add --agents; * = all enabled) to scope the report — agentsync status --agents claude shows just Claude Code. Orphaned-state warnings still consider the full enabled set, so narrowing the view never mislabels a deselected agent as an orphan.

Pass --json to emit the structured drift report (per-agent items + a summary tally keyed by drift class) for CI gates or dashboards; advisory diagnostics still flow to stderr so the JSON payload stays clean. --json is never collapsed — it carries every tracked file regardless of the human view — and omits the legend (the class field is the machine contract).

The formatted report shows a converged item as clean. The two are distinct in the internal drift classifier — converged means the source and the destination changed independently but landed on the same value, versus clean where neither changed — but both mean apply has nothing to do, so the dashboard folds them into one word and one tally rather than surfacing a distinction only the classifier cares about. --json keeps the real classification, since a script may want it.

agentsync status --legend prints a standalone glossary explaining all nine drift classification statuses — including clean and converged spelled out separately, since that’s exactly the distinction the formatted view folds away — and exits without running the drift scan at all. It rejects being combined with --json, --exit-code, or --agents (all of which it would otherwise silently ignore) rather than accept-and-ignore them. A run whose summary has anything to explain ends with a one-line hint pointing at --legend; it’s suppressed whenever there’s nothing tracked to explain — the “no agents enabled” short-circuit, or an enabled agent that renders nothing yet (“(no tracked items)”).

For a gate that should fail the build on drift, add --exit-code: agentsync status --exit-code exits 2 when any item is not clean/converged and 0 when the tree is fully in sync (exit 2 is distinct from the generic error exit 1, and the report itself is emitted first with no extra error line). Without the flag, status always exits 0. Interactive prompts such as the scope menu are written to stderr, so a --json payload piped from stdout is never corrupted.

Shows the pending / drift changes in detail. Resolved secrets are redacted, so a piped diff can’t leak credentials. Pass a filesystem path to scope the diff; a path that no enabled agent renders (a typo, or an unmanaged file) is reported distinctly — path <p> is not managed by agentsync … — rather than the ambiguous no diff. --agents <list> narrows the diff to an agent allowlist exactly like status --agents (same validation and empty-rejection). Color is TTY-gated — piped output uses [-…-] / {+…+} text markers instead of raw ANSI. Pass --json for a structured hunk list (the same masked source/dest strings, so the redaction protects both modes), and --exit-code to exit 2 when any hunk exists (0 when clean) for a CI gate.

The interactive merge UX for drift and conflicts. Full guide: The daily loop. Non-interactive flags: --auto-writeback, --auto-override, --auto-safe.

Captures native config back into your canonical source. Drop parts of the selector to widen scope. The plugin component (Claude and Codex) captures installed plugins + their marketplaces by re-fetching them into the agentsync cache, so a real plugin import uses the network. A plugin’s marketplace is resolved from agentsync’s own registered marketplaces first, then the agent’s native config; a plugin whose marketplace is registered in neither (e.g. a built-in like claude-plugins-official you have not yet marketplace added) is reported and skipped.

--scope project (optionally --project <path>) reads the agent’s native project-scope config (e.g. <root>/.claude/) and captures it into the project source tree <root>/.agentsync/ instead of your user tree, seeding central state with the project scope + root so the next apply doesn’t foreign-collide. Plugin import is user-scope only: a named import claude:plugin:<name> --scope project errors, and a bulk import claude:plugin --scope project silently skips (plugins are a user-scope concept across the harnesses). Full guide: Already have configs?.

(network, writes state) Re-fetches every registered marketplace into the local cache, recomputes version pins, and prints the pending bumps — without touching any agent config. Despite the npm outdated prior it is not a pure read: it uses the network and it records each marketplace’s fetch timestamp + head SHA in .state/targets.json. It also re-checks every installed plugin’s manifest SHA and warns on a same-version re-upload. Full guide: Updating from the network.

(network) Re-fetches a plugin, updates its recorded version + manifest sha, and re-applies so the upgrade reaches your agents in the same command. --all first polls every marketplace (like plugin outdated), then upgrades every plugin with a pending bump and re-applies once. --lossless only upgrades when the candidate version introduces no new translation loss (an adapter skip) for an enabled agent — an excluded upgrade is reported, never silently dropped. --scope/--project resolve exactly as apply does.

The check renders every enabled agent and does not honour a plugin’s agents / native_agents, so it can decline over a loss falling on an agent the plugin is never projected to. A refusal on that basis says so and points at agentsync plugin explain <id>; if the affected agent is not listed there, the upgrade is safe for you and you can re-run without the flag. (Under --all that note prints once for the run, not once per bump.) A bump that could not be evaluated is excluded too, but reported separately and without that note — such a refusal is not about targeting, and dropping the flag is not the answer to it.

Terminal window
agentsync plugin outdated
agentsync plugin upgrade --all --lossless
agentsync plugin upgrade atlassian

Prints per-agent translation coverage for one or more installed plugins, without applying. Pass space-separated plugin ids to explain just those, or --all to explain every installed plugin (agentsync plugin list prints the ids). A ◐ partial row’s trailing note is split by kind — (N reduced · M dropped) — so it never reads as “N whole components discarded”: a reduced part still rendered, just without some fields the agent has no home for, while a dropped part had no native target and was not emitted. Each part is itemized beneath a framing header, tagged reduced or dropped with its reason, so the tally is never a dead end. Add --json for machine-readable output (rows for plugin/agent coverage — each with a skipDetails array of {component, name, reason, kind}, where kind is "reduced" or "dropped" and component is the plain kind).

A row’s coverage is one of "full", "partial", "none" — how much of what the plugin ships this agent got — or one of three values meaning it contributed nothing here by CONFIGURATION rather than by failed translation: "disabled" (the plugin is off for this scope, paired with disabled: true), "not-targeted" (its agents allowlist excludes this agent) or "native" (its native_agents list defers to this agent’s own plugin manager). The last two are paired with notTargeted: true; branch on the booleans rather than the strings.

Terminal window
agentsync plugin explain atlassian@anthropic
agentsync plugin explain atlassian@anthropic superpowers@obra
agentsync plugin explain --all

Answers “why does this file look like this?” for a destination an agent reads. diff tells you what changed; explain tells you where it came from — which is exactly what you need on a converged file, where diff is empty.

Terminal window
agentsync explain ~/.claude/agents/reviewer.md
agentsync explain ~/.claude.json#/mcpServers/github
agentsync explain ~/.claude.json --pointer /mcpServers/github
agentsync explain ~/.claude.json --json

Per item it reports the source of record (mcp/github.toml, subagents/reviewer.md, memory/AGENTS.md plus its fragments), the plugin origin when the component came from a projection, the adapter transform (what was reduced or dropped en route), the ownership (managed / untracked / foreign), the drift class in the classifier’s own vocabulary, and which ${secret:…} / ${env:…} references resolved there.

The argument splits on the last #; --pointer is the unambiguous escape hatch and wins over an in-argument #. Paths are symlink-resolved before matching, project scope is inferred when the path lies inside a project tree, and an unmanaged or typo’d path is reported distinctly (with the nearest managed path suggested) — mirroring diff [<path>].

One path can have several owners (the breadth tier shares ~/.agents/skills/), so output is grouped per owning agent, and two agents rendering different content to one path is surfaced as its own answer rather than an error.

For per-plugin translation coverage, see plugin explain.


FlagApplies toEffect
--scope user|projectroot flag — every scope-aware command (init, check, import, apply, status, diff, reconcile, explain, migrate, agent, mcp, plugin upgrade, the component lists)Force the config scope. Commands that act on per-machine state (doctor, revert, version, the plugin / marketplace / secret groups) refuse it with a reason instead of ignoring it.
--project <path>root flag — same set as --scopeTarget a specific project’s tree (implies --scope project).
--dry-runapply, importPreview without writing.
--auto-safereconcileAuto-resolve only no-risk drift classes. (The plugin-side flag of the same name became plugin upgrade --lossless — they meant two unrelated things.)
ls / rmevery list / remove subcommandAliases.
--jsonstatus, diff, explain, plugin explainEmit the structured payload to stdout (advisory diagnostics still go to stderr). plugin explain --json emits the translation rows; explain <path> --json emits the provenance envelope (and still emits it, with "unmanaged": true, on a path nothing renders).
--agents <list>apply, status, diff, reconcile, revertThe single “which agents” selector, with identical parsing everywhere (* = all enabled; an empty or unknown value is rejected identically by all five). On revert it is a spelling of the positional form — --agents, a positional agent, and --all stay mutually exclusive.
--exit-codestatus, diffExit 2 when drift (status) / any hunk (diff) exists, 0 when clean — for CI gates. Distinct from the generic error exit 1; prints no extra error line. Default (unset) always exits 0.
--legendstatusPrint a standalone glossary of all nine drift classification statuses (including clean/converged spelled out separately) and exit, skipping the drift scan. Cannot be combined with --json, --exit-code, or --agents — each would otherwise be silently ignored, so it errors instead. A status run whose summary has anything to explain hints at this flag.
--header "Name: Value"mcp addRepeatable; http/sse only. Sets a request header (secret refs allowed).
--color auto|always|neverallControl ANSI color + bold. Default auto (on for a TTY, off when piped/redirected; honors NO_COLOR).
-v, --verboseallVerbose logging. In status, also expands each collapsed skill directory back to one row per bundled file.
--versionrootPrint version information and exit. The agentsync version subcommand is an alias.

Every command splits what it prints into two kinds, and the difference is visible at a glance.

Diagnostics — anything that is a notice about the run — carry a level label and go to stderr:

✗ ERROR render codex: codex subagents feature-dev/code-reviewer and pr-review-toolkit/code-reviewer both resolve to the agent name "code-reviewer"; rename one or set distinct frontmatter names
⚠ WARN plugin component frontmatter is not strict YAML; parsed leniently (consider quoting values containing ': ')
path=~/.agentsync/.state/cache/plugins/pr-review-toolkit/agents/silent-failure-hunter.md
ℹ INFO scope: project (~/dev/app)

A fourth level, • DEBUG, exists in the vocabulary and is what --verbose unlocks, but nothing in agentsync currently logs at that level — so you will not see one today. It is the level a future library-side diagnostic would use.

The label is a glyph plus the level word, padded so message text always starts at the same column; wrapped detail lines hang under it. When color is on the label is bold red, bold yellow, or bold cyan; DEBUG is faint rather than bold. With color off — piped, redirected, NO_COLOR, or --color never — the glyph and the word carry the whole signal, so the level survives into a log file or a CI transcript.

This applies to the last line a failing run prints too: the terminal error is an ✗ ERROR diagnostic like any other, not a bare agentsync: … line.

Results — what the command was asked to produce — go to stdout and carry no level label. A --json payload, a status table, a diff, and a list are all results, which is why a warning never lands in the middle of one. A success outcome leads with an emoji chosen by what happened:

🎉 applied: 12 ops
✅ added agent: claude
🧹 removed mcp server: github
📥 imported 6 items from claude
🔙 reverted ~/.claude to checkpoint a1b2c3d
✨ agentsync home initialized at ~/.agentsync

Success lines deliberately carry no INFO: labeling an outcome would dilute the labels that mean something.