Summary
Installing a plugin whose repo root has an Agent Plugins $schema manifest and also ships native manifests (.claude-plugin/plugin.json) plus legacy component dirs (commands/, agents/, hooks/) fails. The same plugin installs fine before the $schema line is added. So adding a spec-conformant $schema to a manifest that coexists with a native/legacy layout — a very common intermediate state during migration — makes the plugin uninstallable.
Repro
agents.toml:
version = 1
agents = ["claude"]
[[plugins]]
name = "agent-skills"
# addyosmani/agent-skills#463 head — adds `$schema` to the root plugin.json
source = "addyosmani/agent-skills@0290b86c3dc998c22636a6a408f82ae05e16988c"
targets = ["claude"]
npx @sentry/dotagents@2.2.0 install
# 3.0.0: npx @sentry/dotagents@3.0.0 --project install
→
Failed to resolve plugin "agent-skills": Plugin "agent-skills" not found in
addyosmani/agent-skills@0290b86c... Matching marketplace entries use unsupported
source types: local, github. Only local marketplace sources are supported.
Control (same repo, the commit immediately before $schema was added) installs cleanly, commands + skills present:
source = "addyosmani/agent-skills@0.6.6" # ✅ installs
Adding path = "." swaps the (misleading) marketplace error for the real one:
Failed to resolve plugin "agent-skills": Agent Plugins v1 bundle contains legacy
root components: agents, commands, hooks, .claude-plugin, .codex-plugin.
Move client-specific resources into reverse-domain extension directories.
Root cause (traced in plugins/store.ts)
The upstream commit changes only the root plugin.json, adding:
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json"
This flips the root candidate to a standard manifest, so validateStandardBundleLayout runs and rejects the root because the same repo also has agents/, commands/, hooks/, .claude-plugin/, .codex-plugin/ at the root. With the root candidate rejected, resolveNamedPluginCandidate falls through to the marketplace outcome; addyosmani's .claude-plugin/marketplace.json entry uses a github source (unsupported), so the surfaced error is the marketplace one. Without $schema (the 0.6.6 state) the root is handled as a native/legacy plugin and installs fine.
Expected
A "hybrid" bundle — a standard $schema root manifest coexisting with native manifests (.claude-plugin/plugin.json) and/or legacy root dirs — should still install, ideally by falling back to native/legacy handling (exactly what happens today when $schema is absent) rather than hard-failing. Adding a spec-conformant $schema to an otherwise-working plugin shouldn't make it uninstallable.
Impact
Latent breakage for any consumer that pins such a plugin and later bumps to a release that adds $schema. Reproduces on 2.2.0 and 3.0.0. Real-world trigger: addyosmani/agent-skills#463.
Environment
@sentry/dotagents 2.2.0 and 3.0.0
- macOS, Node 20+
Summary
Installing a plugin whose repo root has an Agent Plugins
$schemamanifest and also ships native manifests (.claude-plugin/plugin.json) plus legacy component dirs (commands/,agents/,hooks/) fails. The same plugin installs fine before the$schemaline is added. So adding a spec-conformant$schemato a manifest that coexists with a native/legacy layout — a very common intermediate state during migration — makes the plugin uninstallable.Repro
agents.toml:→
Control (same repo, the commit immediately before
$schemawas added) installs cleanly, commands + skills present:Adding
path = "."swaps the (misleading) marketplace error for the real one:Root cause (traced in
plugins/store.ts)The upstream commit changes only the root
plugin.json, adding:This flips the root candidate to a standard manifest, so
validateStandardBundleLayoutruns and rejects the root because the same repo also hasagents/,commands/,hooks/,.claude-plugin/,.codex-plugin/at the root. With the root candidate rejected,resolveNamedPluginCandidatefalls through to the marketplace outcome; addyosmani's.claude-plugin/marketplace.jsonentry uses agithubsource (unsupported), so the surfaced error is the marketplace one. Without$schema(the0.6.6state) the root is handled as a native/legacy plugin and installs fine.Expected
A "hybrid" bundle — a standard
$schemaroot manifest coexisting with native manifests (.claude-plugin/plugin.json) and/or legacy root dirs — should still install, ideally by falling back to native/legacy handling (exactly what happens today when$schemais absent) rather than hard-failing. Adding a spec-conformant$schemato an otherwise-working plugin shouldn't make it uninstallable.Impact
Latent breakage for any consumer that pins such a plugin and later bumps to a release that adds
$schema. Reproduces on 2.2.0 and 3.0.0. Real-world trigger: addyosmani/agent-skills#463.Environment
@sentry/dotagents2.2.0 and 3.0.0