← Default view
workflow· on: pull_request· 5 deterministic gates· 1 optional model check· survey · 17 sources

The per-PR floor,
$ rendered as a pipeline

What a 3-person team can run on every .claude/** change without standing up an eval platform — deterministic gates first, one cheap headless model check last. Each stage below is a real command and the tool that runs it.

claude-codecitesting pluginsskillsmcp
▮ decision

For a small team the realistic floor is deterministic, no-model-call checks gated on .claude/** paths: plugin validate --strict, JSON-schema validation against the official SchemaStore schemas, one sub-second frontmatter linter, and a "does it load" smoke test. Add at most one headless claude -p review — only after the deterministic layer is green. A full eval platform is overkill here, and honestly little is standardized yet. [2][1]

//

The pipeline

Left to right: each gate must pass before the next runs. The first three lanes never call a model — they finish in seconds, cost nothing, and can't flake. The fourth lane is optional, spends tokens, and is advisory only.

▸ TRIGGER on: pull_request — paths: ['.claude/**', '.claude-plugin/**', '.mcp.json'] — the cost-control lever: gates run only when extension files change [6]
STAGE 01

Deterministic lint

Manifest structure + SKILL.md frontmatter

No model call
claude plugin validate . --strict
# then one frontmatter linter:
npx pulser eval

runs: claude plugin validate (built-in) + pulser ⭐ 17

Catches: misspelled / leftover manifest fields (--strict = warnings-as-errors), unparseable YAML, missing description, the 1,536-char listing cap. [2][3]

STAGE 02

Schema validate

Manifests + MCP defs vs SchemaStore

No model call
npx ajv-cli validate \
  -s https://json.schemastore.org/\
claude-code-plugin-manifest.json \
  -d ".claude-plugin/plugin.json"

runs: ajv-cli / check-jsonschema → official SchemaStore schema

Catches: structurally invalid plugin.json/marketplace.json/.mcp.json. The community schema repo is now archived because Anthropic's schemas shipped to SchemaStore — use the official path. [2][8]

STAGE 03

Load smoke test

"Does it actually load?"

One trivial run
claude --bare -p "ok" --plugin-dir ./plug \
  --output-format stream-json --verbose \
| jq -e '.plugin_errors | length == 0'

runs: claude -p headless → parse system/init

Catches: plugins that fail to load. Docs say outright: "use the plugin fields to fail CI when a plugin did not load." --bare = same result on every machine; for MCP add --strict-mcp-config (⚠ doesn't override disabledMcpServers — pin a clean HOME). [1][4]

STAGE 04 · GATE

Headless model check

Optional · advisory · spends tokens

Optional · 1 model call
git diff origin/main | claude --bare -p \
  --append-system-prompt "review CC skills…" \
  --output-format json \
  --json-schema '{…"issues":[…]}' \
| jq -e '.structured_output.issues|length==0'

runs: claude -p · or claude-code-action ⭐ 8.1k

Catches: descriptions that won't trigger, references to missing files. Schema-conforming output lands in structured_output; payload carries total_cost_usd to budget. Keep it a single advisory check, not a hard gate. [1]

⚠ security caveat — stage 04 only

Any PR-triggered model run is a prompt-injection surface. A June 2026 disclosure showed a flaw where one malicious issue could hijack repositories through the Claude Code GitHub Action. Pin action versions, scope --allowedTools tightly (or --permission-mode dontAsk), and never grant write/secrets to fork-triggered runs. [14]

//

Stage-01 linters — pick exactly one

They overlap heavily; running more than one just duplicates findings. Stars are a triage signal — most are weeks-to-months old and single-maintainer. skill-validator is the most feature-complete (and the only one with built-in CI annotations); pulser is the fastest zero-dep option.

Validates plugin.json / marketplace.json structure. --strict = warnings-as-errors; wrong-typed fields fail even without it.

CLI · instantno depsmanifests
skill-validator ⭐ 174

Spec compliance, token counts (o200k_base), link resolution (HEAD), file hygiene, unclosed code fences. Optional LLM-judge score evaluate mode.

Go CLIpre-commitActions · --emit-annotations--strict
★ most feature-complete · only one with CI annotations
pulser ⭐ 17

5 checks: YAML parse, required fields, description quality, file structure, cross-refs. ~200ms / 40 skills, zero deps.

CLI · npxAction · pulserin/pulser@v1exit 0/1/2
★ fastest, zero-dependency option

Cross-agent skill schema (Claude / Codex / Cursor / …). name + description core plus per-flavor rules — keeps a skill portable.

npx @swarmclawai/agent-skills-lintcross-agent
SkillCheck hosted

Validates against the Agent Skills open standard (free). Pro adds anti-slop, WCAG, and security scanning.

hosted / webnot a CI gate

Pioneered JSON-schema for manifests — now archived, superseded by the official SchemaStore schemas. Use stage 02 instead.

archived→ use SchemaStore
//

Why the cheap layer is where the value is

73%
of 214 audited skills had silent structural defects in one community audit — treat the exact number as marketing, the direction as real: nobody is linting these files. [15]
~15s
added to the pipeline when skill linting is gated on .claude/** — paths filter keeps it off every other PR. [6]
$0
cost of stages 01–03 — deterministic, non-flaky, no model calls. The whole floor before you ever spend a token. [1]
1
built-in validator Anthropic ships (claude plugin validate); it's intentionally lenient, so deterministic community checks have a high catch rate. [2]
//

Marketplace-scale precedent & test corpora

Large marketplaces already gate manifests exactly this way — and these repos double as fixtures to test your own tooling against.

Runs claude plugin validate over marketplace.json + every plugin.json in CI so invalid manifests can't merge. [17]

The reference marketplace.json to diff your schema against. [18]

A clean small skill collection — a starting corpus to test tooling against. [19]

//

The minimum bar, in priority order

Stop wherever the budget for maintaining checks runs out. Steps 1–5 are the floor and they're enough.

1CI path filter on .claude/** + manifests so checks run only on extension changes. [6]5 min
2claude plugin validate --strict on every manifest. [2]built-in · free
3One frontmatter linterpulser or skill-validator — as a required check. [5][7]free · sub-second
4JSON-schema validate manifests/MCP defs against SchemaStore. [2]free
5"Does it load" smoke test via claude -p --output-format stream-json → assert empty plugin_errors. [1]one trivial run
6Optional, last: one headless claude -p model review of the diff with --json-schema, behind the security guardrails. [1][14]spends tokens

Anything beyond this — golden datasets, LLM-as-judge rubrics, statistical delta gates — is the eval-platform territory this brief deliberately leaves out. A local claude doctor belongs in the contributor checklist, not the gate. [13]

//

Sources

// view: pipeline · canonical: the lightweight per-PR floor · expedition: testing & regression-checking Claude Code agent extensions
// stages 01–03 are the floor — deterministic, free, non-flaky. stage 04 is the only place you spend a token.