[BUG] `claude plugin validate` silently validates zero skills when the manifest's skills path is `./.claude/skills` — no enumeration, no warning, exit 0

Status Open
Reported on v2.1.232
Maintainer reply None cached
Activity 1 comment · opened Aug 15, 2026

Summary

claude plugin validate (incl. --strict) validates zero skills when a plugin manifest's skills array points at ./.claude/skills — it prints ✔ Validation passed (exit 0) with no Validating skill: lines, no "0 skills found" notice, and no warning that the configured path was not enumerated. The identical skill files under a ./skills path are enumerated and validated normally.

The silence is the defect: a plugin author who configures a path the validator does not enumerate gets a green check that has never looked at a single skill, and --strict's documented promise ("Use in CI to fail on … issues that the runtime tolerates") is structurally unfulfillable for that plugin.

Environment

  • Claude Code CLI 2.1.232, macOS (darwin 25.5.0)

Reproduction (minimal, with a control)

Both variants contain the byte-identical control skill — a SKILL.md deliberately missing description, i.e. something the validator demonstrably warns about when it looks:

repro-a/
  .claude-plugin/plugin.json   → "skills": ["./.claude/skills"]
  .claude/skills/ctrl/SKILL.md → frontmatter with name only, no description
repro-b/
  .claude-plugin/plugin.json   → "skills": ["./skills"]
  skills/ctrl/SKILL.md         → identical bytes

plugin.json (variant A; B differs only in the skills value):

{
  "name": "repro-a",
  "version": "0.0.1",
  "description": "repro: dotclaude skills path",
  "author": { "name": "repro" },
  "skills": ["./.claude/skills"]
}

Actual output

Variant A (./.claude/skills):

Validating plugin manifest: …/repro-a/.claude-plugin/plugin.json

✔ Validation passed

exit 0 — no Validating skill: line at all; the defective control skill is never seen.

Variant B (./skills):

Validating plugin manifest: …/repro-b/.claude-plugin/plugin.json

Validating skill: …/repro-b/skills/ctrl/SKILL.md

⚠ Found 1 warning:

  ❯ description: No description in frontmatter. A description helps users and Claude understand when to use this skill.

✘ Validation failed (--strict treats warnings as errors)

exit 1 — enumerated and caught, as expected.

Expected

Either of these would close the trap; the first alone would already surface it:

  1. A configured skills entry that yields zero skills produces a loud warning (and a --strict failure) — "skills path ./.claude/skills matched no skills" — instead of silence. A validator run that inspected nothing should never be indistinguishable from one that inspected everything and found it clean.
  2. Ideally, the enumerator also handles the ./.claude/skills layout, since the runtime does load skills from it (see impact below) — validate and runtime currently disagree about the same manifest.

Real-world impact (how this stayed invisible)

Our published plugin (formtrieb/flotilla, manifest uses "skills": ["./.claude/skills"]) ships 15 skills that load and run fine at runtime. Five of them carry frontmatter the validator's own YAML parser rejects outright (YAML frontmatter failed to parse — unquoted description: values containing : , invalid as a YAML plain scalar, which the runtime parser tolerates). Every claude plugin validate run over the real manifest printed Validation passed — the parse failures only surfaced when we pointed the validator at the skills via a path form it enumerates. So the silent zero-coverage hid a real, validator-detectable defect class in a shipped plugin for weeks.

Related but distinct existing reports, for triage context: #77912 (validate passes hook commands referencing missing files), #82749 (marketplace git-sync silently drops invalid skills), #76448 (desktop loader ignores the skills array). This one is specifically: validate never enumerates the configured ./.claude/skills path and stays silent about it.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗