# Millrace architecture

This page describes the shipped Millrace runtime architecture as documented today.

## Five-layer system model

Millrace has five major layers:

1. operator-owned workspace input and configuration
2. compiler-resolved runtime structure
3. deterministic runtime orchestration
4. stage-runner dispatch into an external harness
5. persisted artifacts and inspection surfaces

In practice:

- the operator points Millrace at a workspace
- Millrace bootstraps `millrace-agents/` under that workspace
- config, modes, loops, entrypoints, and skills compile into one frozen runtime plan
- each tick processes control input, intake, reconciliation, claim or activation, at most one stage run, and authoritative result application
- the runtime persists meaningful artifacts so later ticks and later operators can inspect real state

## Workspace boundary and ownership

The runtime tree lives under `<workspace>/millrace-agents/`.

Operator-owned surfaces include:

- the workspace root itself
- the source repository being worked on
- runtime configuration choices in `millrace-agents/millrace.toml`
- queue intake through supported CLI or import surfaces

Runtime-owned surfaces include:

- queue movement between `queue/`, `active/`, `done/`, `blocked/`, `incoming/`, and `resolved/`
- active-stage identity in snapshot state
- recovery counters and stale-state repair context
- compiled plan persistence
- run directories and stage-result artifacts
- closure-target state for Arbiter-driven completion

One daemon owns one workspace through `state/runtime_daemon.lock.json`. `millrace status watch` is read-only monitoring and does not acquire ownership locks.

## Canonical on-disk model

### Markdown work documents

Canonical queue artifacts are markdown documents:

- `millrace-agents/tasks/{queue,active,done,blocked}/*.md`
- `millrace-agents/specs/{queue,active,done,blocked}/*.md`
- `millrace-agents/incidents/{incoming,active,resolved,blocked}/*.md`

JSON is still accepted as an import format for queue intake, but canonical long-lived queue artifacts are markdown.

### Runtime/state artifacts

Key runtime-owned state and compile artifacts include:

- `millrace-agents/state/runtime_snapshot.json`
- `millrace-agents/state/recovery_counters.json`
- `millrace-agents/state/compiled_plan.json`
- `millrace-agents/state/compile_diagnostics.json`
- `millrace-agents/state/execution_status.md`
- `millrace-agents/state/planning_status.md`

The Arbiter adds its own durable subtree under `millrace-agents/arbiter/` for contracts, targets, rubrics, verdicts, and reports.

## Compiler-resolved runtime structure

Millrace does not execute directly from loose config, mode, and loop inputs on every handoff. It compiles those inputs into one frozen, inspectable plan first.

The compiler resolves:

- active mode
- active execution loop
- active planning loop
- entrypoint path per stage
- required stage-core skills
- optional attached skills added at compile time
- runner, model, and timeout per stage
- completion behavior when present

Persisted compile artifacts live under `millrace-agents/state/`:

- `compiled_plan.json`
- `compile_diagnostics.json`

`compiled_plan_id` is deterministic for a given effective structure. Failed recompiles keep the last known good plan active.

## Module topology

The importable package namespace is `millrace_ai`. The main source tree lives under `src/millrace_ai/`.

Important runtime-facing modules include:

- `src/millrace_ai/workspace/paths.py`: workspace contract and bootstrap
- `src/millrace_ai/workspace/work_documents.py`: headed markdown parsing and serialization
- `src/millrace_ai/workspace/queue_store.py`: queue claim and transition facade
- `src/millrace_ai/workspace/state_store.py`: snapshot, status, and counter persistence
- `src/millrace_ai/compiler.py`: mode and loop compile into one runtime plan
- `src/millrace_ai/runners/`: runner contracts, normalization, dispatcher, and adapters
- `src/millrace_ai/runtime/engine.py`: stable `RuntimeEngine` façade
- `src/millrace_ai/runtime/lifecycle.py`: startup, shutdown, compile bootstrap, watcher rebuild, lock lifecycle
- `src/millrace_ai/runtime/tick_cycle.py`: deterministic one-tick orchestration
- `src/millrace_ai/runtime/completion_behavior.py`: closure-target activation and readiness checks
- `src/millrace_ai/runtime/reconciliation.py`: stale or impossible state detection
- `src/millrace_ai/runtime/result_application.py`: authoritative post-stage mutation
- `src/millrace_ai/runtime/control.py`: runtime control abstraction
- `src/millrace_ai/doctor.py`: integrity and lock-health diagnostics

## Tick lifecycle

The shipped tick lifecycle is deterministic. In broad terms it does the following:

1. process mailbox commands such as pause, resume, stop, retry-active, reload-config, or intake
2. run stale-state reconciliation and recovery routing
3. consume watcher or poll intake events
4. respect pause and stop gates
5. claim planning or execution work
6. if no claimable work remains, consult frozen `completion_behavior` and activate `arbiter` when an open closure target is eligible
7. execute one stage through the configured runner adapter
8. route result markers and persist snapshot, status, counters, and events

Millrace is intentionally single-stage per claim cycle. The runtime, not the stage prompt, owns queue mutation and authoritative routing.

## Stage dispatch and runner boundary

The runtime builds a `StageRunRequest` from the compiled plan and active work item. The `StageRunnerDispatcher` resolves the adapter by runner name precedence. The adapter executes and returns `RunnerRawResult`. The runtime then normalizes and applies the result.

The stable boundary is:

- `StageRunRequest -> RunnerRawResult`

That narrow boundary is what lets Millrace change harness adapters without rewriting the orchestration model.

## Run artifacts and inspection

Each run persists under `millrace-agents/runs/<run-id>/`.

Common artifacts include:

- `stage_results/*.json`
- `runner_prompt.<request_id>.md`
- `runner_invocation.<request_id>.json`
- `runner_completion.<request_id>.json`
- runner stdout/stderr artifacts where present
- per-request Codex event logs where present
- stage-authored reports such as `troubleshoot_report.md` or `arbiter_report.md`

Operator inspection surfaces include:

- `millrace status`
- `millrace runs ls`
- `millrace runs show <run_id>`
- `millrace runs tail <run_id>`
- `millrace compile show`

## Planning and execution authority

The current execution loop is a repair-capable governance loop. The current planning loop is a separate domain for specs, incidents, remediation, and closure. The runtime keeps those planes distinct instead of hiding their transitions inside a single agent session.

That is the architectural point of Millrace: raw harness output is bounded, while durable governance stays in the runtime.

See also:

- `/ai/runner-architecture.md`
- `/ai/modes-and-loops.md`
- `/ai/arbiter-and-completion.md`
