LinkLoomAI Editorial

MarkTechPost(Asif Razzaq)

综合资讯Agent 与工具昨天 05:05精选

78

Score

Anthropic Adds Plugin Evals to Claude Code: 6 Grader Types, a No-Plugin Baseline, and a CI Gate for Skills

AI 摘要

模型生成,可能有偏差;请以原文为准

Anthropic 在 Claude Code v2.1.269 及以上版本中上线了插件评测工作流 claude plugin eval。该工具通过 6 种评分器(含免额外费用的本地检查及大模型裁判)运行双臂对照实验,自动对比加载与未加载插件的表现差异 Δ,并支持设定阈值和成本上限集成至 CI 门禁。这为开发者量化评估 Skill 触发率及实际增益提供了标准化的工程测试方案。

正文

Anthropic has published a new plugin evals workflow for Claude Code. The claude plugin eval command runs a plugin against realistic prompts, grades what Claude produced, and compares the result with a run where the plugin is not loaded. It answers 3 questions plugin developers could not previously measure: does the skill trigger, does it survive an edit or a new model, and does it beat a bare model.

Deployable: Yes. It runs on Claude Code v2.1.269 or later against any directory with a plugin.json or .claude-plugin/plugin.json manifest, or a skills-directory plugin. Every eval run and judge grader is a real model call billed to your plan or API account.

What a case looks like

An eval suite lives in an evals/ directory inside the plugin. Each case is a subdirectory holding a prompt.md and a graders/ folder. The prompt body goes to Claude exactly as written, and @path mentions are not expanded. Frontmatter on prompt.md can set max_turns (default 10), timeout_seconds (default 300), model, tags, and allowed_tools.

Graders are markdown files whose frontmatter sets a type, an optional weight, and an optional arm. There are 6 types. Four cost nothing because they are computed from the transcript and the files on disk: regex, tool_used, tool_order, and file_exists. Two call a judge model and add to the bill: llm, which scores the reply against prose criteria you write, and baseline, which compares it against a reference answer.

claude plugin eval init reads the plugin, asks what a good result looks like, proposes cases and graders, tries them, and writes the files. In CI, --bare writes a blank template instead.

The number that matters is Δ

By default every case runs twice: a with-arm where the plugin is loaded and a without-arm where it is not. Their difference, Δ, is what the plugin contributed. If a case scores 1.0 in both arms, the plugin is not why it passed. The docs example output shows a single case at WITH 1.00, W/OUT 0.33, Δ +0.67 across 6 runs, costing an estimated $0.41 and taking 74 seconds. A grader marked with-only, typically tool_used: Skill, is reported as an indicator and excluded from the score, since the without-arm has no skill to fire.

Anthropic calls out the most common first finding: a Δ near zero with the tool_used: Skill grader failing, which means Claude is not choosing the skill on natural phrasing. That is the defect claude plugin validate cannot see, because it checks manifest syntax and schema rather than behavior.

Results land under evals/results//report.html with per-grader verdicts and judge votes. Where the account supports it, the report is also published to claude.ai unless --no-publish is set.

Cost and CI

A suite makes roughly cases × runs × arms agent runs, plus 3 short judge calls per llm or baseline grader per run, and results vary between runs. The documented CI invocation is:

claude plugin eval . \
  --trust-plugin \
  --json results.json \
  --threshold 0.8 \
  --model claude-sonnet-5 \
  --judge-model claude-haiku-4-5 \
  --no-publish \
  --max-cost-usd 20

The runner needs a Claude Code install and credentials such as ANTHROPIC_API_KEY. Without --trust-plugin, an untrusted checkout is refused with exit 1 when there is no terminal. Report problems never change the exit code, and --json suppresses progress output.

Interactive explainer

<meta name="viewport" content="width=device-width,initial-scale=1"><style>html,body{margin:0;padding:0;background:transparent}</style></head><body><style> #mtp-plugin-evals{--bg:#1F1E1D;--panel:#2A2927;--line:#3D3B38;--cream:#F0EFE8;--muted:#B1ADA1;--orange:#D97757;--orange2:#F2A57F;--green:#7FB77E;--red:#E36B5B;--mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;--sans:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif;background:var(--bg)!important;color:var(--cream)!important;font-family:var(--sans)!important;border:1px solid var(--line)!important;border-radius:14px!important;padding:22px!important;max-width:820px!important;margin:0 auto!important;line-height:1.45!important;box-sizing:border-box!important} #mtp-plugin-evals *{box-sizing:border-box!important} #mtp-plugin-evals h3,#mtp-plugin-evals h4,#mtp-plugin-evals p{margin:0!important;color:var(--cream)!important} #mtp-plugin-evals .pe-head{display:flex!important;align-items:baseline!important;justify-content:space-between!important;gap:12px!important;flex-wrap:wrap!important;margin-bottom:14px!important} #mtp-plugin-evals .pe-head h3{font-size:19px!important;font-weight:600!important;letter-spacing:-.01em!important} #mtp-plugin-evals .pe-head span{font-family:var(--mono)!important;font-size:12px!important;color:var(--orange)!important;background:rgba(217,119,87,.12)!important;border:1px solid rgba(217,119,87,.4)!important;padding:3px 9px!important;border-radius:999px!important} #mtp-plugin-evals .pe-tabs{display:flex!important;gap:6px!important;flex-wrap:wrap!important;margin-bottom:16px!important} #mtp-plugin-evals .pe-tab{background:var(--panel)!important;color:var(--muted)!important;border:1px solid var(--line)!important;border-radius:8px!important;padding:8px 13px!important;font-size:13px!important;cursor:pointer!important;font-family:var(--sans)!important;transition:all .2s!important} #mtp-plugin-evals .pe-tab:hover{color:var(--cream)!important;border-color:var(--orange)!important} #mtp-plugin-evals .pe-tab.on{background:var(--orange)!important;color:#1F1E1D!important;border-color:var(--orange)!important;font-weight:600!important} #mtp-plugin-evals .pe-tab:focus-visible,#mtp-plugin-evals button:focus-visible{outline:2px solid var(--orange2)!important;outline-offset:2px!important} #mtp-plugin-evals .pe-pane{display:none!important} #mtp-plugin-evals .pe-pane.on{display:block!important;animation:peFade .3s ease!important} @keyframes peFade{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}} #mtp-plugin-evals .pe-lead{color:var(--muted)!important;font-size:14px!important;margin-bottom:14px!important} #mtp-plugin-evals .pe-grid{display:grid!important;grid-template-columns:1fr 1.2fr!important;gap:14px!important} #mtp-plugin-evals .pe-tree{background:var(--panel)!important;border:1px solid var(--line)!important;border-radius:10px!important;padding:12px!important;font-family:var(--mono)!important;font-size:13px!important} #mtp-plugin-evals .pe-node{display:block!important;width:100%!important;text-align:left!important;background:transparent!important;border:1px solid transparent!important;border-radius:6px!important;color:var(--muted)!important;padding:5px 8px!important;cursor:pointer!important;font-family:var(--mono)!important;font-size:13px!important;transition:all .15s!important} #mtp-plugin-evals .pe-node.dir{color:var(--cream)!important;cursor:default!important} #mtp-plugin-evals .pe-node.file:hover{color:var(--cream)!important;border-color:var(--line)!important} #mtp-plugin-evals .pe-node.file.on{color:var(--orange2)!important;background:rgba(217,119,87,.12)!important;border-color:rgba(217,119,87,.4)!important} #mtp-plugin-evals .pe-node .d1{padding-left:14px!important;display:inline-block!important} #mtp-plugin-evals .pe-node .d2{padding-left:28px!important;display:inline-block!important} #mtp-plugin-evals .pe-node .d3{padding-left:42px!important;display:inline-block!important} #mtp-plugin-evals .pe-code{background:#151412!important;border:1px solid var(--line)!important;border-radius:10px!important;padding:12px 14px!important;font-family:var(--mono)!important;font-size:12.5px!important;color:var(--cream)!important;white-space:pre-wrap!important;word-break:break-word!important;min-height:180px!important;margin:0!important;line-height:1.55!important} #mtp-plugin-evals .pe-code .k{color:var(--orange2)!important} #mtp-plugin-evals .pe-code .c{color:var(--muted)!important} #mtp-plugin-evals .pe-note{font-size:13px!important;color:var(--muted)!important;margin-top:10px!important;padding:10px 12px!important;border-left:3px solid var(--orange)!important;background:rgba(217,119,87,.07)!important;border-radius:0 8px 8px 0!important} #mtp-plugin-evals .pe-btn{background:var(--orange)!important;color:#1F1E1D!important;border:0!important;border-radius:8px!important;padding:10px 16px!important;font-size:14px!important;font-weight:600!important;cursor:pointer!important;font-family:var(--mono)!important;transition:transform .1s,opacity .2s!important} #mtp-plugin-evals .pe-btn:hover{transform:translateY(-1px)!important} #mtp-plugin-evals .pe-btn:disabled{opacity:.5!important;cursor:wait!important} #mtp-plugin-evals .pe-btn.ghost{background:transparent!important;color:var(--cream)!important;border:1px solid var(--line)!important} #mtp-plugin-evals .pe-arms{display:grid!important;grid-template-columns:1fr 1fr!important;gap:14px!important;margin-top:14px!important} #mtp-plugin-evals .pe-arm{background:var(--panel)!important;border:1px solid var(--line)!important;border-radius:10px!important;padding:12px!important} #mtp-plugin-evals .pe-arm h4{font-size:14px!important;font-weight:600!important;margin-bottom:8px!important;display:flex!important;justify-content:space-between!important} #mtp-plugin-evals .pe-arm h4 em{font-style:normal!important;font-family:var(--mono)!important;color:var(--muted)!important;font-size:12px!important} #mtp-plugin-evals .pe-run{display:grid!important;grid-template-columns:52px 1fr 1fr 1fr!important;gap:6px!important;align-items:center!important;padding:6px 0!important;border-top:1px dashed var(--line)!important;font-family:var(--mono)!important;font-size:12px!important} #mtp-plugin-evals .pe-run:first-of-type{border-top:0!important} #mtp-plugin-evals .pe-run .lbl{color:var(--muted)!important} #mtp-plugin-evals .pe-g{height:26px!important;border-radius:6px!important;background:#151412!important;border:1px solid var(--line)!important;display:flex!important;align-items:center!important;justify-content:center!important;color:var(--muted)!important;font-size:11px!important;position:relative!important;overflow:hidden!important;transition:all .25s!important} #mtp-plugin-evals .pe-g.busy::after{content:""!important;position:absolute!important;inset:0!important;background:linear-gradient(90deg,transparent,rgba(217,119,87,.35),transparent)!important;animation:peSweep .8s linear infinite!important} @keyframes peSweep{from{transform:translateX(-100%)}to{transform:translateX(100%)}} #mtp-plugin-evals .pe-g.pass{background:rgba(127,183,126,.18)!important;border-color:var(--green)!important;color:var(--green)!important} #mtp-plugin-evals .pe-g.fail{background:rgba(227,107,91,.18)!important;border-color:var(--red)!important;color:var(--red)!important} #mtp-plugin-evals .pe-g.skip{background:transparent!important;border-style:dashed!important;color:var(--muted)!important} #mtp-plugin-evals .pe-score{margin-top:10px!important;font-family:var(--mono)!important;font-size:13px!important;display:flex!important;justify-content:space-between!important;align-items:center!important} #mtp-plugin-evals .pe-bar{height:8px!important;background:#151412!important;border:1px solid var(--line)!important;border-radius:999px!important;overflow:hidden!important;margin-top:6px!important} #mtp-plugin-evals .pe-bar i{display:block!important;height:100%!important;width:0!important;background:var(--orange)!important;transition:width .8s cubic-bezier(.2,.8,.2,1)!important} #mtp-plugin-evals .pe-table{margin-top:14px!important;background:#151412!important;border:1px solid var(--line)!important;border-radius:10px!important;padding:12px 14px!important;font-family:var(--mono)!important;font-size:12.5px!important;overflow-x:auto!important} #mtp-plugin-evals .pe-table table{border-collapse:collapse!important;width:100%!important;min-width:420px!important} #mtp-plugin-evals .pe-table th,#mtp-plugin-evals .pe-table td{white-space:nowrap!important;text-align:left!important;padding:5px 10px 5px 0!important;border:0!important;color:var(--cream)!important;font-size:12.5px!important;background:transparent!important} #mtp-plugin-evals .pe-table th{color:var(--muted)!important;font-weight:500!important;border-bottom:1px solid var(--line)!important} #mtp-plugin-evals .pe-table td.big{color:var(--orange2)!important;font-weight:600!important} #mtp-plugin-evals .pe-chips{display:grid!important;grid-template-columns:repeat(3,1fr)!important;gap:8px!important;margin-bottom:12px!important} #mtp-plugin-evals .pe-chip{background:var(--panel)!important;border:1px solid var(--line)!important;border-radius:9px!important;padding:10px!important;text-align:left!important;cursor:pointer!important;color:var(--cream)!important;font-family:var(--mono)!important;font-size:13px!important;transition:all .15s!important;display:flex!important;flex-direction:column!important;gap:4px!important} #mtp-plugin-evals .pe-chip small{font-family:var(--sans)!important;font-size:11px!important;color:var(--muted)!important} #mtp-plugin-evals .pe-chip.paid small{color:var(--orange2)!important} #mtp-plugin-evals .pe-chip:hover{border-color:var(--orange)!important} #mtp-plugin-evals .pe-chip.on{border-color:var(--orange)!important;background:rgba(217,119,87,.12)!important} #mtp-plugin-evals .pe-detail{background:#151412!important;border:1px solid var(--line)!important;border-radius:10px!important;padding:14px!important;min-height:120px!important} #mtp-plugin-evals .pe-detail h4{font-family:var(--mono)!important;font-size:14px!important;color:var(--orange2)!important;margin-bottom:6px!important} #mtp-plugin-evals .pe-detail p{font-size:14px!important;color:var(--cream)!important} #mtp-plugin-evals .pe-detail p+p{margin-top:8px!important;color:var(--muted)!important;font-size:13px!important} #mtp-plugin-evals .pe-ctrls{display:grid!important;grid-template-columns:repeat(3,1fr)!important;gap:12px!important;margin-bottom:12px!important} #mtp-plugin-evals .pe-ctrl label{display:flex!important;justify-content:space-between!important;font-size:13px!important;color:var(--muted)!important;margin-bottom:4px!important;font-family:var(--mono)!important} #mtp-plugin-evals .pe-ctrl label b{color:var(--orange2)!important;font-weight:600!important} #mtp-plugin-evals input[type=range]{width:100%!important;accent-color:var(--orange)!important;margin:0!important;background:transparent!important} #mtp-plugin-evals .pe-out{display:grid!important;grid-template-columns:1fr 1fr!important;gap:12px!important} #mtp-plugin-evals .pe-box{background:var(--panel)!important;border:1px solid var(--line)!important;border-radius:10px!important;padding:12px 14px!important;font-family:var(--mono)!important;font-size:13px!important} #mtp-plugin-evals .pe-box .n{font-size:26px!important;font-weight:600!important;color:var(--orange2)!important;line-height:1.1!important;transition:color .3s!important} #mtp-plugin-evals .pe-box .n.ok{color:var(--green)!important} #mtp-plugin-evals .pe-box .n.bad{color:var(--red)!important} #mtp-plugin-evals .pe-box .s{color:var(--muted)!important;font-size:12px!important;margin-top:4px!important;font-family:var(--sans)!important} #mtp-plugin-evals .pe-foot{margin-top:16px!important;padding-top:10px!important;border-top:1px solid var(--line)!important;display:flex!important;justify-content:space-between!important;flex-wrap:wrap!important;gap:8px!important;font-size:12px!important;color:var(--muted)!important} #mtp-plugin-evals .pe-foot b{color:var(--orange)!important;font-weight:600!important} #mtp-plugin-evals .pe-foot a{color:var(--muted)!important;text-decoration:underline!important} #mtp-plugin-evals hr,#mtp-plugin-evals p:empty,#mtp-plugin-evals del,#mtp-plugin-evals s{display:none!important} @media (prefers-reduced-motion:reduce){#mtp-plugin-evals *{animation:none!important;transition:none!important}} @media (max-width:640px){#mtp-plugin-evals{padding:14px!important}#mtp-plugin-evals .pe-grid,#mtp-plugin-evals .pe-arms,#mtp-plugin-evals .pe-out{grid-template-columns:1fr!important}#mtp-plugin-evals .pe-chips,#mtp-plugin-evals .pe-ctrls{grid-template-columns:1fr 1fr!important}#mtp-plugin-evals .pe-code{min-height:0!important}} </style><div id="mtp-plugin-evals"><div class="pe-head"><h3>How claude plugin eval scores a case</h3><span>Claude Code v2.1.269+</span></div><div class="pe-tabs" role="tablist"><button class="pe-tab on" data-t="0" role="tab">1. The suite on disk</button><button class="pe-tab" data-t="1" role="tab">2. Run both arms</button><button class="pe-tab" data-t="2" role="tab">3. The 6 graders</button><button class="pe-tab" data-t="3" role="tab">4. Gate and cost</button></div><div class="pe-pane on" data-p="0"><p class="pe-lead">A suite is a folder. Each case is a realistic prompt plus 1 or more graders. Click a file to read it.</p><div class="pe-grid"><div class="pe-tree"><span class="pe-node dir">my-plugin/</span><span class="pe-node dir"><span class="d1">.claude-plugin/plugin.json</span></span><span class="pe-node dir"><span class="d1">skills/release-notes/SKILL.md</span></span><span class="pe-node dir"><span class="d1">evals/</span></span><span class="pe-node dir"><span class="d2">first-case/</span></span><button class="pe-node file on" data-f="prompt"><span class="d3">prompt.md</span></button><span class="pe-node dir"><span class="d3">graders/</span></span><button class="pe-node file" data-f="skill"><span class="d3">&nbsp;&nbsp;uses-skill.md</span></button><button class="pe-node file" data-f="rubric"><span class="d3">&nbsp;&nbsp;format.md</span></button><span class="pe-node dir"><span class="d2">results/<timestamp>/report.html</span></span></div><pre class="pe-code" id="pe-code"></pre></div><div class="pe-note" id="pe-tree-note"></div></div><div class="pe-pane" data-p="1"><p class="pe-lead">Every case runs in 2 arms: with your plugin loaded and without it. Each arm repeats 3 times by default. Press run.</p><button class="pe-btn" id="pe-run">$ claude plugin eval .</button><div class="pe-arms"><div class="pe-arm"><h4>with-arm <em>plugin loaded</em></h4><div id="pe-with"></div><div class="pe-score"><span>WITH</span><span id="pe-with-n">0.00</span></div><div class="pe-bar"><i id="pe-with-b"></i></div></div><div class="pe-arm"><h4>without-arm <em>no plugin</em></h4><div id="pe-wo"></div><div class="pe-score"><span>W/OUT</span><span id="pe-wo-n">0.00</span></div><div class="pe-bar"><i id="pe-wo-b"></i></div></div></div><div class="pe-table"><table><thead><tr><th>CASE</th><th>WITH</th><th>W/OUT</th><th>Δ</th><th>RUNS</th><th>COST</th><th>NOTES</th></tr></thead><tbody><tr><td>first-case</td><td id="pe-t-w">0.00</td><td id="pe-t-o">0.00</td><td class="big" id="pe-t-d">+0.00</td><td id="pe-t-r">0</td><td>est.</td><td id="pe-t-n">not run</td></tr></tbody></table></div><div class="pe-note">Δ is what the plugin contributed. A case that scores 1.0 in both arms passed without your plugin's help. The uses-skill grader is marked with-only, so it is reported as an indicator and left out of the score in a 2-arm run. The most common first finding is Δ near 0 with that grader failing: Claude is not choosing your skill on natural phrasing.</div></div><div class="pe-pane" data-p="2"><p class="pe-lead">A grader is a pass/fail check with a type and an optional weight. 4 types cost nothing. 2 call a judge model.</p><div class="pe-chips" id="pe-chips"></div><div class="pe-detail" id="pe-detail"></div></div><div class="pe-pane" data-p="3"><p class="pe-lead">Drag the sliders. The threshold decides the exit code; the counts decide the bill.</p><div class="pe-ctrls"><div class="pe-ctrl"><label>case score <b id="pe-v-score">0.80</b></label><input type="range" id="pe-score" min="0" max="1" step="0.05" value="0.8"></div><div class="pe-ctrl"><label>--threshold <b id="pe-v-thr">0.80</b></label><input type="range" id="pe-thr" min="0" max="1" step="0.05" value="0.8"></div><div class="pe-ctrl"><label>cases <b id="pe-v-cases">4</b></label><input type="range" id="pe-cases" min="1" max="20" step="1" value="4"></div><div class="pe-ctrl"><label>--runs <b id="pe-v-runs">3</b></label><input type="range" id="pe-runs" min="1" max="10" step="1" value="3"></div><div class="pe-ctrl"><label>arms <b id="pe-v-arms">2</b></label><input type="range" id="pe-arms" min="1" max="2" step="1" value="2"></div><div class="pe-ctrl"><label>llm/baseline graders per case <b id="pe-v-llm">1</b></label><input type="range" id="pe-llm" min="0" max="5" step="1" value="1"></div></div><div class="pe-out"><div class="pe-box"><div class="n" id="pe-gate">exit 0</div><div class="s" id="pe-gate-s"></div></div><div class="pe-box"><div class="n" id="pe-calls">24 + 72</div><div class="s" id="pe-calls-s"></div></div></div><div class="pe-note">Agent runs = cases × runs × arms. Judge calls = 3 short calls per llm or baseline grader per run. Every one is a real model call on your account, so set --max-cost-usd in CI.</div></div><div class="pe-foot"><span>Source: <a href="https://code.claude.com/docs/en/plugin-evals" target="_top" rel="noopener">Claude Code docs, Test plugins with evals</a>. Numbers in the demo mirror the docs example.</span><span>Built by <b>Marktechpost</b></span></div></div><script> (function(){ var root=document.getElementById('mtp-plugin-evals');if(!root)return; var $=function(s){return root.querySelector(s)},$$=function(s){return Array.prototype.slice.call(root.querySelectorAll(s))}; var esc=function(s){return s.replace(/&/g,'&amp;').replace(/</g,'<').replace(/>/g,'>')}; /* tabs */ $$('.pe-tab').forEach(function(t){t.addEventListener('click',function(){$$('.pe-tab').forEach(function(x){x.classList.remove('on')});$$('.pe-pane').forEach(function(x){x.classList.remove('on')});t.classList.add('on');$('.pe-pane[data-p="'+t.getAttribute('data-t')+'"]').classList.add('on');resize();});}); /* files */ var files={ prompt:{code:'<span class="c">// evals/first-case/prompt.md</span>\n<span class="k">---</span>\n<span class="k">max_turns:</span> 10 <span class="c">// default</span>\n<span class="k">timeout_seconds:</span> 300 <span class="c">// default</span>\n<span class="k">allowed_tools:</span> [Read, Glob]\n<span class="k">---</span>\nWrite release notes for everything merged since the v2.3 tag.',note:'The body is the prompt, sent to Claude exactly as written. Phrase it the way a real user would, and do not name your skill in it: a prompt that says "use the release-notes skill" cannot test whether Claude would have found the skill on its own.'}, skill:{code:'<span class="c">// evals/first-case/graders/uses-skill.md</span>\n<span class="k">---</span>\n<span class="k">type:</span> tool_used\n<span class="k">arm:</span> with-only\n<span class="k">---</span>\nSkill',note:'A tool_used grader checks the transcript for a named tool call. Marked with-only, it becomes a "did the plugin fire" indicator rather than part of the score, because the baseline arm has no skill to fire.'}, rubric:{code:'<span class="c">// evals/first-case/graders/format.md</span>\n<span class="k">---</span>\n<span class="k">type:</span> llm\n<span class="k">weight:</span> 2\n<span class="k">---</span>\nThe reply groups changes under Added, Changed and Fixed headings and cites at least 1 PR number per line.',note:'An llm grader hands your prose criteria to a judge model. It costs 3 short judge calls per run, and weight makes it count for more of the score. Regex, tool_order and file_exists are the other free options.'} }; function showFile(k){$$('.pe-node.file').forEach(function(b){b.classList.toggle('on',b.getAttribute('data-f')===k)});$('#pe-code').innerHTML=files[k].code;$('#pe-tree-note').textContent=files[k].note;resize();} $$('.pe-node.file').forEach(function(b){b.addEventListener('click',function(){showFile(b.getAttribute('data-f'))})}); showFile('prompt'); /* runs */ var withRes=[[1,1,1],[1,1,1],[1,1,1]]; /* uses-skill, format, regex-title */ var woRes=[[0,0,1],[0,0,1],[0,0,1]]; /* col0 excluded from score (with-only) */ var gnames=['uses-skill','format (x2)','has-title']; function buildRows(host){host.innerHTML='';for(var r=0;r<3;r++){var row=document.createElement('div');row.className='pe-run';row.innerHTML='<span class="lbl">run '+(r+1)+'</span>'+gnames.map(function(n){return '<div class="pe-g" title="'+n+'">'+n+'</div>'}).join('');host.appendChild(row);}} var wHost=$('#pe-with'),oHost=$('#pe-wo');buildRows(wHost);buildRows(oHost); var running=false; function scoreOf(res){/* weighted: format weight 2, has-title 1; uses-skill not scored in 2-arm run */var t=0;for(var i=0;i<res.length;i++){t+= (res[i][1]*2+res[i][2]*1)/3;}return t/res.length;} function fmt(n){return (Math.round(n*100)/100).toFixed(2)} $('#pe-run').addEventListener('click',function(){ if(running)return;running=true;var btn=this;btn.disabled=true;btn.textContent='running 6 agent runs...'; buildRows(wHost);buildRows(oHost); var cells=[];$$('#pe-with .pe-g').forEach(function(c,i){cells.push({el:c,arm:'w',r:Math.floor(i/3),g:i%3})});$$('#pe-wo .pe-g').forEach(function(c,i){cells.push({el:c,arm:'o',r:Math.floor(i/3),g:i%3})}); ['#pe-with-n','#pe-wo-n','#pe-t-w','#pe-t-o'].forEach(function(s){$(s).textContent='0.00'});$('#pe-t-d').textContent='+0.00';$('#pe-t-r').textContent='0';$('#pe-t-n').textContent='running';$('#pe-with-b').style.width='0';$('#pe-wo-b').style.width='0'; var i=0; function step(){ if(i>=cells.length){finish();return;} var c=cells[i];c.el.classList.add('busy'); setTimeout(function(){ c.el.classList.remove('busy'); var v=(c.arm==='w'?withRes:woRes)[c.r][c.g]; if(c.arm==='o'&&c.g===0){c.el.classList.add('skip');c.el.textContent='n/a';} else{c.el.classList.add(v?'pass':'fail');c.el.textContent=(v?'pass':'fail');} if(c.arm==='w'&&c.g===0){c.el.textContent='fired';} var done=c.r+1; if(c.g===2){var host=c.arm==='w'?withRes:woRes;var s=scoreOf(host.slice(0,done));var sel=c.arm==='w'?'#pe-with':'#pe-wo';$(sel+'-n').textContent=fmt(s);$(sel+'-b').style.width=(s*100)+'%';$('#pe-t-r').textContent=String((c.arm==='w'?0:3)+done);} i++;step(); },260); } function finish(){var w=scoreOf(withRes),o=scoreOf(woRes);$('#pe-t-w').textContent=fmt(w);$('#pe-t-o').textContent=fmt(o);$('#pe-t-d').textContent=(w-o>=0?'+':'')+fmt(w-o);$('#pe-t-n').textContent='report.html written';btn.disabled=false;btn.textContent='$ claude plugin eval . (run again)';running=false;resize();} step(); }); /* graders */ var graders=[ {n:'regex',paid:false,what:'Matches a pattern you supply against the reply.',why:'Computed from the transcript. Free. Good for headings, IDs, or phrases that must (or must not) appear.'}, {n:'tool_used',paid:false,what:'Checks that a named tool was called, such as Skill.',why:'Computed from the transcript. Free. Mark it with-only to turn it into a plugin-fired indicator that is excluded from the score.'}, {n:'tool_order',paid:false,what:'Checks that 1 named tool was called before another.',why:'Computed from the transcript. Free. Use it when the sequence matters, for example Read before Edit.'}, {n:'file_exists',paid:false,what:'Checks that the run left a file at a path the case names.',why:'Computed from the files on disk. Free. It says nothing about what the file contains.'}, {n:'llm',paid:true,what:'A judge model scores the reply against pass criteria you write in prose.',why:'3 short judge calls per run, billed to your account. Use it for what only a model can judge, and set a weight if it should dominate the score.'}, {n:'baseline',paid:true,what:'A judge model compares the reply against a reference answer instead of written criteria.',why:'Also 3 short judge calls per run. Keep the reference current, because it is the definition of correct.'} ]; var chips=$('#pe-chips');graders.forEach(function(g,i){var b=document.createElement('button');b.className='pe-chip'+(g.paid?' paid':'');b.innerHTML=esc(g.n)+'<small>'+(g.paid?'judge model, costs':'free, from transcript')+'</small>';b.addEventListener('click',function(){showG(i)});chips.appendChild(b);}); function showG(i){$$('.pe-chip').forEach(function(c,j){c.classList.toggle('on',i===j)});var g=graders[i];$('#pe-detail').innerHTML='<h4>type: '+esc(g.n)+'</h4><p>'+esc(g.what)+'</p><p>'+esc(g.why)+'</p>';resize();} showG(1); /* gate & cost */ function calc(){ var sc=+$('#pe-score').value,th=+$('#pe-thr').value,cs=+$('#pe-cases').value,rn=+$('#pe-runs').value,ar=+$('#pe-arms').value,ll=+$('#pe-llm').value; $('#pe-v-score').textContent=sc.toFixed(2);$('#pe-v-thr').textContent=th.toFixed(2);$('#pe-v-cases').textContent=cs;$('#pe-v-runs').textContent=rn;$('#pe-v-arms').textContent=ar;$('#pe-v-llm').textContent=ll; var g=$('#pe-gate'),ok=sc>=th;g.textContent=ok?'exit 0':'exit non-zero';g.className='n '+(ok?'ok':'bad'); $('#pe-gate-s').textContent=ok?'Every case scored at or above --threshold '+th.toFixed(2)+'. CI proceeds.':'A case scored '+sc.toFixed(2)+', below --threshold '+th.toFixed(2)+'. The job fails.'; var runs=cs*rn*ar,judge=3*ll*runs;$('#pe-calls').textContent=runs+' + '+judge;$('#pe-calls-s').textContent=runs+' agent runs ('+cs+' × '+rn+' × '+ar+') plus '+judge+' judge calls (3 × '+ll+' × '+runs+').'; } $$('input[type=range]').forEach(function(r){r.addEventListener('input',calc)});calc(); /* resize to parent (WordPress iframe) */ function resize(){try{if(window.parent&&window.parent!==window){window.parent.postMessage({type:'mtp-plugin-evals-resize',height:root.offsetHeight+40},'*');}}catch(e){}} window.addEventListener('load',resize);setTimeout(resize,300);setTimeout(resize,1200); })(); </script></body></html>">

Key Takeaways

  • claude plugin eval scores realistic prompts with 6 grader types; 4 are free, llm and baseline bill a judge model.
  • Every case runs with and without the plugin by default; Δ is the only number that proves the plugin did the work.
  • A Δ near zero with a failing tool_used: Skill grader means the skill never triggers on natural phrasing.
  • --threshold, --max-cost-usd, and --trust-plugin turn it into a CI gate; usage-limit errors can fake a regression.
  • Requires Claude Code v2.1.269+; claude plugin eval init writes the first suite for you.


Check out the Technical details. Also, feel free to follow us on Twitter and don’t forget to join our 150k+ML SubReddit and Subscribe to our Newsletter. Wait! are you on telegram? now you can join us on telegram as well.

Need to partner with us for promoting your GitHub Repo OR Hugging Face Page OR Product Release OR Webinar etc.? Connect with us

The post Anthropic Adds Plugin Evals to Claude Code: 6 Grader Types, a No-Plugin Baseline, and a CI Gate for Skills appeared first on MarkTechPost.

MCP·工具编码Anthropic评测·基准
Anthropic Adds Plugin Evals to Claude Code: 6 Grader Types, a No-Plugin Baseline, and a CI Gate for Skills · LinkLoom