···11+# mill
22+33+A runtime for executing TypeScript programs that spawn and coordinate AI agents. Write plain TS with `await` and `Promise.all` — mill handles the lifecycle, persistence, and observability.
44+55+## What you can do
66+77+**Orchestrate agents in plain TypeScript** — no DSL, no YAML, just sequential and parallel `await` calls with a single injected `mill.spawn()` API.
88+99+**Run async by default** — `mill run` returns a `runId` immediately and executes in a detached worker. Attach later with `watch`, `wait`, or `inspect`.
1010+1111+**Swap agent backends** — drivers are generic adapters. Ship with pi, Claude, and Codex drivers. Write your own by implementing a codec that parses process output into structured events.
1212+1313+**Observe everything** — structured NDJSON event log per run, real-time streaming via `mill watch`, and full session replay via `mill inspect --session`.
1414+1515+## Quick example
1616+1717+```ts
1818+// review.ts
1919+const scan = await mill.spawn({
2020+ agent: "scout",
2121+ systemPrompt: "You are a code risk analyst.",
2222+ prompt: "Review src/auth and summarize top security risks.",
2323+ model: "openai/gpt-5.3-codex",
2424+});
2525+2626+const plan = await mill.spawn({
2727+ agent: "planner",
2828+ systemPrompt: "You turn findings into an execution-ready plan.",
2929+ prompt: `Create remediation steps from:\n\n${scan.text}`,
3030+});
3131+3232+console.log(plan.text);
3333+```
3434+3535+```bash
3636+mill run review.ts # returns runId, executes in background
3737+mill watch abc123 # stream events live
3838+mill run review.ts --sync # or block until done
3939+```
4040+4141+## CLI
4242+4343+```
4444+mill run <program.ts> [--sync] [--json] [--driver <name>]
4545+mill status <runId> show run state
4646+mill wait <runId> --timeout block until complete/failed/cancelled
4747+mill watch <runId> stream tier-1 events (NDJSON with --json)
4848+mill inspect <id>[.<spawnId>] inspect run or spawn detail
4949+mill inspect <id> --session resolve full agent session via driver
5050+mill cancel <runId> interrupt run and all live spawns
5151+mill ls [--status <filter>] list runs
5252+mill init generate starter mill.config.ts
5353+```
5454+5555+All commands accept `--json` for machine-readable output on stdout (diagnostics go to stderr).
5656+5757+## Configuration
5858+5959+```ts
6060+// mill.config.ts
6161+import { defineConfig, processDriver, piCodec } from "@mill/core";
6262+6363+export default defineConfig({
6464+ defaultDriver: "pi",
6565+ defaultModel: "openai/gpt-5.3-codex",
6666+ defaultExecutor: "direct",
6767+ drivers: {
6868+ pi: processDriver({
6969+ command: "pi",
7070+ args: ["-p"],
7171+ codec: piCodec(),
7272+ }),
7373+ },
7474+});
7575+```
7676+7777+Resolved in order: `./mill.config.ts` → walk up to repo root → `~/.mill/config.ts` → built-in defaults.
7878+7979+## Packages
8080+8181+| Package | Purpose |
8282+|---|---|
8383+| `@mill/core` | Engine, run lifecycle, public API, config loader |
8484+| `@mill/cli` | CLI commands wrapping core |
8585+| `@mill/driver-pi` | Process driver for pi agent |
8686+| `@mill/driver-claude` | Driver for Claude |
8787+| `@mill/driver-codex` | Driver for Codex |
8888+| `@mill/pi-mill` | Pi extension integrating mill as execution backend |
8989+9090+## Architecture
9191+9292+```
9393+mill program (TS)
9494+ → executor (direct | vm)
9595+ → engine (lifecycle, API injection, events, persistence)
9696+ → driver (generic process/http adapter + codec)
9797+ → agent process
9898+```
9999+100100+Layers are orthogonal: executor decides *where* the program runs, driver decides *how* spawns invoke agents, extensions add hooks and extra API surface.
101101+102102+### Run storage
103103+104104+```
105105+~/.mill/runs/<runId>/
106106+ run.json metadata
107107+ events.ndjson append-only structured event log
108108+ result.json final output
109109+ program.ts copied source
110110+```
111111+112112+### Internals
113113+114114+Built on [Effect](https://effect.website). The public API (`src/public/**/*.api.ts`) exposes Promise-based contracts. Everything else — engine, drivers, persistence — is Effect-first with Schema-validated domain types. `Runtime.runPromise` is the only bridge between the two worlds.
115115+116116+## Development
117117+118118+```bash
119119+bun install
120120+bun test # run tests
121121+bun run check # full pipeline: ast-grep + lint + format + typecheck + test
122122+bun run typecheck # tsgo --noEmit
123123+bun run lint:ast-grep # structural guardrails
124124+bun run lint:boundary # public/internal boundary enforcement
125125+bun run format # oxfmt
126126+```
127127+128128+Toolchain: ast-grep (structural rules), oxlint, oxfmt, tsgo, bun test.