Upgrading
This page lists every change that needs you to do something after an upgrade, newest first. It is what the CLI’s one-time upgrade notice links to.
0.11.0
Section titled “0.11.0”A plugin an agent installs itself is no longer projected into that agent
Section titled “A plugin an agent installs itself is no longer projected into that agent”If you ran agentsync import claude and then agentsync apply while a plugin
was still enabled inside Claude Code, you ended up with two of everything that
plugin ships. Claude kept serving its own copy from its install dir, and
agentsync projected the same components into Claude’s standalone paths. Because
those components are namespaced, the two sets did not collide — they coexisted:
| Claude’s own copy | agentsync’s projection | |
|---|---|---|
| skill | /feature-dev:code-review | /feature-dev-code-review |
| subagent | feature-dev:code-reviewer | @agent-feature-dev-code-reviewer |
| hook | runs | runs again |
apply never writes plugin enablement back into an agent’s config — that is a
deliberate invariant, so agentsync never fights the agent’s own /plugin
UI — and it never removed it either. So the fix is not to project there.
plugins/<id>.toml gains native_agents: the agents whose own plugin
manager installs this plugin.
[plugin]id = "feature-dev@claude-plugins-official"agents = ["*"] # your fan-out choicenative_agents = ["claude"] # claude installs this itself — don't project thereagentsync import claude:plugin now asks, per plugin:
ℹ INFO claude already installs the plugin "feature-dev". agentsync can leave those components to claude, or project its own copy alongside them. Let claude keep serving this plugin? [Y]es / [n]o, project it there too:Accepting records native_agents = ["claude"]. Every other enabled agent still
receives the full fan-out — that is the reason to import a plugin in the first
place.
Declining is allowed, and warns you what it means: agentsync will duplicate the
plugin’s content in that harness, so you should disable or uninstall the plugin
there now that agentsync manages it. Under --no-input or a non-TTY stdin the
deferral is recorded without asking, so a scripted import never silently
produces two of everything.
What you need to do. Existing installs are unchanged until you act: your
plugins/*.toml have no native_agents, so apply keeps projecting exactly as
before. Either re-run agentsync import <agent>:plugin to record the deferral,
or add the key by hand. agentsync status and agentsync doctor now warn when
a plugin is installed in an agent and projected there, so you can see which
ones are affected.
To hand a plugin over to agentsync completely, uninstall it in the agent
(/plugin uninstall in Claude Code) and remove that agent from native_agents.
The next apply projects the components there.
agents in plugins/<id>.toml now actually narrows fan-out
Section titled “agents in plugins/<id>.toml now actually narrows fan-out”The agents allowlist has been documented since v1.0 and was never read: a
plugin with agents = ["codex"] still fanned out to every enabled agent. It now
works, and it composes with native_agents — a plugin renders for an agent only
if agents targets it and native_agents does not claim it.
If you narrowed a plugin’s allowlist expecting it to take effect, check it now: it will start being honoured on your next apply, and components that were previously written to the excluded agents are removed.
Plugin-provided components are namespaced by their plugin
Section titled “Plugin-provided components are namespaced by their plugin”A subagent, skill, or slash command that comes from an installed plugin now
renders under <plugin>-<name>. feature-dev’s code-reviewer becomes
feature-dev-code-reviewer; its code-review skill becomes
feature-dev-code-review.
This is what makes two plugins shipping the same component name work. Before,
feature-dev and pr-review-toolkit — both stock official plugins, both
shipping agents/code-reviewer.md — made agentsync status and agentsync apply exit 1, and there was no way to resolve it: both files live in the
marketplace-managed plugin cache, so you could not rename either one.
| Before | After |
|---|---|
~/.claude/agents/code-reviewer.md (collision — apply failed) | ~/.claude/agents/feature-dev-code-reviewer.md and ~/.claude/agents/pr-review-toolkit-code-reviewer.md |
/review | /feature-dev-review |
@agent-code-reviewer | @agent-feature-dev-code-reviewer |
What you need to do: invoke plugin-provided agents and commands by their new
names. If you have scripts, hooks, or --agent flags naming a plugin
component, update them.
Components you wrote yourself are not renamed. Only components projected
from a plugin are namespaced — anything in your own ~/.agentsync/ tree keeps
the name you gave it.
In the rare case where a plugin’s derived name lands on one of yours — you
wrote feature-dev-code-reviewer and the feature-dev plugin ships
code-reviewer — agentsync tells you, naming both sides, instead of picking a
winner. Rename your copy or disable the plugin to resolve it.
The old files are cleaned up for you. The next agentsync apply removes the
un-namespaced destination files agentsync previously wrote, so you are not left
with duplicate agents. A file you hand-edited since the last apply is backed up
under ~/.agentsync/.state/backups/ before removal, never silently discarded.
The v1.x CLI surface
Section titled “The v1.x CLI surface”The v1.x CLI surface was locked in this release, so several names moved. All of them are hard renames with no aliases — the old spellings fail, loudly, rather than working quietly for a while. Scripts and CI pipelines need updating.
| Old | New |
|---|---|
agentsync verify | agentsync check |
agentsync plugin install | agentsync plugin add |
agentsync secrets … | agentsync secret … |
agentsync explain <plugin> | agentsync plugin explain <plugin> |
agentsync update | agentsync plugin outdated |
~/.agentsync/agents/ | ~/.agentsync/subagents/ (run agentsync migrate subagents) |
The canonical subagent directory moved: agents/ → subagents/
Section titled “The canonical subagent directory moved: agents/ → subagents/”The canonical tree carried the [agents] harness registry (in
agentsync.toml) and the subagent files one directory apart — the same word
naming two different types. Only the subagent side moved.
agentsync migrate subagents # your ~/.agentsync treeagentsync migrate subagents --project ~/code/repo # a project's committed treeRun it once per tree. It moves the files and rewrites that tree’s recorded
source_id values in one step. If a file exists under both agents/ and
subagents/ it refuses and lists the collisions — nothing is ever overwritten.
After a user-scope move, commit the rename: ~/.agentsync is usually a dotfiles
repo.
Until you migrate, every command that loads the source refuses, naming this
command, and doctor reports it as a failing check. That is deliberate: an
unmigrated tree loads with zero subagents, and one apply would then delete
every subagent it had already rendered.
Nothing else named agents changed. The [agents] table, --agents on
status/diff/mcp add, the agents field on MCP/LSP servers, the agents
array in status --json, and the agentsync agent command group are all
exactly as they were. Rendered destination paths are untouched too — every
harness spells its own directory agents/, so the mapping is now deliberately
asymmetric (subagents/reviewer.md → ~/.claude/agents/reviewer.md).
verify is now check
Section titled “verify is now check”verify and doctor overlapped with no stated boundary. They now split along
the axis they actually differ on: doctor validates your machine (PATH,
home/state writability, adapter detection, secrets backend, destination git
state); check validates your config (schema lint plus every
${secret:…}/${env:…} reference, scope-aware). Reach for doctor when
something is set up wrong and check when something is written wrong.
AGENTSYNC_ALLOW_OFFLINE_VERIFY keeps its name — it names the behavior, not the
command.
The noun groups share one verb set
Section titled “The noun groups share one verb set”plugin install became plugin add (every other group creates with add, and
“install” wrongly suggested installing into the agent), and the secrets group
became singular secret. Both are hard renames.
Two gaps closed at the same time: mcp enable / mcp disable (the
enabled field already existed and the loader already read it — only a
hand-edit could flip it), and secret list / secret remove (previously
secret edit, which decrypts the whole vault into $EDITOR, was the only way
to see or delete a key). secret list prints keys only.
Every component you can author, you can now list
Section titled “Every component you can author, you can now list”skill, subagent, command, hook, and lsp each gained list (and ls).
There is no add for them on purpose — unlike an MCP server, none is
flag-authorable.
--scope / --project are root flags
Section titled “--scope / --project are root flags”Declared once, inherited everywhere. mcp add … --scope project now actually
writes the project tree (it used to silently write the user tree), and a command
that cannot honor scope — doctor, revert, version, and the plugin /
marketplace / secret groups — refuses the flag with the reason instead of
ignoring it.
--agents works on apply now
Section titled “--agents works on apply now”apply had no --agents while status / diff did, so the filter you use in
the daily loop vanished at the one step that writes. apply, status, diff,
reconcile, and revert all take it now, with identical parsing.
Plugin lifecycle verbs moved under plugin
Section titled “Plugin lifecycle verbs moved under plugin”| Before | After |
|---|---|
agentsync update | agentsync plugin outdated |
agentsync update --apply | agentsync plugin upgrade --all |
agentsync update --apply --auto-safe | agentsync plugin upgrade --all --lossless |
agentsync explain <plugin> | agentsync plugin explain <plugin> |
agentsync explain --list | agentsync plugin list |
updatewas removed, with no alias. A draft of this release kept a deprecated forwarding alias for one minor, sinceupdateis the spelling most likely to sit in a cron line. It was cut before shipping: it would have been the only alias in a release whose point is that the renames are hard, and “no aliases except this one” is a worse rule to remember than “no aliases”. A cron line callingagentsync updatenow fails as an unknown command, and “louder” here means something specific: what a scheduler acts on is the exit status, not the text. A deprecation warning would have gone to the same discarded stderr as everything else, leaving the job green while doing nothing; a non-zero exit is the one signal cron, systemd, and CI all actually surface.explainhas no alias either, and it is the one change that can break a script silently: the top-level name still exists but now answers a different question (see below), soagentsync explain <plugin-id>fails from this release. That is most of why the upgrade notice exists.plugin upgrade <id>now re-applies. It used to re-fetch and leave your agents stale until the nextapply; both it and--allnow finish by re-applying, so one verb has one ending state.--auto-safebecame--losslesson the plugin side only, because the name meant two unrelated things.reconcile --auto-safeis unchanged.
New: agentsync explain <path>
Section titled “New: agentsync explain <path>”The freed name answers “where did this file come from?” — which canonical file, which plugin, what the adapter changed on the way, and whether it has drifted.
agentsync explain ~/.claude/agents/reviewer.mdagentsync explain ~/.claude.json#/mcpServers/githubIt prints metadata only — never file content — so unlike diff it still answers
with a locked secrets vault. Full details in
the CLI reference.