Etium · quick start

Quick start

Two hello-worlds: one that runs offline in sixty seconds and shows you what etium is, and one that drives a real coding agent (Pi).

This is the human path. Having an AI agent do the setup instead? Hand it etium.dev/agent-install.txt — deterministic steps with a PASS criterion each, stop-on-fail.

Setup

npm install -g @etium/core

(Permission error? Your Node is system-installed — the macOS .pkg installer, or a Linux distro package — so its global prefix is root-owned. Quick fix: sudo npm install -g @etium/core. Permanent fix: install Node via Homebrew or a version manager and sudo is never needed again.)

Etium setup is four questions, the same ones an agent asks on the agent path: which repo (wherever you run etium), etium only or with the ai-engineer loop library (this page is etium only — the tutorial is the library path), GitHub wiring or terminal only (this page is terminal only), and where throwaway work may go (yours to pick when testing).

Prefer being walked through it? etium init checks your machine (each missing dependency printed with the command that fixes it), asks the setup questions with sensible defaults, and applies your answers.

Hello world, offline — the shape of a run

Etium's whole model: a loop is a plain TypeScript file that sequences steps (headless subprocesses) and gates (parks until a human decides). No tokens, no model, no network needed to see it work — exec runs any command as a step.


export default async function (run) {
  await run.step("greet", { harness: "exec", command: "echo hello > hello.txt" });
  const d = await run.gate("publish?", { show: ["hello.txt"] });
  await run.step("publish", {
    harness: "exec",
    command: `echo "hello, ${d.by}" > published.txt`,
  });
}
etium run "say hello" --loop hello.ts
etium status
etium gates

The run parked. Nothing is running — kill -9 anything you like. Now decide:

etium approve <run> "publish?" --note "ship it"
etium tail <run>

Everything that happened is files: ls .etium/runs/<run>/events.jsonl is the append-only ledger (authority for control flow), steps/ holds each step's exact prompt and raw stream, decisions/ carried your approval. grep gate .etium/runs/*/events.jsonl works. That's the product.

Hello world with Pi — a real agent in the loop

Pi authenticates itself — etium never touches model credentials (see the model-auth doc in the repo). One-time, per machine:

pi

(API-key users can skip the login: the pi adapter passes ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, or OPENROUTER_API_KEY through from your environment — values are redacted from everything etium writes to disk.)

Now give an agent a task under the bundled ralph loop — iterate until the check passes:

mkdir hello-pi && cd hello-pi
echo "Create hello.txt containing exactly: hello world" > PROMPT.md
etium run "pi says hello" --harness pi --workspace . \
  --param check="grep -q 'hello world' hello.txt" \
  --param iterations=3
etium tail <run>

(--workspace . makes the current directory the step workspace — that's where PROMPT.md is found and where the agent's files land. Omit it and each run gets a fresh empty workspace under .etium/runs/<run>/ws/.)

The step's full model conversation is captured under .etium/runs/<run>/steps/001-iterate.0/prompt.md is exactly what was sent, raw.jsonl(.zst) is exactly what came back. A word on failure: pi ships no auth-status command and exits 0 even when the model call errors, so etium can't refuse up front the way it does for harnesses with a check command — instead the error surfaces as a message in etium tail (e.g. error: No API key for provider: …), the check step fails, and ralph iterates or parks at the guard. Authenticate (pi/login) and etium resume <run>.

Where to go next