Skip to content
Back to skills

Evals

ASecurity

Composable eval operations — a persistent, stack-agnostic regression net plus optional LM-judge scoring. Called by create-story (BUILD), dev-story and code-review (RUN/SCORE). Directly invocable as /evals to run the current eval set. Works for Swift, web, and Python alike.

  • 2 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 19, 2026
ai-agentspythongoswiftshellbashtestingcode-reviewgitsecurity

Works with

  • cli

Security analysis

A100/100

Scanned September 19, 2026

npx -y skills add rterakedis/leanwheel-skills --skill evals --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Evals?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Evals
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/rterakedis-evals/badge)](https://www.skillsdirectory.com/skills/rterakedis-evals)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: evals
description: Composable eval operations — a persistent, stack-agnostic regression net plus optional LM-judge scoring. Called by create-story (BUILD), dev-story and code-review (RUN/SCORE). Directly invocable as /evals to run the current eval set. Works for Swift, web, and Python alike.
---

# Evals Skill

**Goal:** Give the flywheel the *non-deterministic* half of verification the
Build & Test Gate can't cover, and a **persistent regression net** so a later
story can't silently revert an earlier story's behavior — the exact failure mode
that motivated the Build & Test Gate, now made cumulative.

**Token philosophy (Pro plan):** the default eval type is `command` — a shell
command with an expected result. **Zero model tokens.** It works identically for
`swift test`, `xcodebuild`, `pytest`, `npm test`, `playwright`, or `curl`. The
`judge` type (LM-as-judge) is **opt-in and token-flagged** — used only where
behavior is genuinely non-deterministic and no command can assert it.

---

## Eval set layout

```
docs/evals/
  README.md         ← format reference (scaffolded by /setup)
  epic-{n}.md       ← accumulated cases for epic n, one block per case
  e2e-{area}.md     ← retro-fit cases registered by /e2e-tests (backfill net)
```

Each case is a fenced block:

```
### EVAL {epic}.{story}-{seq} — {short title}
type: command            # command | judge
origin: story {epic}.{story} AC{n}   # provenance
enabled: true
run: swift test --filter CartTotalTests     # command type only
expect: exit-0                               # exit-0 | output-contains:"<s>" | output-matches:/<re>/
# judge type only:
# target: git diff -- Sources/Cart.swift     # what the judge reads
# rubric: |
#   - Empty cart returns 0, never nil
#   - Discounts never produce a negative total
```

Cases are **append-only** and live beyond their origin story. `command` cases are
the regression net; `judge` cases are reserved for trajectory/quality checks.

---

## Operations

### BUILD — derive cases from a story (called by create-story / dev-story)

Input: a story file path (and its `{epic}.{story}`).

1. Read the story's **Acceptance Criteria** and, if present, the `### Behavior
   Contract` invariants and enumerated edge cases.
2. For each AC / invariant that maps to a **deterministic, runnable** check, append
   a `type: command` case to `docs/evals/epic-{epic}.md`:
   - Prefer the project's existing test command with a filter to the new test(s)
     (`swift test --filter X`, `pytest -k x`, `npm test -- -t "x"`, `go test -run X`).
   - **Exception — runners that boot a Simulator** (`xcodebuild … test`): use the
     **same unfiltered suite command** for every case, with a per-case
     `output-contains:` needle on the test/suite name. RUN batches identical
     commands into one launch; per-case filtered invocations cost one Simulator
     launch each and exhaust it on a long run.
   - If the AC is an HTTP/CLI behavior, a `curl`/CLI invocation with
     `output-contains:` is fine.
   - **A needle containing a quote must escape it as `\"`.** Swift Testing prints
     `✔ Suite "Name" passed after N seconds.`, so any case pinning a suite result
     carries an inner quote:
     `expect: output-contains:"CapacityBar target floor\" passed"`.
   - **`-only-testing:` takes the type name, not `@Suite("Display Name")`.** A target
     that matches nothing runs 0 tests and exits 0; RUN fails such a case outright
     (`0 tests executed — gate cannot discriminate`), but pin the right name anyway.
   - `expect: exit-0` unless a specific output assertion is needed.
2b. **A case that enumerates must assert it enumerated.** If the check walks a
   source tree, globs files, or greps the codebase, the underlying test must
   assert a plausible lower bound on what it found — `expect: output-contains:"X"`
   over a walk that produced no output is a gate that cannot fail. Also pick the
   needle so it can only match the intended target: a generic summary line
   (`output-contains:"Test run with"`) matches whichever target printed first and
   passes while the target you care about is red.
3. Only when an AC is **inherently non-deterministic** (LLM output quality, "reads
   naturally", visual judgment not covered by design-verify) add a `type: judge`
   case — and note in your report that it carries per-run token cost.
4. Do **not** invent tests that don't exist yet. A case must reference a check that
   the dev-story implementation will actually create. If the test doesn't exist
   yet, write the case `enabled: false` with a `# pending: <test to write>` note;
   dev-story flips it to `true` once the test lands.

Report: `N command cases, M judge cases appended to docs/evals/epic-{epic}.md`.

### RUN — execute the regression net (called by dev-story Build & Test Gate, code-review Verify-green, or `/evals`)

**RUN is a script, not a model pass.** Collection, batching, assertion and reporting all
live in `scripts/evals.sh`:

```bash
bash scripts/evals.sh --epic {n}          # one epic's set
bash scripts/evals.sh                     # the whole cumulative net (default for /evals)
bash scripts/evals.sh --epic {n} --quiet   # failures + summary only
bash scripts/evals.sh --list               # parse and list, run nothing
```

The script's last line **is** the RUN report — quote it, don't re-derive it:

```
RUN {scope}: {p}/{t} command pass, {j} judge skipped. Regressions: <list or none>
```

Exit 0 = green, 1 = regressions, 2 = usage / no eval files. **Never read
`docs/evals/*.md` into context to run the set** — that read grows with every story and is
the whole reason the script exists.

What the script guarantees, so no skill has to restate it:

- Identical `run:` commands execute **once** and score every case sharing them. On Apple
  projects a per-case invocation means one Simulator launch per case, which exhausts it.
- **Empty output fails** an `output-contains:` / `output-matches:` case regardless of exit
  code (`empty output — gate cannot discriminate`) — the mechanical form of "a gate that
  enumerates must assert it enumerated".
- An `enabled: true` command case with no `run:`, or an unparseable `expect:`, is a
  **failure**, never a silent skip.
- A `run:` containing `-only-testing:` whose output reports **0 tests executed** fails
  regardless of the declared `expect:` (`0 tests executed — gate cannot discriminate`) —
  the second vacuous-gate shape, which produces plenty of output and exits 0. (DD-77)
- `\"` inside an `output-contains:` needle is unescaped before matching, so expectations
  can pin output that itself contains quotes.
- `enabled: false` cases are skipped and counted; `docs/evals/README.md` is excluded (its
  format example would otherwise parse as a case).

A failing `command` case is a **regression**: surface it exactly like a red Build & Test
Gate — the caller must fix and re-run or HALT, never proceed over red.

**Judge cases.** The script counts `type: judge` cases and reports them skipped; judging
needs a model. Run them only when requested (`/evals --judge`, or a caller passing
`judge=true`): read each enabled case's `target:`, score against `rubric:`, pass if all
rubric points hold. Add the judge tally to the script's report line rather than replacing
it. Skipped by default to protect the token budget.

**If `scripts/evals.sh` is absent** (a project scaffolded before it shipped): run
`/upgrade-project` to install it. Parsing the eval files by hand is the fallback of last
resort — do it only if the user declines, and say that you are doing the expensive thing.

**CI.** The script is the CI seam: leanwheel ships no pipeline config because the CI is
unknown (Actions, Jenkins, GitLab, a pre-push hook). Anything that can run a shell command
and read an exit code can gate on the regression net.

### SCORE — emit the rubric line (called by code-review)

Code-review already runs its adversarial passes; SCORE just turns that into a
**structured pass/fail line per dimension** — no extra model calls. Dimensions:
`correctness`, `edge-cases`, `ac-coverage`, `design` (n/a if non-UI), `security`
(n/a if not flagged). GATE = PASS only if every applicable dimension is PASS.
Append the line to the story's `### Review Findings`; the GATE value goes to the ledger via `scripts/ledger.sh … --rubric-gate` (per code-review → Ledger).

---

## Notes

- The eval set is **versioned with the project** (it's in `docs/`), reviewed like
  code — matching the paper's "set the bar at the eval, not the demo."
- `command` cases make the regression net **cumulative and cheap**; that is the
  single highest-leverage, lowest-cost eval mechanism for a Pro-plan workflow.
- Keep `judge` cases rare. Each one is a recurring token cost on every RUN --judge.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.