Test Runner
This project is a Claude Code plugins marketplace. "Tests" here means verifying the repository structure, version consistency, JSON syntax, and SKILL.md/agent frontmatter validity.
Process
- Determine test scope:
- If
$ARGUMENTScontains--base-commit <sha>: rungit diff --name-only <sha>to get changed files (includes committed, staged, and unstaged changes) - Otherwise: run
git diff --name-only HEADto detect changed files (if HEAD is unavailable or no changed files detected, run full verification) - Any change touching
.claude-plugin/marketplace.json,plugins/**,skills/**, or.claude-plugin/plugin.jsonshould trigger full verification. If only unrelated files (e.g.README.md,CHANGELOG.md,docs/**) changed, still run full verification
- If
- Spawn a subagent (Agent tool, subagent_type:
general-purpose,model: sonnet) to execute verification — passsonnetas theAgenttool'smodelparameter. - Return the subagent's structured summary to the caller
Subagent Instructions
Verify this Claude Code plugins marketplace repository. Perform the following checks yourself, directly, in this agent, using Read/Bash/Glob — do not spawn a nested
Agentand do not dispatch anySkill(). Re-delegation is an observed failure mode: the executor stops to wait on its child and returns no verdict, which the caller then treats as a parse failure. Return a structured summary.Checks
Load marketplace manifest: Read
.claude-plugin/marketplace.json. Extract thepluginsarray. For each plugin, capturename,source,skills(optional), andversion.Skill entity existence: Verify each
skills/*/directory containsSKILL.md.Plugin source directory structure: For each plugin in marketplace.json, dispatch by
sourceprefix:
- If
sourcestarts with./skills/(direct-skill plugin): verify<source>/SKILL.mdexists andskills: ["./"]is present- If
sourcestarts with./plugins/(wrapper plugin): verify<source>/exists; if<source>/skills/exists, each entry under it must be either a symlink (usereadlink) resolving to an existingskills/<skill>/SKILL.mdor a real directory containingSKILL.md; if<source>/agents/exists, each.mdfile must have YAML frontmatter; if<source>/.claude-plugin/plugin.jsonexists, its JSON must be valid
- Real directories are expected, not a defect. Do not report a real directory as a broken/missing symlink. Content equality between a real-directory copy and its canonical
skills/<name>/is out of scope here:verify-bundle-syncowns that check- Additionally, for wrapper bundles (wrapper plugin with
skillsarray of specific paths like./skills/<name>): verify each path inskillsarray resolves to an existingskills/<name>/SKILL.md, AND verify the set of paths matches the set of entries under<source>/skills/(each entry has a correspondingskillsentry, and vice versa — detect drift in either direction)Version consistency: For each plugin, if
<source>/.claude-plugin/plugin.jsonexists (only possible for./plugins/sources), verify itsversionmatches marketplace.json.JSON syntax: Validate
.claude-plugin/marketplace.jsonand everyplugins/*/.claude-plugin/plugin.jsonwithjq empty.Frontmatter presence: Verify each
skills/*/SKILL.mdand each agent file (plugins/*/agents/*.md) starts with---on the first line (YAML frontmatter).Cross-member directive identity: for each path in the
dev-workflow-bundleplugin'sskillsarray, verify<path>/SKILL.mdcontains a line that is exactly## Dispatch authorization(an anchored whole-line match — a heading carrying extra text, e.g.## Dispatch authorization (caller-side), does not count and is reported as missing), and that that section's body — the lines between that heading and the next##heading (or end of file, if it is the last##section), with leading and trailing blank lines trimmed — is identical character-for-character, internal whitespace included, across every member, taking the first member that has the section as the reference body.Readeach member's section and compare the delimited bodies directly — the directive sits in each member's preamble (within the first ~170 lines of every current member), so passReadanoffset/limitwindow around the heading instead of reading whole files. The sections that follow the directive differ per member, so comparing anything wider than the delimited body reports false divergence. Report any member that is missing the section or whose body diverges.Return Format
Return a structured summary with one of three statuses:
Status: SUCCESS
- All checks passed
- Per-check summary: counts (e.g., "15 skills verified, 13 plugins, 0 version mismatches")
Status: TEST_FAILED
- Per-check results with failures highlighted
- For each failure:
- The specific check that failed
- File path and what was expected vs actual
- Remediation hint (e.g., "recreate symlink", "bump version in plugin.json")
- Keep the summary concise but include enough detail to fix without re-running
Status: EXECUTION_ERROR
- Command that failed to execute (e.g.,
jqmissing, marketplace.json unreadable)- Error output
- This status is for infrastructure/environment errors, not verification failures