metadata.pluginRoot in marketplace.json is ignored — bare plugin source fails validation despite being documented
FOR HUMANS
Hi, Claude Code v2.1.179 detected a docs mismatch in how plugin metadata is structured, please see below. Have a nice day!
FOR A.I.
Summary
The docs say metadata.pluginRoot lets you write a bare plugin source (e.g. "formatter") instead of a ./-prefixed relative path. In practice the validator/resolver does not apply pluginRoot: a bare source fails with plugins.N.source: Invalid input. The two relevant doc rows also contradict each other.
Environment
- Claude Code
2.1.178and2.1.179(reproduces on both), macOS.
Docs in question
On https://code.claude.com/docs/en/plugin-marketplaces:
- The optional-fields table says:
> metadata.pluginRoot — Base directory prepended to relative plugin source paths (for example, "./plugins" lets you write "source": "formatter" instead of "source": "./plugins/formatter")
- The Plugin sources table says, for a relative-path string source:
> Local directory within the marketplace repo. Must start with ./.
These conflict: the first says a bare "source": "formatter" is allowed when pluginRoot is set; the second says a relative source must start with ./. The validator enforces the second and ignores pluginRoot.
Minimal reproduction
repro/
.claude-plugin/marketplace.json
plugins/formatter/.claude-plugin/plugin.json
plugins/formatter/.claude-plugin/plugin.json:
{ "name": "formatter", "version": "0.1.0", "description": "Minimal test plugin" }
.claude-plugin/marketplace.json — the exact documented pluginRoot example:
{
"name": "pluginroot-repro",
"owner": { "name": "repro" },
"metadata": { "pluginRoot": "./plugins" },
"plugins": [
{ "name": "formatter", "source": "formatter", "description": "bare source per docs pluginRoot example" }
]
}
Run:
claude plugin validate repro
Actual:
✘ Found 1 error:
❯ plugins.0.source: Invalid input
✘ Validation failed
Changing only the source to "./plugins/formatter" (leaving pluginRoot in place) → ✔ Validation passed. So pluginRoot has no effect; the ./ prefix is what's actually required.
Expected
Either:
- The resolver/validator applies
metadata.pluginRootso a baresourceresolves to<pluginRoot>/<source>(matching the docs), or - The docs drop the
pluginRoot-enables-bare-source affordance and state plainly that every relativesourcemust start with./.
Impact beyond validation
A marketplace published with bare sources still "adds" successfully, but each affected plugin is then treated as an unreadable remote source. In the /plugin Discover panel this shows up as a missing description and Will install: · Component summary not available for remote plugin, so the plugins look broken to anyone browsing the marketplace — with no error pointing at the real cause. (Found this on an internal team marketplace; claude plugin validate was what surfaced the actual source: Invalid input.)
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗