Skip to content

CLI Guide

Documentation source v0.5.0-rc.1. Published releases

This document defines the command surface and machine contract for loopexec.

The generated command, flag and JSON field contract is checked against the actual runtime by tests. This guide defines value semantics and examples; both must be updated together when the behavior changes.

Commands

  • loopexec models plan
    • Preview the selected workflow task’s configured model profiles, role assignments, reasoning settings, capability declarations and rationale. --workflow <file> is required; --workdir defaults to .. Read-only: no hooks, calls, reservations or runtime initialization. Supports human output and one --json object with model_selection. See model assignments.
  • loopexec init
    • Initialize local loopexec workspace metadata.
  • loopexec demo
    • Run a zero-credential deterministic proof of the execution-integrity contract; no agent, model, API key, or network is used.
    • Creates a red local fixture, executes the real bounded loop, turns the external check green, writes a typed JSONL receipt, and verifies its fingerprint through the same verifier as loopexec replay.
    • --workdir <dir> keeps artifacts at a known path. The target may contain unrelated files, but it must not already contain .loopexec or status.txt; the command refuses to overwrite either. Without the flag, a retained temporary directory is created.
    • Supports global --json and emits exactly one final response object.
  • loopexec run
    • Run a bounded check_fixpoint loop until the check passes, a bound trips, or the work command fails.
    • Flags: --check "<cmd>" (required external oracle; exit 0 = converged), --exec "<cmd>" (work step run each iteration), --max-iterations N (fuse, default 10), --once (run exactly one iteration for debugging; overrides --max-iterations; converges or halts max_iterations_reached), --run-id, --workdir, --budget-usd.
    • Optional set-based progress (section 3.2): --failures-cmd "<cmd>" prints the current open failures (one identity per line) and enables the no-regression ratchet; --no-progress-k N halts after N iterations with no new best failing-set size.
    • Optional metric-integrity gate (section 6): --integrity-cmd "<cmd>" prints the test-determining surface (one identity per line); its t0 set MUST NOT lose a member. Evaluated before the green check (guards dominate success); a violation halts metric_integrity_violation.
    • Optional receipt pinning (section 8): --model-provider/--model-id/--model-version, --temperature/--seed/--max-tokens, --context-file <path> (repeatable; recorded with sha256), --cost-usd. A check fingerprint (exit code + output sha256) is always recorded for replay. The --model-* flags record only — they do not select or constrain the model (the model is chosen and invoked inside --exec), and the pin is not verified against the actual call. See the Models and Agents guide for wiring a specific model.
    • Optional comprehension gate (section 9): --comprehension-every N halts comprehension_debt_exceeded after N merged-but-unread iterations (cleared by loopexec ack). Each iteration also updates a heartbeat for loopexec watch.
    • Halt reasons are computed from observed state (success_condition_met / max_iterations_reached / execution_failure / workspace_invalid, plus no_progress_detected / oscillation_detected / same_test_regressed when --failures-cmd is set), never forced by a flag.
    • Writes a typed JSONL receipt to .loopexec/run-<id>.jsonl and atomic state to .loopexec/state.json.
    • Optional workflow model_policy selects advisory guidance or explicit argv-bound task/role assignments. Explicit mode requires reservation/usage identity, rejects other exec overrides and legacy model identity flags, and reports drift as exit 19 while retaining incurred usage. Selection appears in run JSON, state, per-attempt receipt events and reports; provider identity is adapter-reported, not independently verified. No automatic model escalation, budget renewal or quality-target change occurs.
  • loopexec probe-check
    • Measure check determinism as a confidence bound (SPEC O2): no check, no loop.
    • Flags: --check "<cmd>" (required), --runs N (default derived), --max-flake-rate R (derives run count via the rule of three, runs >= 3/R), --workdir.
    • Reports the achieved 95% upper bound on the flake rate; halts check_flaky (exit 14) if the verdict varies across runs.
  • loopexec doctor
    • Gate loop preconditions. Enforces determinism (via the probe), an isolation preflight, and — when --mutate-cmd is given — check-adequacy via a mutation canary (O4); hermeticity (O3) and the coverage-delta tier remain planned (SPEC O2-O5, section 7).
    • Flags: --check "<cmd>", --runs N, --max-flake-rate R, --workdir, plus isolation preflight --bind-model-home (a $HOME/.model-home credential mount fails closed -> credential_scope_invalid, 13), --exec-network <policy> (must be none -> else isolation_unsatisfiable, 30), and --mutate-cmd "<cmd>" (an operator command that plants a mutation in the changed code; the --check MUST then turn red, else check_inadequate, 15). The canary runs in an isolated copy of the workdir, so the real tree is never mutated; it is skipped when the check is not deterministic.
    • Exit 0 on a green doctor; check_flaky (14), credential_scope_invalid (13), isolation_unsatisfiable (30), check_inadequate (15), execution_failure (40, if --mutate-cmd cannot apply), or workspace_invalid (30) otherwise.
  • loopexec explain-halt
    • Render why the recorded run halted, distinguishing raise-the-limit (the failing set was still shrinking) from do-not-retry (stalled, regressed, oscillating, or infeasible). Reads the latest run by default; --run-id <id> explains a specific recorded run.
  • loopexec replay
    • VERIFY a recorded receipt: re-run the recorded check against the current end-state and confirm the fingerprint matches. Agent-free and budget-free; never re-runs the agent. Exit 0 on a match; objective_unverified (13) on a mismatch. Verifies the latest run by default; --run-id <id> verifies a specific recorded run. (reexecute --confirm provides live reruns of legacy configs.)
  • loopexec attest
    • HMAC-sign the receipt (over the model pin, sampling, context manifest, cost, and fingerprint) so provenance is checkable; --verify checks the stored signature. Signs the latest run by default; --run-id <id> targets a specific recorded run. Key from --key, else $LOOPEXEC_ATTEST_KEY, else a dev default.
  • loopexec report
    • Render 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), signature-file presence, and the per-iteration timeline parsed from .loopexec/run-<id>.jsonl. Re-runs nothing and exits 0 even for a failed run (it reports, it does not re-decide). Reports the latest run by default; --run-id <id> targets a specific recorded run.
    • Unreleased reporting additions: report.timeline contains readable typed events, including phase, duration, cause and output-truncation flags; the response preserves failure_cause. report.receipt_status is readable, incomplete, missing, or unreadable; report.warnings names lost evidence. Invalid JSON/events and mismatched run IDs are excluded with warnings, while valid events remain visible. readable means parsing succeeded, not that the trajectory or receipt integrity was verified. Warnings do not change the read-only report exit code.
    • report.attestation_status is absent, present_unverified, or unreadable. The legacy report.attested boolean retains its signature-file-presence meaning. Verify explicitly with attest --verify and the signing key. Human reports show the best retained score, configured score_target, review counts and candidate retention separately from convergence; an accepted candidate from a capped run is not quality approval.

run writes a per-run state snapshot (.loopexec/run-<id>.state.json) next to its receipt, so replay / explain-halt / attest / report can address any recorded run by --run-id even after later runs advance the default .loopexec/state.json pointer.

  • loopexec reexecute
    • Live re-run of the recorded loop config --samples N times in isolated copies; reports the halt-reason distribution and convergence rate (a statistical match, not byte identity). --confirm required (it burns budget).
  • loopexec escalate
    • Emit a structured escalation packet (--channel file|stdout; github/slack Planned) and mark the run paged. Cleared by ack.
  • loopexec watch
    • Read .loopexec/heartbeat and report alive or heartbeat_stale (19) when its age exceeds --stall-timeout. The kill-the-wedged-PID actuator is Planned.
  • loopexec ack
    • Clear comprehension debt and any paged escalation, recording --reviewer (a forcing/visibility gate, not proof of comprehension).
  • loopexec build-context
    • Assemble a narrow, budgeted context slice (state + the open failure + relevant files) under a code-calibrated token ceiling. Relevance = files named in the --failure stack trace + the last git diff (--diff-base) + untracked files. Flags: --failure <file|-|text>, --budget-tokens N (default 8000), --diff-base, --workdir, --out (confined to --workdir). Never fatal on no files; context_budget_unsatisfiable (19) only if the mandatory state+failure slice cannot fit. File resolution is workdir-confined and symlink-safe (untrusted failure text cannot read outside the workdir), reads are size-bounded, and untrusted content is fence-escaped.
  • loopexec isolate
    • Orchestrate two-zone isolation (SPEC section 7): a hardened detached-clone sandbox (no origin, no host hooks, no inherited credentials), a per-run minted/revoked credential (injected via a 0600 --env-file, never on the argv / in the receipt; --mint-cmd requires --revoke-cmd), and a rendered exec-zone (--network none) + agent-zone (egress-allowlist via --egress-proxy) launch plan. --execute --confirm launches via --runtime (default docker); otherwise the plan is rendered only. Image/run-id inputs are validated and a -- separator stops docker flag parsing (no argument-injection). A failed zone surfaces as execution_failure (40). The container engine, the auditing egress proxy, and the provider key API are operator-provided hooks.
  • loopexec inspect-cost
    • Analyze a per-iteration cost ledger against a run-total cap and a sigma anomaly bound. This command analyzes supplied costs; workflow runs meter provider-neutral actuals through adapter hooks. Inputs: --ledger <file> (one USD per line) and/or --cost <usd> (repeatable). --budget-usd is the run-total hard cap (over it halts budget_exceeded, 18); --sigma N (default 3) flags any iteration exceeding the rolling mean + N standard deviations of the iterations before it (cost_anomaly, 18). A flat ledger has no variance, so it raises no anomaly; negative costs and an empty ledger are rejected (invariant_failed, 20). Provider-specific parsing lives in adapters; run --workflow now reconciles their usage and enforces reservations/allowances.
  • loopexec budget status / loopexec budget reserve
    • Opt-in shared call allowance for child model subprocesses across independent run IDs. Both require --store-dir <absolute-existing-directory> and --policy <file>. Reserve also requires --phase <name> and a unique --call-id <id>; call it immediately before launching that child. A reservation consumes its slot even if the child later fails, and a duplicate call ID is rejected rather than granting a free retry.
    • Policy JSON: {"schema_version":1,"scope":"studio-floor-rack","max_calls":2,"phase_limits":{"builder":1,"critic":1}}. The first reservation pins this policy in the shared store. Later runs must supply the same policy; a changed limit or damaged ledger fails closed. A zero limit blocks all calls. The store is independent of the run workdir, and status is read-only.
    • Exceeding the total or phase allowance returns budget_exceeded (18). Duplicate calls, changed policy, or malformed records return cost_anomaly (18). This is a call-count gate, not a provider token or monetary cap; adapters must still report usage through workflow metering where available.
  • loopexec status
    • Show loop status.
  • loopexec check
    • Validate invariants (state hygiene, not the application oracle).
  • loopexec step
    • Execute a single step.

Global flags

  • --json
    • Emit exactly one JSON object to stdout.
    • Human logs and error text go to stderr.

JSON output schema

All commands in --json mode emit one object with these fields:

  • tool (string)
  • version (string)
  • status (string)
  • run_id (string, optional)
  • iteration (integer, optional)
  • halt_reason (string, optional)
  • errors (array of strings)

Example:

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

Exit codes

The halt_reason string is the stable contract; the exit code is its coarse class (see SPEC.md section 5). Every class 13-19 emits today alongside the base 0/10/12/20/30/40/50 (class 18, budget_exceeded / cost_anomaly, via inspect-cost and workflow runs; class 15, check_inadequate, via the doctor --mutate-cmd adequacy canary); only class 11’s task-list reasons remain reserved (the task_list loop topology). A few individual reasons inside active classes, the doctor coverage-delta and hermeticity tiers, are still Planned (see SPEC.md section 11).

A computed halt is an outcome, not a crash: the command emits its result object (JSON or the human summary) to stdout and exits with the class code, and prints nothing to stderr. A converged run exits 10 cleanly. Only genuine failures (invalid usage, unreadable state, I/O errors) print a message to stderr.

  • 0 success (loop ran, no halt)
  • 10 converged: success_condition_met
  • 11 terminal-blocked: no_actionable_tasks, human_required
  • 12 iteration-cap: max_iterations_reached
  • 13 integrity: blocked_path_modified, reward_hacking_detected, metric_integrity_violation
  • 14 oracle-untrusted: check_flaky, check_not_hermetic, hermeticity_violation
  • 15 check-inadequate: check_inadequate
  • 16 resumable-judgment: escalation_pending, reviewer_rejected
  • 17 no-convergence: no_progress_detected, oscillation_detected, infeasible_suspected
  • 18 budget: budget_exceeded, cost_anomaly
  • 19 liveness/drift: heartbeat_stale, model_drift_detected, comprehension_debt_exceeded
  • 20 invariant failed
  • 30 workspace invalid or missing
  • 40 execution failure (timeout or command failure)
  • 50 internal error

Full example

Human mode:

Terminal window
loopexec init
loopexec run
loopexec status --run-id local --iteration 1

JSON mode:

Terminal window
loopexec run --json

Unattended workflow flags

  • run --timeout <duration>: total deadline, default disabled.
  • --command-timeout <duration>: every subprocess/hook, default disabled.
  • --terminate-grace <duration>: process-group TERM-to-KILL grace, default 250ms.
  • --workflow <file>: schema-1 JSON, relative to workdir or absolute; argv work, verification, reservation/usage hooks, candidate manifest, and numeric policy.
  • --resume: same run ID and immutable config/bounds; reconcile pending actuals first, preserve attempt count, original total deadline, and cumulative spending.
  • --budget-usd: a nonzero allowance now requires workflow strict/observed mode. It is rejected when metering is absent; --cost-usd is metadata only.

See workflows.md for the full request/response schemas, strict versus observed/unknown guarantees, migration, protected-path rules, and executable examples. Existing JSON fields and exit classes remain; workflow state/report add metering status, numeric progress, candidate IDs, and explanatory causes. Workflow replay verifies the exposed best candidate’s saved check. Generic reexecute rejects workflow receipts to prevent reuse of absolute live hooks.

Version identity

Use loopexec --version for a standard version string or loopexec version --json for the normal JSON identity contract.