···11# mill
2233-A runtime for executing TypeScript programs that can spawn agents. Write plain TS with `await` and `Promise.all` — mill handles the lifecycle, persistence, and observability.
44-55-## What you can do
33+A simple TypeScript runtime for orchestrating subagent work. The orchestrator writes a short program that spawns agents — you review it before it runs.
6477-**Orchestrate agents in plain TypeScript** — no DSL, no YAML, just sequential and parallel `await` calls with a single injected `mill.spawn()` API.
55+## How it works
8699-**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`. Use the built-in `mill watch` or build a TUI around it.
77+You talk to your main agent (in Pi, Claude Code, OpenCode etc.). When work needs to be farmed out, it writes a mill program: a TypeScript file that spawns subagents with specific instructions. You see the code before it executes.
148159## Quick example
16101711```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",
1212+const analysis = await mill.spawn({
1313+ agent: "analyzer",
1414+ systemPrompt: "Map key risks and unknowns.",
1515+ prompt: "Analyze the auth module and summarize weak points.",
1616+ model: "anthropic/claude-sonnet-4-5",
2417});
25182619const plan = await mill.spawn({
2720 agent: "planner",
2828- systemPrompt: "You turn findings into an execution-ready plan.",
2929- prompt: `Create remediation steps from:\n\n${scan.text}`,
3030- model: "anthropic/claude-opus-4.6",
2121+ systemPrompt: "Turn findings into a concrete implementation plan.",
2222+ prompt: `Use this analysis to propose fixes:\n\n${analysis.text}`,
2323+ model: "anthropic/claude-opus-4-6",
3124});
32253326console.log(plan.text);
···55485649All commands accept `--json` for machine-readable output on stdout (diagnostics go to stderr).
57505858-### Help & authoring guidance
5959-6060-- `mill` or `mill --help`: prints root help with authoring guidance
6161-- `mill <command> --help`: prints command help with authoring guidance
6262-- If resolved config overrides `authoring.instructions`, help uses that text.
6363-- Otherwise help falls back to built-in static guidance (`systemPrompt` = WHO, `prompt` = WHAT).
6464-6565-## Configuration
6666-6767-```ts
6868-// mill.config.ts (local)
6969-// ~/.mill/config.ts (global)
7070-export default {
7171- authoring: {
7272- instructions:
7373- "Use systemPrompt for WHO (role/method), prompt for WHAT (explicit task + scope + validation).",
7474- },
7575-};
7676-```
5151+## FAQ
77527878-`mill init` creates `./mill.config.ts`.
7979-`mill init --global` creates `~/.mill/config.ts`.
5353+**Couldn't I just do this with bash and claude -p?**
5454+Yes — that's the point. The orchestrator can use any language to express a plan. TypeScript is optional; it's just easy to read and lets mill hook into the spawn calls to offer structured output, event logs, and session replay.
80558181-Resolved in order: `./mill.config.ts` → walk up to repo root → `~/.mill/config.ts` → built-in defaults.
5656+**How is this different from Claude Code tasks?**
5757+Tasks are scoped to Claude Code. Mill programs are portable across drivers — same program can spawn Claude, Codex, or pi subagents. The program is also a readable artifact you confirm before execution, not an internal dispatch.
82588383-## Packages
5959+**Do I have to write the programs myself?**
6060+No. The orchestrator writes them. You review and confirm.
84618585-| Package | Purpose |
8686-| --------------------- | -------------------------------------------------- |
8787-| `@mill/core` | Engine, run lifecycle, public API, config loader |
8888-| `@mill/cli` | CLI commands wrapping core |
8989-| `@mill/driver-pi` | Process driver for pi agent |
9090-| `@mill/driver-claude` | Driver for Claude |
9191-| `@mill/driver-codex` | Driver for Codex |
9292-| `pi-mill` | Pi extension integrating mill as execution backend |
6262+## Configuration
93639494-## Architecture
6464+`mill.config.ts` gives the orchestrator precise instructions — model preferences per task type, driver selection, authoring conventions. The orchestrator reads the config and makes choices accordingly.
95659696-```
9797-mill program (TS)
9898- → executor (direct | vm)
9999- → engine (lifecycle, API injection, events, persistence)
100100- → driver (generic process/http adapter + codec)
101101- → agent process
6666+```bash
6767+mill init # creates ./mill.config.ts
6868+mill init --global # creates ~/.mill/config.ts
10269```
10370104104-Layers are orthogonal: executor decides _where_ the program runs, driver decides _how_ spawns invoke agents, extensions add hooks and extra API surface.
7171+Resolved in order: `./mill.config.ts` → walk up to repo root → `~/.mill/config.ts` → built-in defaults.
10572106106-### Run storage
7373+## Drivers
10774108108-```
109109-~/.mill/runs/<runId>/
110110- run.json metadata (status is canonical)
111111- events.ndjson append-only structured event log
112112- result.json final output
113113- program.ts copied source
114114- worker.pid detached worker pid (best effort)
115115- logs/worker.log worker lifecycle breadcrumbs
116116- logs/cancel.log cancel/kill lifecycle breadcrumbs
117117- sessions/<spawn>.jsonl per-spawn pi session transcripts (pi driver)
118118-```
7575+Drivers translate `mill.spawn()` into whatever protocol the agent needs. Ships with Claude, Codex, and pi drivers. Write your own by implementing a codec that parses process output into structured events.
11976120120-For operations/debugging conventions, see `docs/references/mill-v0-operations-and-troubleshooting.md`.
7777+| Package | Purpose |
7878+| --------------------- | ------------------------------------------ |
7979+| `@mill/core` | Engine, lifecycle, API, config |
8080+| `@mill/cli` | CLI commands |
8181+| `@mill/driver-claude` | Claude driver |
8282+| `@mill/driver-codex` | Codex driver |
8383+| `@mill/driver-pi` | Pi driver |
8484+| `pi-mill` | Pi extension for mill as execution backend |
12185122122-### Internals
8686+## Internals
12387124124-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.
8888+Built on [Effect](https://effect.website). Public API is Promise-based (`src/public/**/*.api.ts`). Engine, drivers, and persistence are Effect-first with Schema-validated domain types.
8989+9090+Run storage: `~/.mill/runs/<runId>/` — metadata, NDJSON event log, results, per-spawn session transcripts.
1259112692## Development
1279312894```bash
12995bun install
130130-bun test # run tests
131131-bun run check # full pipeline: ast-grep + lint + format + typecheck + test
132132-bun run typecheck # tsgo --noEmit
133133-bun run lint:ast-grep # structural guardrails
134134-bun run lint:boundary # public/internal boundary enforcement
135135-bun run format # oxfmt
9696+bun test
9797+bun run check # ast-grep + lint + format + typecheck + test
13698```
137137-138138-Toolchain: ast-grep (structural rules), oxlint, oxfmt, tsgo, bun test.