Skip to content

Latest commit

 

History

49 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Mill

Mill is a local-first software factory for new and existing codebases. It turns approved product intent into bounded, tested, reviewed pull requests with repository-native evidence and explicit human approval for delivery and merge.

It is designed for a founder or small team that wants to use coding agents without handing one agent an open-ended ticket, production credentials, and the power to judge its own work. Product truth stays in the repository. Codex writes inside a disposable worktree. Native tests and scenarios verify the committed candidate. A separate read-only pass reviews that exact commit. Only the attended shipper can use your GitHub identity. Draft-only is the default; repositories may explicitly enable a separately approved, exact-plan merge.

Release channels and exact artifact evidence are facts of a particular publication. Read the latest GitHub release, its attached release-evidence-final.json, and npm view @davidahmann/mill dist-tags --json before selecting a version. GitHub Latest and npm latest are separate provider pointers. The v0.1.5 genesis release remains the historical trust root; failed release candidates remain preserved evidence.

Why Mill

Coding is only one part of software delivery. The difficult failure modes live between a PRD and a merged change: ambiguous intent, changing architecture, weak acceptance tests, context drift, cumulative regressions, credential leakage, interrupted side effects, noisy review, and artifacts that cannot be reconstructed later.

Mill makes those boundaries explicit:

  • approved outcomes, invariants, scenarios, impacts, and tasks are versioned in Git;
  • each run is bound to an exact base, authority closure, worker profile, budget, candidate commit, validation result, and review result;
  • product code remains independently buildable and testable without Mill;
  • the builder cannot push, merge, deploy, or rewrite the oracle that certifies its own candidate;
  • GitHub mutations are separately planned, approved, journaled, and reconciled;
  • one complete review is repaired systemically instead of creating micro-PR churn;
  • longitudinal qualification checks whether accepted behavior survives a sequence of dependent changes;
  • releases preserve and publish one independently reproduced tarball rather than rebuilding at publication time.

Mill is a small delivery control plane around the coding agent you already use. It makes scope, evidence, and external actions inspectable.

Capability status

Capability Status Evidence and limit
Core Node/npm delivery path Qualified for the release-specific support tuple See the release evidence attached to the selected version.
Proposal assessment Shipped and exercised init propose is read-only; approval remains outside Mill.
Cancellation, diagnostics, and state upgrade Shipped and tested Diagnostics do not create or upgrade state. A mutating command takes the writer lease and preserves a pre-upgrade backup.
Retained verifier reports Shipped and exercised Paths and limits are task-controlled. Mill lists descriptors, not report bytes.
Shallow pnpm workspace Exercised One pinned OCI fixture only. It is not general pnpm or native-package support.
Synthetic provider migration replay Exercised Private disposable fixtures, not live provider behavior, customer acceptance, or demand evidence.

What it can do

For its one qualified shape, Mill can:

  1. inspect a PRD, source manifest, structured product proposal, and repository without executing repository code;
  2. freeze an approved product contract, stable invariants, scenarios, and per-change impact;
  3. create a repository from the bundled web recipe or plan a compatible adoption without overwriting existing truth;
  4. prepare exact npm dependencies as a separate attended network effect;
  5. run one approved task through Codex build, OCI validation, exact-candidate review, and one bounded repair generation;
  6. plan and open one draft GitHub PR through the operator's own gh session;
  7. observe exact-head CI and review, optionally execute a separately approved attended merge, then verify resulting-main closure;
  8. back up, restore, purge, reconcile, cancel, detach, and export a redacted support bundle through explicit commands;
  9. audit the exact repository candidate and validate a public-alpha qualification record;
  10. derive bounded, source-revision-bound TypeScript repository evidence from a clean Git root without executing its code;
  11. combine inspected planning drafts into a read-only proposal summary, then compile an operator-supplied follow-up change request and approved impacts into dependency-checked task packets and an outcome plan;
  12. project a durable run into a versioned, read-only continuation packet that names the next attended safe action without taking it;
  13. report the built-in builder's trusted-host boundary and reject an unqualified request for isolated execution rather than silently claiming containment; and
  14. report redacted aggregate lifecycle counts with millctl stats, plus a repository-owned development-evidence ledger with millctl report.

Mill does not autonomously research the web or turn prose into approved product intent. The operator supplies the structured drafts that Mill assesses and freezes.

Repository playbooks, run timelines and outcomes

The source branch can index small repository-owned playbooks, search compact metadata, and bind a selected set into a task's frozen context. A playbook can carry reusable migration knowledge or a repository procedure, while the task's approved acceptance criteria and native checks remain authoritative. The selection is digest-pinned and recorded in the context manifest; stale or mismatched index or playbook bytes block admission. See repository playbooks.

millctl --json timeline projects the selected durable run and its append-only events into a schema-checked timeline. It includes lifecycle facts only, never event payloads, and marks malformed, discontinuous, forbidden, or stale state evidence as inconsistent. See run timelines.

millctl --json outcome projects the same durable run into a redacted outcome record. It binds local lifecycle, validation, review, delivery and measured usage facts, and summarizes adaptation provider/configuration matrix evidence when present. It reports owner acceptance as not_recorded; checks, review and delivery cannot certify that decision. Invalid, stale or cross-candidate records block the projection. See run outcomes.

These capabilities remain outside the qualified public-alpha support claim until separately qualified. They do not grant a builder authority to change acceptance criteria, deliver, merge, or release.

The source also contains a constrained pnpm workspace path. A real local OCI canary exercised Node 24, pnpm 10.23.0, a shallow workspace, a service, CLI, SQLite scratch state, an offline verifier, a retained report, and cleanup under failure, timeout, and cancellation. It rejects install hooks, native-build allowlists, and arbitrary layouts. That evidence is limited to the pinned fixture; the public alpha does not support general pnpm workspaces.

Supported shape

The first recipe is intentionally exact:

  • Node.js 24.18.1 and npm 11.16.0 inside the verifier image;
  • TypeScript 6.0.3;
  • Next.js 16.3.4 and React 19.2.8;
  • Playwright 1.62.1;
  • GitHub as the only forge;
  • Codex CLI with the operator's existing login;
  • Docker-compatible OCI verification;
  • macOS arm64 as the first candidate host tuple.

Mill itself is developed with Node.js 24.20.0 and npm 11.19.0. Exact support is published in each release qualification record, not inferred from nearby versions. All other stacks, operating systems, architectures, forges, models, and worker harnesses are experimental or unsupported until independently qualified. Experimental Node package-manager adoption is separate from this qualified web recipe.

Install

Inspect the available channels, choose a released version, and pin that exact version with lifecycle scripts disabled. Do not install a floating tag into an existing repository.

npm view @davidahmann/mill dist-tags --json
npm install --save-dev --ignore-scripts @davidahmann/mill@<released-version>
npx --no-install millctl --version

To develop Mill itself from a clean source checkout:

git clone https://github.com/davidahmann/mill.git
cd mill
asdf install
node_bin_dir=$(dirname "$(asdf which node)")
PATH="$node_bin_dir:$PATH" "$node_bin_dir/npm" ci --ignore-scripts
PATH="$node_bin_dir:$PATH" "$node_bin_dir/npm" run check
PATH="$node_bin_dir:$PATH" "$node_bin_dir/npm" run build
node dist/cli.js --version

Downstream repositories should pin the exact selected version so a later release cannot alter their delivery machinery implicitly. Updating an existing Mill installation is deliberate: preserve state and repository snapshots, inspect the release evidence, and requalify the changed toolchain. There is no automatic upgrade or proven general downgrade path for operational state.

Policy starters for downstream repositories

The packed source includes reviewed starters for a Node/npm repository under policy-starters/node-npm/. They provide a documentation check, an agent-policy addendum, Dependabot grouping, and a DCO workflow that verifies an eligible Dependabot commit without running pull-request code under pull_request_target. Copy them only through a repository review. Add the dco check to the target branch-protection settings through that repository's own approved process.

One successful path

The first useful outcome is a reviewed draft PR. Follow this route: inspect the repository, approve the proposal and task materials, then run one attended delivery through review and draft delivery. The detailed commands below expose the same boundaries when you need to inspect them separately.

1. Inspect the repository

These commands are read-only and do not execute repository code:

npx --no-install millctl doctor --mode inspect
npx --no-install millctl inspect --prd product/PRD.md
npx --no-install millctl adopt --scan-only

2. Approve the proposal

Use init propose to read the PRD and planning drafts together. It returns a reviewable summary and compiled task drafts without writing authority files. Review its contradictions, assumptions, questions, and digests. Commit and approve the product contract, scenarios, impact, and task packet through the repository's normal review process. Mill does not turn prose into approval or acceptance criteria on its own.

millctl --json init propose \
  --prd product/PRD.md \
  --sources product/sources.yaml \
  --proposal product/proposal.yaml \
  --product product/contract.yaml \
  --scenarios quality/scenarios.yaml \
  --impact product/impact.yaml \
  --request product/change-request.yaml

3. Get a reviewed draft PR

Once one outcome is approved and ready, start its attended lifecycle. It selects that outcome or resumes its existing run, verifies the committed candidate, and keeps all delivery effects separate:

millctl --json start --prd product/PRD.md --attended
millctl --json status
millctl --json stats
millctl --json report

start checks authority before dependency or model spend. status explains the selected run; stats gives lifecycle counters; report adds redacted outcome and measured-usage aggregates. When start reports a reviewed candidate, plan and make the separately proposed draft delivery effect:

millctl --json pr plan --task product/tasks/TASK.yaml --run <run-id>
millctl --json pr open --task product/tasks/TASK.yaml --run <run-id> \
  --approve sha256:<delivery-plan> --attended

Mill never treats these commands as approval to mark ready, merge, deploy, or release. See the glossary before creating or reviewing authority files.

Expert reference

Discover a TypeScript repository

The remaining examples use millctl as shorthand for the installed executable; use npx --no-install millctl when it is installed locally. Supply your actual PRD and approved authority paths; installing the CLI does not create them.

Static discovery is a separate read-only operation. It requires a clean Git repository root and rejects sensitive paths, symbolic links, unsafe Git configuration, and incomplete source traversal. It parses local TypeScript and JavaScript imports only after each regular file's physical bytes match its blob in the captured HEAD tree. The same check protects parsed package metadata. It reports source locations, inventories test files, and gives conservative importer leads for named paths. Nonliteral module loads and option-bearing test commands remain explicit unknowns. It never installs dependencies, runs the target's code, or claims executed coverage or delivery authority.

millctl --json discover /absolute/path/to/repository --changed src/service.ts

The first increment is a deterministic TypeScript extractor, not arbitrary-stack support, a graph database, a watcher, or an AI-generated knowledge graph. Read product/brownfield-discovery.md and docs/canaries/brownfield-discovery.md for the exact boundary and real-fixture evidence.

For a source-backed specification, supply the PRD, source manifest, and structured proposal:

millctl --json plan specification \
  --prd product/PRD.md \
  --sources product/sources.yaml \
  --proposal product/proposal.yaml

Review the returned contradictions, assumptions, questions, and exact proposal digest. Approval freezes that proposal; it does not grant repository writes.

Create a repository

Preview the exact file plan first, then apply the same plan attended:

millctl --json new my-product --dry-run \
  --prd product/PRD.md --sources product/sources.yaml \
  --proposal product/proposal.yaml --approve-product sha256:<product> \
  --repository-id <uuid> --approved-by <identity> \
  --approved-at <iso-time> --author-name <name> --author-email <email>

millctl --json new my-product --apply --attended \
  --prd product/PRD.md --sources product/sources.yaml \
  --proposal product/proposal.yaml --approve-product sha256:<product> \
  --approve-plan sha256:<integration-plan> --repository-id <uuid> \
  --approved-by <identity> --approved-at <iso-time> \
  --author-name <name> --author-email <email>

Greenfield apply stages and runs the complete native recipe gate before the target becomes a Git repository. It never replaces an existing path.

Adopt a compatible repository

Use the same two-step boundary with adopt --plan and then adopt --apply --attended. Adoption supports only the exact recipe-compatible Node/Next.js shape. It keeps the operator checkout unchanged, writes an isolated branch, and blocks on conflicting product truth, drifted native oracle files, unsafe Git state, symlinks, credential-like files, or incompatible versions.

Prepare dependencies separately because it is the only recipe step that needs registry network access:

millctl --json dependencies prepare --attended

Later verification has no network and receives read-only source.

Deliver one approved task

The downstream repository owns mill.yaml, product/contract.yaml, quality/scenarios.yaml, an approved impact manifest, and a version 2 task. Qualify the unchanged base, then use the returned digest once:

millctl --json qualify --baseline --task product/tasks/TASK.yaml
millctl --json run --task product/tasks/TASK.yaml \
  --approve sha256:<baseline-approval> --attended
millctl --json verify --task product/tasks/TASK.yaml --run <run-id>
millctl --json review --task product/tasks/TASK.yaml --run <run-id>

The shorter resumable path is:

millctl --json start --prd product/PRD.md --attended

millctl start selects exactly one approved ready outcome or resumes its sole existing lifecycle. It checks authority before dependency or model spend.

Open a reviewed draft PR

Raise trustCeiling to propose only after configuring the exact GitHub repository node ID, branch, allowed operator and merger, checks, review policy, and approval TTL in mill.yaml.

millctl --json pr plan --task product/tasks/TASK.yaml --run <run-id>
millctl --json pr open --task product/tasks/TASK.yaml --run <run-id> \
  --approve sha256:<delivery-plan> --attended
millctl --json pr observe --task product/tasks/TASK.yaml --run <run-id>
# By default, a human marks ready and merges in GitHub.
millctl --json pr finalize --task product/tasks/TASK.yaml --run <run-id>

Or use millctl ship --draft twice: first to return the proposal, then with its exact digest and --attended to perform it. Draft delivery never implicitly authorizes readiness or merge.

Approve a merge from your work surface

With propose.attendedMerge: true, producer-bound required checks, strict up-to-date protection enforced for administrators, and no bypass-role grants, the attending operator can inspect and approve:

millctl --json pr merge-plan --task product/tasks/TASK.yaml --run <run-id> --method squash
millctl --json pr merge --task product/tasks/TASK.yaml --run <run-id> \
  --approve sha256:<merge-plan> --attended
millctl --json pr finalize --task product/tasks/TASK.yaml --run <run-id>

The plan binds PR/head/base, exact tree, actor, method, policy and expiry. A chat host can submit the operator's approval through this CLI; Mill does not authenticate arbitrary chat messages or let the builder approve its own work. See attended approvals and recovery.

Mill checks classic branch-protection enforcement and exact check-producer bindings. The operator must separately inspect bypass-role/ruleset grants; do not infer a complete permissions audit from a successful merge preflight.

Compile follow-up work and adopt native brownfield commands

plan tasks --request product/change.yaml deterministically compiles an operator-supplied PRD/plan/bug/review change request and approved impact manifests into version-2 tasks and a dependency-checked outcome plan. Its separate --apply --approve sha256:<plan> --attended step writes an isolated worktree. It does not infer approval or acceptance tests from prose. See planning.

adopt-native --config adoption.yaml offers experimental Node ESM/npm adoption that adds only mill.yaml and mill.lock, preserving existing code and native scripts. Apply requires the exact digest and attendance; dependency preparation, baseline qualification and task execution remain separate. See brownfield scope and qualification.

Pull-request and resulting-main checks

The source implementation keeps propose.requiredChecks as the complete gate for the exact pull-request head. Optional propose.postMergeRequiredChecks selects a nonempty subset of those names for resulting-main readback only; omitting it retains the full requiredChecks list for both phases. New delivery plans approval-bind and persist both effective lists. Missing or pending required checks prevent completion; skipped or failed required checks fail the phase that requires them.

In this repository, dependency-review runs only for pull requests, while validate and codeql also run on pushes to main. The maintainer-prepared mill.yaml requires all three at the exact PR head and explicitly selects [validate, codeql] for resulting-main readback.

New delivery records identify the policy source as configured or implicit_default. A historical record with a full defaulted list and no provenance can bind the configured subset once only if its exact reviewed candidate proves omission of the optional policy and authoritative merge readback establishes every other delivery identity. That compatibility path cannot relax a new delivery. See repository settings and the migration record for the conditions and outstanding live evidence for delivery 01801a1b-58f9-480f-8cee-54ea2bbeabb2. Human readiness, merge authority, and exact candidate/tree checks remain required.

Public interface

The supported programmatic surface is the millctl CLI, its versioned JSON result envelope, and the published JSON schemas. Shell automation should invoke the CLI with --json and check ok, status, and reasons; it should not parse the human-readable formatter.

Mill does not expose a direct JavaScript library API. Build integrations on the CLI and schemas until Mill publishes a separately supported library contract.

Trust model

Mill separates four principals:

Principal May do Cannot do
Builder Edit approved paths in a disposable worktree Push, merge, deploy, change authority or oracles
Verifier Run declared commands in bounded no-network OCI Write candidate source or use forge credentials
Reviewer Read the exact committed candidate Execute or edit code
Attended shipper Push/open a draft; separately approved opt-in readiness/merge Change the candidate, self-approve, bypass protection, or deploy

Codex uses your existing Codex CLI session and therefore your own provider billing. GitHub operations use your existing gh session by default. A repository can instead declare the fixed MILL_GITHUB_TOKEN environment name for a reviewed fine-grained token. Another maintainer can clone Mill and use their own Codex and GitHub accounts after the downstream repo explicitly allows their identity. Mill stores neither credential.

Use a separate, repository-scoped GitHub identity where the risk warrants it. The delivery credential guide describes the required review and current limits. Mill does not inspect or attest the permissions of the gh session it invokes.

The Codex worker runs on the trusted host with a workspace-write sandbox. This is not containment against hostile code, host files, keychains, processes, or network access. Native candidate verification is the stronger boundary: a pre-pulled digest-pinned OCI image, no network, read-only source/root, dropped capabilities, deadlines, bounded output and resources, and explicit cleanup. Do not use this alpha with hostile repositories or sensitive source.

millctl isolation --request trusted-host reports the exact built-in boundary. millctl isolation --request isolated fails closed because no isolated builder adapter has been qualified; run and resume accept the same --isolation option and will not silently fall back. See the reliability boundary.

Recovery

Every run has durable state and an append-only event history. If a controller is interrupted, inspect before acting:

millctl --json status --run <run-id>
millctl --json continuation --run <run-id>
millctl --json timeline --run <run-id>
millctl --json stats
millctl --json report
millctl --json resume --task product/tasks/TASK.yaml --run <run-id>
millctl --json cancel --run <run-id>
millctl --json pr reconcile --task product/tasks/TASK.yaml --run <run-id>

Mill never signals a process solely from a stored PID and never retries an uncertain external effect without authoritative readback. Use explicit local recovery for state and diagnostics:

millctl --json state backup
millctl --json state restore --from /absolute/path/returned-backup.sqlite3
millctl --json state purge --confirm <repository-uuid>
millctl --json support-bundle --run <run-id>
millctl --json detach plan

status remains compact: it does not reveal the worktree, raw worker context, validation/review data, logs, private commit trailers, or credentials. Its continuation projection binds task/base/candidate/configuration identities, observed interruption/effect uncertainty, measured resource fields, and the next attended action without performing it. It reports provider-measured input, output, and cache-input tokens when present, partial fields when a completed call omitted them, and unavailable currency cost rather than an estimate.

timeline is a separate read-only diagnostic view. It shows event sequence, timestamp, event type and state transitions, never event payloads. It blocks if the recorded sequence, lifecycle contract or durable run status disagree; it cannot repair state or authorize the next action.

An unresolved push, PR, readiness or merge blocks repair, new delivery and state purge/restore even if the enclosing run says blocked or cancelled. Cancellation records intent without discarding the receipt. Use pr merge-reconcile for readiness/merge; a confirmed merge then requires pr finalize and green main checks before cleanup. See approval recovery.

Before any remote attempt, stale review scope can use review --task product/tasks/TASK.yaml --run <run-id> --refresh --base <exact-provider-commit> --attended. This preserves the candidate and remaining review budget, invalidates the unexecuted delivery plan and does not move frozen Git refs. Plan delivery again after the fresh review passes.

For generated authority, state reconcile-plans verifies the exact committed files. A failed plan can instead be explicitly discontinued with state abandon-plan --approve <original-plan-digest> --attended, after preserving partial output in a clean commit on its recorded branch. Abandonment retains evidence and does not certify successful apply. See plan recovery.

Restore validates the database before atomic replacement and quarantines newer unreferenced worktrees. Detach is plan-only; the operator performs the reviewed removal. A generated/adopted repo must continue to build and test natively after Mill is removed.

Run purge from a surviving original checkout, never a worktree scheduled for deletion. Preserve an external state backup and committed candidate branches first. The known purge-from-a-deletable-worktree P2 can leave cleanup incomplete; it does not grant permission to discard unresolved effects or foreign files.

Audit and qualification

millctl audit is a bounded, read-only milestone check for Mill's selected recipe and release path. It requires a clean exact Git candidate and reports product, code, UX, accessibility, security, dependency, architecture, operations, and release checks in a schema-valid JSON envelope. These checks are labelled assurance: structural: they inspect contracts and hooks, not executed security, accessibility or business behavior. Native command results, realistic scenarios and release canaries are separate evidence.

millctl --json --cwd . audit
millctl --json --cwd . qualify public-alpha \
  --file /absolute/path/qualification.json

Public-alpha qualification requires at least five dependent accepted changes, item-level new-behavior and preservation evidence, a rejected and recovered seeded-fault branch, a current exact support tuple, every required packed and integration canary, and all nine audits. A later success cannot conceal an earlier unresolved preservation failure.

Every qualified release also requires two independent clean builds from the exact annotated tag, canonical content equality, a preserved tarball, SBOM, trusted npm OIDC publication, provenance, registry reinstallation, and GitHub Release readback. See the release runbook.

Troubleshooting

  • WRONG_MILL_VERSION: run the exact package version in mill.lock; Mill does not silently delegate to another version.
  • BASE_REF_DRIFT or context drift: stop, review the new repository state, and requalify. Never reuse the old approval digest.
  • missing OCI image: pull the exact digest explicitly outside Mill, then rerun readiness. Mill never pulls implicitly.
  • provider login failure: run codex login as the operator; do not pass a token through the task or repository.
  • GitHub identity or destination mismatch: correct mill.yaml or log in with the explicitly allowed gh identity. Do not weaken the binding.
  • effect_unknown: run read-only reconciliation. Do not retry push or PR creation until absence or success is authoritative.
  • active-run conflict: resume or safely terminalize the existing run; do not start a second writer.

Use GitHub Issues for reproducible defects and private vulnerability reporting for security issues. Support is best-effort with no SLA.

Limitations

  • local and attended only;
  • one repository, outcome, and writer at a time;
  • one exact web recipe and compatible adoption shape;
  • operator-supplied structured proposal, not autonomous planning research;
  • Codex and GitHub through the operator's existing sessions;
  • no hostile-host containment for the coding agent;
  • no daemon, hosted control plane, scheduler, fleet, or parallel agents;
  • no automatic readiness, merge, deployment, repository provisioning, or issue synchronization;
  • no general migration engine, automatic upgrade/rollback, or automatic detach;
  • no self-improvement loop or model-authored acceptance authority.

For system detail, read the product requirements, architecture, development guide, workflow, and agent operating contract.

About

Local-first software factory that turns approved product intent into tested, reviewed PRs for new and existing codebases.

Topics

Resources

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages