Skip to content

Plugin with a standard $schema root manifest + native/legacy components fails to install #161

Description

@mohdhassaan

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+

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions