Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ updates:
groups:
development:
dependency-type: development
ignore:
- dependency-name: "@types/node"
update-types:
- version-update:semver-major
- dependency-name: typescript
update-types:
- version-update:semver-major
open-pull-requests-limit: 5
- package-ecosystem: github-actions
directory: /
Expand Down
46 changes: 45 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,19 @@ All notable changes follow Keep a Changelog and Semantic Versioning.
mode-aware doctor command.
- Pinned least-privilege CI, CodeQL, dependency review, DCO, package smoke,
coverage, and trusted-publishing release foundations.
- Attended local task delivery through explicit canonical approval, a disposable
worktree, lifecycle-owned commit, digest-pinned no-network OCI verification,
and exact-candidate read-only Codex review.
- Repository-namespaced SQLite state with append-only events, exclusive writer
leases, cancellation, interruption recovery, backup/validated restore,
terminal-only purge, and redacted support export.
- Executable task-packet, context-manifest, validation-evidence, and
review-result contracts with aligned runtime and JSON Schema validation.

### Changed

- None.
- Dependabot preserves the qualified Node type and TypeScript major boundaries;
incompatible major upgrades require an intentional toolchain qualification.

### Deprecated

Expand All @@ -33,6 +42,31 @@ All notable changes follow Keep a Changelog and Semantic Versioning.
errors, malformed-contract classification, operator-tool discovery, Node
readiness, valid `..name` paths, Git-root lock authority, JSON help isolation,
and runtime/JSON Schema parity now honor their documented contracts.
- Codex builder invocation uses approval routing's workspace-write sandbox
without passing the mutually exclusive explicit sandbox selector.
- Structured review schemas use Codex-compatible explicit and nullable types;
failed provider JSONL retains only a safe error code for diagnosis.
- Builder and reviewer invocations disable host skill search so operator-global
skills cannot silently widen behavior or inflate provider usage.
- Transient or invalid review-provider results can retry the unchanged verified
candidate once through a durable per-candidate attempt budget, without
consuming the one post-repair review generation.
- Builder, retry, repair, and review completions record source-qualified token
usage while refusing to invent currency cost.
- Baseline approval now requires matching successful qualification state and
binds the exact base, task, command configuration, and normalized evidence.
- Exact-candidate checks reject ignored-file contamination, repair reasserts the
reviewed candidate before writes, and failed context setup removes provisional
worktree and branch state.
- Bound task, configuration, authority, context, instruction, and declared
command-control inputs cannot overlap candidate output scope or be rewritten
into a validated commit.
- Writer exclusion now uses a crash-released SQLite transaction instead of a
stale-directory protocol; cancellation is polled by the exact foreground
owner, persisted PIDs are never signalling authority, and delayed exits clear
active attempts only through compare-and-swap.
- Named OCI verifier containers are force-removed under an independent cleanup
deadline after success, failure, timeout, output exhaustion, or cancellation.

### Security

Expand All @@ -42,3 +76,13 @@ All notable changes follow Keep a Changelog and Semantic Versioning.
fail closed; scan digests include Git hazard and truncation state. Git config
syntax and linked-worktree metadata now fail closed at their parsing and
indirection boundaries, and explicit tool overrides must be absolute.
- Candidate building is restricted to an exact-base disposable worktree and
approved paths. Tracked symlinks and configured sensitive paths are rejected
before builder access; Git hooks and transforming attributes are disabled or
blocked. Required verification runs without network under resource bounds,
process-group cancellation escalates across signal-ignoring descendants, and
public runtime output excludes host worktree paths and frozen context
contents.
- Codex invocations ignore ambient execution rules, and OCI verification uses a
clean read-only candidate workspace so uncommitted ignored artifacts cannot
affect promotion evidence.
86 changes: 82 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
Mill is an experimental local-first software-delivery system for turning an
approved product outcome into a tested, reviewed draft pull request.

The project is pre-alpha. Wave 1 provides an installable source package, compact
schemas, static PRD/repository inspection, and readiness diagnostics. The CLI is
The project is pre-alpha. Wave 1 provides the installable source package,
compact schemas, static PRD/repository inspection, and readiness diagnostics.
Wave 2 adds an attended local path from one explicit task approval to an exact
committed, OCI-validated, independently reviewed candidate. The CLI is
`millctl`, published eventually as `@davidahmann/mill` to avoid collision with
the existing `mill` command and npm package.

Expand Down Expand Up @@ -33,6 +35,51 @@ node dist/cli.js inspect --prd product/PRD.md
node dist/cli.js adopt --scan-only
```

## Run one attended local task

A build-enabled downstream repository supplies `mill.yaml`, a task packet, and
the product/scenario/policy files whose digests the task binds. First qualify
the unchanged base and copy the returned `data.approvalDigest`; that digest is
issued only for a passing baseline and binds the exact base, task, repository
configuration, selected commands, and baseline evidence. Then approve and run
that exact qualified input set. Qualification is executable build authority: an
`inspect` trust ceiling rejects it before OCI discovery or command execution,
and interruption terminates the foreground verifier and completes cleanup:

```yaml
commands:
test:
argv: ["npm", "test"]
cwd: "."
controlPaths: ["package.json", "package-lock.json", "test/**"]
capability: test
required: true
timeoutSeconds: 600
execution: oci
```

```sh
node dist/cli.js --json qualify --baseline --task product/tasks/TASK.yaml
node dist/cli.js --json run --task product/tasks/TASK.yaml \
--approve sha256:<digest-from-qualification> --attended
node dist/cli.js --json verify --task product/tasks/TASK.yaml --run <run-id>
node dist/cli.js --json review --task product/tasks/TASK.yaml --run <run-id>
node dist/cli.js --json status --run <run-id>
```

`run` creates the candidate on a Mill-owned branch in a disposable worktree; it
does not modify the operator checkout. `resume` reconciles an interrupted
controller only when no recorded execution can still be active, or performs the
one allowed review-repair pass. `cancel` records durable intent; the exact
foreground lease owner polls that intent and terminates its own in-memory child
group. Mill never signals a process from a persisted PID. Ambiguous orphaned
execution state fails closed for attended reconciliation. `state backup`,
`state restore`, `state purge`, and `support-bundle` provide explicit local
recovery and redacted diagnostics. The unchanged exact candidate may retry one
transient or invalid provider review; the durable per-candidate attempt budget
prevents an unbounded token loop while still allowing the one reviewed repair
generation.

Use `--json` before the command for the stable machine-readable envelope.
`--json --version` is machine-readable; help is human-only and combining it with
`--json` returns a typed usage error. `doctor` and static adoption never execute
Expand All @@ -45,10 +92,41 @@ adoption validates normal and linked-worktree Git metadata, inspects common and
worktree configuration, and blocks syntax it cannot classify without running
repository-controlled commands.

Codex build execution uses the operator's existing Codex login and provider
billing. It is attended trusted-host execution: the builder receives an explicit
`workspace-write` sandbox and `never` approval policy, so Mill cannot approve an
escalation request. Workspace scope is checked before promotion, but Mill does
not claim that the Codex process is isolated from the host, network, keychain,
or unrelated files. Repository validation is separate: selected commands run in
an already-present digest-pinned OCI image with no network, a read-only
container root, dropped capabilities, bounded resources, deadlines, and bounded
output. Mill never pulls the image implicitly. The candidate workspace is
mounted read-only and ignored builder artifacts are removed before
exact-candidate evidence is accepted. Each verifier command has a unique
Mill-owned container name, and Mill force-removes that exact container under a
fresh cleanup deadline before accepting evidence. Mill ignores operator Codex
configuration, disables host skill search, and ignores ambient execution rules
for builder/reviewer invocations; repository-local `AGENTS.md` instructions
still apply. Provider usage is measured when Codex reports it, while currency
cost is reported as unavailable rather than estimated. Completion events in the
redacted support bundle preserve that source-qualified token evidence for the
initial build, retries, repairs, and review.

The builder can read the non-sensitive tracked files in its disposable worktree;
`contextPaths` are frozen, read-only priority inputs, not a filesystem read ACL.
They, `mill.yaml`, the active task, authority files, repository instructions,
and each selected command's declared `controlPaths` cannot overlap task output
scope or enter the candidate. `controlPaths` name the scripts, tests, manifests,
or other repository files that define the selected command's acceptance oracle.
Qualification therefore rejects tracked symlinks and any tracked path matched by
`sensitivePaths`. Keep secrets and other excluded material untracked and outside
the repository.

## Status

Not published. No Codex execution, GitHub mutation, compatibility, containment,
or release claim exists until its corresponding later-wave canary passes.
Not published. Local attended delivery is implemented, but no GitHub mutation,
hostile-host containment, release, or generalized stack-compatibility claim
exists until its corresponding later-wave canary passes.

## License

Expand Down
76 changes: 70 additions & 6 deletions architecture/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,21 @@ and exits to resumable state for long waits—there is no daemon.

## Boundaries

The implemented Wave 2 boundary is:

```text
exact human-authored task + product/scenario/policy digests
-> passing exact-base qualification and explicit approval digest
-> disposable exact-base worktree
-> bounded Codex builder using operator authentication
-> lifecycle-owned clean local commit
-> selected digest-pinned OCI commands without network
-> fresh read-only Codex review of the exact verified commit
-> reviewed local candidate or one repair-and-revalidate cycle
```

The complete planned v1 boundary extends that path:

```text
untrusted PRD/repo/web inputs
-> source and product compiler (proposal only)
Expand All @@ -30,6 +45,51 @@ The builder never receives forge/deployment authority. The shipper cannot create
or amend the candidate commit. Product/oracle changes invalidate the candidate.
Provider state is authoritative for external effects.

In Wave 2, the qualification approval digest binds a passing baseline's exact
base commit, canonical task and repository configuration, selected command
definitions, and normalized evidence identity. The context manifest, candidate
commit/tree, validation evidence, and review result are durably linked in
repository-namespaced SQLite state. Public CLI results and support bundles omit
the worktree path, context payload, prompts, raw model streams, command output,
and credentials. Codex invocations ignore operator configuration and execution
rules and disable host skill search to prevent globally installed workflows from
silently changing task behavior or token use. They still use the operator-owned
authentication home and honor repository-local instructions, so this is input
control rather than host containment. `contextPaths` select frozen priority
read-only context rather than limiting filesystem reads. The active task,
`mill.yaml`, authority files, repository instructions, and selected-command
`controlPaths` form the immutable oracle closure and cannot overlap candidate
output scope. Build qualification rejects tracked symlinks and configured
sensitive paths, Git replacement refs, and graft metadata before creating the
worktree; lifecycle Git commands also disable replacement objects. Secrets must
remain untracked and outside the repository.

Baseline qualification is part of build authority, not static inspection. The
runtime enforces the repository trust ceiling before OCI discovery or command
execution. Verifier preflight and commands inherit the caller's same absolute
deadline and foreground signal lifecycle, while safety cleanup alone retains its
independent bounded deadline.

## Local lifecycle and recovery

Only one writer lease may mutate a repository namespace. The lease is a
dedicated SQLite exclusive transaction: kernel ownership makes acquisition
atomic and releases it on controller death, without stale-directory deletion or
ABA races. Child processes run in their own process group with an absolute
deadline and output cap. The persisted absolute run deadline is reused for
verification, review, retry, repair, and resume; no checkpoint grants a fresh
budget. An attempt ID plus PID, PGID, and process-start digest is diagnostic
state, not signalling authority. Cancellation is durable state polled by the
foreground lease owner, which terminates its own in-memory child; no command
signals a stored PID. If the lease is free but a recorded process may still
exist, resume and terminal cancellation fail closed for attended reconciliation.
State events are append-only, backup restore validates SQLite integrity, schema,
and required objects before atomic replacement, and purge requires every run to
be terminal. A failed pre-build context setup removes its provisional worktree
and branch. Review attempt budgets are scoped to an exact candidate generation,
and repair reasserts the reviewed commit/tree before allowing writes. There is
no background daemon or implicit retry.

## Core modules

- intake/source classifier;
Expand All @@ -53,12 +113,16 @@ before the call and reconciles unknown outcomes before retry.

## Containment claim

Build/test commands should run in a pinned OCI environment where available.
Codex initially runs in attended trusted-host mode using workspace-write
sandboxing and promotion-time scope checks. Mill does not claim this prevents
all host access. Stronger containment requires a separately qualified
container/VM worker with controlled model authentication and no host-home,
Docker-socket, keychain, or forge credential access.
Selected verification commands run against a clean exact candidate in a
digest-pinned OCI environment with no network, a read-only root and workspace,
dropped capabilities, no-new-privileges, resource bounds, and no implicit image
pull. Every command receives an opaque Mill-owned container name and evidence is
withheld until an unconditional, separately bounded `docker rm --force`
succeeds. Codex runs in attended trusted-host mode using workspace-write
sandboxing and promotion-time Git scope and identity checks. Mill does not claim
this prevents all host access. Stronger containment requires a separately
qualified container/VM worker with controlled model authentication and no
host-home, Docker-socket, keychain, or forge credential access.

## Release trust

Expand Down
28 changes: 27 additions & 1 deletion docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Install the pinned runtime through asdf, then use `npm ci`.

## Required commands

The implementation establishes these native gates in Wave 1:
The repository enforces these native gates:

- `npm run format:check`
- `npm run lint`
Expand Down Expand Up @@ -42,6 +42,32 @@ Only applicable tiers are active. A skipped required lane blocks promotion.
| Scenario | active | normal, exception, degradation, recovery, adversarial |
| Cross-system | Wave 3+ | Codex, OCI and GitHub canaries |

Wave 2 keeps a deterministic fake-adapter suite in CI and requires an attended
real Codex/OCI canary before the wave is accepted. The realistic scenario set
covers:

- normal approval, build, lifecycle commit, verification, and clean review;
- negative controls for failed, stale, inspect-only, or interrupted baseline
qualification, changed command configuration, mutable command-control paths,
bound-input/output overlap, dirty checkout, ignored-file contamination,
hostile Git metadata, unauthorized paths, symlinks, replacement/graft history
substitution, hidden index flags, authority drift, and attempted automatic
Codex escalation approval;
- degradation from provider failure, missing OCI runtime/image, nonzero command,
deadline, cancellation, and output exhaustion;
- recovery through crash-released writer leases, PID-reuse-safe orphan
reconciliation, explicit OCI container cleanup, provisional workspace cleanup,
exact-candidate repair revalidation, per-candidate review budgets, validated
state backup/restore, and terminal-only purge;
- provenance through exact base, context, candidate commit/tree, validation, and
review identity checks;
- packaging through installation of the generated tarball and execution of its
public CLI and schema exports.

The real provider canary is maintainer evidence, not a deterministic CI job: it
uses the maintainer's personal Codex account and a pre-pulled digest-pinned
image, and it must never push or create a pull request in Wave 2.

## Architecture questions

Before medium/high-risk code, answer:
Expand Down
4 changes: 4 additions & 0 deletions product/PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,7 @@ Owner: David Ahmann
Each item is one vertical delivery wave, not a bucket of microtasks. Later-wave
choices close only before their wave. The current detailed task is in
`product/tasks/`.

Wave 1 is landed. Wave 2 is implemented and remains active until its packed CLI
and attended real-provider canaries, exact-candidate review, PR CI, human merge,
and resulting-main checks are complete.
Loading