Skip to content

CLI Reference

This page is the command surface from the spec, section 10, annotated against the capability matrix, section 11. It documents the whole contract - and it is exact about what runs in the binary today versus what the contract specifies for commands not yet built.

  • Shipped - in cmd/loopexec with tests. Runs today.
  • In progress - on a feature branch. Not in a release build.
  • Planned - specified in the contract. Not yet built.

The source of truth for this column is SPEC section 11. When a capability moves status, the spec changes first; this page and the binary tests both reference it.

The full engine ships - eighteen commands:

Terminal window
loopexec init # scaffold workspace metadata
loopexec run # real bounded check_fixpoint loop
loopexec status # show loop status
loopexec check # validate invariants (state hygiene)
loopexec step # execute a single step
loopexec probe-check / doctor / explain-halt
loopexec replay / attest / reexecute
loopexec escalate / watch / ack
loopexec build-context / isolate
Terminal window
loopexec run --json # emit exactly one JSON object to stdout

The iterating run is Shipped, and computed halts now emit across the 13 (integrity), 14 (oracle-untrusted), 15 (check-inadequate, via the doctor --mutate-cmd adequacy canary), 16 (resumable-judgment), 17 (no-convergence), 18 (budget, via inspect-cost), 19 (liveness/drift), and 30 (workspace/isolation) classes, alongside the original 0/10/12/20/40/50. Every class 13-19 now emits; the only reasons still reserved are class 11’s task_list-mode reasons (no_actionable_tasks / human_required), which belong to the task_list loop topology. A few individual reasons inside active classes, and in-loop budget enforcement during run, stay Planned. See Exit codes below.

CommandPurposeStatusExit semantics
initscaffold .loopexec/ workspace metadata (versioned loop.yml scaffold Planned)Shipped0 / workspace_invalid
runthe real iterating loop (section 4); computed haltShippedper halt map
run --oncesingle iteration for debugging; absorbs stepShippedper halt map
probe-checkdeterminism as a confidence bound; agent-freeShipped (core)0 / class 14
build-contextbounded relevant slice; budget ceiling; workdir-confinedShipped0 / context_budget_unsatisfiable (19)
isolatetwo-zone orchestration: detached-clone sandbox + per-run minted/revoked key + rendered/launched zonesShipped0 / isolation_unsatisfiable (30) / execution_failure (40)
doctorprecondition gate: determinism + isolation preflight + adequacy mutation canary (hermeticity O3 and coverage-delta tier still Planned)Shipped (determinism + isolation preflight + adequacy canary)0 / class 13
checkSMALL / state-hygiene validation (not the oracle)Shipped0 / invariant_failed
ratchetno-regression ratchet over the failing set (ships inside run via --failures-cmd); standalone inspect/advance command PlannedShipped (in run)0 / class 17
replayVERIFY a recorded receipt (agent-free, budget-free)Shipped0 / class 13
reexecutelive re-run; statistical match; --confirmShipped0
reportrender a recorded receipt (digest + timeline); re-runs nothingShipped0
statuslive status / tailShipped0
inspect-costcost ledger -> run-total cap + sigma anomalyShipped0 / class 18
explain-halthuman rationale; “raise the limit” vs “never retry”Shipped0
escalatestructured packet (file/stdout); marks the run pagedShipped0 (paged)
watchheartbeat staleness detection (kill-PID actuator Planned)Shipped0 / heartbeat_stale (19)
attestHMAC-sign + verify a receiptShipped0 / class 13
ackclear comprehension debt + paged escalation; records --reviewerShipped0
  • --json - Shipped. Emit exactly one JSON object to stdout. Human logs and errors go to stderr. See JSON contract.

Scaffold the workspace. Today init creates the .loopexec/ metadata directory; durable, resumable run state (.loopexec/state.json, section 8) is written by run and is Shipped. The contract additionally extends init to scaffold a versioned loop.yml; that fuller scaffold is Planned.

  • Flags: --json.
  • Exit: 0 on success; workspace_invalid (30) if the workspace cannot be written.
Terminal window
loopexec init
loopexec init --json

The real iterating loop, section 4: execute the work step (--exec), run the external check (--check) once, evaluate guards before any green branch (guards dominate success), apply the anti-regression ratchet, append a receipt, then continue or halt on a computed condition. With no --check it refuses to start (workspace_invalid): no check, no loop.

  • Flags: --check (required oracle), --exec, --max-iterations, --run-id, --workdir, --budget-usd; optional --failures-cmd (ratchet), --integrity-cmd (metric-integrity gate), the receipt-pinning flags, and --comprehension-every. --budget-usd is recorded today; live metering is Planned.
  • --halt-reason survives as a hidden test fixture only. The contract forbids a flag-forced halt: every halt reason is derived from observed state.
  • Exit: per the halt-reason map. run emits 0/10/12/40 plus the computed 13 (integrity), 17 (no-convergence), and 19 (liveness) reasons it owns. run itself does not emit class 15 (check-inadequate) or class 18 (budget): those come from doctor --mutate-cmd and inspect-cost respectively, and in-loop budget enforcement during run stays Planned. No class is globally reserved except class 11’s task_list-mode reasons.
Terminal window
loopexec run --run-id local --max-iterations 20 --json

A single iteration, for debugging. It runs one iteration of the real loop (--exec then --check) and halts on the computed outcome: success_condition_met if the check passes, else max_iterations_reached. It overrides --max-iterations, and absorbs the legacy step stub.

  • Exit: per the halt-reason map - 10 if the one iteration converges, 12 if not, 40 if the work step fails.
Terminal window
loopexec run --once --check "go test ./..." --exec "make fix"
loopexec step # legacy stub; prefer run --once

Determinism as a confidence bound, not a pass/fail of N runs. probe-check reports an achieved confidence bound on the check’s flake rate; the run count is derived from a target max_flake_rate, not a magic constant. Probing is adversarial where configured - test order, seed, clock, concurrency, load - and reports which dimension broke. Agent-free.

  • Exit: 0, or class 14 (oracle-untrusted): check_flaky, check_has_side_effects, check_not_hermetic, hermeticity_violation.

See Determinism for the sequential in-loop monitor that maintains this bound across the run.

Emits a narrow, budgeted context slice: machine state + the open failure + relevant source files (from the failure stack trace, the last git diff via --diff-base, and untracked files). The token budget is a true ceiling, measured with a code-calibrated estimator. It is never fatal on no relevant files; it emits context_budget_unsatisfiable only when the mandatory state+failure slice cannot fit. File resolution is workdir-confined and symlink-safe - untrusted failure text cannot read files outside the workdir; reads are size-bounded and untrusted content is fence-escaped. The import_closure / dep_graph relevance tiers are Planned.

  • Exit: 0 / context_budget_unsatisfiable (class 19).

doctor - Shipped (determinism + adequacy canary)

Section titled “doctor - Shipped (determinism + adequacy canary)”

The precondition gate. The contract requires doctor to refuse to start a loop when the check is not deterministic (O2) or not hermetic (O3), is inadequate - coverage delta plus a mutation canary that MUST turn the check red (O4) - or when two-zone isolation is unsatisfiable: a cloud or local-host model paired with network: none, a ~/.claude bind-mount, an exec_zone with network, or a missing egress allowlist (section 7). Fail-closed.

--mutate-cmd now ships the core of the O4 adequacy gate: it runs an operator-provided mutation in an isolated copy of the workdir and verifies the --check turns RED. If the check stays green with a planted bug, that is check_inadequate (15); a --mutate-cmd that cannot apply is execution_failure (40). The coverage-delta tier of adequacy and the hermeticity (O3) gate remain Planned.

  • Exit: 0, class 15 (check_inadequate) via --mutate-cmd, or 40 (execution_failure) when the mutation cannot apply. The specified surface also covers class 13 (credential_scope_invalid) | 14 (oracle-untrusted) | 30 (isolation_unsatisfiable).

SMALL / state-hygiene validation only. This is the small check --strict analog: it validates structural state hygiene. It is explicitly not the application oracle - it cannot decide application correctness, and the contract forbids treating it as a check_fixpoint stop condition.

  • Flags: --fail-invariant (fixture, forces failure), --json.
  • Exit: 0 / invariant_failed (20).
Terminal window
loopexec check --json

The no-regression ratchet over the failing-test set is the anti-random-walk Lyapunov function (section 3.2). It ships inside run: pass --failures-cmd and each iteration’s failing set is tracked against a best-so-far; the loop halts same_test_regressed (a resolved failure returned), oscillation_detected (the set exactly repeated an earlier iteration), or no_progress_detected (no new best within --no-progress-k iterations). A standalone ratchet inspect/advance command and git revert-to-best are Planned.

  • Exit: 0 standalone; class 17 (no-convergence) when the ratchet halts a run.

VERIFY a recorded receipt. replay re-runs the deterministic check against the recorded end-state and confirms the fingerprint matches the receipt. Agent-free, budget-free, deterministic. It answers “does this receipt’s verdict still hold?”

A live-LLM trajectory is not reproducible; only the verdict is. This is why the contract says replayable verdicts, never “replayable runs.”

  • Exit (specified): 0 / class 13 (integrity), e.g. objective_unverified.

RE-RUN the live agent loop. Non-deterministic - the LLM samples - so it reports a statistical match, never byte identity. Budget-burning and --confirm-gated.

  • Exit (specified): 0.

report renders a recorded receipt as a digest: the run’s outcome (phase, halt reason, exit class), its pins (check, fingerprint, model, sampling, cost, context-manifest size), whether it is attested, and the per-iteration timeline parsed from the JSONL log. It re-runs nothing and exits 0 even for a failed run - it reports, it does not re-decide. --run-id addresses any recorded run (default: the latest). status is the live tail and ships today.

  • status flags: --run-id, --iteration, --halt-reason, --json.
  • Exit: 0.
Terminal window
loopexec status --run-id local --iteration 1 --json

Analyze a per-iteration cost ledger against a run-total hard cap and a sigma anomaly bound. loopexec does not meter live token cost (the model call lives in --exec); it owns the math over costs you supply, and decides the class-18 halt. The cap and the anomaly detector are distinct: a run can be under budget yet flag a spike.

  • Inputs: --ledger <file> (one USD per line) and/or --cost <usd> (repeatable).
  • --budget-usd is the run-total cap; over it halts budget_exceeded. --sigma N (default 3) flags any iteration above the rolling mean + N standard deviations of the iterations before it -> cost_anomaly. A flat ledger has no variance and raises nothing; an empty ledger or a negative cost is invariant_failed.
  • Exit: 0 within cap and no spike; 18 for budget_exceeded / cost_anomaly; 20 on bad input.
  • Planned: auto-parsing provider usage and in-loop enforcement during run.

The honest realization of “explain why.” It reads .loopexec/state.json and distinguishes max_iterations_reached reached while the failing-test set was still strictly decreasing (“raise the limit, retry”) from a stalled, regressed, oscillating, or infeasible halt (“do not retry - it burns budget forever”). That distinction is the one piece of information the 3am operator actually needs.

  • Exit: 0.

escalate emits a structured human-handoff packet (--channel file|stdout; github/slack Planned) and marks the run paged, cleared by ack. watch is the external supervisor that polls the heartbeat’s age and emits heartbeat_stale (19) when it goes stale - a heartbeat nobody reads is just a file. The SIGKILL-the-wedged-PID actuator is Planned.

  • Exit (specified): escalation_pending (16) / heartbeat_stale (19).

attest signs a receipt so provenance is checkable. ack records a signed comprehension ack that clears comprehension_debt_exceeded - a forcing/visibility gate, not proof of comprehension.

  • Exit (specified): 0.
Terminal window
loopexec ack --through <sha> --reviewer <id> # Planned

Every command in --json mode emits exactly one JSON object to stdout. Human logs and errors go to stderr. The object includes at least {tool, version, status, errors[]} and, where applicable, {run_id, iteration, halt_reason}. The schema is additive: new fields MAY be added; existing field meanings MUST NOT change within a major spec version.

FieldTypeNotes
toolstringalways "loopexec"
versionstringbinary version
statusstringe.g. ok, initialized, halted, error
run_idstringpresent where applicable
iterationintegerpresent where applicable
halt_reasonstringthe computed halt reason, when halted
errorsarray of stringsalways present (may be empty)

Current example object, emitted by the Shipped binary:

{
"tool": "loopexec",
"version": "0.2.0",
"status": "ok",
"run_id": "local",
"iteration": 1,
"errors": []
}

The halt_reason string is the stable integration contract. Integrations SHOULD branch on it. The exit code is a coarse class for CI that does not parse JSON.

The base codes 0/10/12/20/30/40/50 are wired in the binary today, and classes 13, 14, 15, 16, 17, 18, and 19 now emit their core reasons - from the iterating run, the determinism / ratchet / receipt / ops / context / isolation commands, (class 18) inspect-cost, and (class 15) the doctor --mutate-cmd adequacy canary. Every class 13-19 now emits; only class 11’s task-list reasons remain reserved. The full canonical map:

ExitClasshalt_reason stringsWired today
0nominal(loop ran, no halt)Yes
10convergedsuccess_condition_metYes
11terminal-blockedno_actionable_tasks, human_requiredReserved (task-list mode)
12iteration-capmax_iterations_reachedYes
13integrityblocked_path_modified, reward_hacking_detected, metric_integrity_violation, credential_scope_invalid, objective_unverifiedPartial (metric_integrity_violation, credential_scope_invalid, objective_unverified)
14oracle-untrustedcheck_flaky, check_has_side_effects, check_not_hermetic, hermeticity_violationPartial (check_flaky)
15check-inadequatecheck_inadequateYes (via doctor --mutate-cmd)
16resumable-judgmentescalation_pending, reviewer_rejectedPartial (escalation_pending)
17no-convergenceno_progress_detected, same_failure_repeated, oscillation_detected, same_test_regressed, unsatisfiable_constraints, infeasible_suspectedPartial (no_progress_detected, oscillation_detected, same_test_regressed)
18budgetbudget_exceeded, cost_anomalyYes (via inspect-cost)
19liveness/driftheartbeat_stale, model_drift_detected, comprehension_debt_exceeded, context_budget_unsatisfiablePartial (heartbeat_stale, comprehension_debt_exceeded, context_budget_unsatisfiable)
20invariantinvariant_failedYes
30workspaceworkspace_invalid, isolation_unsatisfiableYes (workspace_invalid, isolation_unsatisfiable)
40executionexecution_failureYes
50internalinternal_errorYes