Skip to content
zero2vibecodelearn vibe coding
Level 6 · Electives 9 min Reviewed by the author · Oct 15, 2026 Verified against Claude Code v2.1.292 · Oct 15, 2026Official docs: Plugin evals, Plugins: publishSomething out of date? Tell us

Testing and publishing a plugin

claude plugin validate checks a plugin's files, claude plugin eval checks its behaviour by comparing runs with and without it. Publishing is a marketplace.json in a git repository, and a new version reaches users only when you bump version.

Level 6 · 0 / 4 lessons0%
In this lesson

In the plugins level you installed them. Now the other side: releasing your own in a way people can trust. There are two kinds of checks, and publishing turns out simpler than it seems.

Two checks

claude plugin validate reads files: manifests and frontmatter. With --strict, even a warning fails the check.

claude plugin validate --strict ./plugins/commit-helper
claude plugin validate --strict .

Check both the plugin and the marketplace: validating the marketplace looks at its file and each plugin’s plugin.json, but does not look inside skill files.

claude plugin eval measures behaviour. Each case is a prompt plus graders — checks that score the run. A case runs in a fresh, isolated session where only your is loaded: by default three times with it (the WITH arm) and as many times without it (W/OUT). The difference between their scores is Δ, the plugin’s own contribution.

The first case

cd plugins/commit-helper
claude plugin eval init --bare names-the-rename

--bare runs nothing: it creates prompt.md and a graders/criteria.md draft — a rubric for a judge model. It is usually replaced with free checks.

prompt.md is the prompt, with frontmatter:

---
max_turns: 10
allowed_tools: [Skill]
---

Write me a commit message for this change: I renamed getUser to fetchUser and updated the three call sites.

A run gets only the tools listed, so allowed_tools: [Skill] is what lets Claude run the skill. Two checks in graders/:

---
type: tool_used
tool: Skill
input_match: 'commit-message'
---
---
type: regex
pattern: 'fetchUser'
---

The first means “the skill ran”, the second “the answer contains a fact from the prompt”. Claude words things differently each time, so the regex looks for what the prompt supplied, not a specific phrase.

Which graders are free

GraderCost
regex, tool_used, tool_order, file_existsfree
llm, baselinea judge model call in every run

A good rule: one check on the result and one on the steps. Keep the judge for what free checks cannot see.

Running it

A cheap trial run — once, with the plugin only, the report stays with you:

claude plugin eval . --runs 1 --ablation none --no-publish

A full run with a threshold:

claude plugin eval . --threshold 0.8 --no-publish

Without --threshold, any case below a perfect score counts as failed. Results land in evals/results/ — keep those out of git, and commit the cases themselves.

One trap. The check “the skill did NOT fire on an unrelated request” is tool_used on Skill with min: 0 and max: 0. But in a run with two arms, tool_used graders on Skill do not count by default: without the plugin there is no skill. For the check to count, add arm: both.

Publishing and releasing

To publish is to put .claude-plugin/marketplace.json in a git repository and push. No application forms: whoever can clone the repository can install from it.

claude plugin marketplace add owner/claude-plugins
claude plugin install commit-helper@owner-plugins

The marketplace’s name comes from marketplace.json, not from the repository’s name. Some marketplace names are reserved — for example, anything starting with claudeai-.

A new release: bump version in plugin.json (and do not set a version of your own in the marketplace entry), push, and users update with:

claude plugin update commit-helper@owner-plugins

It ends with the line Restart to apply changes. If it says the version is already the latest, the new version has not been pushed yet.

Treat the plugin’s name as permanent: it is installed and configured as name@marketplace, and a renamed plugin is a different plugin for everyone. displayName exists for a new label.

Quick check

The eval table shows WITH 0.9, W/OUT 0.9, Δ 0. What does that mean?

Careful

Practice in the terminal

Check your understanding

Answered 0/3
Mode:

What does Δ show in a claude plugin eval report?

You fixed a skill and pushed the changes, but claude plugin update tells users they already have the latest version. Why?

Why does a tool_used grader on Skill in a "the skill must not fire" case need arm both?

Finish the task in the terminal and answer the questions to complete the lesson.

📝 My notes

Saved automatically in this browser · shows up on the Notes page.

Task

Prepare the commit-helper plugin for its 1.0.1 release: keep eval run results out of git, create the folder for the first eval case, and bump the version in the manifest.

Tab complete · ↑ history · Ctrl+L clear · help commands

  • Not done: Eval run results stay out of git
  • Not done: An eval case folder with graders exists
  • Not done: The manifest version is bumped to 1.0.1

Lesson Q&A

What does Δ show in a claude plugin eval report?

The difference between the score with the plugin (WITH) and without it (W/OUT) — what the plugin itself contributed — Each case runs in two arms: with the plugin and without. Δ = WITH minus W/OUT. If Δ is near zero, the plugin changes nothing — Claude would have managed anyway.

You fixed a skill and pushed the changes, but claude plugin update tells users they already have the latest version. Why?

version in plugin.json was not bumped — users get a new release only when it changes — If a plugin sets version, an update arrives only when it changes. Bump the version, push — and update installs it.

Why does a tool_used grader on Skill in a "the skill must not fire" case need arm both?

Otherwise, in a run with two arms, such a grader does not count toward the score — Without the plugin there is no skill at all, so by default tool_used graders on Skill are excluded from the score. arm both includes the check in both arms.

The eval table shows WITH 0.9, W/OUT 0.9, Δ 0. What does that mean?

Δ is the plugin's contribution. Zero means the result is the same without the plugin: either the cases are too easy, or the plugin is not needed.

Commands in this lesson

Terms in this lesson

Move between lessons with ← → · search with ⌘K

Written and reviewed by Mikhail Kuzmitskii