From e3d17279df64d1b2cf0f48949c72556c5dbd3522 Mon Sep 17 00:00:00 2001 From: garrytan Date: Tue, 13 Oct 2026 01:37:54 +0000 Subject: [PATCH] v1.91.97.0: closable unattended autoplan runs on Capy Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --- CHANGELOG.md | 23 +++++++++++++++++++++++ VERSION | 2 +- agents-digest/gstack-AGENTS.md | 2 +- docs/unattended.md | 15 +++++++++++++-- package.json | 2 +- 5 files changed, 39 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60c6fd419..bfcc94b2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,28 @@ # Changelog +## [1.91.97.0] - 2026-10-13 + +**An unattended `/autoplan` run on Capy now closes in its own run directory. Reviews done by Capy subagents bind with one command, a revised plan is reviewed in the same run, and the gate asks fewer, better questions.** + +### What this means for you + +- **`submit --record ` binds a review a subagent wrote by hand.** It accepts the canonical findings fence, one findings table (Severity and Title columns), one severity-tagged list (`- [High] title`) or a `No findings.` line, and it never guesses a severity. A record whose `INPUT:` line is present but wrong is refused. A record without one binds only with `--attest "" --attempt `; it is labeled `receipt: attested`, `validate` counts it (`attested=`), and it is refused if the plan was revised after that attempt was dispatched. `--attempt` is optional when exactly one attempt is open. `submit --voice outside --unavailable|--failed ""` closes a phase whose outside voice cannot run, and `next` and `resume` never redispatch it. +- **`revise --plan ` reviews a revised plan in the same run.** Every phase whose reviewed Implementation-plan hash differs reopens (plus Eng) on the new snapshot; at the gate it starts the next gate revision. The revise is one recoverable step (`resume` finishes an interrupted one), and archives never overwrite each other. `next` prints `PLAN_CHANGED` and `answer` prints `PLAN_SOURCE_CHANGED` when the plan file moved since its snapshot. +- **Accepted plan changes must reach the plan.** When the owner accepts a change at the gate, `answer` prints one `APPLY:` line per change and `NEXT: gstack-autoplan revise …`. `next` refuses with `PLAN_AMEND_PENDING` until `revise --incorporates ` binds the edit, or the owner withdraws a change with `--withdraw `. A run cannot export as complete with a change pending. +- **User-challenge defaults follow agreeing voices, and say why.** When both voices flag the same finding as a change to scope, cost or direction (the same `changes` value) and both give a remedy, the item now recommends the change. Option b shows both remedies word for word, and the default is labeled `recommended: b (both voices; remedies shown)`. Anything weaker keeps your direction, labeled `(plan direction; voices disagree)`. **`all` now accepts those agreed changes**; reply `all as-is` to keep every direction in one token. p1's recommended text names the changes it would apply. +- **Reruns stop churning.** Reviewers set `user_challenge` only for a change to scope, cost or direction (`changes`). On a rerun, a challenge without one becomes the agent's own decision and does not reopen anything. Rerun prompts carry a `DECIDED AT THE GATE` block, and answers to items from phases that did not rerun carry forward instead of being asked again. A partial reply never overwrites an earlier answer, and the gate stays open until every approval is settled. +- **A plan without the two sections is scaffolded, not refused with empty output.** The first `next` explains `PLAN_SECTIONS_INVALID`; `next --scaffold` reviews a copy with the missing heading added and never edits your file. +- **Runs gated on older gstack still validate.** A run directory from an older gstack prints `GSTACK_VERSION_CHANGED` once and moves forward, and decision ids minted before 1.91.95 are renamed and journaled, so a reopened run exported after upgrading validates. A run written by a newer gstack is refused. +- **Admission on Capy.** `next`, `submit`, `answer`, `revise`, `export` and `run` make the same install check as skill start: under `GSTACK_CAPY=1` they refuse without a passing install verdict (`INSTALL_UNVERIFIED`), and in an unattended session they refuse a PATH Bun below the supported minimum. `status` and `resume` always work. +- **Scope keys on what changes.** The Design phase needs a rendered surface in the Implementation plan (a `.tsx`, `.css` or similar file, or a UI word next to a visual one); words in the Review record no longer count. `next` prints the evidence and the source per axis (`source=ui:flag,dx:detected`). `--no-dx` is new. A `` marker on the plan's first line keeps flags across runs, and `next` prints the marker to add; gstack never writes your plan. The interactive skill uses the same detector. +- **PLAN_REALITY wants a receipt per measured number and the rule itself.** Each clause stating a measured quantity (seconds, %, $, tokens, MB) needs its own file:line, script or command receipt (`unreceipted_numbers=` plus one `NUMBER_UNRECEIPTED:` line each), and a line claiming a decision rule must quote or link it (`unquoted=`). Receipts on dot paths such as `.gstack/ship-policy.json:1` count. `submit` records the check for each plan revision; it never refuses a submit. +- **`autoplan/DRIVER.md` is the compact driver.** About a hundred lines generated from the code: the phase order, the artifact contract, the gate protocol and the coordinator contract, with no hook prose. `gstack-autoplan --help` and the first `next` print its path, and any host can read it instead of the full autoplan skill. + +### For contributors + +- New modules: `lib/autoplan-revise.ts`, `lib/autoplan-migrate.ts`, `lib/autoplan-plan-text.ts`, `lib/autoplan-admission.ts`, `lib/autoplan-scope.ts`, `lib/source-root.ts`, `scripts/resolvers/autoplan-driver.ts`. +- `test/autoplan-capy-e2e.test.ts` drives the whole unattended loop on the simulated Capy host: canonical and attested records, an unavailable outside voice, partial replies, the amendment interlock, revise, an interrupted run resumed, three gate revisions and a validating export. + ## [1.91.96.0] - 2026-10-13 **On a Capy machine, gstack now tells the truth about itself and fixes the common cases on its own. An old checkout upgrades itself at session start, the install check agrees with the Bun your workflows run, and every fix line names a command that exists.** diff --git a/VERSION b/VERSION index 821746e64..1b3816353 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.91.96.0 +1.91.97.0 diff --git a/agents-digest/gstack-AGENTS.md b/agents-digest/gstack-AGENTS.md index 02a666044..9c0e1f510 100644 --- a/agents-digest/gstack-AGENTS.md +++ b/agents-digest/gstack-AGENTS.md @@ -1,4 +1,4 @@ -# gstack digest v1.91.96.0 — regenerate/re-copy after upgrading gstack +# gstack digest v1.91.97.0 — regenerate/re-copy after upgrading gstack Behavioral rules from gstack (https://github.com/garrytan/gstack), compressed for agent hosts without a full skill install. The full skills add workflows, diff --git a/docs/unattended.md b/docs/unattended.md index d6b08e744..e566bdf49 100644 --- a/docs/unattended.md +++ b/docs/unattended.md @@ -138,18 +138,29 @@ On a host where the parent dispatches the reviewers itself (Capy, any orchestrator without a Claude Code harness), `bin/gstack-autoplan` is the explicit, durable state machine for the whole run. The parent never reads the review record; it runs a loop over two commands and reads the printed lines. +A parent on any host reads `autoplan/DRIVER.md` (its path is printed as +`DRIVER:` by `gstack-autoplan --help` and the first `next`) instead of +autoplan/SKILL.md: the phase order, the artifact contract and the gate protocol +in about a hundred lines, generated from the code. ```bash AP=bin/gstack-autoplan -$AP next --out --plan [--ui|--no-ui] [--developer-tool] [--light] [--spend-cap ] +$AP next --out --plan [--ui|--no-ui] [--developer-tool] [--no-dx] [--light] [--spend-cap ] # PHASE: ceo snapshot= order=ceo,design,dx,eng -# Skipped sections: none (scope: ui=yes,dx=yes,source=detected; checklist=loaded) +# SCOPE: ui=yes (...) dx=yes (detected: ...) source=ui:detected,dx:detected +# DRIVER: /autoplan/DRIVER.md +# Skipped sections: none (scope: ui=yes,dx=yes,source=ui:detected,dx:detected; checklist=loaded) # ATTEMPT: -a1 phase=ceo voice=native prompt=/ceo-native-prompt.md result=/ceo-native.md model_family=... # ATTEMPT: -a2 phase=ceo voice=outside prompt=/ceo-outside-prompt.md result=/ceo-outside.md model_family=differs from the native reviewer # SPEND: spent=0.00 reserved=0.00 unknown=0(0.00) worst_case=0.00 cap=none # GSTACK_RESULT: skill=autoplan status=awaiting_result run= ``` +The first `next` prints `SCOPE: … source=ui:,dx:<…>` +and, when CLI flags differ from the plan's marker, `SCOPE_PIN: add as the first line of `; gstack never writes +the plan. + 1. **Dispatch each `ATTEMPT:`.** The native voice is a subagent on the parent's own model given the prompt file; the outside voice is a subagent on another model family, or `bin/gstack-outside-voice run --runner codex-cli|api diff --git a/package.json b/package.json index df2a68342..038bf314a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gstack", - "version": "1.91.96", + "version": "1.91.97", "description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.", "license": "MIT", "type": "module",