[BUG] `claude plugin validate` hard-errors on `argument-hint` bracket syntax that the runtime accepts (coerces to string)
Summary
claude plugin validate rejects a SKILL.md whose argument-hint frontmatter value uses the documented bracket form (e.g. argument-hint: [issue-number]), reporting a fatal "YAML frontmatter failed to parse" error. But the runtime accepts the same file — it coerces the argument-hint value to a string (the fix shipped for #25826 / #22161). The bundled validator was never aligned with that runtime coercion, so it produces false positives for a pattern that:
- the official docs show as the example (
skills.md,argument-hintrow: "Example:[issue-number]or[filename] [format]"), and - the runtime explicitly tolerates by design.
Net effect: skills that load and run perfectly are reported as broken by the project's own validator.
Environment
- Claude Code v2.1.187 (macOS)
- Runtime coercion fix referenced: #25826 / #22161 (closed, fixed 2026-02-18)
Steps to reproduce
- Create a skill
my-plugin/skills/demo/SKILL.md:
``yaml`
---
name: demo
description: Demo skill.
argument-hint: [<plan-path>] "<note>"
---
Body.
argument-hint: [issue-number]` triggers the same behavior.)
(The docs' own simpler example
- Run
claude plugin validate ./my-plugin.
Actual
✘ Found 1 error:
❯ frontmatter: YAML frontmatter failed to parse: YAML Parse error: Unexpected token.
At runtime this skill loads with empty metadata (all frontmatter fields silently dropped).
✘ Validation failed
Expected
Validation passes (optionally with a warning suggesting quotes), consistent with how the runtime handles the same value. The validator should apply the same argument-hint string-coercion the runtime uses, rather than hard-failing.
Why this is genuinely inconsistent
A leading [ makes the value a YAML flow sequence, so a strict parser rejects it — confirmed independently with PyYAML:
import yaml
yaml.safe_load('argument-hint: [<plan-path>] "<note>"') # -> ParserError (block mapping)
yaml.safe_load("argument-hint: '[<plan-path>] \"<note>\"'") # -> OK (quoted, parses to string)
The point is not "the YAML is technically loose" — it's that the same product behaves two ways on the same input: the runtime coerces and runs fine (#25826), while the bundled claude plugin validate hard-errors. The validator should match the runtime.
The error text "At runtime this skill loads with empty metadata (all frontmatter fields silently dropped)" also appears inaccurate post-#25826 — the runtime renders name/description fine for these files.
Secondary: authoring guidance gap (docs)
The trap is easy to hit because the canonical guidance leads authors straight into it and never warns about quoting:
skills.mddocumentsargument-hintwith the example[issue-number]/[filename] [format]— i.e. it demonstrates exactly the unquoted bracket form that is parsed as a YAML flow sequence rather than a string.- The official
plugin-devplugin'sskill-developmentskill documents SKILL.md frontmatter as onlyname/description/version— it never mentionsargument-hint, and gives no guidance on quoting frontmatter values that begin with YAML-structural characters ([,{,*,&,!).
Suggested doc fixes:
- In
skills.md, quote the examples (argument-hint: '[issue-number]') and add a note: "Frontmatter values beginning with[,{,*,&,!are interpreted as YAML structures; wrap them in single quotes to keep them as strings." - In the
skill-developmentskill, listargument-hint(andallowed-tools,disable-model-invocation) among the frontmatter fields and add the same quoting note.
Related
- #25826 / #22161 — runtime crash fixed via string coercion (validator not aligned)
- #62127 —
argument-hintnot displayed in hint area (separate display issue)
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗