[BUG] Plugin agents silently collapse to one generic identity when a sibling's frontmatter has invalid multi-line YAML
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
When a plugin declares multiple agents via an explicit "agents" array in plugin.json (each agent as agents/<name>/AGENT.md), and any one of those agents' frontmatter description: field is a plain (unquoted, non-block-scalar) multi-line YAML value containing a blank line — e.g. the common description: Use this agent when X. Examples: pattern followed by a blank line and then <example>...</example> blocks — Claude Code fails to register the plugin's agents individually. Instead:
- Only a single generic
<plugin-name>:AGENTidentifier is exposed (not the expected<plugin-name>:<agent-name>scoped identifiers). - Invoking that generic identifier silently serves exactly one of the plugin's declared agents' content (which one varies — not always the same agent across runs/contexts).
- The remaining agents become completely inaccessible under any name, with no error, warning, or indication anywhere (not in
/plugin, not in--debugoutput that I could find) that anything was dropped.
This does not match the documented behavior for a YAML parse failure (plugin-marketplaces.md's validation-errors table: "YAML frontmatter failed to parse... At runtime this file loads with no metadata" — scoped to the one malformed file). Here, a parse issue in one agent file causes other, unrelated agent files in the same plugin to lose their registered identity entirely.
I initially assumed the collapsed identity's system prompt was a raw concatenation of multiple agents' bodies (I saw output like "...for Claude.You are a pragmatic software engineer..." and read it as two agents mashed together with no separator). On closer, verified inspection this was a misreading on my part — the collapsed agent reliably serves exactly one clean, coherent agent's content (not concatenated garbage), it's just registered under the wrong (generic, unscoped) identifier while its siblings vanish. I'm noting this in case anyone else searching for "concatenated agent prompt" symptoms lands here — the actual defect is silent collapse-to-one, not concatenation.
What Should Happen?
Every agent listed in a plugin's "agents" array should register under its own scoped identifier (<plugin-name>:<agent-name>), independent of whether a sibling agent's frontmatter has a YAML issue. If an individual agent file's frontmatter fails to parse, that specific file should degrade per the documented contract (loads with no metadata / is skipped), without affecting registration of any other agent in the same plugin.
Error Messages/Logs
Steps to Reproduce
Minimal repro, no special install method required — a personal Claude Code marketplace pointed at a local directory:
- Create a plugin directory:
````
my-repro/.claude-plugin/plugin.json
my-repro/agents/agent-one/AGENT.md
my-repro/agents/agent-two/AGENT.md
plugin.json:
``json``
{
"name": "my-repro",
"version": "0.0.1",
"description": "Minimal repro of agent-collapse bug.",
"agents": [
"./agents/agent-one/AGENT.md",
"./agents/agent-two/AGENT.md"
]
}
agents/agent-one/AGENT.md:
```markdown
---
name: agent-one
description: Use this agent when implementing something. Examples:
<example>
Context: User needs to add a feature
user: "Add secure storage for uploads"
assistant: "I'll invoke the agent-one agent to implement this."
<commentary>
Implementation requires expertise.
</commentary>
</example>
model: haiku
tools: ["Read"]
---
Agent ONE's system prompt body.
```
agents/agent-two/AGENT.md— same shape,name: agent-two, distinct body text.
- Register and install as a personal marketplace:
````
claude plugin marketplace add ./my-repro-marketplace-dir # dir containing .claude-plugin/marketplace.json + my-repro/
claude plugin install my-repro@<marketplace-name>
- In a fresh session, list available agent types (e.g. via the Agent tool, or
/context→ Custom Agents): onlymy-repro:AGENTappears. Neithermy-repro:agent-onenormy-repro:agent-twois registered. Invokingmy-repro:AGENTreturns one agent's content cleanly (not both).
Isolating variables (confirmed via a 2×2 test matrix): the trigger is specifically the combination of (a) an explicit "agents" array in plugin.json, and (b) a blank line inside an agent's frontmatter description: value. Removing either one independently is sufficient to fix it:
- Explicit array + blank line in description → collapses (bug reproduces)
- Explicit array + no blank line → registers both agents individually, correctly
- No explicit array (auto-discovery) + blank line → registers both agents individually, correctly
- No explicit array + no blank line → registers both agents individually, correctly
The <example>/<commentary> XML-like tags themselves are not the trigger — a variant with those tags but no blank line inside the frontmatter block resolves correctly. Only the blank line (in combination with the explicit array) matters.
Claude Model
None
Is this a regression?
Yes, this worked in a previous version
Last Working Version
_No response_
Claude Code Version
2.1.232
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
iTerm2
Additional Information
- This is exactly the same underlying YAML-parsing issue reported in #49727 (a plain scalar
description:terminating early at a blank line, with the following content parsed as an invalid key) — but with a different, narrower blast radius: #49727 reported crashing all plugin loading; this issue is scoped to one plugin's agents silently collapsing to a shared generic identity, with siblings vanishing without any error surfaced. #49727 was closed by stale-bot without a fix. - #40370 shows Anthropic's own bundled
claude-plugins-officialagents had this exact frontmatter defect (fixed viadescription: |block scalars in PRs #48338, #48341, #48342, #48343, #48344, #48348, #48349) — so this is a recurring authoring trap, not a one-off mistake, and even Anthropic's own plugin authors have hit it repeatedly. - #76985 shows the bundled
validate-agent.shlinter also mishandles this shape (grep '^description:'only reads the first physical line), so tooling doesn't catch it either. - We found this while debugging why a real internal plugin's 9 declared agents (
my-plugin) all collapsed into one genericmy-plugin:AGENTidentity serving only one agent's content. The fix that resolved it in production was addingdescription: |to each agent's frontmatter. We're filing this because the degradation behavior itself — one malformed file silently taking down sibling agents' registration with zero error surfaced — seems like the real defect worth fixing, independent of whatever plugin authors get wrong with their YAML.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗