From 2db3396e58247bb1cdbc34e416a64f412db56afa Mon Sep 17 00:00:00 2001 From: Panopticon Agent Date: Thu, 29 Oct 2026 00:13:51 -0700 Subject: [PATCH] docs: align runtime architecture and document 2119 workflows Replace stale read-only checkout and three-tier image descriptions with the current writable clone, in-place branch provisioning, and base/harness/workflow/repository composition. Correct layer ownership, source freshness, harness transport and credentials, and the full container-status selection rules. Add linked pages for all three 2119 workflows covering lifecycle, human gates, reviewer defaults and evidence, repository overrides, artifacts, and the distinction between recorded responsibilities and actual test execution. Validation: all 33 local links and anchors pass. Source-backed independent review passes, including a fresh review of corrected status precedence. Ruff, format, mypy, wheel build, and clean-wheel smoke pass. The change-scoped 2119 check has zero affected requirements; the full gate retains 203 pre-existing verdict violations. --- docs/container.md | 87 +++++++++++++--------- docs/design/ARCHITECTURE.md | 46 ++++++------ docs/layers.md | 71 ++++++++++-------- docs/workflows/2119-auto-sol.md | 116 ++++++++++++++++++++++++++++++ docs/workflows/2119-auto-spec.md | 112 +++++++++++++++++++++++++++++ docs/workflows/2119-human-spec.md | 112 +++++++++++++++++++++++++++++ docs/workflows/README.md | 16 ++++- 7 files changed, 470 insertions(+), 90 deletions(-) create mode 100644 docs/workflows/2119-auto-sol.md create mode 100644 docs/workflows/2119-auto-spec.md create mode 100644 docs/workflows/2119-human-spec.md 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.