diff --git a/docs/container.md b/docs/container.md index 8889666..ee6c659 100644 --- a/docs/container.md +++ b/docs/container.md @@ -1,8 +1,9 @@ # The lifecycle of a task container -Every task in panopticon runs in its own **container** — a throwaway Docker container with a -`claude` agent inside it, working on a private clone of the repo. This doc explains that -container's life from the operator's chair: how one comes up, the statuses you watch on the +Every container-backed task in panopticon runs in its own **container** — a throwaway Docker +container running its selected agent harness (Claude Code, Codex, Pi, or Outfitter), working +on a private clone of the repo. Shell workflows such as `setup-repo` run on the host instead. +This doc explains the container's life from the operator's chair: how one comes up, the statuses you watch on the dashboard, what each means, and how a container recovers or is torn down. It's about *observable behaviour* from the operator's side. @@ -11,9 +12,9 @@ For the token a container authenticates with, see [auth](auth.md); for the image ## One task, one container, one session -A task's work happens in exactly one place: its container. Nothing else in panopticon runs an +A container-backed task's agent work happens in its container. Nothing else in panopticon runs an LLM — the task service (control plane) and the session service (runner) are deterministic host -processes that never call `claude`. That's the **determinism invariant**: the container is the +processes that never call an LLM. That's the **determinism invariant**: the container is the *only* LLM-bearing component, so everything the agent does is scoped to it. Concretely, each running task has: @@ -30,31 +31,43 @@ service** only ever *records* and *displays* what the runner reports; it spawns ## The status you see on the dashboard -The dashboard shows one **container status** per task — a single word the task service computes -by folding three signals together: the spawn *phase* the runner is reporting, whether the -container has an open **registration** (its live connection), and whether the **runner** itself -is still connected. First match wins, so a status higher in this table always overrides a lower -one. +The dashboard shows one **container status** per task. The task service combines the task's +terminal state, launch pause, dependencies, and runner claim with the reported lifecycle +*phase*, the container's open **registration** (its live connection), and runner liveness. +The table explains the statuses; the selection rules below determine which one appears. | Status | What it means | What you do | |---|---|---| -| `queued` | Non-terminal but unclaimed — no runner has picked it up yet. | Wait; if it sticks, check a runner is actually running (`make start`). | +| `–` | Terminal task (COMPLETE / DROPPED) — no container concept. | Nothing. | +| `paused` | Launch is paused and no container registration is open; no failed phase takes precedence. | Resume launch when ready. | +| `gated` | The task is unclaimed and dependencies block launch. | Wait for the dependencies to clear, or inspect the blocking tasks. | +| `queued` | The task is unclaimed and eligible for a runner to pick up. | Wait; if it sticks, check a runner is actually running (`make start`). | +| `live` | The claimed task has an open container registration and no reported failed phase. The registration alone does not prove the agent is healthy. | Attach with `t` to watch or steer. | +| `disconnected` | The task is claimed, has no open registration, and its runner is no longer connected. | Bring that runner's host back, or the task stays stranded until its claim is released. | | `claiming` | A runner just claimed it; the spawn is about to start. | Nothing — transient. | | `preparing` | Readying the per-task clone / workspace. | Nothing — transient. | -| `building` | Composing and `docker build`-ing the image. **The slow step on a first run** for a repo (later runs hit Docker's cache). | Wait; first build of a repo image can take minutes. | +| `building` | Composing and building the image. Uncached steps can take time. | Wait; a first image build can take minutes. | | `starting` | `docker run` and the tmux session are coming up. | Nothing — transient. | -| `awaiting` | Container and tmux are up; waiting for the agent to open its `/live` connection. | Nothing — transient; if it lingers, see *When it goes wrong*. | -| `live` | A container registration is open — the agent is running and reachable. | Attach with `t` to watch or steer. | -| `down` | Claimed, the runner is alive, but the container is gone and unregistered. It came up and vanished, or never reported. | Respawn from the dashboard with `R` (the runner also self-heals — see below). | -| `failed` | A spawn step raised an error (hover / inspect for the detail). | Read the detail; fix the cause (bad image layer, missing secret) and respawn. | -| `disconnected` | Claimed by a runner that's **no longer connected** to the task service. | Bring that runner's host back, or the task stays stranded until its claim is released. | -| `–` | Terminal task (COMPLETE / DROPPED) — no container concept. | Nothing. | - -The dashboard only *displays* this status; it does no liveness guessing of its own. The five -middle statuses (`claiming`→`awaiting`) are the **spawn phases** the runner pushes as it works; -`queued`, `live`, `down`, and `disconnected` are *derived* by the task service from -registration + runner liveness, so the runner never invents them. (See -`compose_container_status` in `core/models.py` for the exact precedence.) +| `awaiting` | Container and tmux are up; waiting for the container's `/live` registration. | Nothing — transient; if it lingers, see *When it goes wrong*. | +| `healing` | The runner is recovering the task's missing session. | Wait for recovery; inspect repeated failures. | +| `failed` | A launcher or runner failure has been reported. It can remain visible even while the container's liveness process is registered. | Read the detail; fix the cause (bad image layer, missing secret) and respawn. | +| `down` | The task is claimed, its runner is live, and neither a registration nor a lifecycle phase remains. | Respawn from the dashboard with `R` (the runner also self-heals — see below). | + +The selection rules in `compose_container_status` (`core/models.py`) run in this order: + +1. A terminal task shows `–`. +2. A launch-paused task without a registration shows `paused`, or `failed` if that phase + was reported. +3. An unclaimed task shows `gated` when dependencies block it, otherwise `queued`. +4. A claimed task with an open registration shows `live`, except that a reported `failed` + phase wins. Other stale phases and runner disconnection do not override that registration. +5. Without a registration, a claimed task whose runner is disconnected shows `disconnected`, + even if a lifecycle phase remains. +6. Otherwise the reported phase shows through; with no phase, the task shows `down`. + +The dashboard only displays this result. The runner reports `claiming`, `preparing`, +`building`, `starting`, and `awaiting` during spawn, plus `healing` during recovery and +`failed` on failure. Those phases are inputs to the rules, not a separate priority order. ## Coming up: the spawn sequence @@ -71,9 +84,9 @@ reporting each as a status above. and its `origin` is pointed at the real forge rather than the local cache. 3. **Build** (`building`). The runner composes and `docker build`s the task's image. It's tagged - per `(workflow, repo)`, so once built it's cached — only the **first** task for a repo pays the - full build cost, which is why `building` can be slow that first time. See [layers](layers.md) - for how the image is composed. + per `(harness, workflow, repo)`, with an optional runtime suffix. Docker reuses unchanged + layers, which is why the first build can be slow and later builds are usually faster. + See [layers](layers.md) for how the image is composed. 4. **Start** (`starting`). The runner does `docker run --detach` (injecting the repo's secrets via `--env-file`, mounting `/workspace`, and a small config volume that persists the agent's @@ -104,17 +117,21 @@ For what a slug, branch, clone, and `provisioned` mean as task concepts, see [ta connection to the task service. While it's open the task reads `live`; if it drops (crash, kill, network blip) the registration clears and the task stops being `live`. The container reconnects with backoff across transient blips. -- **The agent.** In the tmux pane, the launcher wires everything the agent needs and then execs - `claude`: it renders the workflow's **skills** and **operations** as slash-commands, points the - agent's **MCP** client at the task service (so it can read/write artifacts and drive its own - state), and puts the workflow's state-machine overview in the system prompt. +- **The agent.** In the tmux pane, the launcher bootstraps and starts the task's selected + harness. It renders workflow **skills** and **operations** in that harness's format and + supplies the workflow's state-machine overview. Claude Code and Codex connect their **MCP** + clients to the task service; Pi and Outfitter use rendered **REST** instructions for task + operations and artifacts because they have no MCP client. - **The task memo is pre-filled.** On a task's first spawn the runner pastes the task's description into the agent's input box (unsent), so you see the ask waiting when you attach. - **Turn and blocked.** As the agent and user hand the work back and forth, the task's **turn** flips (`agent` ↔ `user`) via in-container hooks; a separate **blocked** marker is a deliberate "waiting on something" flag the agent sets. Both are shown on the dashboard. -- **Auth.** The agent authenticates from a `CLAUDE_CODE_OAUTH_TOKEN` injected from the repo's - env-file — see [auth](auth.md). +- **Auth.** Credentials depend on the selected harness: Claude Code uses an OAuth token or + API key from the repo's env-file; Codex uses its API credentials or a mounted `auth.json`; + Pi and Outfitter use Pi-compatible provider credentials or a mounted credential directory. + These model-provider credentials are separate from the task-service capability token used + by MCP and REST calls. See [auth](auth.md) for setup and credential layouts. ## When it goes wrong @@ -166,6 +183,6 @@ wedges the runner. After cleanup the task shows `–`: no container, nothing to ## See also -- [auth](auth.md) — giving a repo its `claude` token. -- [layers](layers.md) — how a task's image is composed (base → workflow → repo). +- [auth](auth.md) — setting up model-provider and task-service credentials. +- [layers](layers.md) — how a task's image is composed (base → harness → workflow → repo). - [tasks](tasks.md) — slug, branch, clone, and provisioning as task concepts. diff --git a/docs/design/ARCHITECTURE.md b/docs/design/ARCHITECTURE.md index bd4d5d9..00176ce 100644 --- a/docs/design/ARCHITECTURE.md +++ b/docs/design/ARCHITECTURE.md @@ -115,11 +115,12 @@ The execution-backend ABC realized as a separate **host process** (ADR 0008). Pe - owns **one tmux session per task** — *not inside the agent container*; its panes exec into the task's container(s), so a task with separate planner + implementer containers (M2) shares one session; -- **builds/selects the composed image** for a task (base → workflow → repo, ADR 0005); +- **builds/selects the composed image** for a task (base → harness → workflow → repo, ADR 0005); - **injects per-repo secrets** at launch (env vars + creds mount, ADR 0007); -- **provisions the worktree** once the slug is set — observing the task over its pull loop, it - builds the slug-named worktree on its host and repoints the container into it, then runs the - workflow's provisioning (ADR 0010); +- **prepares a writable per-task clone before spawn**, mounted at `/workspace`, with `origin` + pointed at the forge; once the slug is set, its pull loop branches that existing clone as + `panopticon/` and records the branch and clone path with the task service (ADR 0011). + The container keeps the same mount and working directory; - **registers with the task service** and reports session status. Concrete adapters behind the same interface, over time: local Docker+tmux (now), remote @@ -237,9 +238,9 @@ tool/REST. A container **hook** detects an unset slug and instructs the agent to decouples identity from naming and lets the agent (which has the most context) choose the slug. *(Refines PARITY §14's "YYYY-MM-DD-" id.)* -The task's **worktree/branch are named from the slug**, so the slug must be set before the -core can create the (always-required) worktree — and therefore before any workflow -provisioning that needs the branch (e.g. the parity workflow's PR). See the §9 lifecycle. +The task's **branch is named from the slug**. Its writable clone already exists at spawn, +keyed by task id; setting the slug lets the runner branch that clone in place. Work needing +the named branch, such as opening a PR, follows that provisioning step. See the §9 lifecycle. ### 8.4 Secrets (ADR 0007) @@ -252,31 +253,30 @@ mounted creds. Values never enter the DB, artifacts, or image layers. 1. **Idea → task.** A user captures an idea / promotes it via the dashboard (REST). The task service creates a Task row (internal id, chosen workflow, `repo_id`), in the workflow's initial state, with the turn assigned appropriately. No slug yet. -2. **Assign & spawn.** The task service assigns the task to a session service (runner). The - runner builds/selects the composed image (ADR 0005), injects the repo's secrets (ADR 0007), - creates the task container (sibling, DooD) and its tmux session, and starts the agent. The - container begins on a **read-only checkout** of the repo (there's no slug, hence no worktree, - yet) for the agent to plan against; step 5 upgrades it to the writable worktree. +2. **Claim & spawn.** A session service (runner) claims the task and creates its writable + per-task clone from the repository cache, pointing `origin` at the forge. It builds/selects + the composed image (base → harness → workflow → repo, ADR 0005), injects the repo's secrets + (ADR 0007), and starts the container on the host Docker daemon plus its host tmux session. + The clone is mounted read-write at `/workspace` from the start, before a slug exists. 3. **Connect & register.** The container entrypoint **connects to the task service and stays connected** — registering that this container is working on this task (liveness). It loads the workflow's in-container skills (from the active workflow) on top of the core operations. 4. **Slug.** A hook notices the slug is unset and instructs the agent to set one via a task tool; the task service records it. -5. **Worktree & provisioning.** The **session service**, observing the task over its pull loop - (ADR 0010), sees the slug land and creates the task's **worktree/branch** on the host where - the container runs — always required, named from the slug, so it cannot precede step 4 — then - repoints the container's working path to it (the agent `cd`s in). The active workflow's - **provisioning** then runs (e.g. the parity workflow opens its PR); because it needs that - branch, PR creation is transitively gated on the slug too. -6. **Work.** The agent plans/implements; artifacts (plan/notes) flow over MCP; the agent runs - workflow skills (e.g. `babysit-ci`) that may use `gh`/git and call back over REST/MCP to +5. **Branch & provisioning.** The **session service**, observing the task over its pull loop + (ADR 0011), sees the slug land and creates `panopticon/` from the existing clone's + current HEAD. It records the branch and clone path with the task service. The container's + `/workspace` mount and working directory stay in place; `origin` was set during spawn. + The agent can then perform workflow work that needs the named branch, such as opening a PR. +6. **Work.** The agent plans/implements; artifacts (plan/notes) flow over MCP or REST, + depending on the harness; the agent runs workflow skills (e.g. `babysit-ci`) that may use `gh`/git and call back over REST/MCP to request transitions. The task service deterministically enforces the workflow's state machine and responsibility gating, flips the turn per the fg/bg classification, and appends history. 7. **Observe & steer.** The dashboard reflects state/turn/history live (REST); the user presses `t` to drop into a task's tmux and back. -8. **Terminal states & cleanup.** On COMPLETE/DROPPED (or the workflow's terminals), cleanup - runs the core's agnostic teardown (tmux/worktree/branch) plus the workflow's specific - steps; the session service stops the container/session. +8. **Terminal states & cleanup.** On COMPLETE/DROPPED (or the workflow's terminals), the + session service stops the container/session, releases its claim, and removes the per-task + clone. Durable task artifacts remain in the task service's artifact store. ## 10. Deployment topology (ADR 0008) diff --git a/docs/layers.md b/docs/layers.md index 27c2b86..64a882e 100644 --- a/docs/layers.md +++ b/docs/layers.md @@ -1,23 +1,29 @@ # Container image layers — how they work and how to add your own -Every task runs its agent inside a container. That container's image is not one fixed blob — it is -**composed from three layers** stacked in order: **base → workflow → repo**. The base stays small -and general; a workflow adds what its skills need; a repo adds its own toolchain. This doc explains -the model and gives copy-pasteable recipes for adding a workflow layer and a repo layer. +A task container's image is **composed from four tiers** stacked in order: **base → harness → workflow → repo**. The base +provides shared tools; the harness adds its agent CLI; a workflow adds what its skills need; +a repo adds its own toolchain. This doc explains the model and gives copy-pasteable recipes +for adding a workflow layer and a repo layer. -## The three tiers +## The four tiers -Each tier is a Dockerfile fragment, and the effective image is those fragments `FROM`-chained on top -of one another: +The base has a Dockerfile; the other tiers contribute optional Dockerfile fragments that the +composer appends in order after `FROM panopticon-base`: -- **Base** — minimal and general: `python`, `git`, `gh`, `bash`, `curl`, `tmux`; the `claude` CLI - the agent execs; the `panopticon` package; and the entrypoint (uid/gid remap → privilege drop). +- **Base** — minimal and general: `python`, `git`, `gh`, `bash`, `curl`, `vim`; the `claude` CLI + available to the launcher; the `panopticon` package; and the entrypoint + (uid/gid remap → privilege drop). Built from `src/panopticon/docker/Dockerfile` and tagged `panopticon-base` (`make build`). It is deliberately **not** opinionated about any single workflow or repo; `gh` is shared because credentials and GitHub-bound work are workflow-independent. +- **Harness** — the selected harness's local `image_layer()` installs its agent CLI and runtime + dependencies. Claude's fragment is empty because the base already installs Claude Code; + Codex, Pi, and Outfitter contribute their own installation steps. `tmux` runs on the host, + not in the base task image. - **Workflow** — a fragment a `Workflow` subclass contributes via its `image_layer()` method, adding workflow-specific additions its skills need. It is empty when the base already supplies every - required tool, as it is for the GitHub-forge workflows. + required tool, as for `github-peer-reviewed` and `github-self-reviewed`. The 2119 workflows + add Codex for review even when the interactive harness is different. - **Repo** — a fragment referenced by a repo's `image_layer_file`, adding repo-specific setup: build toolchain, dependencies, pre-launch configuration (e.g. `uv`, `make sync`). @@ -28,17 +34,23 @@ The repo layer sits on top because it is the most specific and most frequently c When the session service (the runner) spawns a task, it composes the image before `docker run` (`sessionservice/spawner.py` `_compose_image`, `sessionservice/images.py`): -1. It fetches the two layers over REST from the task service — - `GET /workflows/{name}/image-layer` and `GET /repos/{id}/image-layer` — and drops any that are - empty. -2. If none remain, the task runs on **`panopticon-base`** directly (no build). +1. It gets the harness fragment from the runner's local harness adapter, then fetches the + workflow and repo fragments over REST from the task service — + `GET /workflows/{name}/image-layer` and `GET /repos/{id}/image-layer`. It keeps that order + and drops empty fragments. +2. If none remain, the task runs on **`panopticon-base`** directly (no composed-image build; + the base freshness check below still applies). 3. Otherwise it writes a Dockerfile that starts `FROM panopticon-base` and appends the fragments, - then `docker build`s it, tagged **`panopticon--`**. + then `docker build`s it, tagged **`panopticon---`**. When + `PANOPTICON_RUNTIME_ID` is set, a 12-character hash suffix separates that runtime's + composed tags. Every spawn first compares the base image's content/version fingerprint with the packaged -Dockerfile, entrypoint, and Panopticon release, rebuilding the static `panopticon-base` tag when it -is missing or stale. Docker layer-caches that rebuild and the composed image, so unchanged inputs -are cheap. Change a layer and the next spawn rebuilds only the affected steps. +Dockerfile, entrypoint, Panopticon version, installed package source, and optional development +wheel, rebuilding the static `panopticon-base` tag when it is missing or stale. The packaged-source +digest is cached once per runner process: restart the runner after changing installed package +source so it computes a fresh digest. Docker layer-caches the base rebuild and composed image, +so unchanged inputs are cheap. Change a layer and the next spawn rebuilds the affected steps. Each published Panopticon release also produces a multi-platform copy of that base image at `ghcr.io/unsupervisedcom/panopticon-next:` and updates `latest` for a non-prerelease. The @@ -79,13 +91,14 @@ A repo layer is **operator-authored** and referenced by name, so you don't touch example `~/.config/panopticon/layers/myrepo.dockerfile`: ```dockerfile - # Layered on top of base → workflow, so shared tools such as gh are already present. + # Layered on top of base → harness → workflow, so shared tools such as gh are already present. RUN curl --location --silent https://astral.sh/uv/install.sh | sh ``` It's a plain Dockerfile fragment — `RUN`/`ENV`/`COPY` lines, no `FROM` (the composer supplies - that). It builds on top of the workflow layer as the unprivileged `panopticon` user's - environment. + that). It inherits the preceding layer's build user and environment; set `USER` explicitly + if the install needs a particular user. The entrypoint runs the task as the unprivileged + `panopticon` user at container startup. 2. **Point the repo at it** in the dashboard's repo form: set `image_layer_file` to the file's **name** (`myrepo.dockerfile`), not a path. The form offers a picker over the files in your @@ -93,21 +106,21 @@ A repo layer is **operator-authored** and referenced by name, so you don't touch The value is a **reference**, not inline content — see the `image_layer_file` field in [`repos.md`](repos.md). The task service resolves it against its layers dir and serves the content -over REST; the runner composes it onto base → workflow. Names that escape the layers root (`..`, -absolute paths) are rejected; nested names (`team/myrepo.dockerfile`) are allowed. An empty or unset -`image_layer_file` means no repo layer. +over REST; the runner composes it onto base → harness → workflow. Names that escape the layers +root (`..`, absolute paths) are rejected; nested names (`team/myrepo.dockerfile`) are allowed. +An empty or unset `image_layer_file` means no repo layer. ## Notes -- **The layer file lives on the host that spawns the container.** Like `env_file` (see - `docs/auth.md`), `image_layer_file` is a bare name resolved against each runner host's - own layers dir. With a single host that's your machine; with remote runners (M5), place a - same-named file under each runner host's layers dir. +- **The repo layer file lives with the task service.** `image_layer_file` resolves against + the task service's layers directory; remote runners fetch its contents over REST. Unlike + an `env_file` secret, it does not need a same-named file on every runner host. - **Rebuilds & cleanup.** Editing a layer rebuilds the affected steps on the next spawn (Docker caches the rest). A packaged base-input or version change also refreshes a stale base automatically. `make clean` removes `panopticon-base` and every composed `panopticon-*` image; `make build` rebuilds the base immediately with the current development wheel. Changes to - package code outside the fingerprinted Dockerfile/entrypoint/version still require `make build`. + installed package source require a runner restart to refresh its cached source digest; + `make build` remains the explicit development rebuild path. - **Elevated privileges are a capability, not a layer.** Docker-in-Docker is opt-in via the repo's `capabilities` map (`docker_in_docker`), which makes the runner spawn `--privileged` and the entrypoint start a nested daemon — it is not something you add through a Dockerfile fragment. diff --git a/docs/workflows/2119-auto-sol.md b/docs/workflows/2119-auto-sol.md new file mode 100644 index 0000000..64ff9df --- /dev/null +++ b/docs/workflows/2119-auto-sol.md @@ -0,0 +1,116 @@ +# `2119-auto-sol` + +Runs the RFC 2119 specification, implementation, and proof stages autonomously. By default, +it sends the final diff through two independent Sol review contexts before waiting for your +approval. +It trades cross-model diversity for a predictable same-model review path. + +``` +SPECIFYING → BUILDING → TESTING → REVIEWING → MERGING → COMPLETE +``` + +(plus `DROPPED`, reachable from any nonterminal state.) + +**When to use:** GitHub changes where the agent may proceed from specification into +implementation without waiting and two independently dispatched Sol reviews are the intended +default. + +This workflow is **opt-in**: enable it for a repo before it appears in the task-creation +picker. It sets no default interactive harness or model; explicit task settings, repository +defaults, and the application's fallback determine those separately from reviewer settings. + +## Lifecycle + +| State | What happens | Who advances | +|---|---|---| +| **SPECIFYING** | The agent writes individually addressable requirements under `specs/`, annotates genuine tests for every MUST-level requirement, obtains fresh-context test-honesty verdicts, and publishes the specification as a task artifact. | **The agent**, which proceeds directly to implementation once the specification responsibilities are resolved. | +| **BUILDING** | The agent implements the specification, makes reviewable commits, opens a draft PR, and records its URL on the task. | **The agent**, once every building responsibility is resolved. | +| **TESTING** | The agent runs the full test suite, the 2119 check, the repo's own local gate, and PR CI. | **The agent**, once every gate is green. | +| **REVIEWING** | Two independently dispatched, fresh-context reviewers inspect the final diff, attempt targeted mutations, and publish evidence-bearing PR comments. The agent triages every finding, applies accepted fixes, reruns the testing gates, and publishes the review outputs and triage summary as task artifacts. | **You**: advancing to MERGING is your approval of the reviewed PR. | +| **MERGING** | The agent considers the triage summary's suggested follow-up issues, files those you endorsed or did not reject, and shepherds the PR through the merge queue. | **The agent**, which advances itself once the PR is merged. | +| **COMPLETE** | Terminal. The change has landed. | n/a | + +Before leaving SPECIFYING, spec lint and `npx rfc2119 check` must pass, including annotated +coverage and recorded test-honesty verdicts. The tests themselves may still fail until +BUILDING implements the requirements. The 2119 check does **not** execute the test suite: +TESTING separately requires the full suite, the 2119 check, the repo's own gate (when one +exists, run under `pipefail`), and PR CI to pass. Use the repository's pinned CLI version +when its instructions specify one. + +If the agent accepts a must-fix, it runs one fresh review round after retesting. Review is +capped at two rounds. A failed or unverified reviewer dispatch does not count as a clean +review. Every finding needs an explicit accept/reject decision and a reason. + +These are the workflow's agent responsibilities and skill instructions. The control plane +checks responsibility status when advancing; it does not execute the suite or independently +audit every agent claim. The final-review helper additionally checks the supplied review +evidence before its triage and responsibility callbacks run. + +## Same-model independence + +The test-honesty reviewer and both final-review slots default to +`codex:gpt-5.6-sol`. The default final reviews run in separate fresh contexts and each reviewer +chooses its own targeted mutation, preserving independence from the author and from the other +review context. They do **not** provide cross-model diversity. + +Repository reviewer settings can replace any default, so “Sol” describes this workflow's +shipped configuration rather than a lock. + +Final-review evidence carries the requested and observed model, verification source, +reviewed commit, review round, and review body. The helper checks the two final comments in +configured slot order against the final reviewed commit; failed dispatches, missing or +ambiguous evidence, and identity mismatches block acceptance. See the +[shared verification rules](2119-human-spec.md#reviewer-defaults). + +Each reviewer attempts at least one targeted mutation in a throwaway copy, verifies tests +actually run the mutated code, and reports killed or survived. A survivor is an evidence +defect; a kill alone does not establish why the test failed. The task checkout must remain +unchanged. + +## Repository overrides and artifacts + +The repository fields `honesty_reviewer`, `reviewer_1`, and `reviewer_2` independently replace +the test-honesty reviewer and the two final-review slots. Values are atomic +`:` pairs; supported reviewer harnesses are `claude` and `codex`, and a blank +value falls back to the workflow default. The model suffix remains opaque, including any +further colons. The runner transports these as `PANOPTICON_2119_HONESTY_REVIEWER`, +`PANOPTICON_2119_REVIEWER_1`, and `PANOPTICON_2119_REVIEWER_2`; resolution and reviewer calls +happen inside the task container. Ensure that container has credentials for the chosen +reviewers. The workflow layer installs Codex, and the base image supplies Claude Code. + +The specification is a required task artifact. The review skill also directs the agent to +publish final review outputs and its triage summary; the universal `artifacts` skill asks +it to publish other reviewable documents, such as gate reports, as they are produced. +Read these durable documents with the dashboard's `a` hotkey. Merely writing a file in +`/workspace` does not publish it: the agent uses `put_artifact` over MCP, or the artifact +REST endpoint on a harness without MCP. These task artifacts complement the specification +and tests in the repository and review comments on the PR. Record the PR URL in the task's +external URL field for the `p` hotkey, rather than using an artifact as the link. + +## Your part and the agent's part + +- **You**: react to suggested follow-up issues in the triage PR comment and approve the + reviewed PR by advancing from REVIEWING. +- **The agent**: writes and publishes the contract, creates and gets the tests judged, + implements only the specified change, proves it locally and in CI, runs and triages two + configured final reviews, and merges after your approval. + +## Skills + +- **`spec-2119`** writes the specification and annotated tests, dispatches test-honesty + reviews, records their verdicts, and publishes the specification artifact. +- **`open-pr`** opens a draft PR that references the published specification and records + its URL on the task. +- **`babysit-ci`** watches CI and repairs failures or base conflicts. +- **`dual-review-sol`** dispatches the configured final reviewers, verifies their evidence, + requires targeted mutations, and drives triage and any re-review. +- **`babysit-merge`** files approved or unopposed deferred-work issues, then shepherds the + PR through the merge queue. + +## Related + +- [`2119-auto-spec`](2119-auto-spec.md): the same automatic lifecycle with Fable-plus-Sol + final-review defaults. +- [`2119-human-spec`](2119-human-spec.md): adds a human specification gate and defaults to + cross-provider final review. +- [Workflow catalog](README.md). diff --git a/docs/workflows/2119-auto-spec.md b/docs/workflows/2119-auto-spec.md new file mode 100644 index 0000000..40c80a2 --- /dev/null +++ b/docs/workflows/2119-auto-spec.md @@ -0,0 +1,112 @@ +# `2119-auto-spec` + +Runs the RFC 2119 specification, implementation, and proof stages autonomously, then waits +for you to approve the reviewed PR. It keeps the spec-first contract and cross-provider final +review of [`2119-human-spec`](2119-human-spec.md), but removes the human specification gate. + +``` +SPECIFYING → BUILDING → TESTING → REVIEWING → MERGING → COMPLETE +``` + +(plus `DROPPED`, reachable from any nonterminal state.) + +**When to use:** GitHub changes where the agent may proceed from an honestly tested +specification into implementation without waiting, while the final reviewed PR still needs +your approval. + +This workflow is **opt-in**: enable it for a repo before it appears in the task-creation +picker. It sets no default interactive harness or model; explicit task settings, repository +defaults, and the application's fallback determine those separately from reviewer settings. + +## Lifecycle + +| State | What happens | Who advances | +|---|---|---| +| **SPECIFYING** | The agent writes individually addressable requirements under `specs/`, annotates genuine tests for every MUST-level requirement, obtains fresh-context test-honesty verdicts, and publishes the specification as a task artifact. | **The agent**, which proceeds directly to implementation once the specification responsibilities are resolved. | +| **BUILDING** | The agent implements the specification, makes reviewable commits, opens a draft PR, and records its URL on the task. | **The agent**, once every building responsibility is resolved. | +| **TESTING** | The agent runs the full test suite, the 2119 check, the repo's own local gate, and PR CI. | **The agent**, once every gate is green. | +| **REVIEWING** | Two fresh-context reviewers inspect the final diff, attempt targeted mutations, and publish evidence-bearing PR comments. The agent triages every finding, applies accepted fixes, reruns the testing gates, and publishes the review outputs and triage summary as task artifacts. | **You**: advancing to MERGING is your approval of the reviewed PR. | +| **MERGING** | The agent considers the triage summary's suggested follow-up issues, files those you endorsed or did not reject, and shepherds the PR through the merge queue. | **The agent**, which advances itself once the PR is merged. | +| **COMPLETE** | Terminal. The change has landed. | n/a | + +Before leaving SPECIFYING, spec lint and `npx rfc2119 check` must pass, including annotated +coverage and recorded test-honesty verdicts. The tests themselves may still fail until +BUILDING implements the requirements. The 2119 check does **not** execute the test suite: +TESTING separately requires the full suite, the 2119 check, the repo's own gate (when one +exists, run under `pipefail`), and PR CI to pass. Use the repository's pinned CLI version +when its instructions specify one. + +If the agent accepts a must-fix, it runs one fresh review round after retesting. Review is +capped at two rounds. A failed or unverified reviewer dispatch does not count as a clean +review. Every finding needs an explicit accept/reject decision and a reason. + +These are the workflow's agent responsibilities and skill instructions. The control plane +checks responsibility status when advancing; it does not execute the suite or independently +audit every agent claim. The final-review helper additionally checks the supplied review +evidence before its triage and responsibility callbacks run. + +## Reviewer defaults + +The test-honesty reviewer defaults to `codex:gpt-5.6-sol`. The two final-review slots +default to `claude:claude-fable-5` and `codex:gpt-5.6-sol`, providing cross-provider review. +Repository reviewer settings can replace any of those defaults without changing the task's +interactive harness or model. + +Final-review evidence includes the requested and observed model, verification source, +reviewed commit, review round, and review body. The helper requires the two final comments +in configured slot order for the final reviewed commit. Claude identity comes from JSON +`modelUsage`; Codex identity comes from the matching persisted rollout, a weaker source +than a documented stdout identity field. A mismatch, missing evidence, or dispatch failure +blocks acceptance. + +Each reviewer chooses at least one targeted mutation of a specific claimed property and +applies it only in a throwaway copy, verifies tests actually run the mutated code, and +reports whether it was killed or survived. A survivor is an evidence defect; a kill alone +does not prove that the right assertion failed. The task checkout must remain unchanged. + +## Repository overrides and artifacts + +The repository fields `honesty_reviewer`, `reviewer_1`, and `reviewer_2` independently replace +the test-honesty reviewer and the two final-review slots. Values are atomic +`:` pairs; supported reviewer harnesses are `claude` and `codex`, and a blank +value falls back to the workflow default. The model suffix remains opaque, including any +further colons. The runner transports these as `PANOPTICON_2119_HONESTY_REVIEWER`, +`PANOPTICON_2119_REVIEWER_1`, and `PANOPTICON_2119_REVIEWER_2`; resolution and reviewer calls +happen inside the task container. Ensure that container has credentials for the chosen +reviewers. The workflow layer installs Codex, and the base image supplies Claude Code. + +The specification is a required task artifact. The review skill also directs the agent to +publish final review outputs and its triage summary; the universal `artifacts` skill asks +it to publish other reviewable documents, such as gate reports, as they are produced. +Read these durable documents with the dashboard's `a` hotkey. Merely writing a file in +`/workspace` does not publish it: the agent uses `put_artifact` over MCP, or the artifact +REST endpoint on a harness without MCP. These task artifacts complement the specification +and tests in the repository and review comments on the PR. Record the PR URL in the task's +external URL field for the `p` hotkey, rather than using an artifact as the link. + +## Your part and the agent's part + +- **You**: react to suggested follow-up issues in the triage PR comment and approve the + reviewed PR by advancing from REVIEWING. +- **The agent**: writes and publishes the contract, creates and gets the tests judged, + implements only the specified change, proves it locally and in CI, runs and triages the + final reviews, and merges after your approval. + +## Skills + +- **`spec-2119`** writes the specification and annotated tests, dispatches test-honesty + reviews, records their verdicts, and publishes the specification artifact. +- **`open-pr`** opens a draft PR that references the published specification and records + its URL on the task. +- **`babysit-ci`** watches CI and repairs failures or base conflicts. +- **`dual-review`** dispatches the configured final reviewers, verifies their evidence, + requires targeted mutations, and drives triage and any re-review. +- **`babysit-merge`** files approved or unopposed deferred-work issues, then shepherds the + PR through the merge queue. + +## Related + +- [`2119-human-spec`](2119-human-spec.md): adds a human approval gate after specification. +- [`2119-auto-sol`](2119-auto-sol.md): the same automatic lifecycle with two Sol final-review + slots by default. +- [Workflow catalog](README.md). diff --git a/docs/workflows/2119-human-spec.md b/docs/workflows/2119-human-spec.md new file mode 100644 index 0000000..82de8b3 --- /dev/null +++ b/docs/workflows/2119-human-spec.md @@ -0,0 +1,112 @@ +# `2119-human-spec` + +Defines a change as an RFC 2119 contract and reviewed tests before implementation. You +approve that contract, the agent builds and proves it, two independent reviewers challenge +the final diff, and you approve the reviewed PR before it can merge. + +``` +SPECIFYING → BUILDING → TESTING → REVIEWING → MERGING → COMPLETE +``` + +(plus `DROPPED`, reachable from any nonterminal state.) + +**When to use:** consequential GitHub changes where you want to inspect the specification +before any implementation and inspect the reviewed result before merge. + +This workflow is **opt-in**: enable it for a repo before it appears in the task-creation +picker. It sets no default interactive harness or model; explicit task settings, repository +defaults, and the application's fallback determine those separately from reviewer settings. + +## Lifecycle + +| State | What happens | Who advances | +|---|---|---| +| **SPECIFYING** | The agent writes individually addressable requirements under `specs/`, annotates genuine tests for every MUST-level requirement, obtains fresh-context test-honesty verdicts, and publishes the specification as a task artifact. | **You**, after reviewing the specification. | +| **BUILDING** | The agent implements the specification, makes reviewable commits, opens a draft PR, and records its URL on the task. | **The agent**, once every building responsibility is resolved. | +| **TESTING** | The agent runs the full test suite, the 2119 check, the repo's own local gate, and PR CI. | **The agent**, once every gate is green. | +| **REVIEWING** | Two fresh-context reviewers inspect the final diff, attempt targeted mutations, and publish evidence-bearing PR comments. The agent triages every finding, applies accepted fixes, reruns the testing gates, and publishes the review outputs and triage summary as task artifacts. | **You**: advancing to MERGING is your approval of the reviewed PR. | +| **MERGING** | The agent considers the triage summary's suggested follow-up issues, files those you endorsed or did not reject, and shepherds the PR through the merge queue. | **The agent**, which advances itself once the PR is merged. | +| **COMPLETE** | Terminal. The change has landed. | n/a | + +Before leaving SPECIFYING, spec lint and `npx rfc2119 check` must pass, including annotated +coverage and recorded test-honesty verdicts. The tests themselves may still fail until +BUILDING implements the requirements. The 2119 check does **not** execute the test suite: +TESTING separately requires the full suite, the 2119 check, the repo's own gate (when one +exists, run under `pipefail`), and PR CI to pass. Use the repository's pinned CLI version +when its instructions specify one. + +If the agent accepts a must-fix, it runs one fresh review round after retesting. Review is +capped at two rounds. A failed or unverified reviewer dispatch does not count as a clean +review. Every finding needs an explicit accept/reject decision and a reason. + +These are the workflow's agent responsibilities and skill instructions. The control plane +checks responsibility status when advancing; it does not execute the suite or independently +audit every agent claim. The final-review helper additionally checks the supplied review +evidence before its triage and responsibility callbacks run. + +## Reviewer defaults + +The test-honesty reviewer defaults to `codex:gpt-5.6-sol`. The two final-review slots +default to `claude:claude-fable-5` and `codex:gpt-5.6-sol`, providing cross-provider review. +Repository reviewer settings can replace any of those defaults without changing the task's +interactive harness or model. + +Final-review evidence includes the requested and observed model, verification source, +reviewed commit, review round, and review body. The helper requires the two final comments +in configured slot order for the final reviewed commit. Claude identity comes from JSON +`modelUsage`; Codex identity comes from the matching persisted rollout, a weaker source +than a documented stdout identity field. A mismatch, missing evidence, or dispatch failure +blocks acceptance. + +Each reviewer chooses at least one targeted mutation of a specific claimed property and +applies it only in a throwaway copy, verifies tests actually run the mutated code, and +reports whether it was killed or survived. A survivor is an evidence defect; a kill alone +does not prove that the right assertion failed. The task checkout must remain unchanged. + +## Repository overrides and artifacts + +The repository fields `honesty_reviewer`, `reviewer_1`, and `reviewer_2` independently replace +the test-honesty reviewer and the two final-review slots. Values are atomic +`:` pairs; supported reviewer harnesses are `claude` and `codex`, and a blank +value falls back to the workflow default. The model suffix remains opaque, including any +further colons. The runner transports these as `PANOPTICON_2119_HONESTY_REVIEWER`, +`PANOPTICON_2119_REVIEWER_1`, and `PANOPTICON_2119_REVIEWER_2`; resolution and reviewer calls +happen inside the task container. Ensure that container has credentials for the chosen +reviewers. The workflow layer installs Codex, and the base image supplies Claude Code. + +The specification is a required task artifact. The review skill also directs the agent to +publish final review outputs and its triage summary; the universal `artifacts` skill asks +it to publish other reviewable documents, such as gate reports, as they are produced. +Read these durable documents with the dashboard's `a` hotkey. Merely writing a file in +`/workspace` does not publish it: the agent uses `put_artifact` over MCP, or the artifact +REST endpoint on a harness without MCP. These task artifacts complement the specification +and tests in the repository and review comments on the PR. Record the PR URL in the task's +external URL field for the `p` hotkey, rather than using an artifact as the link. + +## Your part and the agent's part + +- **You**: approve the specification, react to suggested follow-up issues in the triage PR + comment, and approve the reviewed PR by advancing from REVIEWING. +- **The agent**: writes and publishes the contract, creates and gets the tests judged, + implements only the specified change, proves it locally and in CI, runs and triages the + final reviews, and merges after your approval. + +## Skills + +- **`spec-2119`** writes the specification and annotated tests, dispatches test-honesty + reviews, records their verdicts, and publishes the specification artifact. +- **`open-pr`** opens a draft PR that references the published specification and records + its URL on the task. +- **`babysit-ci`** watches CI and repairs failures or base conflicts. +- **`dual-review`** dispatches the configured final reviewers, verifies their evidence, + requires targeted mutations, and drives triage and any re-review. +- **`babysit-merge`** files approved or unopposed deferred-work issues, then shepherds the + PR through the merge queue. + +## Related + +- [`2119-auto-spec`](2119-auto-spec.md): the same reviewer defaults, without the human + specification gate. +- [`2119-auto-sol`](2119-auto-sol.md): automatic specification with two Sol review slots + by default. +- [Workflow catalog](README.md). diff --git a/docs/workflows/README.md b/docs/workflows/README.md index 9061eb3..3bc4584 100644 --- a/docs/workflows/README.md +++ b/docs/workflows/README.md @@ -17,6 +17,9 @@ lifecycle — see [Tasks](../tasks.md). |---|---|---| | [`github-peer-reviewed`](github-peer-reviewed.md) | Ships a GitHub PR that a **peer** reviews before it merges. Use for GitHub changes that need a second person's sign-off. | A GitHub PR (peer-approved) | | [`github-self-reviewed`](github-self-reviewed.md) | Ships a GitHub PR that **you** review yourself, with no peer-review gate. | A GitHub PR (self-approved) | +| [`2119-human-spec`](2119-human-spec.md) | Defines requirements and reviewed tests first. **You approve the spec and the final reviewed PR.** Default final reviewers: Fable and Sol. | A GitHub PR | +| [`2119-auto-spec`](2119-auto-spec.md) | Proceeds from specification into implementation automatically. **You still approve the final reviewed PR.** Default final reviewers: Fable and Sol. | A GitHub PR | +| [`2119-auto-sol`](2119-auto-sol.md) | Uses the same automatic specification flow with **two independent Sol review contexts** by default; you still approve the final reviewed PR. | A GitHub PR | | [`local-git-self-reviewed`](local-git-self-reviewed.md) | Keeps the work **local**: commits to a branch and merges it, with no GitHub, PR, or CI. Use when the change never leaves the machine. | A local branch merged into the base | | [`spike`](spike.md) | **Open-ended** agent work with no gates. Use for exploration, debugging, and research, until you call it done. | Nothing lands on its own | | [`orchestrator`](orchestrator.md) | An agent that **decomposes a goal into child tasks**, each pre-planned and handed to you ready to approve. Use to fan work out across agents. | New pre-planned child tasks | @@ -43,6 +46,13 @@ You approve the plan by advancing the task out of PLANNING. Attach with `t`, the operation using your harness's explicit syntax: `/advance` in Claude, `$advance` in Codex, or `/skill:advance` in Pi and Outfitter. `spike` and `setup-repo` have no planning step. +The three `2119-*` workflows instead begin in **SPECIFYING**: requirements, annotated tests, +test-honesty verdicts, and a published specification artifact. `2119-human-spec` waits for +your specification approval; `2119-auto-spec` and `2119-auto-sol` advance automatically +when that stage's responsibilities are satisfied. All three still wait for your approval +in **REVIEWING**, after final review and triage, before proceeding to merge. See their +pages for the separate suite, 2119, repository, and CI gates. + ## Who advances a state Each state is advanced by either **you** or the **agent**: @@ -56,9 +66,9 @@ Each state is advanced by either **you** or the **agent**: ## How workflows are offered - **Default-on vs. opt-in.** `spike` and `orchestrator` are shown for every repo by - default. `github-peer-reviewed`, `github-self-reviewed`, and `local-git-self-reviewed` - are **opt-in**: enable them per repo (in the repo's workflow settings) before they show - up in the task-creation picker. + default. `github-peer-reviewed`, `github-self-reviewed`, `local-git-self-reviewed`, + `2119-human-spec`, `2119-auto-spec`, and `2119-auto-sol` are **opt-in**: enable them per + repo (in the repo's workflow settings) before they show up in the task-creation picker. - **Hidden utilities.** `setup-repo` is hidden from the pickers entirely; you launch it from the repos screen's setup hotkey, not by creating an ordinary task.