implement-and-check — make the contract real
SkillAI & modelsRuns 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.
No other account needed.
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
-
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 asctx; capture output + trace + tool calls + cost. Do not score here. Forwardseedif the runner is stochastic; setRollout.erroron 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 yieldingctx),apply(candidate_dir, edits=None)(back-compat inject),trajectories(split, ctx=None)andrunner_model()(both defaultNone). Three optional fast paths are not on the base class at all — the harness feature-detects them withhasattrand uses them only if you define them:run_batch(tasks, ctx, *, seed)(drive a benchmark's own batch runner instead ofrun_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.mdis the full contract, including the shown-onlymetricscatalogscore()may return.Note
capability_sourcesis not an adapter method — it is acapevolve.yamlkey (the data-model/types files copied into the optimizer's context), owned by intake. -
Implement any selected skill's
scripts/abstract.py(most are concrete and need nothing). -
Run the gate:
python scripts/run.py --project .capevolve/project \ --skill-check <skills>/capabilities/<cap>/scripts/check.pyExit 0 = green. The JSON has three fields with three different meanings — see the table below before you react to it.
-
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.pythen runspipeline_selftest.py(zero API cost): the optimizer-prompt template named bycapevolve.yaml::optimizer_instructions_fileexists, still carries its{{...}}placeholders, and renders through the real harness renderer with none left over; and whether the adapter definestrajectories()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 — onlyhill-climbis passed--instructions-file(cli.py:869-876).--no-pipeline-selftestskips 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 / message | what it means | do this |
|---|---|---|
stubs: ["<name>"] | that method still raises the IMPLEMENT ME marker | write 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 import | fix 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 wrong | point tasks() at real data; check the split argument is being honored |
"tasks('val') returned an empty list" | the split has no tasks | usually a filter or path that matched nothing — print the list before returning |
"tasks('val') is not stable across calls" | ids differ between two calls | remove set/dict iteration order and any per-call shuffle; sort explicitly |
"scorer is non-deterministic: X vs Y" | score() returned two rewards for one rollout | remove 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 output | make 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 mismatch | read; do not treat as failure |
skill check.py red | that capability/algorithm skill's own contract is unmet | run 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_targetis never called on the default path, so apass-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. Bothscore()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 runreturns 1 before creating a run dir (cli.py:721-726), and the standalone/cap-evolve:baselinere-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 theprovides: checkedtoken — 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