j-rig-skill-binary-eval

July 19, 2026 · View on GitHub

Part of the Intent Eval Platform — the umbrella grouping the platform's six repos: five converge via a shared Evidence Bundle schema (intent-eval-core, intent-eval-lab, audit-harness, j-rig-skill-binary-eval, intent-rollout-gate), plus intent-eval-dashboard as a satellite consumer (not part of the convergence taxonomy).

Software-grade release discipline for Claude Skills

Binary evaluation harness that treats SKILL.md artifacts as production software. Package integrity, trigger precision, functional quality, regression gating, baseline comparison, model-aware testing, and evidence-backed rollout decisions — all through binary yes/no criteria with external evaluators.

License CI Release

Links: Master Blueprint · Epic Index · Doc Index · Contributing · Security


One-Pager

The Problem

Claude Skills ship on instinct. A skill author writes a SKILL.md, eyeballs it, maybe runs it once, and pushes. There is no regression gate, no trigger precision measurement, no baseline comparison, no model-variance tracking, and no evidence trail for rollout decisions. When a skill breaks silently after a model update or a description tweak causes sibling confusion across a pack, nobody knows until users complain.

The Solution

J-Rig Binary Eval is a seven-layer evaluation harness. All seven layers are implemented; a default eval run wires five of them and honestly reports which layers actually scored the skill in the evidence bundle's coverage.dimensionsSkipped (never a silent overclaim). The seven layers:

  1. Package Integrity — Does it parse, validate, and reference real files? (runs by default)
  2. Trigger Quality — Does it fire on the right prompts and stay silent on the wrong ones? (runs by default, given a roster)
  3. Functional Quality — Does it complete its task and produce correct artifacts? (runs by default)
  4. Regression Protection — Did this change break anything that previously worked? (coded; runs when a prior-run baseline is supplied — otherwise reported as skipped)
  5. Baseline Value — Does the skill actually outperform the naked model? (coded; runs on an opt-in naked-model comparison pass — otherwise reported as skipped)
  6. Model Variance — Does it work across Haiku, Sonnet, and Opus? (runs per model; true cross-model variance needs distinct provider models configured)
  7. Rollout Safety — Any prompt leakage, overreach, or unsafe automation? (runs by default)

Coverage honesty: all seven layers are runnable. Layers 4 and 5 are opt-in — enable them with --regression-baseline <prior-run.json> (regression) and --baseline-check (baseline, which doubles execution+judge cost). When they are not enabled, every run declares that in the signed evidence bundle's coverage.dimensionsSkipped — the harness never claims a layer scored a skill when it did not. A sacred (regression_critical) regression blocks release.

Every criterion is binary (yes/no). The evaluator is always separate from the skill under test. Observed behavior outranks claimed behavior.

W5

WhoClaude Skill authors, skill pack maintainers, enterprise skill library operators
WhatEvaluation harness + regression gate + optimization engine for Claude Skills
WhereLocal CLI (author workflow), CI/CD (PR gate), team dashboard (reporting)
WhenEvery skill change: new skill, description edit, body rewrite, model update
WhySkills are production software — they need release-quality discipline, not vibes

Stack

LayerTechnology
RuntimeTypeScript, Node.js 20+, pnpm
CLI/Parsingcommander, @clack/prompts, picocolors, yaml, unified/remark
Validationzod
LLM Integration@anthropic-ai/sdk
Persistencebetter-sqlite3, drizzle-orm
Concurrencyp-limit, async-retry
Artifact Extractionpdf-parse, mammoth
Dashboard (future)Next.js, Tailwind, shadcn/ui

Key Differentiators

  • Binary criteria only — if a criterion can't be answered yes or no, it isn't ready. No fuzzy scores, no vibes.
  • External evaluators — the skill under test never judges itself. Deterministic checks first, LLM judges second.
  • Sacred regressions — a change that improves average score but breaks a sacred case is rejected. Period.
  • One change at a time — the optimizer proposes exactly one atomic change per experiment. No multi-variable confusion.
  • Baseline gating — if the base model already does the job without the skill, the skill gets flagged for obsolete review.
  • Model-aware — Haiku, Sonnet, and Opus are tested independently. Model variance is product reality, not noise.
  • Evidence-backed rollout — every ship/no-ship decision comes with a structured evidence trail.

Operator-Grade System Analysis

Architecture (Seven Layers)

┌─────────────────────────────────────────────────┐
│                   CLI / CI / API                 │  Layer 7: Surfaces
├─────────────────────────────────────────────────┤
│                 Evidence Layer                   │  Layer 6: Persistence
├─────────────────────────────────────────────────┤
│               Optimization Layer                 │  Layer 5: Experiments
├─────────────────────────────────────────────────┤
│                Judgment Layer                    │  Layer 4: Scoring
├─────────────────────────────────────────────────┤
│              Observation Layer                   │  Layer 3: Capture
├─────────────────────────────────────────────────┤
│               Execution Layer                    │  Layer 2: Harness
├─────────────────────────────────────────────────┤
│                  Spec Layer                      │  Layer 1: Contracts
└─────────────────────────────────────────────────┘
LayerResponsibilityKey Entities
SpecHuman-authored YAML eval contracts, criteria, test caseseval_specs, criteria, test_cases
ExecutionRuns skills against trigger, functional, regression, adversarial, baseline casesruns, skill_versions
ObservationCaptures outputs, artifacts, cost, latency, timing, observed outcomesobserved_outcomes, outputs
JudgmentDeterministic checks first, external LLM judges second, calibration, disagreement handlingcriterion_results
OptimizationFailure clustering, weakest-criterion targeting, single atomic changes, accept/reject/revertexperiments
EvidenceStores runs, scores, artifacts, diffs, regressions, baselines, launch reportsregressions, baselines, launch_reports
CLI/CI/APILocal author workflows, PR gating, team reporting, dashboard

Epic Roadmap (10 Epics, Sequential)

#EpicScope
01Repo FoundationWorkspace skeleton, governance, CI
02Spec LayerYAML eval contracts, criteria schema, test case format
03Package IntegrityDeterministic structure/metadata validation
04Evidence LayerSQLite persistence, run lifecycle, evidence serialization
05Trigger HarnessRoster builder, trigger simulation, precision/recall
06Functional ExecutionSkill invocation, context injection, artifact capture
07Judgment LayerBinary judge engine, calibration, per-model matrix
08Regression/CLI/CIRegression comparison, baseline gating, score aggregation, CLI, PR gate
09OptimizerFailure clustering, one-change proposals, experiment runner
10Team ProductDashboard, eval packs, drift reevaluation, obsolete-review

Non-Negotiable Design Principles

  1. Criteria must be binary — yes or no, no gradients
  2. Evaluator is always separate — the skill never judges itself
  3. Observed behavior outranks claimed behavior — grade what happened, not what the skill says it does
  4. Regression tests are sacred — a regression on a sacred case blocks release regardless of average improvement
  5. One change at a time — optimizer proposes exactly one atomic change per experiment
  6. Blockers block release — a blocker failure cannot be averaged out
  7. Baseline value matters — if the naked model matches the skill, flag for obsolete review
  8. Model-aware testing is required — Haiku/Sonnet/Opus differences are product reality

Reference Library (32 files)

Self-contained library of templates, reference standards, agent patterns, and workflow diagrams under 000-docs/:

DirectoryContents
templates/skill-templates/6 SKILL.md structural patterns
templates/eval-schemas/Eval JSON schemas
references/skill-standards/AgentSkills.io spec, source-of-truth, frontmatter, validation rules
references/eval-patterns/Eval methodology, workflows, output patterns
references/agents/Grader, comparator, analyzer agent patterns
references/enterprise-standards/100-point rubric, production validator schema registry
references/drift-and-consistency/Drift categories, source-of-truth hierarchy
references/epic-workflows/10 ASCII workflow diagrams (one per epic)

Current Status

Phase: Well beyond the initial foundation epic — the monorepo publishes four @intentsolutions/* packages (jrig-cli, refiner, refiner-core, rollout-gate) with the root semver line at v2.1.0. See the CHANGELOG and Epic Index for shipped scope.

pnpm monorepo with nine workspace packages — four published to npm (@intentsolutions/{jrig-cli,refiner,refiner-core,rollout-gate}) and five internal-only (@j-rig/{core,dashboard,db,migrate,pr-comment}, the eval engine plus its migrate/pr-comment helpers; the @j-rig scope is unpublished) — on a TypeScript baseline (tsup builds), with quality guardrails (ESLint, Prettier, Vitest) and CI/CD workflows.

Choosing a provider

j-rig eval runs the trigger / functional / judgment layers against a real model API so the rollout decision is ground truth. It supports the real Anthropic Messages API and any OpenAI-Chat-Completions-compatible endpoint — DeepSeek, Kimi/Moonshot, OpenRouter, Together — through one configurable adapter (providers/openai-compatible.ts). No vendor SDK is added; every call routes through the same injectable Transport seam, so it stays CISO-gate-clean (no key logging, no subprocess spawn).

Switch providers with at most three env vars. Set a per-provider key for a built-in preset, or the generic LLM_* triple to point at any compatible gateway:

ProviderKey env varBase URL (default)Default model
DeepSeekDEEPSEEK_API_KEYhttps://api.deepseek.comdeepseek-v4-flash (V4 Lite; or deepseek-reasoner)
Kimi / MoonshotMOONSHOT_API_KEYhttps://api.moonshot.ai/v1kimi-k2.6
OpenRouterOPENROUTER_API_KEYhttps://openrouter.ai/api/v1deepseek/deepseek-chat or moonshotai/kimi-k2
AnthropicANTHROPIC_API_KEYhttps://api.anthropic.com/v1/messagessonnet / haiku / opus
Generic (any compatible)LLM_API_KEY + LLM_BASE_URL + LLM_MODEL
# DeepSeek (default OpenAI-compatible preset) — model deepseek-v4-flash
DEEPSEEK_API_KEY=sk-... node packages/cli/dist/index.js eval ./my-skill --models deepseek-v4-flash

# Kimi / Moonshot
MOONSHOT_API_KEY=sk-... node packages/cli/dist/index.js eval ./my-skill --provider kimi --models kimi-k2-0711-preview

# Any OpenAI-compatible gateway via the generic triple
LLM_API_KEY=sk-... LLM_BASE_URL=https://my-gateway/v1 LLM_MODEL=some-model \
  node packages/cli/dist/index.js eval ./my-skill

Running a real DeepSeek eval (Intent Solutions internal). The DEEPSEEK_API_KEY is SOPS-encrypted (age) in the lab repo at intent-eval-lab/.env.sops — never hardcoded, never committed in plaintext. Decrypt it into the process at runtime (only into /dev/shm, never to disk) and run a real behavioral model-matrix eval:

# from intent-eval-lab/ (where the SOPS file lives)
eval "$(sops -d --input-type dotenv .env.sops \
  | sed -nE 's/^(DEEPSEEK_API_KEY)=(.*)$/export \1=\2/p')"

# then, from j-rig-binary-eval/:
node packages/cli/dist/index.js eval ./path/to/skill --provider deepseek --models deepseek-v4-flash --json

The unit tests never touch the network or a real key — the adapter's wire format + normalization are exercised through an injected stub transport that returns canned OpenAI Chat-Completions payloads (providers/openai-compatible.test.ts). Only this documented runtime path makes a real DeepSeek call.

Model ids are overridable (via --models or LLM_MODEL) because vendor model ids churn — pin a dated snapshot when you need reproducibility. Auto-detection precedence when no --provider flag is given: an OpenAI-compatible key (DeepSeek → Kimi → OpenRouter → generic LLM_*) wins first, then ANTHROPIC_API_KEY, then stub. A --provider deepseek|kimi|moonshot|openrouter|anthropic|stub flag forces the choice. The chosen provider + model are recorded in --json output and in the OTel events.

Where to get Kimi (K2): the Moonshot console at platform.moonshot.ai / platform.kimi.ai (OpenAI-compatible API), routed through OpenRouter (moonshotai/kimi-k2), or the open weights on Hugging Face for self-hosting behind any OpenAI-compatible server (vLLM / SGLang).

⚠️ Stub providers — output is NOT ground truth

When no real provider key is present, j-rig eval falls back to stub providers that emit synthetic outputs, and the CLI refuses to run unless you explicitly opt in by setting J_RIG_ALLOW_STUB=1. When stub mode is active, a loud banner is emitted to stderr on every invocation. Do not consume stub-mode output as evidence of skill quality; CI gates that ingest j-rig artifacts must refuse rows produced under stub mode.

Full discipline: STUB-PROVIDERS.md.


Skill scoring — adoption signal + intake verbs

The skill-scoring gap-fill layer (epic intent-eval-lab#206, ratified by ISEDC DR-103) adds a deterministic, time-decayed adoption signal and the intake verbs that feed it. It answers a question the static rubric and the behavioral eval cannot: is this skill still earning its keep versus the bare model, in the real world? It consumes the kernel usage_events + human_reviews entities (@intentsolutions/core@0.9.0).

Intake — j-rig ingest-skill and j-rig review

# Record one CASS-gated usage event (anti-gaming — verified sessions only, never raw loads)
node packages/cli/dist/index.js ingest-skill my-skill \
  --session-id sess-123 --source ci \
  --tests-passed --clear-resolution --code-changes

# Record a curated-signal human thumb + open-ended rationale
node packages/cli/dist/index.js review my-skill --verdict up \
  --rationale "saved a manual step" --reviewer jeremy@intentsolutions.io
  • CASS anti-gaming gate (≥0.30). A usage row is scored on session quality (tests-passed +0.25, clear-resolution +0.25, code-changes +0.15, user-confirmed +0.15, backtracking −0.10, abandoned −0.20). A failing row is persisted but excluded from every adoption rollup — load-in-a-loop to inflate adoption is visible in the data, never silently counted. There is no force-count flag.
  • Source split. --source ci (gate-anchored, trusted) vs --source plugin (unverified). The adoption signal weights unverified loads at/near zero.
  • j-rig review is a curated signal, not a trust root. It is explicitly not the signed in-toto human-review/v1 predicate; rows carry governance_class: "curated-signal".
  • Both write local SQLite fact tables (@j-rig/db); no OTel events are minted (the OTel name set is closed/normative). The tenant_id column is reserved in the first CREATE TABLE; an absent tenant is a first-class global bucket, never pooled cross-tenant.

Adoption verdict — the deterministic 2×2 (@intentsolutions/refiner-core)

computeAdoptionVerdict() joins the existing baseline-value flag (does the bare model match the skill?) with a time-decayed adoption rate into one advisory verdict:

bare model matches?users keep it?verdict
skill adds valuehigh adoptionkeep
skill adds valuelow adoptionwatch (discoverability problem)
bare model matcheshigh adoptiondeprecate_review (model caught up but used)
bare model matcheslow adoptionobsolete_review (both axes agree)

The two axes are AND-combined, never averaged — there is no rolled "usefulness %" (C3). Each event's weight decays exponentially with age (weight = 0.5 ** (ageDays / halfLifeDays)), so a skill that rots as base models improve loses signal. The mechanism is a deterministic decay-with-thresholds — the Thompson-sampling bandit is rejected (DR-103 D5): a bandit is non-deterministic by construction, which would break the Evidence-Bundle audit-reproducibility contract and could route a fail-closed gate to the inferior skill version. Adoption is advisory-and-deprecate-only: it never promotes a skill and never overrides the deterministic accept() / decideRollout() gate, which stays the shipping authority. It rides the additive opt-in LaunchReport.adoptionVerdict? field — the RolloutDecision union is not mutated. Thresholds ship explicitly provisional (thresholdsProvisional: true) until back-tested against a real soak window; buildLaunchReport takes an injected clock so the artifact the signal lands in is replayable.


License

Apache 2.0 — see LICENSE and NOTICE for details.

Note: versions 0.x shipped under the MIT license. Starting with v1.0.0, the project is licensed under Apache 2.0. Any existing 0.x artifacts remain available under their original MIT terms; new releases (>= 1.0.0) are Apache 2.0.

Author

Jeremy Longshorejeremylongshore · Intent Solutions