中文 · English
A restart-on-exit supervisor for autonomous coding CLIs. Tested with Claude Code and aider out of the box; any prompt-arg CLI via custom config. Spawn the agent round-after-round under defenses that prevent the failure modes that bite in production: stuck rounds, orphan commits, OAuth burn loops, full disks, runaway memory.
┌──────────────────────────────────────────┐
│ Layer 3: The Witness (monitor) │ 10 detectors + auto-stop
├──────────────────────────────────────────┤
│ Layer 2: The Loop (serve, ~60 LOC) │ signal-trapping restart loop
├──────────────────────────────────────────┤
│ Layer 1: The Round (round) │ one agent invocation
└──────────────────────────────────────────┘
pip install cli-agent-runnerThe installed CLI command is agent-runner (the PyPI distribution name is
prefixed for namespace disambiguation; the import name and command are not).
cd your-project
agent-runner init # scaffold agent-runner.toml + prompts/main.md
$EDITOR agent-runner.toml # point agent.command at your CLI
agent-runner install --monitor # systemd user units for serve + monitor
agent-runner status # confirm running
agent-runner peek # snapshot of project state
agent-runner monitor # live anomaly detectionFull walkthrough: docs/quickstart.md.
| Lifecycle | Observation |
|---|---|
init / install / uninstall |
peek — state snapshot |
start / stop / kill / cancel |
watch — peek in a refresh loop |
restart / status |
monitor — 10 detectors, alerts, auto-stop |
round / serve |
Verb reference: docs/commands.md.
11 named defenses, structured as data — see agent-runner peek --select defenses.
Each carries the historical incident it codifies and the invariant test that
guards it. Highlights:
- round_timeout_s — hard wall, never the agent's word on when to stop
- process_group_isolation — kill the round, not just the parent
- orphan_stash_idempotency_s — no 3-stashes-per-second pile-ups
- sha_locked_stash —
stash@{N}indices drift; SHAs don't - set_diff_classification — line-set comparison, not unified-diff +/- scan
- startup_smoke_check — refuse to run with a clearly-truncated prompt
Full list and rationale: docs/architecture.md.
Notify only: timeout_rate, hung, orphan_chain, disk_warning,
mem_pressure, smoke_fail_rate, network_fail, rate_limit_active.
Auto-stop the service (continuing is harmful):
oauth_fail— burning API quota on auth-rejected roundsdisk_critical— writing to a near-full disk risks corruption
Runs locally or against a remote host via ssh:
agent-runner monitor # local, 30s poll
agent-runner monitor --host pi # remote, 60s poll
agent-runner monitor --json | jq -c # pipe to downstream consumersNote: Remote monitor (
monitor --host <alias>) relies on your local~/.ssh/configforStrictHostKeyCheckingand other ssh policy. Useaccept-neworyesto avoid MITM exposure.
docs/quickstart.md— 5-step install + first rounddocs/commands.md— verb referencedocs/configuration.md—agent-runner.tomlschemadocs/runbook.md— operator troubleshooting (OAuth, disk, orphan)docs/architecture.md— 3-layer model, defenses-as-data
git clone https://github.com/wan9yu/cli-agent-runner.git
cd cli-agent-runner
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
./build.sh check # full local-CI sweep
./build.sh test # unit + integration only
AGENT_RUNNER_E2E_PI=1 ./build.sh e2e # opt-in pi e2e (needs ssh alias `pi`)Some docs/*.md blocks are generated from code — ./build.sh docs rewrites
the <!-- gen:* --> regions, and ./build.sh check verifies they are fresh.
POSIX-only (Linux, macOS). Tested under Python 3.11+ on x86_64 and aarch64.