The outer loop for coding agents.
Pi's equation is agent = model + minimal harness. Etium's is team = harnesses + minimal loop. Etium is the loop.
Two ways in — you: follow the quick start · your AI agent: hand it etium.dev/agent-install.txt — it interviews you for the setup choices, then follows deterministic steps with a PASS criterion each.
What it is
Etium is a supervisor for headless coding agents. It owns the outer loop — tasks, runs, budgets, gates, and the event ledger — and delegates the entire inner loop (context, tools, model calls) to existing harnesses via thin adapters: Codex, Pi, Claude Code, OpenHands, or any command. Vendor loops are excellent but per-vendor, per-session, and opaque. Etium gives you what they can't: harness neutrality per step, multi-day lifecycles with human gates, and a durable, replayable ledger you own as files.
Sixty seconds
A loop is a plain TypeScript file. No DSL, no YAML, no build step:
// review.ts — plan, wait for a human, implement
export default async function (run) {
await run.step("plan", {
harness: "pi",
prompt: run.t("PLAN_PROMPT.md"),
artifacts: ["PLAN.md"],
});
const d = await run.gate("plan-approved", { show: ["PLAN.md"] });
await run.step("implement", {
harness: "pi",
prompt: run.t("IMPLEMENT_PROMPT.md"), // gate notes injected here
grade: "npm test",
budget: { wall: "2h", tokens: 400_000 },
});
}
$ etium run "add retry to fetchUser" --loop review.ts
$ etium gates # what's waiting on you, across all runs
$ etium approve <run> plan-approved --note "keep the timeout at 5s"
$ etium tail <run> # human-readable event stream
The run parks at the gate — no process stays resident. approve
writes a decision file; the loop replays from its ledger, skips completed
work, and continues with your note injected into the next prompt.
kill -9 anything at any time; etium tick
(cron-safe, idempotent) reconciles every run back to where it should be.
That is the whole liveness story.
Batteries included: the ai-engineer
The bundled ai-engineer package is a
complete multi-persona workflow on these primitives: assign a GitHub issue
to it, and it triages, plans, implements, and reviews on its own branch —
parking at gates you answer with /et comments, opening a
draft PR you merge. The whole state machine is a 97-line loop; the GitHub
integration is one cron line. Follow the
tutorial — the first half runs entirely in your terminal, token-free.
Having an AI agent do the install? Point it at
agent-install.txt.
Six primitives
- Task
- a goal plus acceptance criteria; a markdown file.
- Run
- one attempt; a directory you can
grep,jq, andrsync. - Loop
- a program of steps and gates; ordinary code.
- Step
- one headless harness invocation under a budget, fresh context by default.
- Gate
- a named pause requiring a human decision, consumed exactly once.
- Ledger
- an append-only
events.jsonl; every other view is a projection.
What etium will never do
- Call a model. No API keys, no context management. Model auth is harness-owned; all intelligence lives in harness subprocesses.
- Ship a workflow DSL. Loops are code. YAML workflow languages are how orchestrators become 100,000-line projects.
- Run a server, web UI, daemon, or database. Files and a CLI. Your state is yours.
- Be the fleet coordinator. No scheduler, queue, or control plane in core. Etium scales by composition — more repos, more machines, each running the same daemonless loop, aggregated by projections of the ledger. The one constraint core keeps: one machine per active run (a run's single writer). Across machines there is nothing to outgrow, because nothing is shared.
Size is a feature
| area | budget (LOC) |
|---|---|
| core — ledger, engine, runner, supervisor, tick | 3,000 |
| each adapter | 300 |
| each bundled loop | 150 |
Budgets are enforced in CI. Current core: ~2,100 lines — small enough to read in an afternoon, and that is the credibility test.