mirror of
https://github.com/garrytan/gstack.git
synced 2026-10-31 14:06:50 +01:00
* refactor: share the decision-trail append rules (lib/decision-trail.ts) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * feat(autoplan): carry the owner's answer to a later gate that asks nothing new, gate.json eli5, stacked approvals import A later gate revision with nothing new is answered with the owner's recorded words (CARRIED); a 'do it' also covers new auto items that change no scope, cost or direction; an unreviewed post-cap delta gets one cross-family reviewer first (CARRY_CHECK, gstack-autoplan check). gate.json gains eli5 and the Captain brief requires ## ELI5 on runs that carry it. gstack-approvals import --stack writes every branch or none. The first next prints REVIEW_ESTIMATE. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs: carry-forward, ELI5 section and stacked approvals import Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix(autoplan): carry only fully owner-answered gates; void stale delta checks - a pending delta check is voided (reservation released) when the owner answers, the plan is revised, or a new gate is written; a check bound to an older delta is void - carry refuses a gate with any approval item still pending or answered in item tokens - "do it" never covers an option that changes the plan; isDoIt ignores Captain-relayed prefixes - captain brief rebuilds ELI5 from the current plan and lists items taken under "do it" - gstack-approvals import --stack locates every branch before writing any - DRIVER.md back under its 162-line budget Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs: carry-forward conditions, delta-check voiding and import --stack match the final code Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * chore: changelog for autoplan carry-forward (unreleased; stamped at merge) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * chore: stamp v1.91.314.0 Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --------- Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
87 lines
7.1 KiB
Cheetah
87 lines
7.1 KiB
Cheetah
# /autoplan driver: run the review loop from a parent agent
|
|
|
|
Read this file instead of `autoplan/SKILL.md` when you (a parent agent on any host) drive an
|
|
unattended /autoplan run through `gstack-autoplan`: the reviewers are subagents you dispatch,
|
|
and the runner keeps the state. The commands live in `<root>/bin/`, where `<root>` is the
|
|
folder that holds this `autoplan/` directory; `gstack-autoplan --help` and the first `next`
|
|
print `DRIVER: <root>/autoplan/DRIVER.md`. Run every command with the `GSTACK_LAUNCH` assignments your installer printed: `. <the GSTACK_LAUNCH_FILE it printed>` in the shell that runs the command,
|
|
never `export $(...)`, `env`, `printenv` or a bare `set` in a tool fence (a bare `export` prints every variable, credentials included). Read printed lines and files, never prose: every workflow
|
|
command ends with `GSTACK_RESULT: skill=autoplan status=<s> run=<dir>`, and every error line
|
|
ends with `(<CODE>)`.
|
|
|
|
## Phases and scope
|
|
|
|
{{AUTOPLAN_DRIVER_PHASES}}
|
|
The first `next` prints `SCOPE: ui=… (terms; visual; files) dx=… (detected) docs_only=yes|no (<s>) source=ui:<s>,dx:<s>`
|
|
(each is `flag`, `marker` or `detected`). Docs-only (`--docs-only`, or every Implementation-plan path is README*, CHANGELOG*,
|
|
TODOS*, docs/** but not docs/*-policy.md, or other markdown outside a skill dir) runs CEO on the native voice only, then Eng. UI needs a rendered file path or a UI term next
|
|
to a visual noun in the Implementation plan. To keep flags for later runs on the same plan, add
|
|
the `SCOPE_PIN:` marker it prints (`<!-- gstack-autoplan-scope: … -->`) as the plan's first
|
|
line yourself; gstack never writes the plan.
|
|
|
|
## The loop
|
|
|
|
1. `next` prints one `ATTEMPT: <id> phase=<p> voice=native|outside prompt=<file> result=<file>`
|
|
per voice. Dispatch the native prompt to a subagent on your model and the outside prompt to
|
|
a subagent on another model family (or `gstack-outside-voice run`). Each writes `result=`. The first `next` also prints `REVIEW_ESTIMATE:` (most attempts and reservations the review can take).
|
|
2. Submit each voice exactly once (`BOUND:`). Both voices in closes the phase (`PHASE_CLOSED:`).
|
|
3. Repeat `next` until `status=gate_pending` (`GATE: gate_rev=<n>`); render it with `gstack-gate render <dir>/gate.json --all` and relay every page with the two cost lines printed under `GATE:`: `GATE_SPEND:` (spent, worst case, cap, headroom, attempts; host-subagent attempts are priced unknown and counted at their reservation, so quote their real figure from the host's cost view) and `GATE_REC_COST:` (the phases `rec` can reopen and the estimate for them, an upper bound; `gate_cost` in `--json`).
|
|
You never approve the gate for the owner. Offer `rec` (every recommendation, plan changes included) as the default.
|
|
4. `answer` with the owner's reply and `--by human` (the owner typed the tokens) or `--by agent:<id> --owner-reply "<their words>"` (you relayed them); without `--by` an
|
|
unattended run refuses (`ANSWER_BY_REQUIRED`). `APPLY: <id> <title> -> <change>` lines are
|
|
accepted plan changes (status `amend_pending`): edit the plan, then `revise` (the printed
|
|
`NEXT:` names it), or `revise --settle <id>` when the line says no plan edit is needed. Until
|
|
then `next` refuses with `PLAN_AMEND_PENDING` and `export` will not mark the run complete.
|
|
5. `REOPENED: <phases>` means loop `next` again (Eng last). `APPROVED:` means `export` (`DISPATCHES: <n> est_input_tokens=<k>`, relative).
|
|
6. Rounds: one by default; a second only for High or Critical findings; cap 2 (`--max-rounds`). A `revise` whose decisions all resolve below
|
|
High prints `APPLIED: <ids> without re-review (below High)`. At the cap with High open, `ESCALATE: evidence sufficient, decision needed`: relay it, never ask for another round.
|
|
7. Carry-forward ([docs/unattended.md#carry-forward](../docs/unattended.md#carry-forward); `--no-carry-forward` on the first `next` opts out): a later gate that asks nothing new takes the owner's words from the gate before it (`CARRIED:`, then `APPROVED:`); `CARRY: no (<why>)` leaves it for the owner; `CARRY_CHECK:` means one reviewer from another model family reads the printed delta prompt, then `check --out <dir> --attempt <id> --result <file> --model <id>` (or `--unavailable "<reason>"`).
|
|
|
|
### On Capy
|
|
|
|
- Always drive `gstack-autoplan`; never hand-adapt `autoplan/SKILL.md`. A plan you reviewed by
|
|
hand is not an autoplan run: do not present it as one.
|
|
- Every prompt ends with a `GSTACK TRAILER` block: the reviewer runs the `--for review-voice`
|
|
install on its own machine (no ./setup, no skills; seconds when warm) and starts its reply
|
|
with the `gstack:` line. Never tell a reviewer that no install is needed; relay each
|
|
reviewer's line with its result, and treat a missing line as `gstack: fail not-installed`.
|
|
- Set `GSTACK_AUTOPLAN_CHECKPOINT_DIR` to the private project-user Drive folder (or opt every run in
|
|
with `gstack-config set autoplan_checkpoint drive`) so a run survives machine replacement: a
|
|
generation is published at rest, after each bound voice and after each phase transition; restore
|
|
with `resume --out <new dir> --from <dir>/<run>`, which never redispatches a bound voice.
|
|
- Plans carry `## ELI5` (5-10 plain sentences), `## Before → after`, `## Why it matters`, `## What caused this work`, `## Big decisions`;
|
|
relay the printed `RELAY: gstack-owner-brief render --captain` output to your Captain (or the person), then `gstack-approvals import --autoplan <dir>` after `answer` (`--stack <b1,b2,...>` for a stack; `capy/skill/gstack/captain.md`).
|
|
|
|
### Commands
|
|
|
|
{{AUTOPLAN_DRIVER_COMMANDS}}
|
|
|
|
## Reviewer result format
|
|
|
|
Every prompt ends with this contract; `submit --result` enforces it, `submit --record` accepts the looser shapes above.
|
|
|
|
{{AUTOPLAN_DRIVER_RESULT_FORMAT}}
|
|
|
|
## Gate replies
|
|
|
|
A reply binds to the `gate_rev` you read (`--gate-rev`). Bare `yes`/`no` is unparsed, never guessed.
|
|
|
|
{{AUTOPLAN_DRIVER_GATE}}
|
|
|
|
## Run directory
|
|
|
|
{{AUTOPLAN_DRIVER_FILES}} Reviewer files: `<phase>-native-prompt.md`,
|
|
`<phase>-outside-prompt.md`, `<phase>-<voice>.<attempt>.md` (the reviewer writes it), its sealed
|
|
`<phase>-<voice>.<attempt>.bound.md` (what submit bound), `<phase>-consensus.{json,md}`,
|
|
`gate.json`, `decisions.jsonl`. `export` writes `plan.md`, `review-record.md`, `findings.jsonl`,
|
|
`tasks.jsonl`, `timing.json` and rehashes `run.json`; `gstack-artifact validate <dir>/run.json`
|
|
is the completion check. Copy the whole directory, never single files.
|
|
|
|
## Result codes
|
|
|
|
{{AUTOPLAN_DRIVER_CODES}}
|
|
|
|
{{COORDINATOR_CONTRACT}}
|
|
|
|
Decision trail. A lane keeps `<run dir>/decisions.tsv` through `gstack-decision-trail <file> <phase> <decision> <why> <evidence> <result>` (one row per fork, unit, revert or blocker; evidence a pointer that resolves) and opens it with `gstack-decision-trail start <file> <run id>` when another run wrote it first. Before done it audits the trail against the transcript, superseding a wrong row with a new one rather than editing it, has a reviewer on another model family read the trail, and ends its report with an `Attention` section (`reviewed by <model>`, then the flags, or `No flags`). The full rule is [docs/unattended.md](../docs/unattended.md#the-decision-trail).
|