corral
Generated by
scripts/gen-cli-docs.shfrom corral’s own-houtput and its main.go doc comment. Do not hand-edit — runscripts/gen-cli-docs.shand commit the result.
corral — the CorralAI brain: an OIDC-authenticated, MCP-native coordination server
Usage: corral serve /mcp/ + /healthz on $CORRALAI_ADDR corral secret set|get|list|rm manage provider keys + tokens in the secure keystore (env → OS keyring → age-encrypted file; set reads stdin, never argv) corral control seed [flags] seed one vetted control test into the control-gate store (--spec-db --owner --goal --target --code-path --test-path --test-file) corral certify [<ref>] [--out <file>] [--net=false] [--produced-by a,b] -- <check-cmd>... certify a change by execution: check out <ref> (default HEAD) into a jail, run <check-cmd> there, and write a signed, offline-verifiable record; exits with <check-cmd>'s own exit code signs locally (no server) unless --brain is given flags: --produced-by a,b --out <file> --net=false --repo/--commit/--branch (default: read via git) corral certify --brain <url> [flags] -- <check-cmd>... same as above, and also post the signed record to a brain (report_build) as a tamper-evident build attestation corral certify --adversarial --code <path> --goal "<text>" [--test <path>] -- <test cmd> grade a change's own tests: fire the adversarial pool on the brain, poll to a signed verdict corral certify --repo <dir> [--top n|--all] [--goals <file>] [--dry-run] [--swarm n] [-- <test cmd>] fan the --local audit out over a WHOLE repository: enumerate every source file with a paired test, rank them by churn x size, audit the top --top (default 25, --all for every one) through a bounded swarm, and print a repo report whose kill rate is over the AUDITED surface only, with every excluded file accounted for by reason — including the ones the bound left out each file's goal is DERIVED from its source by --derive-model; --goals <file> instead takes goals from a JSON map and makes no model call --dry-run stops after enumeration (no jail, no LLM calls) an explicit -- <test cmd> grades EVERY file, so it is refused when the scan spans more than one language (omit it and each file is graded with its own language's stock command) the report is NOT signed yet — that lands with the sealed repo statement corral certify verify <record-file> [--pubkey <hex>|--brain <url>] [--allow-unanchored] independently verify a --out (or report_build) record: the Ed25519 signature, the ledger's hash chain, and that the statement is bound to that exact ledger head — requires a trusted key via --pubkey or --brain (a record's own embedded public_key is never a trust anchor); prints "verified" and exits 0, or names the failing check on stderr and exits non-zero corral certify pubkey print the local signing pubkey (for --pubkey trust anchors) corral scorecard [--json] show the bug-catching scorecard (recall/precision per model×role, plus a C-PREC column: the test-critic role's execution-checked precision from criticscore adjudications); table by default, or the raw cells as indented JSON with --json corral models rank [flags] rank the models that have sat in each seat by corral's OWN recorded evidence — a DIFFERENT metric per seat: the writer by proven gaps per survivor attempted, the generator by valid mutants the dev suite missed per run, the critic by precision against human adjudication; the goal-deriver is reported as not scored rather than given an invented number. A model below --min-runs (default 5) is printed with its real numbers, marked insufficient, and never preferred. DISCLOSURE, NOT SELECTION: it writes no config, changes no default and staffs no seat — corral has no default models. flags: --db <dsn> (a pushed warehouse instead of the local bug-catching ledger; unreachable REFUSES, never falls back) --seat <role> --lang <name> --min-runs n --json corral criticscore list list execution-checked test-critic findings still awaiting human adjudication — the local store certify --local writes, or a running brain's when CORRAL_BRAIN is set corral criticscore show <id> print one finding in full (model, target test, evidence) corral criticscore confirm <id> record a human "confirmed" verdict — the finding was real corral criticscore refute <id> record a human "refuted" verdict — the finding was wrong (confirm/refute permanently override the pool's own auto-adjudication; this IS the human gate the critic-precision column measures) corral matrix list [--json] show the tests×mutants matrix (swarm slice 5): per-test execution-proven adequacy against a run's own mutant set, plus a safe-to-delete candidate list — populated only by runs opted in via certify --local --matrix (requires CORRAL_BRAIN — no offline mode) corral scans list|show [flags] read the record certify --repo writes — the ledger directory, one signed entry per scan: list shows recent scans (an id is the entry's position in the chain, oldest = 1), show <id> their per-file dispositions — including WHY a proven-gap count of 0 is 0 (writer failed / test unsound / tried and missed), which the bare number cannot say. show <id> --evidence prints the pool's own authored test, kept even when it proved nothing — that is the case worth reading. Plain files, no brain, no database: --ledger <dir> (default $CORRAL_LEDGER, else ./.corral/ledger), --limit n, --json corral verify --ledger <dir> walk a ledger directory's chain: every entry's hash against its bytes, every link against its predecessor, every signature against --pub or the local certify key; one line per entry, an edited or removed entry named; unsigned said, never "verified" corral ledger append <entry> <dir> re-link an entry to <dir>'s current head (re-hash, re-sign, place) — the verb a fetch → append → push loop runs, since a chain is one writer at a time and a git rebase moves the commit, not the link corral ledger retract <dir> <hash> --reason "…" append an entry retracting an earlier one: the retracted scan stays in the chain and stops being the record (the view, the prior, the verdict cache and scans skip it). Deleting it would break the next link corral ledger checkpoint <dir> prune: one genesis naming the head it replaced (hash, count, date) stands in for everything before it; the verifier says the chain begins there corral ledger push <dir> <dsn> append the directory's record — scans, reviews, adjudications — to a warehouse or md:<db>, skipping what it already holds by entry hash; retracted scans left out; source only with --push-source; --dry-run corral ledger verify <dir> the same walk as corral verify --ledger corral review --scope <dir> --reviewer-model <m> [--verifier-model <m2>] [--repo <dir>] a cold model reviews the scope, told to assume the code is wrong; every REPRODUCED finding's sh script is run against a detached worktree at HEAD (a script that does not hold demotes the finding, out loud); the review — opinion, findings, sound list, the reproductions — is one ledger entry beside the audits. Not a gate. --verifier-model: a third model, never the reviewer's, tries to refute every finding by the same rules; a refutation whose script holds demotes the finding, and is itself on the record. --attest <path>: the reproductions as a signed in-toto statement, the opinion bound by its hash; the entry names the statement, and corral verify --attest <path> --db <ledger dir> cross-checks them corral review plan [--repo <dir>] the round planner: scopes reviewed and not, changed since, findings by outcome, and a proposed next scope — a person names it corral review show <dir> <hash> print a review with its adjudications applied corral review adjudicate <dir> <hash>#<Rn> --confirm|--refute --reason "…" a person's verdict on one finding, as its own entry corral review recheck <dir> <hash>#<Rn> re-run a finding's reproduction on HEAD: still, no longer, or could not run corral brief --scope <path> [--changed <base>] [--ledger <dir>] [--json] the auditor's report: what the record says is still OPEN on these files, for whoever writes next — the newest scan's verdict, each fault your tests missed (with the test that closes a proven gap), each review claim that stands and what a person ruled; claims that did not hold are counted, not listed. Reads the ledger only; writes nothing. --changed <base> takes the files changed since a ref; --max-items bounds it and names the cut corral verify --attest <path> [flags] the checker for a certify --repo --attest statement: verifies its DSSE signature (against --pub or the local certify key, reporting who signed either way), and — opted in per flag — recomputes the pushed warehouse rows' hash from a --db and confirms a Rekor entry (--rekor-index, or read from --db) matches the envelope on disk. Prints check marks and one plain sentence per check; exits 1 only on a real mismatch. Different from "corral certify verify", which checks a corral certify BUILD record, a different artifact. flags: --db <dsn> --rekor-index <n> --pub <hex> corral ui [flags] the record in a browser, read-only, loopback by default: the seal (newest verdict per file), the CHAIN (every entry, its kind, its signature checked, retractions named) and the REVIEWS — each finding with its tier, the scripts, the verifier's answer and the person's verdict. No brain, no writes. corral seal [flags] the repo's CURRENT state as the union of still-valid verdicts, read from a certify --repo --push warehouse (many audits, one current state — not one scan's snapshot). Reads corral_seal (latest kill-rate-bearing row per path), creating the view if a writer never has. With --repo <dir>: judges each of the repo's churn x size top-N ("hot") files live (bytes unchanged since the audit), stale (changed since), never audited, unreadable, or unknown (the row recorded no validity key) — and prints "coverage: N of M hot files carry a live verdict", which counts the live ones only. Without --repo: the warehouse's latest verdict per path, no live/stale judgement. Read-only — never writes a row. flags: --db <dsn> (a ledger directory, a warehouse file or md:<db>; default $CORRAL_LEDGER, else ./.corral/ledger) --repo <dir> --top n (default 20) --json corral demo [flags] a complete audit of a tiny project, in ONE command: writes a small Go package with a five-clause password rule and a test that checks only two of them, then audits it with the real certify --local. Needs a Go toolchain (you installed corral with one) and a provider key — no venv, no database, no fixtures. The fastest honest answer to "what does this do?" flags: --writer-model/--mutant-model (required; corral has no default models) --critic-model --dir corral mcp serve corral's findings corpus over stdio MCP, so an editor or agent can read what past audits found. READ-ONLY and local: no brain, no writes, no network listener. corral doctor [flags] [-- <test cmd>] check the environment BEFORE paying for a run: does the sandbox start, is your test command's toolchain reachable INSIDE it, has every grading seat been given a model (corral has no defaults) with a credential for it, and does the file you named have a test corral can pair with. Every check is free — no model is ever called — and they run in the order an audit would hit them, so the first FAIL is the first thing to fix. Exits non-zero if any failed. flags: --code <path> --test <path> (adds the pairing check) --jail <backend> (default: auto-detect) --mutant-model/--writer-model/--critic-model <name> It does NOT check two things that need a real seeded workspace: whether your suite passes on UNMUTATED code inside the sandbox (the most common way an audit dies), and whether a multi-file project needs --repo-dir. corral eval [flags] run the adversarial pool across the versioned eval corpus and print a soundness report (does the recall metric catch known gaps?) NEEDS A BRAIN: this is the optional daemon's calibration harness, not part of an audit. certify and review never contact one. Its corpus has known defects (a target whose path escapes the workspace; fixtures that do not implement the same rule across languages) — treat its numbers as indicative until those are fixed. flags: --corpus <path> (default eval/corpus/manifest.json) --iterations <n> (default 1) --only <id,id,...> --brain <url> (or $CORRAL_BRAIN) --progress <path> (default eval/.eval-progress.json) corral --version print the build version and exit corral -h print this help and exit
Configuration is entirely environment variables — see CORRALAI_ADDR,CORRALAI_DB, and the rest of the // Env: block at the top of this binary'smain.go (also reproduced in the generated CLI reference).corral brief flags
Section titled “corral brief flags”Usage of corral brief: -changed string report on the files changed since this git ref (base...HEAD), instead of or as well as --scope -json the report as one JSON document, for an agent to read -ledger certify --repo the ledger directory to read (default: $CORRAL_LEDGER, else ./.corral/ledger — where certify --repo writes its entry for the repo you are standing in) -max-items int at most this many items (survivors, gaps, claims) across the report; the cut is named (default 50) -repo string the checkout the paths are relative to (default ".") -scope value a file or directory (repo-relative) to report on; repeatablecorral certify --local flags
Section titled “corral certify --local flags”Usage of certify --local: -bind-dir value extra repo-relative dependency dir to mount read-only into the jail instead of copying it into the workspace (repeatable; node_modules/vendor/.venv/venv/.bundle are auto-detected) — --repo-dir mode only -code string path of the code under review (required) -commit string commit sha (default: git rev-parse HEAD, else "local") -critic-model string model for the test-critic role, which must differ from the writer's; "off" disables the critic entirely (it is advisory and never gates the verdict, so a single-vendor run with only one usable model can drop it). No default -goal string the correctness/security goal the code must satisfy (required) -jail string sandbox backend: bwrap|container (Linux), sandbox-exec (macOS) (default: auto-detect for this OS; "none" is not supported — --local always sandboxes). "container" needs CORRALAI_EXEC_IMAGE set to a toolchain image, e.g. CORRALAI_EXEC_IMAGE=python:3.12-bookworm -lang string source language (default: inferred from --code extension) -local run the adversarial pool in-process (this mode) -local-endpoint value place a LOCAL seat on a specific ollama daemon, as <role>=<url> (repeatable; e.g. test-writer=http://localhost:11436). A daemon is pinned to a GPU by its own environment (HIP_VISIBLE_DEVICES / CUDA_VISIBLE_DEVICES), so this is how two models occupy two cards at once — corral selects the DAEMON, never the device. Without it every local seat shares OLLAMA_URL, one card and one VRAM budget. Roles: mutant-generator, test-writer, test-critic, mutant-generator-shadow, test-writer-shadow. An unknown role, a duplicate role, a non-absolute url, or an endpoint on a seat holding a CLOUD model is refused rather than ignored -matrix opt into the tests×mutants matrix: after the primary pass, re-score EVERY dev test ALONE against the run's mutants — a per-test adequacy readout + a delete-candidate list, instead of one dev-suite-wide number. COSTLY: T tests × M mutants extra jail runs (T×M, on top of the primary pass), so leave off by default on a big suite -max-shards int max mutant-generator seats fanned out across the file's functions (0 = 8). Bounds PARALLELISM only — every function is probed regardless; --n-mutants is the PER-SHARD budget -max-tokens int cap on model TOKENS for the whole run, input + output, every seat (0 = no cap). Checked before each call and charged after it, so one in-flight call can overshoot by its own size. Once reached: a generator seat that has not run makes its file ungradable (executor-error naming the cap), a writer or critic seat is skipped and the file flagged as it is for a provider failure — the dev kill rate already measured stands. The cost line says the cap was reached and after how many calls. Corral has bounded mutants, shards and wall clock and never money; this is the money bound -mutant-model string model for the mutant-generator role — REQUIRED, corral has no default models. Takes a registry alias (.corral/models.json) or a concrete model name -mutants string REPLAY a recorded mutant set (see --record-mutants) instead of generating one: --code is graded against exactly the mutants recorded for it, and no mutant-generator model call is made. Refused (exit 2) if the file is absent from the set or its bytes have changed since it was recorded — a mutant is a single-point edit of specific bytes, and re-applying it to different ones grades an exam nobody wrote. Reads a corral-mutants-2 document, or an older corral-mutants-1 one, whose whole-file mutants still replay byte-for-byte. -n-mutants --n-mutants 5 PER-SEAT seeded-violation mutant budget, when you want to set the exam by hand. Unset (0), the budget is DERIVED from the file's complexity — about one fault per decision point, floor 5, ceiling 40 — and the verdict says which rule it used. Set, it is NOT the run's total: total mutants scale with --max-shards (default 8) seats, and DOUBLE again if you name a --shadow-model. E.g. --n-mutants 5 with 8 seats means up to ~40 full dev-suite executions; `--n-mutants 20` roughly ~320 -no-bind-deps copy dependency dirs into the jail workspace instead of bind-mounting them read-only (the pre-bind behavior; subject to the workspace size cap) -no-fail-fast grade every mutant with the WHOLE selected test set instead of stopping at the first failing test. By default a killed mutant stops at the one test that killed it (pytest -x, go test -failfast, jest --bail, phpunit --stop-on-failure), which is most of the per-mutant cost on a repo with a real suite; the verdict is identical either way, and the baseline always runs everything. COSTS: turning this off makes each killed mutant pay for its whole selected set again — on a 77s suite that is the dominant term in the audit. Use it only if your suite is order-dependent or flaky in a way that makes an early stop misleading. -out corral certify verify <file> --pubkey <hex> --allow-unanchored also write the signed verdict as a self-contained record file, re-verifiable offline with corral certify verify <file> --pubkey <hex> --allow-unanchored -poll duration how long to wait between drive iterations when nothing is claimable (default 2s) -prior string what earlier runs already tried, so this run plants DIFFERENT faults: a corral-mutants document (see --record-mutants), a scan ledger (.duckdb, see --record-db), or a directory holding any number of either — a document brings the hunks, a ledger the outcomes, merged per edit. Applied only to a file whose bytes are EXACTLY what the prior was recorded against; a file the prior knows under other bytes gets none, and the report says so. A run handed a prior sits a different exam from one without — the verdict, the ledger and the signed statement carry priorsApplied and the prior's digest, and the digest is in the cache key, so a repeat audit never reads as the tests changing when only the exam did -quiet suppress the live progress echo on stderr (the verdict, --out and --record are unaffected) -record string write a replayable tape of the run (the pool's reasoning beats, task lifecycle, and findings) to this JSON file — the same {events:[…]} shape the corralai.dev cockpit replays -record-mutants string write the mutants this run actually GRADED to this file, as a replayable corral-mutants-2 document — each mutant its SEARCH/REPLACE hunk, tied to the sha256 of the source it is an edit of. Mutants are authored by a model, so an ordinary run re-draws the exam every time; pin the set and a later comparison measures the thing you changed instead of generator variance. Written even when the verdict is needs-review. A v2 document re-recorded from a --mutants replay of an older corral-mutants-1 set contains that set's WHOLE-FILE entries, not hunks — the run graded what was recorded, and re-recording it does not manufacture anchors it never had -record-stream tail -f stream each run event as newline-delimited JSON to this file AS IT HAPPENS — the same events --record collects into a tape at the end, so a watcher (tail -f, the cockpit) can follow a run in flight instead of waiting hours for it to finish. Independent of --record: either, both, or neither -repo string repository (default: git remote.origin.url, else "local") -repo-dir -- audit --code IN THE CONTEXT of this cloned repo/package: the whole tree is seeded into the jail, the file is mutated in place, and the project's OWN test command (given after --) grades it — so real multi-file projects with package imports work (--code/--test are repo-relative) -shadow-model string challenger model that attacks every region a SECOND time for a region-controlled head-to-head. OFF unless named. Recorded for comparison — NEVER gates the verdict -shadow-writer-model string challenger WRITER model that authors a second suite against the SAME mutant set for a mutant-controlled head-to-head. OFF unless named. Recorded for correlation — NEVER gates the verdict -swarm int max concurrent audit workers (0 = auto-size to this host's cores). The BUDGET clamp: independent role tasks run in parallel up to this bound, so a big audit swarms without melting the box -test string path of the dev's test (default: the sibling test of --code) -test-timeout duration hard cap on a SINGLE test-suite run in the jail (0 = auto: derived from the healthy suite's own runtime, so a mutant that makes the suite hang is killed fast instead of eating the whole --timeout). Raise it only if your suite legitimately runs long -timeout duration WALL-CLOCK budget for the whole run, measured from its start — not a no-progress timer. A run still making steady progress is stopped when it exceeds this, and banks a needs-review TIMEOUT verdict: the dev kill rate and survivors survive (they were measured), the PROVING half does not. A file with many survivors needs room — 13 survivors measured at ~21-24 minutes — so raise it rather than lose the proofs. One in-flight LLM call can overshoot slightly, since the deadline is checked between ticks (default 30m0s) -writer-mode per-survivor how the test-writer attacks this file's survivors: per-survivor (the default) makes ONE call per survivor — each carrying the file once as a cacheable shared prefix plus that survivor's diff, each repaired on its own budget and each PROVEN ALONE against its own mutant — or `batched`, the original shape: one call carrying every survivor, one repair budget, one proof pass over all of them. Nothing measured changes between them (a survivor is proven iff an authored test kills it alone and passes on the original, either way); what changes is that one unbuildable test no longer spends the whole file's retries and takes every other survivor down with it. Each survivor's proof in per-survivor mode runs its OWN compliant baseline (a compliant pass plus a canary, per seat), so a file with N survivors pays N baselines where batched paid one: on a repo whose suite takes a minute, prefer --writer-mode batched or expect N baselines' worth of wall clock. -writer-model string model for the test-writer role — REQUIRED, corral has no default models. Takes a registry alias (.corral/models.json) or a concrete model namecorral control flags
Section titled “corral control flags”corral control: usage: corral control seed --spec-db <path> --owner <principal> --goal <id> --target <repo-path> --code-path <flat> --test-path <flat> --test-file <path> [--kill-rate <float>]note: the brain must be stopped (it holds the control store open); or author via the stage_control / promote_control MCP tools while the brain runscorral control seed flags
Section titled “corral control seed flags”Usage of control seed: -code-path string flat target filename in the jail workspace -goal string goal id -kill-rate float recorded adequacy kill rate (default 1) -owner string control-owner principal -spec-db string controlspec DuckDB path -target string repo-relative target file path -test-file string path to the vetted test source file -test-path string flat test filename in the jail workspacecorral control: flag: help requestedcorral criticscore flags
Section titled “corral criticscore flags”usage: corral criticscore list|show <id>|confirm <id> [--why ...]|refute <id> [--why ...]corral criticscore list flags
Section titled “corral criticscore list flags”usage: corral criticscore list|show <id>|confirm <id> [--why ...]|refute <id> [--why ...]corral demo flags
Section titled “corral demo flags”Usage of demo: -critic-model string model for the test-critic role, which must differ from the writer's ("off" disables it) -dir string where to write the demo project (default: a new temp dir, printed and kept) -mutant-model string model for the mutant-generator role — REQUIRED, corral has no default models. Takes a registry alias (.corral/models.json) or a concrete model name -writer-model string model for the test-writer role — REQUIRED, corral has no default models. Takes a registry alias (.corral/models.json) or a concrete model namecorral doctor flags
Section titled “corral doctor flags”Usage of doctor: -code string the source file you intend to audit (optional, enables the pairing and baseline checks) -critic-model string the test-critic model whose credential to check -derive-model certify --repo the goal-derivation model a certify --repo run will name, if any -jail string sandbox backend (default: auto-detect). "container" needs CORRALAI_EXEC_IMAGE set to a toolchain image, e.g. CORRALAI_EXEC_IMAGE=python:3.12-bookworm -mutant-model string the mutant-generator model whose credential to check -repo string the repository the run will audit — where its .corral/models.json registry is read from, exactly as certify reads it (default ".") -shadow-model string the challenger generator model, if the run will name one — it needs a credential too -test string its test file (optional; otherwise inferred from the language's convention) -writer-model string the test-writer model whose credential to checkcorral eval flags
Section titled “corral eval flags”Usage of eval: -brain string brain endpoint (or $CORRAL_BRAIN) -corpus string corpus manifest path (default "eval/corpus/manifest.json") -iterations int iterations per target (default 1) -only string comma-separated target ids (default: all) -progress string resumable progress file (default "eval/.eval-progress.json")corral ledger flags
Section titled “corral ledger flags”corral ledger — the signed, hash-linked record, as a directory of entries.
corral ledger append <entry.json.gz> <dir> re-link an entry to <dir>'s current head (re-hash, re-sign, place) corral ledger retract <dir> <hash> --reason "…" append an entry retracting an earlier one: the retracted scan STAYS in the chain (deleting it would break the next link) and stops being the record — the view, the prior, the verdict cache and scans skip it corral ledger checkpoint <dir> PRUNE: replace every entry with one genesis naming the head it replaced (hash, count, date); the chain restarts there and the verifier says so corral ledger push <dir> <dsn> [--push-source] [--dry-run] append the directory's record to a warehouse you own (a DuckDB path, or md:<db>): every scan, review and adjudication entry the target does not already hold (by entry hash), retracted scans left out. Source — the authored tests, verdict JSON, scripts and their output — travels only with --push-source. A run's own --push already does this as it goes; this is for a directory that ran without one, or a branch pulled later corral ledger verify [--pub <hex>] [--expect-head <hash>] <dir> walk the chain: every hash, link and signature, one line per entry. A chain verifies against ITSELF, so removing the newest entries leaves the rest valid — --expect-head is the anchor from outside that catches it
A certify --repo run writes its entry into the repo's .corral/ledger/ bydefault (--ledger <dir> to move it, --no-ledger to skip), and reads earlierentries there as its prior. On a runner the Action does the same into acheckout of the corral/ledger branch. To carry a local entry up, or arunner's entry past a branch that moved: fetch, `corral ledger append`, push.corral ledger append flags
Section titled “corral ledger append flags”corral ledger — the signed, hash-linked record, as a directory of entries.
corral ledger append <entry.json.gz> <dir> re-link an entry to <dir>'s current head (re-hash, re-sign, place) corral ledger retract <dir> <hash> --reason "…" append an entry retracting an earlier one: the retracted scan STAYS in the chain (deleting it would break the next link) and stops being the record — the view, the prior, the verdict cache and scans skip it corral ledger checkpoint <dir> PRUNE: replace every entry with one genesis naming the head it replaced (hash, count, date); the chain restarts there and the verifier says so corral ledger push <dir> <dsn> [--push-source] [--dry-run] append the directory's record to a warehouse you own (a DuckDB path, or md:<db>): every scan, review and adjudication entry the target does not already hold (by entry hash), retracted scans left out. Source — the authored tests, verdict JSON, scripts and their output — travels only with --push-source. A run's own --push already does this as it goes; this is for a directory that ran without one, or a branch pulled later corral ledger verify [--pub <hex>] [--expect-head <hash>] <dir> walk the chain: every hash, link and signature, one line per entry. A chain verifies against ITSELF, so removing the newest entries leaves the rest valid — --expect-head is the anchor from outside that catches it
A certify --repo run writes its entry into the repo's .corral/ledger/ bydefault (--ledger <dir> to move it, --no-ledger to skip), and reads earlierentries there as its prior. On a runner the Action does the same into acheckout of the corral/ledger branch. To carry a local entry up, or arunner's entry past a branch that moved: fetch, `corral ledger append`, push.corral ledger checkpoint flags
Section titled “corral ledger checkpoint flags”corral ledger — the signed, hash-linked record, as a directory of entries.
corral ledger append <entry.json.gz> <dir> re-link an entry to <dir>'s current head (re-hash, re-sign, place) corral ledger retract <dir> <hash> --reason "…" append an entry retracting an earlier one: the retracted scan STAYS in the chain (deleting it would break the next link) and stops being the record — the view, the prior, the verdict cache and scans skip it corral ledger checkpoint <dir> PRUNE: replace every entry with one genesis naming the head it replaced (hash, count, date); the chain restarts there and the verifier says so corral ledger push <dir> <dsn> [--push-source] [--dry-run] append the directory's record to a warehouse you own (a DuckDB path, or md:<db>): every scan, review and adjudication entry the target does not already hold (by entry hash), retracted scans left out. Source — the authored tests, verdict JSON, scripts and their output — travels only with --push-source. A run's own --push already does this as it goes; this is for a directory that ran without one, or a branch pulled later corral ledger verify [--pub <hex>] [--expect-head <hash>] <dir> walk the chain: every hash, link and signature, one line per entry. A chain verifies against ITSELF, so removing the newest entries leaves the rest valid — --expect-head is the anchor from outside that catches it
A certify --repo run writes its entry into the repo's .corral/ledger/ bydefault (--ledger <dir> to move it, --no-ledger to skip), and reads earlierentries there as its prior. On a runner the Action does the same into acheckout of the corral/ledger branch. To carry a local entry up, or arunner's entry past a branch that moved: fetch, `corral ledger append`, push.corral ledger push flags
Section titled “corral ledger push flags”corral ledger — the signed, hash-linked record, as a directory of entries.
corral ledger append <entry.json.gz> <dir> re-link an entry to <dir>'s current head (re-hash, re-sign, place) corral ledger retract <dir> <hash> --reason "…" append an entry retracting an earlier one: the retracted scan STAYS in the chain (deleting it would break the next link) and stops being the record — the view, the prior, the verdict cache and scans skip it corral ledger checkpoint <dir> PRUNE: replace every entry with one genesis naming the head it replaced (hash, count, date); the chain restarts there and the verifier says so corral ledger push <dir> <dsn> [--push-source] [--dry-run] append the directory's record to a warehouse you own (a DuckDB path, or md:<db>): every scan, review and adjudication entry the target does not already hold (by entry hash), retracted scans left out. Source — the authored tests, verdict JSON, scripts and their output — travels only with --push-source. A run's own --push already does this as it goes; this is for a directory that ran without one, or a branch pulled later corral ledger verify [--pub <hex>] [--expect-head <hash>] <dir> walk the chain: every hash, link and signature, one line per entry. A chain verifies against ITSELF, so removing the newest entries leaves the rest valid — --expect-head is the anchor from outside that catches it
A certify --repo run writes its entry into the repo's .corral/ledger/ bydefault (--ledger <dir> to move it, --no-ledger to skip), and reads earlierentries there as its prior. On a runner the Action does the same into acheckout of the corral/ledger branch. To carry a local entry up, or arunner's entry past a branch that moved: fetch, `corral ledger append`, push.corral ledger retract flags
Section titled “corral ledger retract flags”corral ledger — the signed, hash-linked record, as a directory of entries.
corral ledger append <entry.json.gz> <dir> re-link an entry to <dir>'s current head (re-hash, re-sign, place) corral ledger retract <dir> <hash> --reason "…" append an entry retracting an earlier one: the retracted scan STAYS in the chain (deleting it would break the next link) and stops being the record — the view, the prior, the verdict cache and scans skip it corral ledger checkpoint <dir> PRUNE: replace every entry with one genesis naming the head it replaced (hash, count, date); the chain restarts there and the verifier says so corral ledger push <dir> <dsn> [--push-source] [--dry-run] append the directory's record to a warehouse you own (a DuckDB path, or md:<db>): every scan, review and adjudication entry the target does not already hold (by entry hash), retracted scans left out. Source — the authored tests, verdict JSON, scripts and their output — travels only with --push-source. A run's own --push already does this as it goes; this is for a directory that ran without one, or a branch pulled later corral ledger verify [--pub <hex>] [--expect-head <hash>] <dir> walk the chain: every hash, link and signature, one line per entry. A chain verifies against ITSELF, so removing the newest entries leaves the rest valid — --expect-head is the anchor from outside that catches it
A certify --repo run writes its entry into the repo's .corral/ledger/ bydefault (--ledger <dir> to move it, --no-ledger to skip), and reads earlierentries there as its prior. On a runner the Action does the same into acheckout of the corral/ledger branch. To carry a local entry up, or arunner's entry past a branch that moved: fetch, `corral ledger append`, push.corral ledger verify flags
Section titled “corral ledger verify flags”corral ledger — the signed, hash-linked record, as a directory of entries.
corral ledger append <entry.json.gz> <dir> re-link an entry to <dir>'s current head (re-hash, re-sign, place) corral ledger retract <dir> <hash> --reason "…" append an entry retracting an earlier one: the retracted scan STAYS in the chain (deleting it would break the next link) and stops being the record — the view, the prior, the verdict cache and scans skip it corral ledger checkpoint <dir> PRUNE: replace every entry with one genesis naming the head it replaced (hash, count, date); the chain restarts there and the verifier says so corral ledger push <dir> <dsn> [--push-source] [--dry-run] append the directory's record to a warehouse you own (a DuckDB path, or md:<db>): every scan, review and adjudication entry the target does not already hold (by entry hash), retracted scans left out. Source — the authored tests, verdict JSON, scripts and their output — travels only with --push-source. A run's own --push already does this as it goes; this is for a directory that ran without one, or a branch pulled later corral ledger verify [--pub <hex>] [--expect-head <hash>] <dir> walk the chain: every hash, link and signature, one line per entry. A chain verifies against ITSELF, so removing the newest entries leaves the rest valid — --expect-head is the anchor from outside that catches it
A certify --repo run writes its entry into the repo's .corral/ledger/ bydefault (--ledger <dir> to move it, --no-ledger to skip), and reads earlierentries there as its prior. On a runner the Action does the same into acheckout of the corral/ledger branch. To carry a local entry up, or arunner's entry past a branch that moved: fetch, `corral ledger append`, push.corral matrix flags
Section titled “corral matrix flags”corral matrix: set CORRAL_BRAIN (and CORRALAI_BRAIN_TOKEN via `corral secret`) — matrix has no offline modecorral mcp flags
Section titled “corral mcp flags”corral mcp — serve corral's findings corpus over stdio MCP.
Usage: corral mcp
Speaks the Model Context Protocol on stdin/stdout so an editor or agent canread what past audits found. READ-ONLY and local: no brain, no writes, nonetwork listener, and no adjudication surface (see mcp_findings.go for why).
Takes no flags. Reads the same local findings store `corral certify --local` writes.corral models flags
Section titled “corral models flags”usage: corral models rank [--db <dsn>] [--seat <role>] [--lang <name>] [--min-runs N] [--json] seats: goal-deriver, mutant-generator, test-writer, test-critic, and — from a ledger directory's review entries — reviewer (claims that held, of those checked) and verifier (verdicts that agreed with the outcome; a person's adjudication is the outcome when there is one, execution otherwise), and committer: the audited party — the commit's author and each Co-authored-by trailer (an agent, in code an agent helped write) — by the changes that held under audit (a scan that passed its gate; a review none of whose checked claims held). The record names a person and an agent the same way, under the same evidence floor; what a reader does with the row is the reader's.
Rank the models that have sat in each seat by what corral's OWN recorded evidence says about them — a different metric per seat, because the seats do different jobs.
This is DISCLOSURE, NOT SELECTION. It prints a table. It writes no config, changes no default, and feeds no router: corral has no default models, and a ranking that quietly staffed a seat would put one back.corral models rank flags
Section titled “corral models rank flags”usage: corral models rank [--db <dsn>] [--seat <role>] [--lang <name>] [--min-runs N] [--json] seats: goal-deriver, mutant-generator, test-writer, test-critic, and — from a ledger directory's review entries — reviewer (claims that held, of those checked) and verifier (verdicts that agreed with the outcome; a person's adjudication is the outcome when there is one, execution otherwise), and committer: the audited party — the commit's author and each Co-authored-by trailer (an agent, in code an agent helped write) — by the changes that held under audit (a scan that passed its gate; a review none of whose checked claims held). The record names a person and an agent the same way, under the same evidence floor; what a reader does with the row is the reader's.
Rank the models that have sat in each seat by what corral's OWN recorded evidence says about them — a different metric per seat, because the seats do different jobs.
This is DISCLOSURE, NOT SELECTION. It prints a table. It writes no config, changes no default, and feeds no router: corral has no default models, and a ranking that quietly staffed a seat would put one back.
flags: -db md:<db> a pushed warehouse to read instead of the local bugcatch ledger: a DuckDB file path or an md:<db> MotherDuck DSN. Unreachable is a refusal, never a quiet fall back to a different body of evidence -json emit the report as JSON -lang string rank only this language — needs evidence that records one (the local bugcatch ledger does not; a pushed warehouse does) -min-runs int the evidence floor (default 5): a model with fewer observations in a seat is still PRINTED, with its real numbers, but marked insufficient and never preferred (default 5) -seat string rank only this seat: goal-deriver, mutant-generator, test-writer, test-critic, reviewer, verifier or committercorral review flags
Section titled “corral review flags”corral review — a cold model reviews a scope of the repository; corral runs its reproductions and records the review beside the audits.
corral review --scope <dir|file> --reviewer-model <m> [--verifier-model <m2>] [--repo <dir>] [flags] The reviewer is told to assume the code is wrong. Every finding carries a tier it declared — REPRODUCED (with a sh script that exits 0 iff the defect is demonstrated), CODE-READ (file:line, argued), HYPOTHESIS — and the run executes every REPRODUCED script against a detached worktree at HEAD. A script that does not hold demotes its finding to CODE-READ on the record, out loud. The reviewer must also list what it checked and found sound. The opinion is printed and carried; only the reproductions are what the entry's signature vouches for. Exit 0 either way unless --fail-on reproduced, which exits 3 when a REPRODUCED finding stands after the run — the record is written first. With --verifier-model, a THIRD model (never the reviewer's) tries to refute every finding by the same rules; a refutation whose script holds demotes the finding, and is itself recorded. flags: --ledger <dir> (default <repo>/.corral/ledger) --no-ledger --timeout 60s --max-bytes 200000 (how much of the scope the reviewer is shown) --fail-on reproduced corral review plan [--repo <dir>] [--ledger <dir>] [--depth 2] The round planner: every scope of the repository, when the ledger last saw it reviewed, its findings by outcome, how many of its files changed since — and a proposal for the next round: never reviewed first, then changed since review (a fix batch nobody re-attacked), then the stalest. No model runs; a person names the scope. corral review show <ledger dir> <review hash> print a review with its adjudications applied corral review adjudicate <ledger dir> <hash>#<Rn> --confirm|--refute --reason "…" [--by <who>] A person's verdict on one finding, as its own entry: the newest verdict per finding stands; automatic passes never write one. --by defaults to the OS user. corral review recheck <ledger dir> <hash>#<Rn> [--repo <dir>] [--timeout 1m] [--json] Re-run one finding's recorded script against the CURRENT HEAD of --repo, in a disposable worktree: still-reproduces (exit 0), no-longer-reproduces (any other exit), or could-not-run (a harness error, a timeout, exit 126/127). Writes nothing; quote it in an adjudication's --reason to put it on the record. Exit 0 when it ran, 3 when it could not.
flags of `corral review`: -attest corral verify --attest <path> --db <ledger dir> write an in-toto statement (predicate https://corralai.dev/review/v1) to this path, and its DSSE envelope beside it when a certify key is configured: the REPRODUCTIONS — every finding's declared and recorded tier, the hash of its script and output, its exit, the verifier's refutation on the same terms — signed; the opinion bound by its hash and not carried. The ledger entry then names the statement. corral verify --attest <path> --db <ledger dir> recomputes the reproductions' hash from the entry -fail-on reproduced exit 3 when a finding STANDS at this tier after the run: reproduced (its script ran and exited 0, and no reproduced refutation or adjudication overturned it). Off by default — the record is written either way; this is the merge gate's switch, for CI -ledger string the ledger directory the review entry is written to (default: <repo>/.corral/ledger, or $CORRAL_LEDGER) -max-bytes int how many bytes of the scope the reviewer is shown; files past the cap are listed by name and the review records them as unshown (default 200000) -no-ledger print the review and write no entry -push review adjudicate --push also append the review's rows to a warehouse you own — a DuckDB path, or md:<db> — as corral_reviews and corral_findings, keyed by the entry's hash so a later review adjudicate --push joins to them. Scripts and outputs travel as hashes unless --push-source -push-source with --push, also send the scripts and what they printed (they quote the audited code); off by default -repo string the checkout to review (a git repository at a commit) (default ".") -reviewer-model <name>:<model> the reviewer seat — an alias from the registry, a provider model name, or an AGENTIC seat: an agent NAME, pinned to a model as <name>:<model>. `claude-code` and `codex` are defined; ANY agent is defined the same way as CORRALAI_AGENT_<NAME>="<command line>" ({dir} the worktree, {out} a reply file, {model} / {model:FLAG} the pin; the brief on stdin, the reply on stdout). An agentic seat is a coding agent started in a disposable copy of the repository: it reads the whole scope itself (no --max-bytes cap) and hands back scripts, which corral runs — nothing it did itself is on the record. Required; corral has no default models -scope string the directory or file under --repo to review (required) -timeout duration wall-clock bound on each reproduction script (default 1m0s) -verifier-model string a VERIFIER seat, adversarial to the reviewer: a different model that tries to refute every finding, by the same rules — a REPRODUCED refutation (a sh script that exits 0 iff the refutation is demonstrated) that holds demotes the finding on the record; a CODE-READ refutation is carried as opinion; a search that finds nothing is never a refutation. Must not be the reviewer's model. Off unless namedcorral review adjudicate flags
Section titled “corral review adjudicate flags”Usage of corral review adjudicate: -by string who is deciding (default: the OS user) -confirm the finding is real as stated -push string also append the verdict as a corral_adjudications row to this warehouse (a DuckDB path, or md:<db>), joined to the review's rows by the entry's hash -reason string why, in your words (required) -refute the finding is not real, or not as statedcorral review plan flags
Section titled “corral review plan flags”Usage of corral review plan: -depth int how many path segments make a scope (2: internal/review, cmd/corral) (default 2) -ledger string the ledger directory whose review entries are the record (default: <repo>/.corral/ledger, or $CORRAL_LEDGER) -limit int how many scopes to list (default 25) -repo string the checkout (default ".")corral review recheck flags
Section titled “corral review recheck flags”Usage of corral review recheck: -json print the result as one JSON object -repo string the checkout whose HEAD the script runs against, in a disposable worktree (default ".") -timeout duration wall-clock bound on the script (default 1m0s)corral review show flags
Section titled “corral review show flags”corral review show: usage: corral review show <ledger dir> <review hash>corral scans flags
Section titled “corral scans flags”usage: corral scans list [--ledger <dir>] [--limit n] [--json] corral scans show <scan-id> [--ledger <dir>] [--json] [--evidence] [--timing]corral scans list flags
Section titled “corral scans list flags”Usage of scans list: -json emit the raw rows as JSON -ledger certify --repo the ledger directory to read (default: $CORRAL_LEDGER, else ./.corral/ledger — where certify --repo writes its entry for the repo you are standing in) -limit int how many scans to show, newest first (default 20)corral scans show flags
Section titled “corral scans show flags”usage: corral scans show <scan-id> [--ledger <dir>] [--json] [--evidence] [--timing] -evidence also print the pool's authored test source for each audited file -json emit the raw rows as JSON -ledger certify --repo the ledger directory to read (default: $CORRAL_LEDGER, else ./.corral/ledger — where certify --repo writes its entry for the repo you are standing in) -timing also print where each audited file's wall clock went, phase by phase — with --json, adds top-level selection_ms, selection_reused and model_calls and wraps the file array in an object ({"files": [...], "selection_ms": ..., "selection_reused": ..., "model_calls": [...]}) instead of emitting it barecorral scorecard flags
Section titled “corral scorecard flags”Usage of scorecard: -json emit the raw cells as JSONcorral seal flags
Section titled “corral seal flags”Usage of seal: -db corral scans what to read: a ledger directory, a warehouse file, or md:<db> (default: $CORRAL_LEDGER, else ./.corral/ledger — the same resolution corral scans uses) -json emit the rows as JSON -repo string a checkout to judge validity against: each hot file's seal row is marked live (bytes unchanged since the audit), stale (changed since), never audited, unreadable, or unknown when the row recorded no validity key to compare against. Only live counts toward coverage. Without this flag, seal prints the raw ledger with no such judgement -top certify --repo how many of the repo's highest-ranked (churn x size) files count as "hot" for the coverage line — same ranking certify --repo uses to bound a scan (default 20)corral secret flags
Section titled “corral secret flags”corral secret: unknown secret subcommand "-h" (set|get|list|rm)corral ui flags
Section titled “corral ui flags”Usage of ui: -addr string local listen address. Loopback by default ON PURPOSE: the ledger is a map of where a codebase's tests are thinnest (default "127.0.0.1:8787") -db corral seal what to read: a ledger directory (the seal, the chain and the reviews) or a warehouse file / md:<db> (the seal only) — default $CORRAL_LEDGER, else ./.corral/ledger, the same resolution corral seal and `corral scans` use -open with --write, also open the URL in a browser. A convenience for a desktop: it hands the URL, token included, to the opener as a command-line argument, which other local processes can read while it runs -print-url print the URL and exit without serving (for scripts and smoke tests) -repo string with --write, the checkout a finding's reproduction is rechecked against (its HEAD, in a disposable worktree) (default ".") -write let this page WRITE: adjudicate findings and recheck them, by running corral's own subcommands. Loopback only; prints a URL carrying a launch token valid until the server exits — anyone with that URL can write verdicts in your name. The URL is printed, never opened, so the token stays off every process's command line; over SSH, tunnel the same port on both ends (ssh -L 8787:127.0.0.1:8787). Agents must never start thiscorral verify flags
Section titled “corral verify flags”Usage of verify: -attest string the --attest statement to verify (required) — the plain JSON path (its signed envelope is expected at <path>.dsse.json) or the envelope itself -db corral review --attest also recompute the warehouse rows' hash from this pushed DuckDB (a path, or md:<db> for MotherDuck) and compare it to the statement's claim; for a corral review --attest statement, the ledger DIRECTORY whose entry names it, so the reproductions' hash is recomputed from the entry. Every push of the scan the warehouse holds is tried (each has its own scan_uid); a VACUUMed warehouse can change row order and trip a false ✗ here without tampering -ledger --push <dir>/ walk a LEDGER DIRECTORY (the JSON entries --push <dir>/ writes, one per scan, each naming the previous entry's hash and carrying a signature): every entry's hash against its bytes, every link against its predecessor, every signature against --pub or the local certify key. One line per entry; an edited entry, a removed one, or a foreign signature is named. Instead of --attest, not with it -pub string hex-encoded Ed25519 public key to verify the signature against (default: the local certify key, CORRALAI_CERTIFY_KEY_FILE) -rekor-index int also confirm this Rekor log index's entry matches the envelope (default: read the index --db recorded for this scan, if --db was given) (default -1)corral certify --repo flags
Section titled “corral certify --repo flags”Usage of certify --repo: -all audit every candidate, ignoring --top -attest string write the scan's verdict as an in-toto Statement to this file — the receipt a reviewer can verify without trusting the run that produced it. Consumed by GitHub's attestation API (actions/attest), which signs it keylessly through the workflow's own OIDC identity, so the signature chains to the repository and workflow rather than to a key that lived on an ephemeral runner. Carries every file's kill rate, survivors and proven gaps WITH the honesty flags that say what a zero means, the thresholds it was judged against, and the models in each role. When a local signing key is configured (CORRALAI_CERTIFY_KEY_FILE), the same statement is ALSO signed into a DSSE envelope written beside this file as <path>.dsse.json — this plain file is unchanged either way, so actions/attest keeps working exactly as it does today; --transparency uploads the envelope, never this file -cache-db string path to corral's local CACHE — derived goals and instrumented test selections a later scan reuses on identical bytes (default: $CORRALAI_CACHE_DB, else ~/.claude/corralai_cache.duckdb). A cache, not a record: nothing a verdict rests on lives only here; deleting it costs a re-derivation and one coverage run, never a fact -commit string commit SHA the report is bound to -critic-model string model for the test-critic role, which must differ from the writer's; "off" disables the critic entirely (it is advisory and never gates the verdict, so a single-vendor run with only one usable model can drop it). No default -derive-model string model that derives a goal per file when --goals is not given — REQUIRED unless --goals is supplied; corral has no default models -diff-base string bound the scan to files changed since this git ref, instead of ranking + --top. In a PR the diff IS the bound: ranking and --top do not apply on this path -dry-run enumerate and emit jobs, then stop — no audits run -goals string JSON file mapping repo-relative paths to goals (default: derive a goal per file) -json with --dry-run, emit the repository's audit surface as JSON instead of the human report: per-language counts, every auditable file with its inferred test pairing, and the machine-stable exclusion tally. Needs no key, no jail and no money — it is the free inventory a UI or a tenant's own tooling can consume instead of scraping stdout -ledger corral verify --ledger the ledger DIRECTORY this scan's entry is written to and earlier entries are read from as the prior (default: <repo>/.corral/ledger, or $CORRAL_LEDGER). One gzipped JSON entry per scan, naming the previous entry's hash, signed when a certify key is configured — the record, in plain text; DuckDB is its view (corral verify --ledger, `seal --db <dir>`, `models rank --db <dir>`). Make the directory a worktree of the corral/ledger branch and a laptop run and an Action run are one writer -local-endpoint value place a LOCAL seat on a specific ollama daemon, as <role>=<url> (repeatable; e.g. mutant-generator=http://localhost:11436). A daemon is pinned to a GPU by its own environment, so this is how two models occupy two cards at once — corral selects the DAEMON, never the device. Without it every local seat shares OLLAMA_URL, one card and one VRAM budget -max-proven-missed string fail the scan (exit 1) if ANY audited file has MORE than this many proven-missed gaps — survivors the pool then killed with a test it WROTE and RAN. Opt-in and unset by default. Prefer this to --min-kill-rate as a merge gate: a kill rate is a proportion of freshly generated mutants and moves between runs on unchanged code, so a threshold set near a healthy value flaps red and gets switched off. A proven-missed gap is a specific demonstrated bug the suite does not catch, established by execution, and 0 means the pool proved nothing — not that it sampled well -max-tokens int cap on model TOKENS for the whole SCAN, every file, input + output, every seat (0 = no cap). Checked before each call and charged after it, so one in-flight call can overshoot by its own size. Once reached: a generator seat that has not run makes its file ungradable (executor-error naming the cap), a writer or critic seat is skipped and the file flagged as it is for a provider failure — the dev kill rate already measured stands. The cost line says the cap was reached and after how many calls. Corral has bounded mutants, shards and wall clock and never money; this is the money bound -min-kill-rate string fail the scan (exit 1) if ANY audited file's kill rate is below this value (0.0-1.0 inclusive; a minimum, so a file exactly at the threshold passes). Opt-in: unset by default, so exit codes are unchanged unless this is given. Applies PER FILE, not to the aggregate — a well-tested file must not mask a weak one -mutant-model string model for the mutant-generator role — REQUIRED, corral has no default models. Takes a registry alias (.corral/models.json) or a concrete model name -mutants string REPLAY a recorded mutant set (see --record-mutants) instead of generating one: every audited file is graded against exactly the mutants in this file, and not one generator model call is made. Mutants are authored by a model, so an ordinary run re-draws the exam every time and two runs of the same audit are not two samples of one measurement — pin the set and a change to anything ELSE becomes measurable. Every selected file must appear in the set with the SAME bytes it was recorded from; a missing file or a changed one is refused (exit 2) up front, never half-replayed. Reads a corral-mutants-2 document, or an older corral-mutants-1 one, whose whole-file mutants still replay byte-for-byte. -no-fail-fast grade every mutant with the WHOLE selected test set instead of stopping at the first failing test. By default a killed mutant stops at the one test that killed it (pytest -x, go test -failfast, jest --bail, phpunit --stop-on-failure), which is most of the per-mutant cost on a repo with a real suite; the verdict is identical either way, and the baseline always runs everything. COSTS: turning this off makes each killed mutant pay for its whole selected set again — on a 77s suite that is the dominant term in the audit. Use it only if your suite is order-dependent or flaky in a way that makes an early stop misleading. -no-goal-cache skip the goal cache — every candidate is re-derived even when a PRIOR scan already derived a goal for the exact same bytes, model and prompt revision. Re-buys a model call per file that a content-addressed cache would otherwise have served for free; use this to isolate goal-derivation variance from a comparison, or on a scan whose operator does not want a goal receipt kept in the ledger at all. The cache lives in the file --cache-db names -no-ledger write no ledger entry and read no prior from the default ledger directory (an explicit --prior still applies) -no-selection-cache skip the selection cache — the ONE instrumented coverage run always executes, even when a PRIOR scan already ran the identical instrumented command over a byte-identical tree. Re-buys a full suite run (the single most expensive measurement a scan makes outside model calls) that a content-addressed cache would otherwise have served for free; use this to isolate selection variance from a comparison, or when the operator does not trust the tree to be unchanged. The cache lives in the file --cache-db names -no-verdict-cache skip the verdict cache — every candidate is re-audited even when a PRIOR scan already earned a verdict for the exact same bytes, tests, models, engine and substrate. Re-buys the whole audit (generation, grading, the writer) per file; use this to isolate model variance from a comparison, or to redo a measurement the cache would otherwise keep serving. The cache is the ledger directory itself (--ledger): a verdict an earlier entry recorded under the same key is served, so --no-ledger also disables it -owner string owning account for the scan (tenant identifier) (default "local") -preflight run the project's test suite once with coverage instrumentation and report which source files it never executes. One extra suite run; reports coverage-grade evidence, not proof -prior string what earlier runs already tried, so this run plants DIFFERENT faults: a corral-mutants document (see --record-mutants), a ledger directory (see --ledger), or a directory holding any number of either — a document brings the hunks, a ledger the outcomes, merged per edit. Applied only to a file whose bytes are EXACTLY what the prior was recorded against; a file the prior knows under other bytes gets none, and the report says so. A run handed a prior sits a different exam from one without — the verdict, the ledger and the signed statement carry priorsApplied and the prior's digest, and the digest is in the cache key, so a repeat audit never reads as the tests changing when only the exam did -push md:<db> append this scan's per-file verdicts to a DuckDB you own — a path, or md:<db> for MotherDuck (which reads motherduck_token from the environment; the database is created on first push if it does not already exist — a MotherDuck SHARE is a read target and cannot be pushed to). corral has no hosted tier and keeps nothing: the warehouse is yours, and any DuckDB works, so this is a destination rather than a lock-in. Append-only. Every row carries the ledger's scan id (0 when --record was not given), and — traceable only with --attest — the sha256 of the signed statement it came from, so a row can be checked against something a third party can verify; without --attest, statement_sha256 is honestly empty rather than fabricated; and with --attest, a statement that FAILS to write withholds the push too, since a row that cannot name the statement it came from is not written. It answers what one pull request cannot — a single kill rate is a sample, and the same unchanged diff has scored 0.85 and 0.90; forty of them are a distribution -push-source with --push, also send the SOURCE BYTES corral holds to your warehouse: the pool's authored test, and the full verdict JSON. Off by default because those bytes are derived from — and quote — your audited code; without this the pushed rows carry numbers, hashes, reasons and model names, and no source leaves the box. Mutant code is NOT carried, by either setting: corral does not keep mutant source at rest, so the corral_mutants.code column exists and is always NULL until something records it. The scan row records which setting was used, so the custody question is answerable from the table rather than from whoever remembers the argv -record-mutants string write the mutants this scan actually GRADED to this file, as a replayable corral-mutants-2 document — one entry per audited file, each mutant its SEARCH/REPLACE hunk, tied to the sha256 of the source it was derived from. Written even when the scan's gates fail: a red verdict is still a recorded exam. A v2 document re-recorded from a --mutants replay of an older corral-mutants-1 set contains that set's WHOLE-FILE entries, not hunks — the run graded what was recorded, and re-recording it does not manufacture anchors it never had -repo string path of the repository to audit (required) -scope-tests REMOVED — see --whole-suite. Selection by coverage evidence is now the default -shadow-model string challenger model that attacks every region a SECOND time. OFF unless named. Recorded for comparison — NEVER gates the verdict -shadow-writer-model string CHALLENGER test-writer: a second writer attacks the SAME survivors as the primary, so the two seats' misses can be compared (Jaccard over survivors, Cohen's kappa). Measurement only — it NEVER gates the verdict. OFF unless named. The per-file Jaccard/kappa land in the ledger entry and in a warehouse with --push; the per-mutant attempt rows are not recorded on the repo path -substrate string where the audit runs: jail (bwrap) or workspace (mutate --repo in place; the caller IS the isolation boundary, e.g. an ephemeral CI runner) (default "jail") -swarm int max concurrent audit workers (0 = auto-size to this host's cores); on --substrate workspace it also sizes the private trees that score one file's mutants at once (budget/4, min 1), so --swarm 4 is one tree -tests string JSON file mapping repo-relative SOURCE paths to their test files, consulted before filename convention. Convention cannot pair a project that names tests after behaviour rather than after source files (expressjs/express: lib/response.js is tested by test/res.send.js, res.json.js …), and it can pair the WRONG file (psf/requests pairs adapters.py to an 8-line test_adapters.py while its real coverage is in a 108KB test_requests.py). A mapping to a file that does not exist is refused, never silently fallen back to convention -timeout certify --local per-file WALL-CLOCK budget, measured from that file's run start — not a no-progress timer. A file still making steady progress is stopped when it exceeds this and banks a needs-review TIMEOUT verdict, keeping its dev kill rate and survivors but losing the PROVING half. Same default and semantics as certify --local's --timeout; raise it for a file with many survivors, which needs the most room and has the most to prove. PER FILE, so it multiplies: a scan of N files with W workers can spend up to (N/W) x this in the worst case, which is what --top and --swarm are for (default 30m0s) -top int audit only the N highest-ranked candidates (0 or --all = every candidate). Bounded by default: a whole-repo audit runs a full herd per file, so an unbounded first scan on a large repo costs hours and real money. The DEFAULT bound does not apply with --goals — a hand-written goals map has already chosen the surface — but an explicit --top does (default 25) -transparency also upload the --attest statement — SIGNED into a DSSE envelope with the local certify key — to Sigstore's public Rekor transparency log (requires --attest — there is nothing to log without one; and a usable local signing key, CORRALAI_CERTIFY_KEY_FILE — refused with exit 2 naming it if none is configured, since an unsigned entry in a public log is worthless and this never mints a fresh key just to have one). THE ENTRY IS PUBLIC AND PERMANENT: once logged it cannot be removed or edited, by anyone, including you. It carries the same statement --attest writes — the repo URL, the audited commit, per-file paths, kill rates and survivor/proven-gap counts, and the models in each role — and never the audited source itself. Fails OPEN for the UPLOAD itself: an unreachable log or a rejected entry prints one line and leaves the scan's own verdict and exit code untouched; the local statement, envelope and ledger are unaffected either way. Prints the log index and entry UUID on success, and records both in the scan ledger and, with --push, the warehouse -whole-suite grade every mutant against the project's WHOLE suite instead of the tests that demonstrably execute each file (the default, from one instrumented run per scan). Costs O(mutants x whole-suite runtime) per file and answers a different question — 'did ANY test catch it' rather than 'do this file's tests test it'. The verdict records which was used -writer-mode per-survivor how the test-writer attacks a file's survivors: per-survivor (the default) makes ONE call per survivor — each carrying the file once as a cacheable shared prefix plus that survivor's diff, each repaired on its own budget and each PROVEN ALONE against its own mutant — or `batched`, the original shape: one call carrying every survivor, one repair budget for the file, one proof pass over all of them. Nothing measured changes between them (a survivor is proven iff an authored test kills it alone and passes on the original, either way); what changes is that one unbuildable test no longer spends the whole file's retries and takes every other survivor down with it. The verdict, the report line, the ledger and the attestation all record which mode earned the numbers. Each survivor's proof in per-survivor mode runs its OWN compliant baseline (a compliant pass plus a canary, per seat), so a file with N survivors pays N baselines where batched paid one: on a repo whose suite takes a minute, prefer --writer-mode batched or expect N baselines' worth of wall clock. -writer-model string model for the test-writer role — REQUIRED, corral has no default models. Takes a registry alias (.corral/models.json) or a concrete model namecorral certify verify flags
Section titled “corral certify verify flags”Usage of certify verify: -allow-unanchored accept a signed-but-not-publicly-witnessed record (weaker: no third-party transparency guarantee) -brain string fetch the public key from this brain's /api/certify/pubkey -pubkey string hex-encoded Ed25519 public key to verify against -rekor-url string Rekor instance to verify the inclusion proof against (default $CORRALAI_REKOR_URL or https://rekor.sigstore.dev)Environment variables
Section titled “Environment variables”CORRALAI_ADDR listen address (default 127.0.0.1:9019)CORRALAI_DB coordination SQLite path (default ~/.claude/corralai_coord.sqlite3)CORRALAI_MEMORY_DB memory DuckDB path (default ~/.claude/corralai_memory.duckdb)CORRALAI_RECORDINGS_DB recordings DuckDB path for scrubbed replay exports (default ~/.claude/corralai_recordings.duckdb)CORRALAI_MEMORY_DIR where new memory entries are written (default ~/.claude/projects/default/memory)CORRALAI_PROJECT_TIERS optional path->tier rules "substr=tier,substr=tier"; front-matter project: wins, else "default"CORRALAI_OIDC_ISSUER OIDC issuer URL (any OIDC provider: Keycloak, Auth0, Okta, Dex, Authentik, …); empty => AUTH DISABLED (dev)CORRALAI_ALLOW_INSECURE set "1" to allow auth-disabled startup on a non-loopback CORRALAI_ADDR (refused otherwise, H-3)CORRALAI_OIDC_AUDIENCE expected token aud (the client_id)CORRALAI_OIDC_CLIENTS extra trusted clients "issuer|aud,issuer|aud"CORRALAI_ALLOWED_PRINCIPALS day-0 SEED of member emails (DB is canonical after; empty => any authenticated)CORRALAI_PRINCIPALS_DB role/allowlist SQLite path (default ~/.claude/corralai_principals.sqlite3)CORRALAI_MEMORY_OWNERS comma list of emails allowed to read/write memory (empty => any authorized)CORRALAI_ALLOWED_HOSTS comma list of accepted Host headers (default: the brain's domains + localhost)CORRALAI_CLIENT_IP_HEADER trusted real-client-IP header for rate limiting (e.g. CF-Connecting-IP); empty => RemoteAddrCORRALAI_RATELIMIT_IP_PER_MIN / _IP_BURST per-IP rate limit (default 300/min, burst 100)CORRALAI_RATELIMIT_USER_PER_MIN / _USER_BURST per-principal rate limit (default 600/min, burst 200)CORRALAI_MAX_BODY_BYTES max request body size (default 1 MiB)CORRALAI_TLS_CERT / _KEY serve HTTPS with these PEM files (built-in TLS, no proxy needed)CORRALAI_TLS_AUTOCERT_DOMAINS comma list => auto Let's Encrypt certs (needs public reachability)CORRALAI_TLS_AUTOCERT_CACHE cert cache dir (default ~/.cache/corralai-autocert)CORRALAI_ADMIN_PRINCIPALS day-0 SEED of superuser emails (DB is canonical after; `corral createsuperuser` adds more)CORRALAI_GATEWAY_DB MCP-gateway registry SQLite path (default ~/.claude/corralai_gateway.sqlite3)CORRALAI_ARTIFACTS_DB fleet skill/hook sync SQLite path (default ~/.claude/corralai_artifacts.sqlite3)CORRALAI_GATEWAY_ALLOWED_HOSTS hosts the gateway may dial despite the SSRF block (private/internal targets); empty => block all private/loopbackCORRALAI_MOTHERDUCK fleet-sync target: "md:<db>" or a .duckdb path; empty => sync offCORRALAI_MOTHERDUCK_TOKEN MotherDuck token (exported as motherduck_token for md: attach)CORRALAI_BRAIN_ID tag for this brain's rows (default hostname)CORRALAI_SYNC_INTERVAL fleet sync interval, seconds (default 30)CORRALAI_FLEET_RETENTION_DISABLE set "1" to disable the retention/compaction cycle entirelyCORRALAI_FLEET_RETENTION_DAYS TTL window in days (default 90; 0 = TTL off, compaction still runs)CORRALAI_FLEET_RETENTION_INTERVAL_SEC how often (seconds) to run the retention cycle (default 3600)CORRALAI_GIT_TOKEN GitHub PAT for repo-work missions (clone + PR); empty => repo engine disabled unless CORRALAI_REPO_ENABLE=1CORRALAI_GITHUB_API GitHub API base URL (default https://api.github.com)CORRALAI_REPO_WORKSPACE root dir for per-mission working copies (default $TMPDIR/corral-repos)CORRALAI_REPO_ENABLE set "1" to enable the repo engine even without a token (anonymous / GitHub Apps token flow)CORRALAI_REVIEW_POLL_SEC how often (seconds) the brain polls open PRs for CHANGES_REQUESTED reviews (default 60)CORRALAI_BRAIN_KEY base64-encoded Ed25519 seed (32 bytes) for cross-swarm brain identity; takes priority over key fileCORRALAI_BRAIN_KEY_FILE path to persist the brain key seed (default ~/.claude/corralai_brain_key); created 0600 on first runCORRALAI_BRAIN_PEERS optional allowlist "brain_id:pubB64" entries (comma or newline separated); empty => TOFU modeCORRALAI_LEARN_DB learning-loop proposals SQLite path (default ~/.claude/corralai_learn.sqlite3)CORRALAI_LEARN_SWEEP_SECONDS how often (seconds) the learn sweep clusters findings/lessons into proposals (default 60)CORRALAI_BUILD_DB `corral certify` signed build-record ledger DuckDB path (default ~/.claude/corralai_build.duckdb)CORRALAI_CERTIFY_KEY hex-encoded Ed25519 seed (32 bytes) `corral certify` build attestations are signed with; takes priority over key fileCORRALAI_CERTIFY_KEY_FILE path to persist the certify signing key seed (default ~/.claude/corralai_certify_key); created 0600 on first runCORRALAI_BRAIN_TOKEN `corral certify`'s bearer token to authenticate to a brain (via `corral secret set`); distinct from CORRALAI_BRAIN_KEY above (that's an Ed25519 IDENTITY SEED, not a bearer token — do not reuse it)CORRALAI_REKOR_URL Sigstore Rekor instance report_build anchors signed build attestations to (default https://rekor.sigstore.dev); `corral certify verify` checks the same default unless --rekor-url overrides itCORRALAI_GATE_POLICY_<NAME> repo merge gate: ONE policy per variable, "repo=owner/name,base=main,net=false,timeout=600,cmd=go test ./..."; cmd= MUST be last — everything after it is the command VERBATIM to the end of the value: commas, semicolons, quotes and newlines included, so nothing can truncate it into a weaker command that exits 0 and posts a wrongful success; timeout= is seconds, defaults to gate.DefaultGateTimeout (600s) when omitted; two policies that would answer the same pull request under the same context= (default corral/gate) are REFUSED — the second would never run — so give one a distinct context=; no such variable => the repo gate is OFF (no poller starts); GitHub-only for v1. Replaces CORRALAI_GATE_POLICIES, which is REFUSED: its ";" separator collided with commands containing ";"CORRALAI_GATE_DB repo gate dedupe/index store DuckDB path (default ~/.claude/corralai_gate.duckdb)CORRALAI_GATE_POLL_SECONDS how often (seconds) the repo gate polls covered repos for new PR heads (default 120)CORRALAI_GATE_EXEC_BACKEND / _EXEC_UNSAFE_HOST same jail backend used by the independent verify-gate (see below); the repo gate reuses it — a missing backend disables the repo gate too, loudly, never unsandboxedCORRALAI_CONTROL_GATE control gate: ";"-separated "repo=owner/name,owner=<principal>,lang=go,base=main" — owner= MUST equal the control owner's authenticated principal (the identity they author controls under), else the gate finds no vetted controls — runs the owner's VETTED tests against PR heads, posts corral/control-gateCORRALAI_CONTROL_GATE_SPEC_DB control-gate vetted-tests store (default ~/.claude/corralai_control_spec.duckdb)CORRALAI_CONTROL_GATE_DB control-gate dedupe/index store (default ~/.claude/corralai_control_gate.duckdb)CORRALAI_CONTROL_GATE_POLL_SECONDS how often the control gate polls for new PR heads (default 120)CORRALAI_BUGCATCH_DB adversarial pool's bug-catching scorecard store DuckDB path (default ~/.claude/corralai_bugcatch.duckdb); also read by `corral scorecard`CORRALAI_CRITICSCORE_DB adversarial pool's critic-accuracy store DuckDB path (default ~/.claude/corralai_criticscore.duckdb); the scorecard's C-PREC column and `corral criticscore` read it over the API — see CORRAL_BRAIN below