eval-harness-first
π―SkillInstallation
npx skills add wshobson/agents --skill eval-harness-firstRun it in a terminal; it asks which AI coding tools to install it for (Claude Code, Codex, Cursor and more).
Uses skills.sh Β· Node.js 22.20+
After installing
Ask for related work and the agent uses it on its own, or call it yourself.
/eval-harness-firstInstall by hand
Copy the whole skill folder from GitHub to the place below. Copying only SKILL.md can leave out files the skill uses.
Open the skill folder β- This project
.claude/skills/eval-harness-first/ - All projects
~/.claude/skills/eval-harness-first/
These paths are for Claude Code. For other tools, the command above puts it in the right place.
SKILL.md
View on GitHub βBuild the evaluation harness that gates every fine-tuning run β golden sets, per-failure-mode graders, judge calibration, and base-model baselines. Use when starting a fine-tuning effort, when converting traces into an eval set, or when calibrating a judge against human labels.
Eval Harness First
The Phase 0 gate for the whole plugin:
finetuning-method-selection and every downstream
skill assume this harness exists before a training
config gets written. The harness is not a run-end
side artifact β it is the data-curation engine. The
same labeled traces that build the goldens feed
training data, minus an explicit holdout.
Input: production/agent traces if they exist, or
a task spec if they don't, plus labelers willing to
grade β₯100 examples.
Output format: the eval/ directory below β
goldens, graders, drift suite, and the base-model
baseline that later phases gate on.
The Gate
No eval harness, no fine-tune. Skip to a training config and there is nothing to measure against, nothing to catch regressions, and no labeled data to train on. The flywheel:
- Collect traces β production/agent spans, or synthetic tasks if none exist yet.
- Error analysis β open coding on β₯100 traces, axial coding into 4β8 failure buckets.
- One grader per bucket β deterministic first; calibrated LLM-judge only for genuinely subjective criteria.
- Prioritize by frequency Γ severity Γ value.
- The labeled traces feed dataset curation, minus
an explicit holdout. Every
eval/goldens.jsonlID stays excluded from training data by ID. - Train.
- Re-run the same harness on the checkpoint β not a different, looser one.
- Drift detection feeds back to step 2 β new production failure modes re-open error analysis.
Steps 2β4 build the harness; steps 5β8 are why it must exist first β it is both the training data source and the checkpoint's exit gate.
Building Goldens
- From traces, when they exist: run error analysis β open coding on β₯100 real traces (read them, tag failures in your own words, no fixed taxonomy yet), then axial coding to collapse those tags into 4β8 named failure buckets. Fewer than 4 means the coding pass was too shallow; more than 8 means buckets need merging. Exception: single-failure-surface tasks (e.g. strict-schema extraction) may land at 1β2 buckets with per-field sub-metrics inside one grader β don't invent artificial splits with no evidence behind them.
- Synthetic, when traces don't exist yet: dimension-based generation β enumerate the axes that matter (task type, difficulty, edge case, persona) and sample the cross-product; free- generated prompts cluster around whatever's easiest to write.
- Goldens are versioned like code β commit
eval/goldens.jsonl, diff it in review, tag it per release. It doubles as the CI regression suite.
Graders
One grader per failure bucket from error analysis β not one for the whole eval set. A single blended score hides which bucket regressed.
- Deterministic first. Regex, schema validation, or execution checks are cheaper, reproducible, and need no calibration.
- LLM-judge only for genuinely subjective criteria β tone, faithfulness, "which response is better" β where no deterministic check can express it.
- Binary pass/fail over Likert. A 1β5 or 1β10 scale is noisier to calibrate and harder to apply consistently; collapse to pass/fail.
- Drift-suite MMLU-style scoring: prefer logprob
over generate-and-extract β a tight token budget
makes generate-and-extract parse-brittle for models
that preamble, conflating format compliance with
the knowledge being measured. Templates for all
four grader shapes and this scoring note:
references/grader-templates.md.
Judge Calibration Is a Prerequisite
Any bucket routed to an LLM-judge needs calibration before its verdicts count for anything beyond exploration β a hard prerequisite, not a nice-to-have. N/A when no bucket routes to a judge β an all-deterministic harness has nothing to calibrate; state that rather than leaving this section unaddressed.
- Label β₯100 items, split train/dev/sealed test (report once, no re-touching after).
- Report TPR and TNR, not one blended accuracy number β a judge can hit 90% by always saying "pass" on a skewed set.
- Pin the judge to a fixed model snapshot and recalibrate on judge-model change, quarterly regardless.
- The judge must come from a different model family than the model under test.
- A judge that misses the agreed TPR/TNR bar ships
advisory-only β flags for human review, never
gates a promotion. Full protocol, bias correction,
and recalibration checklist:
references/judge-calibration.md.
The Baseline
Before Phase 1 (method selection) starts, run the full harness β goldens plus the capability-drift suite β against the unmodified base model. This is the number every later checkpoint gets compared against.
eval/baseline-<model>.json is the gate token. No
baseline file, no comparison basis for
checkpoint-promotion β a checkpoint that "looks
better" against nothing measured isn't a finding.
Directory Contract
eval/
βββ goldens.jsonl # labeled traces + synthetic goldens, versioned
βββ graders/ # one module per failure bucket
β βββ schema_compliance.py
β βββ exact_match.py
β βββ rubric_judge.py
βββ drift-suite.yaml # frozen benchmarks + 200-500 domain-adjacent items
βββ baseline-<model>.json # gate token: harness + drift suite vs the base model
runs/
βββ <run-id>/
βββ results.json # per-run harness output, one per checkpoint
eval/ persists across runs and lives outside
runs/ β the fixed measuring stick, not a run
artifact. runs/ is disposable; eval/ is not.
Never let a run script write into eval/. Canonical
location: every per-trace results.json β the
Phase 0 baseline included β lives at
runs/<run-id>/results.json, never under
eval/runs/...; an instruction requesting the
latter is wrong, not this contract.
Phase 0 Exit Checklist
Before finetuning-method-selection, confirm:
- β₯100 traces open-coded; 4β8 failure buckets (N/A floor for synthetic goldens on a single-failure- surface task β see the Building Goldens exception; bucket count then comes from post-baseline error analysis instead).
eval/goldens.jsonlcommitted and versioned.- One grader per bucket, deterministic first.
- Judges calibrated β TPR/TNR, snapshot pinned, different family (N/A when no bucket routes to an LLM-judge; state that explicitly).
eval/drift-suite.yamlfrozen.eval/baseline-<model>.jsonwritten.
Missing any of the six (or its stated N/A)? Not
Phase 0 complete β /finetune checks the baseline
file before a run.
Related Skills
General-purpose evaluation guidance (dashboards, A/B
testing, non-fine-tuning harnesses) lives in the
llm-application-dev plugin's llm-evaluation
skill β this skill covers only the fine-tuning
coupling: goldens that double as training data, and
the baseline that gates a checkpoint.
finetuning-method-selectionβ routes here first.dataset-curationβ formats these traces into training rows.trace-to-training-dataβ turns graded traces into training examples.checkpoint-promotionβ consumesbaseline-<model>.json, re-runs this harness on each candidate checkpoint.
References
references/grader-templates.mdβ runnable grader examples per shape, plus adrift-suite.yamlexample and MMLU logprob-scoring note.references/judge-calibration.mdβ the calibration protocol, including the all- deterministic N/A path.
More from this repository10
Helps you build a consistent look for your app with Tailwind CSS v4. It sets up shared colors, sizes, dark mode and reusable components so every screen matches.
A guide to TypeScript's advanced type features, which describe the shape of your data so mistakes are caught before the code runs. It covers reusable types, types that change based on rules, and built-in helper types, with short examples.
Guidance for building reliable server-side apps with Node.js, using Express or Fastify. It covers login, error handling, databases, API design and a list of proven best practices.
Intelligent automation and multi-agent orchestration for Claude Code
Claude Code plugin for AI-powered framework migration workflows, coordinating specialized agents to plan and execute transitions between technology stacks as part of the wshobson/agents marketplace.
A Claude Code plugin for payment system integration covering Stripe, PayPal, and billing platforms with checkout flows, subscription management, and webhook handling in the wshobson/agents ecosystem.
A Claude Code plugin bundling core development tools and agents for everyday tasks like debugging and code generation, part of the wshobson/agents marketplace with 73 focused plugins.
Claude Code plugin for observability and monitoring including logging, metrics, distributed tracing, and alerting, part of the wshobson/agents marketplace with 73 focused plugins.
A Claude Code plugin providing specialized AI agents for deployment strategy planning and execution, covering blue-green deployments, canary releases, rolling updates, and zero-downtime patterns.
Claude Code plugin for JVM language development including Java, Kotlin, and Scala with specialized agents for idiomatic patterns, build tools, and runtime optimization in the wshobson/agents marketplace.