implement-and-check
Skill69 starsChanged 5 months agoApache-2.0View on GitHub
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.
In this repository22 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- llms.txtllms.txt
- agent-optimizeSkill
- evographSkill
- gepaSkill
- hill-climbSkill
- skilloptSkill
- mcp-toolSkill
- skill-packageSkill
- system-promptSkill
- toolsSkill
- wikiSkill
- run-optimizerSkill
- orchestrateSkill
- using-cap-evolveSkill
- baselineSkill
- diagnoseSkill
- evaluateSkill
- finalizeSkill
- gateSkill
- intakeSkill
- reportSkill
The file
We split this skill into the rules it gives an agent
1 rule. About 0 are common, 0 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 116
If your scorer calls a judge, say so in PROJECT.md along with how its decoding is pinned — the gate cannot see it.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
implement-and-check — make the contract real
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:
Exit 0 = green. The JSON has three fields with three different meanings — see the table below before you react to it.python scripts/run.py --project .capevolve/project \ --skill-check <skills>/capabilities/<cap>/scripts/check.py 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.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

