implement-and-check — make the contract real

SkillAI & models

Runs the hard gate that has to pass before any optimization budget is spent. Use right after intake. Walks the agent through implementing the 3 required adapter methods plus any defaulted hooks that need overriding (and any selected skill's abstract methods), then runs `cap-evolve check` on the project plus each involved skill's check.py, listing exactly what is still stubbed or non-deterministic and what to do about each kind of failure.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the implement-and-check — make the contract real skill

What this skill tells your AI

The instructions your AI receives, as published by skillberry-ai/cap-evolve in skills/phases/implement-and-check/SKILL.md and read by ahel’s review.

Optimizing against a half-wired adapter produces a number that means nothing: a stub scorer gives every candidate the same reward, an empty tasks() averages over nothing, a non-deterministic scorer makes the gate chase measurement noise. This phase proves the measurement apparatus works before budget is spent. It is cheaper to fail here than after a full run.

Steps

  1. Implement the 3 required adapter methods in .capevolve/project/adapters/adapter.py. These are the @abstractmethods (core/cap_evolve/adapter.py:77-106) — the gate refuses to run until all three are real:

    • tasks(split)list[Task] for 'train'|'val'|'test'|'all'; non-empty, same list every call.
    • run_target(task, ctx, *, seed=0)Rollout. Run the agent under test with the candidate live as ctx; capture output + trace + tool calls + cost. Do not score here. Forward seed if the runner is stochastic; set Rollout.error on an infra failure so the engine treats it as noise, not as a low score.
    • score(task, rollout)Score: reward in [0,1] + general feedback (it becomes the diagnosis signal, so never leak the gold answer).

    Override a defaulted hook only when its default does not fit: materialize(candidate_dir, edits=None) (pure write of {component: text}), live(candidate_dir) (context manager yielding ctx), apply(candidate_dir, edits=None) (back-compat inject), trajectories(split, ctx=None) and runner_model() (both default None). Three optional fast paths are not on the base class at all — the harness feature-detects them with hasattr and uses them only if you define them: run_batch(tasks, ctx, *, seed) (drive a benchmark's own batch runner instead of run_target), run_trials(tasks, ctx, *, n_trials, base_seed) (all trials in one concurrent run), score_batch(tasks, rollouts) (score a whole trial in one external harness call). docs/ADAPTER_CONTRACT.md is the full contract, including the shown-only metrics catalog score() may return.

    Note capability_sources is not an adapter method — it is a capevolve.yaml key (the data-model/types files copied into the optimizer's context), owned by intake.

  2. Implement any selected skill's scripts/abstract.py (most are concrete and need nothing).

  3. Run the gate:

    python scripts/run.py --project .capevolve/project \
        --skill-check <skills>/capabilities/<cap>/scripts/check.py
    

    Exit 0 = green. The JSON has three fields with three different meanings — see the table below before you react to it.

  4. Pipeline-wiring self-test (automatic once the check is green). A green adapter is necessary but not sufficient — the optimizer also needs its context wired. run.py then runs pipeline_selftest.py (zero API cost): the optimizer-prompt template named by capevolve.yaml::optimizer_instructions_file exists, still carries its {{...}} placeholders, and renders through the real harness renderer with none left over; and whether the adapter defines trajectories() or inherits the base default (both valid, both reported). The template checks are skipped with a note for an algorithm that never reads the template — only hill-climb is passed --instructions-file (cli.py:869-876). --no-pipeline-selftest skips it; it also runs standalone.

    A full one-iteration mock run is deliberately not attempted: it would need a baseline, a frozen split and a run dir that do not exist yet at gate time, and building them is benchmark-specific. This exercises the same workdir-building and prompt-rendering paths.

When it is red — what to do, per failure kind

CheckReport has three fields (core/cap_evolve/check.py:30-38) and only problems affects ok. Treating a note as a failure is how an agent gets stuck in a loop.

report field / messagewhat it meansdo this
stubs: ["<name>"]that method still raises the IMPLEMENT ME markerwrite the method in adapters/adapter.py; nothing later was even probed (check.py:102-107)
"could not load adapter: ..."import/instantiation failed — often an unimplemented @abstractmethod (TypeError) or a bad sibling importfix the import or define all three abstract methods; the adapter's own dir is on sys.path, so sibling helpers import plainly
"tasks('val') raised: ..."the data path is wrongpoint tasks() at real data; check the split argument is being honored
"tasks('val') returned an empty list"the split has no tasksusually a filter or path that matched nothing — print the list before returning
"tasks('val') is not stable across calls"ids differ between two callsremove set/dict iteration order and any per-call shuffle; sort explicitly
"scorer is non-deterministic: X vs Y"score() returned two rewards for one rolloutremove the RNG, or pin an LLM judge's decoding (temperature 0) and cache nothing that hides the variance
"score(...) raised on a probe rollout"the scorer cannot survive an unfamiliar outputmake score() total — an unparseable output is reward 0 with feedback, not an exception
notes: [...]informational, incl. the materialize() probe raise and the consuming-model tier mismatchread; do not treat as failure
skill check.py redthat capability/algorithm skill's own contract is unmetrun its check.py directly; its JSON names the assertion

Re-run until green. Green is the entry condition for baseline.

What the gate does and does not guarantee

Determinism is genuinely executed, not asserted: check.py:133-142 scores one fixed rollout twice and reports a problem when the rewards differ. Do not read more into green than that. Measured on this checkout (issue #358):

  • run_target is never called on the default path, so a pass-body runner goes green and fails later, after the split is frozen.
  • The scorer probe uses a synthetic rollout (output="__probe_output__"), so a scorer that short-circuits on unrecognizable output — every LLM-judge scorer — is not really tested. Both score() calls happen on one in-process instance, so a memoized scorer is unfalsifiable here.
  • materialize() is a probe, not an assertion: a raise is a note and does not fail the check (check.py:166-167), because a real adapter may need its full environment. Green means "callable or explained", not "edit path verified".
  • Both entry paths fail closed, so a red check never freezes a split: cap-evolve run returns 1 before creating a run dir (cli.py:721-726), and the standalone /cap-evolve:baseline re-runs the core check itself and exits non-zero before the run dir exists (baseline/scripts/run.py). What is not a runtime precondition is the provides: checked token — it declares ordering only, so a phase that skips baseline gets no gate from the DAG.

If your scorer calls a judge, say so in PROJECT.md along with how its decoding is pinned — the gate cannot see it. The one failure mode nothing here can catch: feedback that leaks the gold answer passes every wiring check and still corrupts diagnosis.

Dual-mode

Standalone as /cap-evolve:implement-and-check; orchestrator-callable — but uniquely for this phase, cap-evolve run does not invoke scripts/run.py. It calls the core check inline and shells straight to baseline, so --skill-check and the pipeline self-test run in standalone mode only. Run this phase yourself before either cap-evolve run or /cap-evolve:baseline if you want them: both of those re-run the core check, but neither runs --skill-check or the pipeline self-test.

References

  • references/concepts.md — why each check exists, the scorer-determinism-vs-target-stochasticity distinction (load this when deciding whether your scorer's variance is a bug or a measurement), and the sources.

Signals

GitHub stars
56
Forks
16
Last commit
Sep 2026

ahel review

  • K6low
    bundled executables the agent is told to run

Automated review, not a security audit. Ruleset v1+k2.

Advanced
Catalog kind
skill
Gateway key
implement-and-check
Source
github.com/skillberry-ai/cap-evolve