diff --git a/CHANGELOG.md b/CHANGELOG.md index a94f567f0..c78e139be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## [1.91.285.0] - 2026-10-27 + +**A lane plans before it builds, and the /captain skill says so.** Until now a crew thread told to build something started editing, and the first chance for the controller or the owner to say "smaller" or "not that way" was a finished PR with a paid gate behind it; the rule that a sized /autoplan comes first lived only in one crew's rules file, which a crew set up from gstack's templates would never read. The /captain skill, `docs/captain.md` and the crew templates now carry it: a building lane's first act is an /autoplan run sized to the work, the plan and its gate go up to the controller in plain language, the controller relays one ask with the recommended reply as the one-word default and a "do it" reply, and the lane builds only after the owner's word is answered into the run and it reports `APPROVED`. + +### Added +- **`docs/captain.md` § Plan before build**: who plans (any lane that builds; any new scope taken on part-way), the first act (`/autoplan` sized to the work, with the short-run flags for a one-file fix), what the lane sends (`gstack-owner-brief render --captain`, the cost lines, a needs-you report), what the controller relays (shape B, `rec` as the default, "do it"), the build gate (the answer in the run, amendments incorporated, reopened phases finished, `APPROVED`; an imported approval row alone is not completion), the record (`gstack-approvals import --autoplan`, rendered into the report and PR body), and the exemptions (read-only lanes, the daily flaky pass's repairs, slot stamps, CHANGELOG-only resolves, cap re-pins under a written grant; a crew may add, never remove). The rule is row 24 of the "Where each rule lives" table; the READY contract and merge trains are unchanged, and a plan approval is not a READY field. +- **`captain/templates/brief.md`**: the controller's brief to a lane. A header with the lane, controller, rules file, owned files, the files other lanes own, a `Plan: required | approved: | exempt: ` line and the spend cap; step 1 the plan and the plan ask, step 2 the build after the word, step 3 /ship to READY; a done line that names the approval row or the exemption. A brief marked `approved` starts at step 2, one marked `exempt` at step 3. +- **`captain/templates/CREW.md` rule 24** (Plan before build) with its home, and a row for the owner's words in the standing-approvals table. Crew-specific rules now number from 25; a crew whose own rules already took 24 keeps its numbering and cites the section by name. + +### Changed +- **`captain/SKILL.md.tmpl`**: the approvals part carries a "Plan before build" paragraph pointing at the section and the brief, and the rules enumeration names the rule. +- **`capy/skill/gstack/SKILL.md` § Plan, approve, ship**: the short form every Capy thread follows, under a Captain or on its own (the owner, 2026-10-27: "Also incorporate the autoplan and eli5 and ship instructions for Capy-specific gstack usage"): /autoplan sized to the work before new functionality, the ELI5 with `rec` as the one-word default and a "do it" reply, the build only after the word and an `APPROVED` run, /ship at the final pushed head before a PR is called ready with the receipt naming that head, no merge without the owner's word, the review inside /ship and the autoplan sized to the change, and the exempt work. References are plain text, since the folder is copied to a Drive without the repository; the owner copies `capy/skill/gstack/` over the Drive skill folder to pick it up. +- **`capy/skill/gstack/captain.md` § 3**: the lane-side pointer, so a thread launched on Capy sees the first-act rule where it reads the plan-ask shape, pointing at the SKILL.md section. +- **`captain/templates/plan-ask.md`**: the record line names the autoplan path (`gstack-autoplan answer … --owner-reply`, then `gstack-approvals import --autoplan`) and keeps `gstack-approvals add` for plans that are not autoplan gates. +- **`docs/captain.md` Setting it up, step 5**: lanes start with the brief. + +### Tests +- `test/captain-skill.test.ts` ships `brief.md` in the template set (existence, reference, generic prose), pins the CREW template at 24 rules and `docs/captain.md` at 24 mapped rows, and asserts the new section, the brief's `Plan:` line and step order, and the skill's paragraph. + ## [1.91.284.0] - 2026-10-27 **Five small takes from tstack, in gstack's words.** Theo Browne's tstack (MIT, 2026-10-24) is nine short PR-landing skills; its best ideas that gstack lacked were a verb for an aging pull request, a Codex picker that says what each skill is for, a written grant for unattended sessions, a repo-level rule for porting a contributor's PR, and a visible author line on agent-posted comments. Each lands here as gstack prose and gstack code; no sentence is copied (NOTICE.md). Approved by Garry, 2026-10-26: "Do it, send" (yes to the opt-in attribution callout, off by default). diff --git a/VERSION b/VERSION index fc11feb79..7596006bd 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.91.284.0 +1.91.285.0 diff --git a/agents-digest/gstack-AGENTS.md b/agents-digest/gstack-AGENTS.md index 5a111181d..db7e228e6 100644 --- a/agents-digest/gstack-AGENTS.md +++ b/agents-digest/gstack-AGENTS.md @@ -1,4 +1,4 @@ -# gstack digest v1.91.284.0 — regenerate/re-copy after upgrading gstack +# gstack digest v1.91.285.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/captain/SKILL.md b/captain/SKILL.md index d5998f01f..6a1f0f270 100644 --- a/captain/SKILL.md +++ b/captain/SKILL.md @@ -161,7 +161,7 @@ carries its own copy of how to do things. The rules: session-start install check validation discipline, untrusted external diffs, file ownership, pre-approved spend, the READY contract, reports, one routing path (everything through the controller), no merging base into a READY branch, the CHANGELOG entry under `[Unreleased]`, the flaky rule, -approvals, /ship before READY, and review convergence. Every rule that rests on the +approvals, /ship before READY, review convergence, and plan before build. Every rule that rests on the owner's words carries the date and the words. A rule that exists only in a crew's file is a gap in gstack: write it there, then point at it. @@ -351,6 +351,14 @@ option's cost and the recommended one-word reply as the default; and a closing 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`. +**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 +lane builds only after the owner's word is answered into the run and it reports `APPROVED`. +New scope taken on part-way gets its own plan. Read-only lanes, the flaky pass's repairs, +slot stamps, CHANGELOG resolves and cap re-pins under a grant are exempt. The brief a +controller hands a lane, with its `Plan: required | approved | exempt` line, is +`captain/templates/brief.md`; the rule is `docs/captain.md` (Plan before build). + **C. The merge ask.** Every READY the controller brings to the owner, and every PR body: before/after images (uploaded with the host's PR asset tool, each captioned with what changed and why; a skill or CLI change renders its output with `gstack-pr-shots`), why diff --git a/captain/SKILL.md.tmpl b/captain/SKILL.md.tmpl index 038b7f6df..87ed80e88 100644 --- a/captain/SKILL.md.tmpl +++ b/captain/SKILL.md.tmpl @@ -89,7 +89,7 @@ carries its own copy of how to do things. The rules: session-start install check validation discipline, untrusted external diffs, file ownership, pre-approved spend, the READY contract, reports, one routing path (everything through the controller), no merging base into a READY branch, the CHANGELOG entry under `[Unreleased]`, the flaky rule, -approvals, /ship before READY, and review convergence. Every rule that rests on the +approvals, /ship before READY, review convergence, and plan before build. Every rule that rests on the owner's words carries the date and the words. A rule that exists only in a crew's file is a gap in gstack: write it there, then point at it. @@ -279,6 +279,14 @@ option's cost and the recommended one-word reply as the default; and a closing 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`. +**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 +lane builds only after the owner's word is answered into the run and it reports `APPROVED`. +New scope taken on part-way gets its own plan. Read-only lanes, the flaky pass's repairs, +slot stamps, CHANGELOG resolves and cap re-pins under a grant are exempt. The brief a +controller hands a lane, with its `Plan: required | approved | exempt` line, is +`captain/templates/brief.md`; the rule is `docs/captain.md` (Plan before build). + **C. The merge ask.** Every READY the controller brings to the owner, and every PR body: before/after images (uploaded with the host's PR asset tool, each captioned with what changed and why; a skill or CLI change renders its output with `gstack-pr-shots`), why diff --git a/captain/templates/CREW.md b/captain/templates/CREW.md index 0ad04c308..64a01fc96 100644 --- a/captain/templates/CREW.md +++ b/captain/templates/CREW.md @@ -37,6 +37,7 @@ Homes are paths in the gstack checkout the lane checked at session start. | 21 approvals | | "" | the three shapes | | 22 /ship before READY | | "" | every READY, re-READYs included | | 23 blocking floor | | "" | what blocks another review pass | +| 24 plan before build | | "" | a sized /autoplan first, the owner's word before the build | ## Rules @@ -125,8 +126,18 @@ Homes are paths in the gstack checkout the lane checked at session start. skills, scope knob `REVIEW_SCOPE`; record the pass count in your READY. Home: the `/ship` and `/review` skills. +24. **Plan before build.** If you build something, a `/autoplan` run on your brief, sized + to the work, is your first act after the session-start check; send `CONTROLLER` the plan and its gate in plain + language with the recommended reply named; build only after the owner's word is + answered into the run and it reports `APPROVED`; record it with `gstack-approvals + import --autoplan`. New scope taken on part-way gets the same. Exempt: read-only + lanes, the daily flaky pass's repairs, slot stamps, CHANGELOG-only resolves, cap + re-pins under a written grant. Home: `docs/captain.md` (Plan before build), + `captain/templates/brief.md`. + ## Crew-specific rules -Add rules here, numbered from 24, each with the date, the owner's words where there are -any, and the thread that produced it. A rule that stays here for long is a gap in gstack: -file it. +Add rules here, numbered from 25, each with the date, the owner's words where there are +any, and the thread that produced it. A crew whose own rules already took 24 before rule +24 shipped keeps its numbering and cites `docs/captain.md` (Plan before build) by section +name. A rule that stays here for long is a gap in gstack: file it. diff --git a/captain/templates/brief.md b/captain/templates/brief.md new file mode 100644 index 000000000..d185bc0bf --- /dev/null +++ b/captain/templates/brief.md @@ -0,0 +1,42 @@ +# Brief + +Sent by the controller when a lane starts, and again when a lane takes on scope its brief +did not name. The lane reads the rules file first, then this. Everything in angle brackets +is filled by the controller; `Plan:` says whether the lane plans first +(`docs/captain.md`, Plan before build). + +```text +Lane: · Controller: · Rules: /CREW.md · Base: +Owns: +Do not touch: +Plan: required | approved: | exempt: +Spend cap: + +1. Plan (when Plan: required). After the session-start install check, install for autoplan + and follow autoplan/DRIVER.md "On Capy" (launch file sourced, GSTACK_AUTOPLAN_CHECKPOINT_DIR + set, run dir under ~/.capy/work). Write the plan with its ## Before → after, + ## Why it matters, ## What caused this work, ## Big decisions and ## Implementation plan + sections, then run gstack-autoplan next --out --plan + sized to this brief (a one-file fix: --no-ui --no-dx --max-rounds 1 --estimate-usd + --spend-cap ). At the gate send me the output of + gstack-owner-brief render --captain --out whole, as a needs-you report. + Build nothing yet. +2. Build after the word. I bring the owner's exact words back. Answer them into the run + (gstack-autoplan answer --out --gate-rev --reply --rec-hash + --by agent: --owner-reply ""), incorporate every accepted plan + change (revise), finish every reopened phase, and start product edits only when the run + reports APPROVED. Then gstack-approvals import --autoplan --by "". + New scope you take on part-way goes back to step 1 with its own plan. +3. Ship. CHANGELOG entry under [Unreleased]; GUARD_CHECKS, pregate and /ship at the final + head; one unstamped READY block (captain/templates/READY.md) to me; the PR body carries + gstack-approvals render. Never merge; stamp only on my slot call. + +Done when: the READY block is sent at a frozen head, reports/.md is written, +and its Approvals table carries the plan approval row (the owner's words, the date) or the +Plan: exempt reason. +``` + +A lane whose brief says `approved: ` starts at step 2 with that run (restore it with +`gstack-autoplan resume --out --from ` when it lives on another machine); a +lane whose brief says `exempt:` starts at step 3. A brief with no `Plan:` line reads as +`Plan: required`. diff --git a/captain/templates/plan-ask.md b/captain/templates/plan-ask.md index 6d5367b6f..fb298017f 100644 --- a/captain/templates/plan-ask.md +++ b/captain/templates/plan-ask.md @@ -28,5 +28,7 @@ output, a screen, a cost or time number> named: docs, trains, cleanups>, and carry them through to done with no further ask. ``` -When the answer comes back, record it before the work starts: -`gstack-approvals add --ask "" --words "" --by " (via )" --scope ""`. +When the answer comes back, record it before the work starts. For an autoplan gate: +`gstack-autoplan answer --out --gate-rev --reply --rec-hash --by agent: --owner-reply ""`, +then `gstack-approvals import --autoplan --by ""` (the tool records the relayer). For any +other plan: `gstack-approvals add --ask "" --words "" --by " (via )" --scope ""`. diff --git a/capy/skill/gstack/SKILL.md b/capy/skill/gstack/SKILL.md index 9eb16bebc..d0e793395 100644 --- a/capy/skill/gstack/SKILL.md +++ b/capy/skill/gstack/SKILL.md @@ -42,6 +42,17 @@ Run directories and scratch on Capy live under `~/.capy/work/` (`--out ~/. Capy checklist for `/autoplan`: drive `gstack-autoplan`, never a hand adaptation presented as a run. Relay `gstack-gate render /gate.json --all` with `rec` (every recommendation, plan changes included) as the one-word default; answer with `--by agent: --owner-reply ""`. Set `GSTACK_AUTOPLAN_CHECKPOINT_DIR` to a private project-user Drive folder; after machine replacement, `gstack-autoplan resume --out --from ` restores the newest valid checkpoint. +## Plan, approve, ship + +Every Capy thread that uses gstack follows these for new work, under a Captain or on its own. The rule in full is `docs/captain.md`, "Plan before build"; the lane side is section 3 of captain.md in this folder. + +- **Plan first.** Before building new functionality, run `/autoplan` on it as the first act after the install check, sized to the work (scope flags and `--max-rounds`; a one-file fix gets `--no-ui --no-dx --max-rounds 1` with `--estimate-usd` and a small `--spend-cap`, never no run). +- **ELI5, then the word.** Send the plan and gate to the person, or the Captain, in plain language: `gstack-owner-brief render --captain --out `, with `rec` as the one-word default and a "do it" reply that takes every recommendation at full scope. Build only after their word is answered into the run and it reports `APPROVED`; then `gstack-approvals import --autoplan --by ""`. +- **/ship before ready.** Run /ship at the final pushed head before a PR is called ready; `SHIP_RECEIPT: pr= head=` must name that head, and a later push needs a new /ship. The review inside /ship, like the autoplan, is sized to the change. +- **No merge without the owner's word.** A thread never merges on its own; under a Captain the controller merges on a recorded standing approval, and a thread with no Captain asks the person. + +Exempt from the plan step: read-only work, the daily flaky pass's repairs, slot stamps, CHANGELOG-only resolves and cap re-pins under a written grant. + ## Working under a Captain When you work for a Capy Captain (a crew thread) or straight for a person, gstack's decisions reach them through you. Every workflow started with the `GSTACK_LAUNCH` line prints `CAPY: on` and a `capy-asks` block that repeats these rules. The full guide, with worked examples and copy-paste templates, is [captain.md](captain.md) in this folder. diff --git a/capy/skill/gstack/captain.md b/capy/skill/gstack/captain.md index 28564d917..d403cbe55 100644 --- a/capy/skill/gstack/captain.md +++ b/capy/skill/gstack/captain.md @@ -70,6 +70,13 @@ gstack-approvals render # the ## Approvals se ## 3. Plan approvals: the shape +Under a Captain, a thread that builds something plans before any product code. A `/autoplan` run on its +brief, sized to the work, is its first act, the gate goes up in the shape below, and the build starts only +when the answer is in the run and it reports `APPROVED`. The short form every Capy thread follows, with the +exempt work (read-only threads, flaky-pass repairs, slot stamps, CHANGELOG resolves, cap re-pins under a +grant), is the "Plan, approve, ship" section of SKILL.md in this folder; the rule in full is `docs/captain.md`, +Plan before build. + Every plan or gate you bring for approval has these parts, in this order, written so someone outside the project can follow it: diff --git a/docs/PROJECT_STRUCTURE.md b/docs/PROJECT_STRUCTURE.md index fefcd418b..e4315dcc4 100644 --- a/docs/PROJECT_STRUCTURE.md +++ b/docs/PROJECT_STRUCTURE.md @@ -55,7 +55,7 @@ gstack/ ├── deslop-shared-libs/ # Recommendations-only audit for worthwhile shared-code extractions ├── test-audit/ # Report-first sweep for low-value tests (test value bar, audit mode) ├── eval-plan/ # Preregistered paid evals: prereg, arms, $0 dry run, priced pilot (bin/gstack-eval-plan) -├── captain/ # /captain (also /crew): one controller, many lanes; templates/ holds CREW.md, AGENTS.md, NOTES.md, DIGEST.md, the flaky ledger, the lane report, the READY block, slot call, asks and the daily automation prompt +├── captain/ # /captain (also /crew): one controller, many lanes; templates/ holds CREW.md, AGENTS.md, NOTES.md, DIGEST.md, the flaky ledger, the lane report, the READY block, slot call, the lane brief, asks and the daily automation prompt ├── plan-ceo-review/ # /plan-ceo-review skill ├── plan-eng-review/ # /plan-eng-review skill ├── autoplan/ # /autoplan skill (auto-review pipeline: CEO → design → DX → eng, eng always last) diff --git a/docs/captain.md b/docs/captain.md index 03114a8c2..b81988be2 100644 --- a/docs/captain.md +++ b/docs/captain.md @@ -97,6 +97,7 @@ Where each rule lives: | 21 | Approvals, plan asks and merge asks in the three shapes | [Approvals](#approvals-three-shapes); [capy/skill/gstack/captain.md](../capy/skill/gstack/captain.md) | | 22 | /ship before every READY; the block carries `SHIP_RECEIPT`; stamp commits hold only tool output | [ship-policy.md](ship-policy.md#ship-before-ready); [the lane's /ship sequence](#the-lanes-ship-sequence-before-ready) | | 23 | Review loops converge: scope frozen after pass 1, later passes on the delta, a pass cap, a blocking floor | the `/ship` and `/review` skills' own convergence policy ([skills.md](skills.md#ship)); a crew names it in one line and sets only the scope knob (`REVIEW_SCOPE`) | +| 24 | Plan before build: a sized `/autoplan` is a building lane's first act; the plan ask goes up, the build starts after the owner's word is in the run and it reports `APPROVED` | [Plan before build](#plan-before-build); the [brief template](../captain/templates/brief.md) | ## Lane discipline @@ -121,6 +122,61 @@ such decision with a plain-language explanation of every option: what it is, why matters, what each answer does, and what it costs. A gate code or a tool's result line alone is not an ask. +## Plan before build + +A lane that builds something plans first. Its first act after the session-start install +check, before any product code, is a `/autoplan` run on its brief, sized to the work. The +phases run in order, CEO, then design, then DX, then eng, with design and DX only when the +scope has them, and a one-file fix gets a short run (`--no-ui --no-dx --max-rounds 1`, with +`--estimate-usd` set so a small `--spend-cap` still seats its attempts), not no run. On Capy the +unattended loop is `autoplan/DRIVER.md` in the gstack checkout. New functionality a lane +takes on part-way, scope its brief did not name, gets its own plan and its own ask before +the lane builds it. In the rules file this is rule 24 of the +[template](../captain/templates/CREW.md); a crew whose own rules already took 24 before +this rule shipped cites this section by name. + +**What the lane sends.** The plan and its gate in plain language a person outside the +project can follow: what changes, why now, what the change does, what it costs, the lane's +pick, and the recommended one-word reply. `gstack-owner-brief render --captain --out ` +prints that from the plan's `## Before → after`, `## Why it matters`, +`## What caused this work` and `## Big decisions` sections, with the cost lines +(`GATE_SPEND:`, `GATE_REC_COST:`) and a last line for the controller; a plan missing a +section exits `CAPTAIN_BRIEF_INCOMPLETE`, so the lane adds the section and renders again +([capy/skill/gstack/captain.md](../capy/skill/gstack/captain.md) § 3 lists them). The lane +sends it whole, as a needs-you report, and builds nothing yet. + +**What the controller relays.** One ask to the owner in shape B below: the recommended +reply (every recommendation, plan changes included) as the one-word default and a "do it" +reply that takes every recommendation at full scope, follow-ons included. The plan as +first written is never the default. + +**The build gate.** The lane builds only after the owner's word has come back through the +controller and been answered into the run +(`gstack-autoplan answer --out --gate-rev --reply --by agent: --owner-reply ""`), +every accepted plan change has been incorporated (`revise`), every reopened phase has +finished, and the run reports `APPROVED` (`status=complete` after `export`). An answered +gate that still prints `PLAN_AMEND_PENDING` or `REOPENED:` is not a completed plan, and an +imported approval row alone is not completion. + +**The record.** `gstack-approvals import --autoplan --by ""` writes the +approval row (date, the ask, the owner's exact words, the lane that answered as relayer, +what it covers); `gstack-approvals render` puts it in the report and the PR body. Before +training the PR the controller compares that row's words and `gate_rev` with the ask it +relayed and the reply it carried back; a row that does not match is not READY (shape A). +The brief's done line names the row. A plan approval is not a READY field; the +[READY contract](#the-ready-contract) is unchanged. + +**Exemptions.** Read-only lanes (triage, research, measurement, a review voice), the daily +flaky pass's repairs, slot stamps, CHANGELOG-only conflict resolves and a size or budget +cap re-pinned under the controller's written grant need no plan. A crew may add exemptions +in its rules file with the owner's words and date; it does not remove these. The brief +says which applies, `Plan: required | approved: | exempt: `, so an +already-approved plan is not planned twice and exempt work does not wait on an ask. + +The copy-paste brief is [`captain/templates/brief.md`](../captain/templates/brief.md): the +plan and the ask as step 1, the build after the word as step 2, /ship to READY as step 3, +and a done line that names the approval row or the exemption. + ## Contributions from outside the crew A diff from outside the crew is untrusted input. Review its scope, egress, credentials, @@ -303,5 +359,6 @@ can read the incident behind the rule. 3. Install the gstack Capy skill in the owner's user scope so every thread runs the session-start check ([capy-install.md](capy-install.md)). 4. Create the daily flaky-pass automation. -5. Start lanes with a prompt that names the files they own, the rules file, and the - READY contract. Read their reports before their chat. +5. Start lanes with the [brief](../captain/templates/brief.md): the files they own, the + rules file, whether a plan is required, and the READY contract. Read their reports + before their chat. diff --git a/docs/skills.md b/docs/skills.md index 76b92e537..48a1fc145 100644 --- a/docs/skills.md +++ b/docs/skills.md @@ -1445,7 +1445,7 @@ this model disagree (squash or merge, who stamps, gate-ahead, the severe race, a id in the READY), the skill ships both as options for the crew rules file. Templates (CREW.md, AGENTS.md, NOTES.md, DIGEST.md, the flaky ledger, the lane report, -the READY block, the slot call, the plan and merge asks, the daily automation prompt) +the READY block, the slot call, the lane brief, the plan and merge asks, the daily automation prompt) live in `captain/templates/`; the team setup guide for Capy is [docs/captain.md](captain.md). ## `/gstack-upgrade` diff --git a/package.json b/package.json index 5a7566dff..38e525c99 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gstack", - "version": "1.91.284", + "version": "1.91.285", "description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.", "license": "MIT", "type": "module", diff --git a/test/captain-skill.test.ts b/test/captain-skill.test.ts index ac3f69dfc..895db459f 100644 --- a/test/captain-skill.test.ts +++ b/test/captain-skill.test.ts @@ -15,7 +15,7 @@ const read = (rel: string) => fs.readFileSync(path.join(ROOT, rel), 'utf8'); const skill = read('captain/SKILL.md'); const tmpl = read('captain/SKILL.md.tmpl'); const flat = skill.replace(/\s+/g, ' '); -const TEMPLATES = ['CREW.md', 'AGENTS.md', 'NOTES.md', 'DIGEST.md', 'flaky-ledger.md', 'report.md', 'READY.md', 'slot-call.md', 'plan-ask.md', 'merge-ask.md', 'automation-flaky-pass.md']; +const TEMPLATES = ['CREW.md', 'AGENTS.md', 'NOTES.md', 'DIGEST.md', 'flaky-ledger.md', 'report.md', 'READY.md', 'slot-call.md', 'plan-ask.md', 'merge-ask.md', 'automation-flaky-pass.md', 'brief.md']; describe('/captain skill', () => { test('frontmatter names the skill and its /crew alias trigger', () => { @@ -59,12 +59,25 @@ describe('/captain skill', () => { expect(read('captain/templates/slot-call.md')).toContain('STAMP_VERSION='); expect(read('captain/templates/flaky-ledger.md')).toMatch(/## Open[\s\S]*## Fixed[\s\S]*## Won't fix/); const crew = read('captain/templates/CREW.md'); - expect(crew).toMatch(/^23\. /m); - expect(crew).not.toMatch(/^24\. /m); - for (let n = 1; n <= 23; n++) expect(crew, 'rule ' + n + ' names its home').toMatch(new RegExp('^' + n + '\\. \\*\\*[^]*?Home:', 'm')); - for (let n = 1; n <= 23; n++) expect(doc, 'docs/captain.md maps rule ' + n).toMatch(new RegExp('^\\| ' + n + ' \\| ', 'm')); - for (const h of ['## Lane discipline', '## Contributions from outside the crew']) expect(doc).toContain(h); + expect(crew).toMatch(/^24\. /m); + expect(crew).not.toMatch(/^25\. /m); + for (let n = 1; n <= 24; n++) expect(crew, 'rule ' + n + ' names its home').toMatch(new RegExp('^' + n + '\\. \\*\\*[^]*?Home:', 'm')); + for (let n = 1; n <= 24; n++) expect(doc, 'docs/captain.md maps rule ' + n).toMatch(new RegExp('^\\| ' + n + ' \\| ', 'm')); + for (const h of ['## Lane discipline', '## Plan before build', '## Contributions from outside the crew']) expect(doc).toContain(h); + expect(doc).toMatch(/## Plan before build[^]*?reports `APPROVED`[^]*?## Contributions from outside the crew/); + const brief = read('captain/templates/brief.md'); + expect(brief).toContain('Plan: required | approved: | exempt: --gate-rev --reply '); + expect(brief).toMatch(/^1\. Plan[^]*?^2\. Build after the word[^]*?^3\. Ship[^]*?^Done when:/m); + expect(brief).toContain('gstack-approvals import --autoplan'); + expect(flat).toContain('**Plan before build.**'); + const capySkill = read('capy/skill/gstack/SKILL.md'); + expect(capySkill).toMatch(/^## Plan, approve, ship$/m); + expect(capySkill).toMatch(/## Plan, approve, ship[^]*?reports `APPROVED`[^]*?Exempt from the plan step[^]*?## Working under a Captain/); + expect(capySkill).not.toMatch(/## Plan, approve, ship[^]*?\]\((?:\.\.\/)?docs\//); + expect(read('capy/skill/gstack/captain.md')).toContain('"Plan, approve, ship" section of SKILL.md'); expect(read('captain/templates/plan-ask.md')).toContain('**do it**'); + expect(read('captain/templates/plan-ask.md')).toContain('gstack-approvals import --autoplan'); expect(read('captain/templates/automation-flaky-pass.md')).toContain('never merge'); });