agentleFS
AznatkoinyAznatkoiny/plugin-forge/skills/build-evals/SKILL.md

build-evals

Skill1 starsChanged 3 months agoMITView on GitHub

Generate a runnable eval suite (tasks, graders, judges, targets) for a Claude Code plugin BEFORE it is built. Use for "build evals", "eval suite for my plugin", "test my plugin", "retrofit evals", "mine traces into tasks". In the forge pipeline this is the evals phase; retrofit and mine modes run standalone against any existing plugin.

1 other project uses a version of this.

Adopted by

Most recently taken up by

  • Other versions1 project uses a version of this.

    Word for word · 0

    None found.

    Edited · 0

    None found.

    Wrote their own version · 1

    1. understudylabs/understudy-cli★ 1same name

    How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.

  • In this repository10 other files it gives its agents.

The file

Show its rules and text

We split this skill into the rules it gives an agent

14 rules. About 0 are common, 4 are distinctive, and 10 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈4

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 10

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Read design/CONTRACT.md. Extract, per capability row:

    line 43
  2. Distinctive:

    Never one-shot the suite (interviewing beats one-shot generation — LangChain's central empirical finding).

    line 58
  3. Distinctive:

    WAIT for the user's choice before generating anything.

    line 63
  4. Very specific:

    Follow references/task-authoring.md for everything about tasks: the exact task.yaml schema, the 20–50 task budget, the two-experts bar, the …

    line 90
  5. Very specific:

    Follow references/grader-menu.md: deterministic-first hierarchy (workspace → transcript → state_check → judge → trigger, plus the …

    line 98
  6. Very specific:

    Only where the grader menu genuinely runs out of deterministic options.

    line 105
  7. Very specific:

    If the target plugin bundles or drives an MCP server that uses elicitation, headless eval runs will hang or die — no dialog exists under …

    line 113
  8. Distinctive:

    No match → one-line stderr message and exit 2, so the trial fails loudly instead of hanging.

    line 124
  9. Very specific:

    Run every mechanical lint in references/antipatterns.md (L01–L16) and fix all findings before proceeding.

    line 128
  10. Very specific:

    Run forge-eval reference --task <ID> for at least 3 representative tasks (one per archetype used) and show the user the graded output.

    line 139
  11. Very specific:

    Do not modify .forge/state.json.

    line 148
  12. Very specific:

    Read traces from the generated plugin's trace-capture hook output: ${CLAUDE_PLUGIN_DATA}/traces/*.jsonl (tool args, results, errors per …

    line 172
  13. Distinctive:

    Every task ships a reference solution.

    line 191
  14. Very specific:

    Never emit deprecated shapes: no legacy decision/approve hook JSON, no legacy mount-path skill references, and MCP tool names always in the …

    line 202

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

build-evals — the eval builder

!cat .forge/state.json 2>/dev/null || echo NO_STATE

Generate the complete evals/ tree for a target plugin. In new mode the plugin does not exist yet: tasks derive from design/CONTRACT.md (the PDR), not from code. The suite this skill emits becomes the definition of "done" for the entire build — treat every task as a contract clause, not a test.

This skill drafts and lints the suite. It never arms, freezes, or scores it — those are /plugin-forge:arm-evals and bin/forge-eval. It is model-invocable by design (decision D2): the forge conductor chains it via the Skill tool; safety comes from the state guard below, not from invocation control.

State guard (new mode only)

Apply this table to the injected state line above before doing anything else in new mode (also the default when no argument is given). retrofit and mine skip this guard entirely — they run standalone against any plugin, with or without a forge pipeline (see their sections).

Injected stateAction
NO_STATEREFUSE. Say: "No forge pipeline in this project. Run /plugin-forge:forge to start one, or use /plugin-forge:build-evals retrofit <plugin-path> for an existing plugin." Stop.
phase is interview or contractREFUSE. Say: "The contract is not approved yet — evals derive from it. Run /plugin-forge:forge resume." Stop.
phase is evalsProceed with new mode.
phase is armed, building, smoke, verify, or shipREFUSE edits. The suite is frozen (sha256 in .forge/freeze.json); guard hooks will block writes anyway. Say: "The suite is frozen. Append the desired change to .forge/eval-change-requests.md, then run /plugin-forge:arm-evals to apply it, re-gate, and re-freeze as a new version." Stop.

Mode: new (pipeline phase)

Work through the steps in order. Load the referenced file before executing its step — each reference is binding, not advisory.

1. Map the surface from the contract

Read design/CONTRACT.md. Extract, per capability row:

  • the chosen composition (skills, hooks, agents, MCP servers, scripts) and its archetype
  • the C5 Testability column: grader type, observable signal, and planned task IDs — this column IS the task backlog; build-evals exists to make those IDs real
  • the C1 Trigger column: every auto-invoked component (model-invoked skill, hook, agent with proactive description) needs positive AND negative trigger tasks
  • external dependencies (MCP servers, APIs, corpora) and whether the contract chose live or mock for each

Also read design/INTENT.md for the runtime-environment answers (headless/cloud/local) — they constrain what graders can observe.

2. Interview — propose clusters, recommend, WAIT

Never one-shot the suite (interviewing beats one-shot generation — LangChain's central empirical finding). Use AskUserQuestion to:

  1. Propose 3–5 testable ability clusters derived from the PDR rows, each with a one-line description, its archetype, and a rough task count. Recommend one ordering and say why. WAIT for the user's choice before generating anything.
  2. For every external dependency, ask live-vs-mock. Default recommendation: mock fixture stubs for write-heavy, paid, or rate-limited tools; live only for cheap read-only calls the user explicitly accepts. Record the decision per dependency — the harness stores which mode each result came from.

For scientific or business domains where fixture corpora need domain-real content, offer to run the /plugin-forge:skill-forge research pipeline to ground fixtures in real sources instead of inventing plausible-looking data (decision D10).

3. Scaffold

Copy the scaffold from ${CLAUDE_PLUGIN_ROOT}/templates/evals/ into the target plugin as evals/, and create the sibling evals-holdout/ next to it (NOT inside evals/). The scaffold provides registry.yaml, targets/{default,no-plugin,crowded}.yaml, suites/{capability,regression,triggers}.yaml, judges/{fact,rubric,battle}.yaml, labels/labels.jsonl, and tasks/_example/. Delete tasks/_example/ after real tasks exist.

Then vendor the harness runner (stdlib-only, so the suite outlives plugin-forge):

mkdir -p <plugin_dir>/evals/bin && cp "${CLAUDE_PLUGIN_ROOT}/scripts/harness/run.py" <plugin_dir>/evals/bin/run.py && chmod +x <plugin_dir>/evals/bin/run.py

4. Author tasks

Follow references/task-authoring.md for everything about tasks: the exact task.yaml schema, the 20–50 task budget, the two-experts bar, the REQUIRED reference solution, the goal-condition grammar for instruction.md, fixture rules, the holdout split, and elicitation_answers. Every task ID planned in the contract's C5 column must exist in evals/tasks/ or evals-holdout/tasks/ when this step ends.

5. Choose graders

Follow references/grader-menu.md: deterministic-first hierarchy (workspace → transcript → state_check → judge → trigger, plus the simulate_user driver), archetype routing, the mandatory numeric tolerance, the never-assert-tool-ORDER rule, and the crowded-listing requirement for trigger tasks.

6. Author judges

Only where the grader menu genuinely runs out of deterministic options. Follow references/judge-authoring.md: modelgraded-spec YAML shape, one rubric dimension per isolated judge call, Unknown always legal, pinned cheap judge model different from the target model, anti-echo phrasing. Seed evals/labels/labels.jsonl with the unlabeled sample skeleton — calibration itself is arm-evals' gate, not this skill's.

7. Generate the elicitation auto-answer hook (when applicable)

If the target plugin bundles or drives an MCP server that uses elicitation, headless eval runs will hang or die — no dialog exists under claude -p. For every such server:

  • set elicitation_answers in each task.yaml that exercises it (see task-authoring.md)
  • emit evals/hooks/elicitation-auto-answer.sh (bash, set -euo pipefail, executable) and evals/hooks/elicitation-settings.json registering it as an exec-form Elicitation hook: "command": "${CLAUDE_PLUGIN_ROOT}/evals/hooks/elicitation-auto-answer.sh" — harness runs merge this settings file; production users never load it. The script reads the elicitation request JSON from stdin, looks up the requested fields in .forge-eval/elicitation-answers.json (staged into the workspace by the harness from the task's elicitation_answers), and prints the matching answers object to stdout with exit 0. No match → one-line stderr message and exit 2, so the trial fails loudly instead of hanging.

8. Lint the suite

Run every mechanical lint in references/antipatterns.md (L01–L16) and fix all findings before proceeding. L01 (numeric tolerance) and L02 (task-text/grader consistency) are the builder meta-eval contract: plugin-forge's own dogfood suite feeds this skill adversarial specs engineered to reproduce the CORE-Bench and METR grader bugs, and passes only if the emitted suite provably cannot contain them. Do not hand a suite to arm-evals with any lint red.

9. Smoke-run drafts and hand off

An eval that has never run is not delivered:

  • Run forge-eval reference --task <ID> for at least 3 representative tasks (one per archetype used) and show the user the graded output. Use forge-eval run --dry-run for a cost estimate of the full suite; state it plainly — trials × tasks × judges is real money, and --max-cost-usd exists for a reason.
  • Present the suite summary: task count per suite (capability/regression/triggers), holdout count, judge dimensions, live-vs-mock map, estimated full-run cost.
  • Tell the user the exact next command: /plugin-forge:arm-evals — the four arming gates (reference-green, red baseline, judge calibration, freeze) all run there.

Do not modify .forge/state.json. The phase advances to armed only when arm-evals freezes the suite.

Mode: retrofit <plugin-path>

Standalone — no forge pipeline, no state guard, works on any installed or in-repo plugin.

  1. Map the plugin surface from files (there is no PDR): every skills/*/SKILL.md and command frontmatter (descriptions = trigger contracts), agents/*.md, hooks/hooks.json (matchers = firing contracts), .claude-plugin/plugin.json, .mcp.json. Derive one ability cluster per user-facing capability and one trigger axis per auto-invoked component. MCP tool checks must use plugin-scoped names: mcp__plugin_<plugin>_<server>__<tool>.
  2. Then run steps 2–9 above unchanged, writing evals/ and evals-holdout/ into the plugin's own directory. Where step 1 of new mode says CONTRACT.md, use the surface map; flag any capability whose observable signal is unclear as "unverifiable — needs a design decision" instead of inventing a grader for it.
  3. Recommend arming: retrofit suites get the same four gates via /plugin-forge:arm-evals <plugin-path> before their scores mean anything.

Mode: mine

Standalone — converts captured production failures into tasks (the flywheel).

  1. Read traces from the generated plugin's trace-capture hook output: ${CLAUDE_PLUGIN_DATA}/traces/*.jsonl (tool args, results, errors per session). If no traces exist, say so and stop — mine has no other input; suggest confirming the trace-capture hook is installed.
  2. Cluster failures (repeated errors, user corrections, wrong outputs) and propose each cluster as a candidate task via AskUserQuestion — same interview discipline: propose, recommend, WAIT.
  3. For each accepted failure, author a task per references/task-authoring.md with the real failing input as instruction.md seed, a fixture reconstructing the state, and a reference solution showing the correct behavior. New tasks go to evals/tasks/ in the regression suite (they protect against a now-known failure).
  4. A frozen suite that gains tasks is a NEW suite: finish by instructing the user to run /plugin-forge:arm-evals to re-gate and re-freeze (registry version bumps, scores stay comparable). If guard hooks block the writes, that is the freeze working — route the change through .forge/eval-change-requests.md as the guard message says.

Standing rules (all modes)

  • Deterministic-first, always. A judge where a file check would do is a bug.
  • Every task ships a reference solution. No exceptions — 0% pass usually means a broken task, and only the reference proves otherwise.
  • Positive AND negative trigger cases for every auto-invoked component; one-sided suites train over-triggering.
  • Golden answers, key-fact lists, and reference solutions live under reference/, which the harness stages OUTSIDE the agent-visible worktree. Never copy any of it into fixtures/ or instruction.md.
  • Holdout tasks (evals-holdout/) are never named, quoted, or summarized in any session the builder loop can read.
  • Track cost honestly: tracked_metrics are recorded, never graded; suite cost estimates go to the user before, not after, an expensive run.
  • Never emit deprecated shapes: no legacy decision/approve hook JSON, no legacy mount-path skill references, and MCP tool names always in the full plugin-scoped form mcp__plugin_<plugin>_<server>__<tool> — never the short server-only form.

References

  • references/task-authoring.md — task budget, schema, instruction grammar, fixtures, holdout, elicitation fixtures
  • references/grader-menu.md — grader hierarchy, archetype routing, trigger + crowded target, simulate_user
  • references/judge-authoring.md — modelgraded spec shape, judge rules, calibration handoff
  • references/antipatterns.md — reward-hacking catalog with the mechanical lints L01–L16

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.