How the loop works
Five stations, in order: the advisor plans, the queue records, the executor builds, the review gate holds, and a human decides. Two rules make it trustworthy: save before acting, and never lose state.
The cycle
- Advisor plans. The advisor (an agent CLI, a browser ChatGPT session, or you in manual mode) produces a plan. The response is saved to the artifact store first — nothing acts on unsaved text.
- Queue records. Work becomes a job in an append-only ledger with an idempotency key. Re-queueing the same work is refused, so a crash never doubles a job.
- Executor works. The executor receives one packet at a time and implements it.
- Review gate. Results wait at a required gate. Only the final fenced control block of an advisor response is parsed, against a fixed vocabulary; anything ambiguous is quarantined as
control_block_valid: false— which means "get a human", never "use your judgment". - Human decides. A blocking question lands in
human-decisions/open.mdand pauses that project only. Everything else keeps moving.
Tick: the loop's heartbeat
arthur tick costs no tokens and answers one question — what should happen next?
| Verdict | Means | Next move |
|---|---|---|
POLL_DUE | A job is due and nothing blocks it | Claim it and work it |
WAIT | Nothing due yet | Stop; come back at next_due_at |
HUMAN_INPUT_REQUIRED | A project has an open decision | Surface it; that project is paused |
BLOCKED_BY_BROWSER_LOCK | Another session holds a fresh advisor lease | Wait, do not break it |
BLOCKED_BY_QUOTA | Quota at or below your reserve | Checkpoint; start nothing new |
With --exit-verdict, each verdict maps to a distinct exit code (0, 10, 11, 12, 13) so a shell chain can gate on it. Codes start at 10 so a blocked loop is never mistaken for a broken command.
The resource governor
The governor watches two things. Quota: how much of your subscription the agents have left, read from a provider you choose (CodexBar, a command, or a file), classified GREEN/YELLOW/RED, with a reserve line (default 5%) below which the loop checkpoints instead of starting new work. The machine: host memory and CPU pressure, sampled best-effort and shown beside quota in the console topbar. Per-task usage attribution (arthur usage task) tells you what each packet actually cost.
The files under it all
| Path | What | Rule |
|---|---|---|
queue/jobs.jsonl | Job snapshots, last write wins | Only arthur queue writes here |
queue/events.jsonl | The audit trail | Append-only, never rewritten |
projects/<ID>/artifacts/ | Saved advisor responses + index | Written before anything acts on them |
human-decisions/open.md | Blocking questions | Status: OPEN pauses that project only |
runtime/ | Tick state, session registry | Derived; safe to lose |
config/arthur-loop.json | Adapters, quota, projects | Hand-edited, validated on load |
Never hand-edit the ledgers. The full invariants live in the repo's AGENTS.md.