From 6748d54f7f50c1f6be9e27a411bf5a52ed946a27 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Fri, 30 Oct 2026 17:42:31 -0700 Subject: [PATCH] v1.91.343.0 feat(captain): every ask to the owner uses the lettered ask format (R41) (#3655) * feat(captain): every ask to the owner uses the lettered ask format (R41) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test(captain-brief): render the named heading through the brief helper (typecheck:test) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * chore(changelog): add the R41 ask-format fragment Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix(captain-brief): tell the relaying agent how a named option answers (rec except ) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * chore(changelog): name the rec except form in the R41 fragment Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * feat(captain): an ask that needs the owner to act carries the exact link and simple steps (R43) 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> --- CHANGELOG.md | 12 ++++++++ VERSION | 2 +- agents-digest/gstack-AGENTS.md | 2 +- bin/gstack-owner-brief | 11 ++++---- captain/SKILL.md | 23 +++++++++++----- captain/SKILL.md.tmpl | 23 +++++++++++----- captain/templates/AGENTS.md | 8 ++++-- captain/templates/DIGEST.md | 7 ++++- captain/templates/merge-ask.md | 6 +++- captain/templates/plan-ask.md | 17 +++++++++--- captain/templates/report.md | 2 +- capy/skill/gstack/SKILL.md | 4 +-- capy/skill/gstack/captain.md | 24 ++++++++-------- capy/skill/gstack/factory.md | 22 +++++++-------- docs/captain.md | 50 ++++++++++++++++++++++++++++------ docs/recommended-harness.md | 2 +- lib/captain-brief.ts | 43 ++++++++++++++++++----------- package.json | 2 +- test/captain-brief.test.ts | 45 ++++++++++++++++++------------ 19 files changed, 205 insertions(+), 100 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5796e75e..48b47a9f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## [1.91.343.0] - 2026-10-31 + +**Every ask to the owner now uses one lettered format (R41): the Captain's name, then one line per decision with the problem, the options and the recommendation, so the owner can answer "do it" or a letter like "B2" from a phone. When the owner has to do something, the ask links the exact page and lists the steps (R43).** + +### Changed +- **The plan ask lists each gate choice as a lettered line** (`lib/captain-brief.ts`, `gstack-owner-brief render --captain`): "What we need from you" prints one line per choice with the recommended option first and the plan approval as the last letter. The header and the closing line invite **do it** or a named option, and a new `--captain-name ` heads the list. The relaying agent's last line maps every letter to its gate token next to `rec resolves to …` and says a named option answers as `rec except `, so a reply like "B2" translates exactly. A plan that is missing a section still invites no reply. +- **An ask that needs the owner to do something carries the exact link and simple steps (R43).** The ask format says so: the full URL of the page where it happens (never a menu path like "Settings → Tokens"; a Capy app page gets its exact path and field), numbered steps saying what to click and type, and the one word to reply when done. `docs/captain.md`, `plan-ask.md`, `merge-ask.md`, `captain/SKILL.md` and `factory.md` point 11 carry it. +- **docs/captain.md has a new section, The ask format**, and the plan ask, the controller's relay and the digest's Needs you point to it. The captain templates (`plan-ask.md`, `DIGEST.md`, `merge-ask.md`, `AGENTS.md`, `report.md`), `captain/SKILL.md`, the Capy gstack skill (`SKILL.md`, `captain.md`, `factory.md`) and `docs/recommended-harness.md` state the same format. + +### Tests +- `test/captain-brief.test.ts`: lettered lines with the recommendation first and "A1 to take recommendation", the letter-to-token map, the `--captain-name` heading, carried answers in the lettered lines, and no reply invitation on a plan that is missing a section. + ## [1.91.342.0] - 2026-10-30 **gstack now versions its own PRs at merge time: a PR adds `changelog.d/.md` instead of a version, and trains merge through `train land` instead of slot calls.** `.gstack/ship-policy.json` turns `changelog_fragments` on with the checks every PR runs as `required_checks`, and `min_gstack_version` moves to 1.91.340.0, the first release that reads `required_checks` and counts a stamped slot as merged only when GitHub reports it MERGED, so an older gstack refuses the file by name. diff --git a/VERSION b/VERSION index d533ff151..aaa173526 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.91.342.0 +1.91.343.0 diff --git a/agents-digest/gstack-AGENTS.md b/agents-digest/gstack-AGENTS.md index e8417c1b2..3e673ff7b 100644 --- a/agents-digest/gstack-AGENTS.md +++ b/agents-digest/gstack-AGENTS.md @@ -1,4 +1,4 @@ -# gstack digest v1.91.342.0 — regenerate/re-copy after upgrading gstack +# gstack digest v1.91.343.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/bin/gstack-owner-brief b/bin/gstack-owner-brief index a6468e875..bdce6e054 100755 --- a/bin/gstack-owner-brief +++ b/bin/gstack-owner-brief @@ -3,7 +3,7 @@ * gstack-owner-brief — the one-page owner brief at the autoplan gate (plan E3). * * gstack-owner-brief render --out [--page N] [--summary ] [--write] [--json] - * gstack-owner-brief render --captain --out [--allow-incomplete] [--write] [--json] + * gstack-owner-brief render --captain --out [--captain-name ] [--allow-incomplete] [--write] [--json] * gstack-owner-brief close --out --plan [--date YYYY-MM-DD] [--json] * * `render` prints the plain-language summary (--summary , else /summary.md @@ -12,8 +12,9 @@ * taken if unanswered, approval items stay pending) and points at review-record.md * for the full review; --write also saves brief.md in the run directory. * `render --captain` prints the plan ask in the shape Capy Captains relay (lib/captain-brief.ts): header with - * the one-word reply, Before → after, Why it matters, What caused this work, Big decisions, What we need from - * you, and one trailing line for the relaying agent; a plan missing a section exits 1 + * the "do it" reply, Before → after, Why it matters, What caused this work, Big decisions, What we need from + * you (the lettered ask lines of docs/captain.md § The ask format, headed by --captain-name), and one + * trailing line for the relaying agent; a plan missing a section exits 1 * (CAPTAIN_BRIEF_INCOMPLETE) unless --allow-incomplete. --write saves captain-brief.md. * `close` rewrites every `draft direction stands until the owner decides` line in * the plan to the decided option and date; pending lines stay and are reported @@ -29,7 +30,7 @@ import { resultLine } from '../lib/result-codes'; const HELP = `gstack-owner-brief — one page for the owner: summary, URGENT block, numbered decisions (docs/unattended.md#owner-brief) render --out [--page N] [--summary ] [--write] [--json] - render --captain --out [--allow-incomplete] [--write] [--json] the plan ask for a Capy Captain (capy/skill/gstack/captain.md) + render --captain --out [--captain-name ] [--allow-incomplete] [--write] [--json] the plan ask for a Capy Captain (capy/skill/gstack/captain.md); --captain-name heads the lettered ask close --out --plan [--date YYYY-MM-DD] [--json] ${exitTableHelp()}`; @@ -49,7 +50,7 @@ function main(argv: string[]): number { const json = rest.includes('--json'); if (cmd === 'render' && rest.includes('--captain')) { - const brief = renderCaptainBrief(loaded.inputs, { outDir: path.resolve(out) }); + const brief = renderCaptainBrief(loaded.inputs, { outDir: path.resolve(out), captainName: flag(rest, '--captain-name') }); if (rest.includes('--write')) fs.writeFileSync(path.join(path.resolve(out), 'captain-brief.md'), brief.text); if (json) process.stdout.write(JSON.stringify({ run: loaded.inputs.gate.run, gate_rev: loaded.inputs.gate.gate_rev, rec_hash: brief.recHash, pending: brief.pending, missing: brief.missing, brief: brief.text }) + '\n'); else process.stdout.write(brief.text); diff --git a/captain/SKILL.md b/captain/SKILL.md index 9984953c0..419f294fd 100644 --- a/captain/SKILL.md +++ b/captain/SKILL.md @@ -324,8 +324,8 @@ to be outside the merged PR. Reruns on `BASE` are never a way to get a green. The controller keeps one digest file (`captain/templates/DIGEST.md`), rewritten at every turn, three sections in this order, each row with its thread, one line, and an age: -1. **Needs you**: decisions only the owner can make, each with the plain-language ask and - the one-word default. Empty means the owner has nothing to do. +1. **Needs you**: decisions only the owner can make, in the ask format below (the + Captain's name, one lettered line per decision). Empty means the owner has nothing to do. 2. **New**: what landed or changed since the last digest (merges with versions, READYs received, trains built, incidents), newest first. 3. **In progress**: every working lane, what it owns, its state (building, READY, in @@ -352,11 +352,20 @@ says so instead of looking empty. **B. The plan ask**, in this order, written for someone outside the project (no gate codes in the body): before → after with concrete examples; why it matters, with numbers; what caused the work (issue, run, report, or the owner's words quoted); the big decisions -(options, pick, why, what would flip it); what we need from you, one decision with each -option's cost and the recommended one-word reply as the default; and a closing -**"do it"** reply that takes every recommendation at full scope, follow-ons included, -with one line saying what it covers. `gstack-owner-brief render --captain` prints this shape from -a plan; relay it whole. Template: `captain/templates/plan-ask.md`. +(options, pick, why, what would flip it); what we need from you in the ask format; and a +closing **"do it"** reply that takes every recommendation at full scope, follow-ons +included. `gstack-owner-brief render --captain --captain-name ""` prints this +shape from a plan; relay it whole. Template: `captain/templates/plan-ask.md`. + +**The ask format** (every ask to the owner, the digest's Needs you included), explained like +the owner is five: the Captain's name, then one lettered line per decision, letters unique +across the list: `- A: hit problem p, which happens when h. We could fix it in these +ways: 1) x; 2) y; 3) z. Recommendation: x because why. A1 to take recommendation.` The +recommendation is option 1; "do it" takes every recommendation in the last list, and a named +option ("A2") takes that option instead. When the owner has to do something, the line +carries the exact link to the page (never a menu path; a Capy app page gets its exact path +and field), numbered steps in the simplest words, and the one word to reply when done. +Home: `docs/captain.md`, The ask format. **Plan before build.** A lane that builds something runs a sized `/autoplan` on its brief as its first act after the session-start check and sends the controller the plan ask above; the controller relays it, and the diff --git a/captain/SKILL.md.tmpl b/captain/SKILL.md.tmpl index 7cc9f5873..4ccf4b36e 100644 --- a/captain/SKILL.md.tmpl +++ b/captain/SKILL.md.tmpl @@ -252,8 +252,8 @@ to be outside the merged PR. Reruns on `BASE` are never a way to get a green. The controller keeps one digest file (`captain/templates/DIGEST.md`), rewritten at every turn, three sections in this order, each row with its thread, one line, and an age: -1. **Needs you**: decisions only the owner can make, each with the plain-language ask and - the one-word default. Empty means the owner has nothing to do. +1. **Needs you**: decisions only the owner can make, in the ask format below (the + Captain's name, one lettered line per decision). Empty means the owner has nothing to do. 2. **New**: what landed or changed since the last digest (merges with versions, READYs received, trains built, incidents), newest first. 3. **In progress**: every working lane, what it owns, its state (building, READY, in @@ -280,11 +280,20 @@ says so instead of looking empty. **B. The plan ask**, in this order, written for someone outside the project (no gate codes in the body): before → after with concrete examples; why it matters, with numbers; what caused the work (issue, run, report, or the owner's words quoted); the big decisions -(options, pick, why, what would flip it); what we need from you, one decision with each -option's cost and the recommended one-word reply as the default; and a closing -**"do it"** reply that takes every recommendation at full scope, follow-ons included, -with one line saying what it covers. `gstack-owner-brief render --captain` prints this shape from -a plan; relay it whole. Template: `captain/templates/plan-ask.md`. +(options, pick, why, what would flip it); what we need from you in the ask format; and a +closing **"do it"** reply that takes every recommendation at full scope, follow-ons +included. `gstack-owner-brief render --captain --captain-name ""` prints this +shape from a plan; relay it whole. Template: `captain/templates/plan-ask.md`. + +**The ask format** (every ask to the owner, the digest's Needs you included), explained like +the owner is five: the Captain's name, then one lettered line per decision, letters unique +across the list: `- A: hit problem p, which happens when h. We could fix it in these +ways: 1) x; 2) y; 3) z. Recommendation: x because why. A1 to take recommendation.` The +recommendation is option 1; "do it" takes every recommendation in the last list, and a named +option ("A2") takes that option instead. When the owner has to do something, the line +carries the exact link to the page (never a menu path; a Capy app page gets its exact path +and field), numbered steps in the simplest words, and the one word to reply when done. +Home: `docs/captain.md`, The ask format. **Plan before build.** A lane that builds something runs a sized `/autoplan` on its brief as its first act after the session-start check and sends the controller the plan ask above; the controller relays it, and the diff --git a/captain/templates/AGENTS.md b/captain/templates/AGENTS.md index b9c09f064..c60cb966f 100644 --- a/captain/templates/AGENTS.md +++ b/captain/templates/AGENTS.md @@ -25,9 +25,11 @@ a standing approval instead of asking again. Append; never rewrite an owner's wo rerun: . Over the cap is a fresh ask. ## Asks to the owner (, : "") -- Plain language, each option with what it is, why it matters, what each answer does and - the cost. The recommended one-word reply is the default. Every ask ends with "do it": - every recommendation at full scope, follow-ons included, no further ask. +- The ask format (gstack docs/captain.md), explained like I'm five: , then one + lettered line per decision: "A: hit problem p, which happens when h. We could fix it + in these ways: 1) x; 2) y; 3) z. Recommendation: x because why. A1 to take recommendation." + "do it" takes every recommendation in the list at full scope, follow-ons included, no + further ask; a named option ("A2") takes that option instead. ## Parallelism (, : "") - Keep about lanes working on disjoint files whenever there is backlog. Serial steps diff --git a/captain/templates/DIGEST.md b/captain/templates/DIGEST.md index 71246ba60..81cf2d3d2 100644 --- a/captain/templates/DIGEST.md +++ b/captain/templates/DIGEST.md @@ -7,7 +7,12 @@ every row with its thread and an age. Codes are the thread codes the host assign -- · · · default reply: **** · cost: + +- A: hit problem

, which happens when . We could fix it in these ways: 1) ; 2) ; 3) . Recommendation: because (cost: ; asked ago). A1 to take recommendation. +- B: … + +"do it" takes every recommendation above; a named option ("A2") takes that option instead. The +ask format is gstack docs/captain.md, The ask format. ## New diff --git a/captain/templates/merge-ask.md b/captain/templates/merge-ask.md index 568a0a287..19e6cc3b6 100644 --- a/captain/templates/merge-ask.md +++ b/captain/templates/merge-ask.md @@ -24,4 +24,8 @@ flaky: · pregate: pass tree= ``` The controller's merge report: the PR link, the key image inline, the version it will -take, the slot, and the one-word reply if a decision is attached. +take, the slot, and, if a decision is attached, its lettered line in the ask format +(gstack docs/captain.md): "A: … Recommendation: x because why. A1 to take recommendation." +If the merge needs the owner to act (approve a deployment, grant access), the line carries +the exact link to that page and numbered steps in the simplest words, ending with the one +word to reply when done (a Capy app page: its exact path and field instead of a link). diff --git a/captain/templates/plan-ask.md b/captain/templates/plan-ask.md index 854998ffc..ba34245c8 100644 --- a/captain/templates/plan-ask.md +++ b/captain/templates/plan-ask.md @@ -5,7 +5,7 @@ gate codes in the body. `gstack-owner-brief render --captain --out ` pr shape from an autoplan run; write it by hand for any other plan. ```text -Decision needed on : . Reply **rec** to take every recommendation. +Decision needed on : . Reply **do it** to take every recommendation. ## ELI5 <5-10 plain sentences: what changes, for whom, and what it costs> @@ -25,10 +25,19 @@ output, a screen, a cost or time number> 2. … ## What we need from you -:

, which happens when . We could fix it in these ways: 1) (); 2) (); 3) (). Recommendation: because . A1 to take recommendation. +- B: … -**do it** = take every recommendation above at full scope, including , and carry them through to done with no further ask. +**do it** = take every recommendation in this list at full scope, including , and carry them through to done with no further ask. A named +option ("A2") takes that option instead. + + +- C: needs you to , because . Open , then: + 1. Click