Skip to content

Repository files navigation

Runmill

Loop orchestrator daemon for autonomous software engineering.

Runmill watches your backlog, gives issues to coding agents, verifies their work, and delivers reviewed pull requests. It runs Codex or Claude Code; Runmill owns the loop around them.

Runmill OpenTUI showing a live agent review, verification events, and daemon logs

The dashboard follows an issue from backlog claim through implementation, checks, an independent fresh-context review, and PR delivery—then shows the daemon returning to watch for more work.

Documentation · Configuration · Daemon operations

Why it exists

A coding agent can edit a repository. That is only one part of shipping software unattended. Something still has to decide what to work on, prevent duplicate work, run the right checks, review the result independently, and decide whether it is safe to merge.

Runmill handles that control loop:

backlog → select → claim → implement → verify → fresh-context review → PR → merge policy
   ↑                                                                        │
   └──────────────────────────── poll for more work ────────────────────────┘

When the queue is empty, the daemon waits. When a new eligible issue appears, it starts another run. While run or daemon is active, Runmill asks macOS or Linux to keep the machine awake.

What happens to an issue

Runmill:

  1. Selects an eligible issue and routes it to a repository.
  2. Claims it with a Git-backed lease, so another worker cannot take it.
  3. Creates an isolated workspace and starts the implementer.
  4. Runs the repository's required checks against the candidate commit.
  5. Starts a reviewer with brand-new context. The reviewer sees the task and diff, not the implementer's conversation.
  6. Opens a pull request, waits for CI, and applies the configured merge policy.
  7. Records the result in SQLite and appends a readable entry to .runmill/log.md.

Runmill stops a run when evidence is missing or policy says a person must decide. Agents never own backlog mutations, pushes, pull requests, or merges; deterministic orchestration code does.

Quick start

Runmill is not published to npm yet:

git clone https://github.com/mikigraf/runmill.git
cd runmill
npm ci
npm run build
npm link

Direct runtime and development dependencies are pinned to exact versions. npm ci installs the lockfile without silently moving the agent harness underneath you.

In the repository you want it to manage:

runmill config create   # guided setup with discovered GitHub, Linear and agent options
runmill init            # add the check manifest and review rules
runmill doctor          # verify credentials, CLIs, Git and sandbox support
runmill next            # preview selection without changing anything
runmill daemon --detach # start the backlog worker in the background
runmill tui             # open the live interface from any directory

The setup wizard uses authenticated gh, Linear credentials, Codex, and Claude when available. It lets you use installed CLI subscriptions or API keys, preloads repositories and Linear workflow values, and writes conservative defaults. Secrets are never written to runmill.yaml.

For CI or scripted setup:

runmill config create --defaults
runmill config validate
runmill daemon --once

--once drains the work that is eligible now and exits. Without it, daemon checks the backlog every 30 seconds while idle. Change that with --poll-seconds; use --max-runs for a bounded session.

runmill tui is an OpenTUI dashboard for the running daemon. It discovers a user-private local socket, so it works from any directory and does not need runmill.yaml. The dashboard shows live daemon status and logs, recent runs, the active orchestration pipeline, transitions, agent events, and pending external effects. It can also request a safe stop at the next run boundary. Runmill automatically launches this one command with Bun because OpenTUI's native renderer needs it on the Node versions Runmill otherwise supports.

Try it without credentials

The included demo uses in-memory integrations:

cd examples/quickstart
RUNMILL_DEMO=1 npx tsx ../../src/cli/main.ts next --dry-run
RUNMILL_DEMO=1 npx tsx ../../src/cli/main.ts daemon --once

Demo mode is explicit. Runmill never silently substitutes a fake integration in production.

Configuration

A minimal runmill.yaml:

# yaml-language-server: $schema=./runmill.schema.json
version: 1
autonomy: pr-only

providers:
  implementer:
    implementation: codex
  reviewer:
    implementation: claude

backlog:
  provider: linear
  team: ENG
  eligible_states: [Todo, Ready]
  claim_state: In Progress
  delivered_state: In Review

github:
  repositories:
    - match: { team: ENG }
      repo: acme/platform
      base_branch: main

The implementer and reviewer may use the same CLI, different models, or different providers. A different provider is useful, but not required: every review starts without the implementer's history either way.

See the configuration reference for checks, budgets, risk paths, repository routing, credentials, and merge policy.

Designed for unattended work

  • A real idle state. daemon waits for new Linear issues instead of exiting when the queue is empty. GitHub is currently the repository, CI, and pull-request integration; GitHub Issues is a declared backlog type but does not yet have a live adapter.
  • No laptop naps mid-run. Runmill starts caffeinate on macOS or systemd-inhibit on Linux and releases it when the process stops.
  • Safe stopping. SIGINT and SIGTERM finish the in-flight run boundary before exiting.
  • Circuit breakers. Repeated failures, quarantines, escalation rates, and daily spend can stop the daemon before one bad condition is repeated across the backlog.
  • Durable state. Leases, transitions, check evidence, and intended side effects survive a restart.
  • Operator-friendly output. Human-readable commands by default; --json, stable exit codes, inspect, list --needs-attention, and doctor --report for automation and support.
  • A remote terminal UI. Start with runmill daemon --detach, then use runmill tui anywhere on the same machine. The client reads daemon state over a 0600 Unix socket rather than guessing paths or opening the database itself.

Autonomy modes

Mode Behavior
observe Select and plan without claiming work or changing a repository
pr-only Implement, verify, review, and open a pull request; never merge
guarded-merge Merge eligible low-risk changes after every gate passes
continuous Use guarded merge policy across repeated daemon runs

pr-only is the default. A daemon can run continuously in any active mode; the autonomy setting controls what each run may do, not whether the process stays alive.

Safety model

  • Git-ref leases prevent two workers from taking the same issue.
  • Agent workspaces run under Seatbelt on macOS or bubblewrap on Linux.
  • Required checks run against the exact candidate commit in a clean checkout.
  • Reviews run with fresh context and must account for every acceptance criterion.
  • Sensitive paths and incomplete evidence escalate instead of merging.
  • Only the orchestrator can change backlog state, push, open a PR, or merge.

Runmill does not claim that an agent's code is correct. It records what was checked, what was reviewed, which policy ran, and why the change was allowed to continue.

Useful commands

Command Purpose
runmill config create Create a config from discovered tools and integrations
runmill config validate Validate the config and check manifest
runmill config show Print the resolved config and defaults
runmill doctor Check the host, credentials, agent CLIs, and sandbox
runmill next Show the next issue and explain rejected candidates
runmill prepare <issue> Check whether one issue is ready
runmill run [issue] Process one issue
runmill daemon Watch the backlog and process work continuously
runmill daemon --detach Start the daemon in the background
runmill daemon --once Drain eligible work and exit
runmill tui Open the live OpenTUI dashboard from any directory
runmill list --needs-attention Show runs waiting for a person
runmill inspect <run-id> Show transitions, evidence, and pending effects
runmill resume <run-id> Resume a paused run
runmill policy explain <run-id> Explain a merge decision
runmill auth status Show available credentials
runmill auth login / runmill auth logout Add or remove a stored credential
runmill skills eject / runmill skills validate Customize or validate review rules
runmill state Check the local state store
runmill gc Reconcile workspaces left by interrupted runs
runmill eval validate <suite> Validate an evaluation suite
runmill eval replay <suite> Replay historical tasks through the harness
runmill feedback Create a support issue with diagnostics

Every command supports --json, --quiet, and --config <path>. Run runmill --help for the complete list.

Requirements

  • macOS or Linux, arm64 or x64
  • Node.js 20.11 or newer
  • Git and an authenticated GitHub account
  • An authenticated Codex or Claude Code CLI
  • Seatbelt on macOS or bubblewrap on Linux
  • caffeinate on macOS or systemd-inhibit on Linux for sleep prevention
  • Bun for runmill tui (the daemon and other commands only require Node)

Linear is currently the live backlog provider. GitHub handles source, pull requests, CI, branch protection, and merges.

Environment variables

Variable Purpose
RUNMILL_DEMO=1 Use the bundled in-memory integrations
RUNMILL_FAKE_BACKLOG=<file> Load backlog issues from a JSON fixture
RUNMILL_SOURCE_REPO=<path> Override the repository used to create run workspaces
RUNMILL_DATA_DIR=<path> Override the state and workspace directory
RUNMILL_DAEMON_REGISTRY=<path> Override daemon discovery, mainly for isolation and testing

Documentation

License

MIT. See LICENSE.