Skip to content

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.

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 copyagentsync’s projection
skill/feature-dev:code-review/feature-dev-code-review
subagentfeature-dev:code-reviewer@agent-feature-dev-code-reviewer
hookrunsruns 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 choice
native_agents = ["claude"] # claude installs this itself — don't project there

agentsync 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.

BeforeAfter
~/.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 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.

OldNew
agentsync verifyagentsync check
agentsync plugin installagentsync plugin add
agentsync secrets …agentsync secret …
agentsync explain <plugin>agentsync plugin explain <plugin>
agentsync updateagentsync 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.

Terminal window
agentsync migrate subagents # your ~/.agentsync tree
agentsync migrate subagents --project ~/code/repo # a project's committed tree

Run 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 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.

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.

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.

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.

BeforeAfter
agentsync updateagentsync plugin outdated
agentsync update --applyagentsync plugin upgrade --all
agentsync update --apply --auto-safeagentsync plugin upgrade --all --lossless
agentsync explain <plugin>agentsync plugin explain <plugin>
agentsync explain --listagentsync plugin list
  • update was removed, with no alias. A draft of this release kept a deprecated forwarding alias for one minor, since update is 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 calling agentsync update now 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.
  • explain has 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), so agentsync 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 next apply; both it and --all now finish by re-applying, so one verb has one ending state.
  • --auto-safe became --lossless on the plugin side only, because the name meant two unrelated things. reconcile --auto-safe is unchanged.

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.

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

It prints metadata only — never file content — so unlike diff it still answers with a locked secrets vault. Full details in the CLI reference.