@tianhai/pi-workflow-kit 2.8.0 → 2.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -1
- package/docs/developer-usage-guide.md +18 -1
- package/docs/workflow-phases.md +5 -4
- package/extensions/workflow-guard.ts +66 -3
- package/package.json +1 -1
- package/skills/pwk-brainstorming/SKILL.md +36 -19
- package/skills/pwk-brainstorming/references/design-format.md +14 -14
- package/skills/pwk-brainstorming/references/umbrella.md +7 -8
- package/skills/pwk-brainstorming/scripts/validate-design.mjs +239 -0
- package/skills/pwk-code-review/SKILL.md +5 -5
- package/skills/pwk-executing-tasks/SKILL.md +66 -63
- package/skills/pwk-executing-tasks/references/progress-format.md +20 -21
- package/skills/pwk-executing-tasks/references/resume.md +3 -3
- package/skills/pwk-executing-tasks/references/review.md +12 -19
- package/skills/pwk-executing-tasks/scripts/build-review-packet.mjs +399 -0
- package/skills/pwk-executing-tasks/scripts/progress.mjs +180 -0
- package/skills/pwk-executing-tasks/scripts/ref.mjs +71 -0
- package/skills/pwk-executing-tasks/scripts/stage-check.mjs +48 -0
- package/skills/pwk-finalizing/SKILL.md +33 -32
- package/skills/pwk-status/SKILL.md +17 -7
- package/skills/pwk-walkthrough/SKILL.md +1 -1
- package/skills/pwk-brainstorming/scripts/validate-design.py +0 -194
- package/skills/pwk-executing-tasks/scripts/build-review-packet.py +0 -320
package/README.md
CHANGED
|
@@ -12,6 +12,8 @@ AI coding agents tend to skip design and jump straight into implementation, prod
|
|
|
12
12
|
pi install npm:@tianhai/pi-workflow-kit
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
+
The deterministic helpers — design validation, the review packet, the progress writer, the section extractor, and the staging check — are dependency-free Node scripts. No Python is required.
|
|
16
|
+
|
|
15
17
|
For Pi delegation providers that discover project agents, install the canonical PWK roles before starting a gated workflow:
|
|
16
18
|
|
|
17
19
|
```text
|
|
@@ -80,6 +82,10 @@ A **design doc is one PR**; a **requirement is one testable slice within it**. *
|
|
|
80
82
|
| **Walkthrough** | `/skill:pwk-walkthrough` | On demand: generate a detailed, file:line-anchored walkthrough of a shipped feature into `docs/walkthroughs/<topic>.md` (Summary / How it works / Key flows / Gotchas & invariants / Change map); stamped with the commit range, regenerated wholesale, never disposed. **Exits the gated phase** |
|
|
81
83
|
| **Status** | `/skill:pwk-status` | Read-only overview of all active design topics — phase + progress. Use when resuming or juggling several designs in parallel worktrees. Not a pipeline phase; **does not exit the gated phase**. |
|
|
82
84
|
|
|
85
|
+
### ⚡ Batched tool calls (pi ≥ 1.0.0 `codemode`)
|
|
86
|
+
|
|
87
|
+
Every skill treats its shell recipes as fallbacks: when the host grants a sandboxed batch executor, the kit prefers it — on pi ≥ 1.0.0 that is `codemode` (turn it on via pi's "Enable codemode" settings documentation; the guard announces it once per session when active, and the discovery sweeps demonstrate the one-call shape). The dated cross-harness instance table — opencode's `execute`, Claude's Programmatic Tool Calling, and the verified absences — lives in `docs/developer-usage-guide.md`. On hosts without such a tool, the bash recipes are the path and nothing changes.
|
|
88
|
+
|
|
83
89
|
## The Workflow in Detail
|
|
84
90
|
|
|
85
91
|
### Phase Control
|
|
@@ -97,6 +103,8 @@ You control each phase — the agent never advances on its own. Invoke a skill t
|
|
|
97
103
|
|
|
98
104
|
The design doc specifies *what*, not *how*. Each `### R<n>:` requirement block gives **acceptance criteria** (Given/When/Then, edge and error cases included) — no implementation code, no file-by-file recipe, no test-name lists. The executor has full autonomy to choose structure, signatures, and internals. A fine-grained implementation plan invalidates the moment a detail shifts; acceptance criteria survive implementation changes.
|
|
99
105
|
|
|
106
|
+
Brainstorm opens with a **PRD brief** when source material exists — background, current situation, and the delta, cited and zero-context, corrected by you before any requirement is written. Unknowns settle by **decide-by-experiment**: a question a run can answer is answered by a bounded sketch, never guessed. A criterion passes the **probe test**: its `Then` names an outcome a command can observe.
|
|
107
|
+
|
|
100
108
|
### Feature-Gate Execution
|
|
101
109
|
|
|
102
110
|
The feature is implemented via the feature-gate flow:
|
|
@@ -105,7 +113,7 @@ The feature is implemented via the feature-gate flow:
|
|
|
105
113
|
2. **Report it — no stop** — one or two lines saying what the E2E proves, plus its failing output; the run continues straight into implementation (that text was already approved as `## Feature acceptance` during brainstorm, so this is the window to object before code is written, not a sign-off gate)
|
|
106
114
|
3. Implement the requirements back-to-back (TDD: meaningful test → red → green per slice; full autonomy)
|
|
107
115
|
4. Feature review — risk-scaled: four fresh-context roles over a script-assembled review packet when the design carries production-risk content, otherwise one inline pass
|
|
108
|
-
5. ⏸ **ship checkpoint** — full suite + feature E2E green; you review the execution summary + coverage table (full diff on request)
|
|
116
|
+
5. ⏸ **ship checkpoint** — full suite + feature E2E green; you review the execution summary **Evidence rows** (plain words + pointer per requirement) + coverage table (full diff on request)
|
|
109
117
|
|
|
110
118
|
Per-requirement checkpoints/reviews are opt-in (default off); the feature-level review covers everything.
|
|
111
119
|
|
|
@@ -142,6 +150,10 @@ The agent stops and waits there — approve, request changes, or send it back. T
|
|
|
142
150
|
|
|
143
151
|
The feature-level review checks the whole diff composed and runs **before** the **ship checkpoint** — so your one final approval is fully informed (execution summary + coverage table; the raw diff stays one command away). The ship checkpoint already ran the full suite + the feature-acceptance E2E green — that *is* the integration check (there is no separate end pass). Finalize re-runs the full suite too — it never ships a red suite, even across resumed sessions.
|
|
144
152
|
|
|
153
|
+
### Skill-Text Budgets
|
|
154
|
+
|
|
155
|
+
The skill text a host loads is ratcheted. `skill-lint` holds a per-file word budget — the measured count plus 10% headroom, rounded up — and a corpus ceiling, and fails by file name and count when either is exceeded, so a slimming pass cannot quietly undo itself. The numbers come from measurement rather than a target percentage (ADR 0010). Each release's claim is checked by a recorded fidelity probe: six authorized sessions comparing the kit before and after on one fixture task, with the transcripts committed and the token totals recomputed from raw usage lines (`tests/evals/skill-slimming/`).
|
|
156
|
+
|
|
145
157
|
## Quick Start
|
|
146
158
|
|
|
147
159
|
```bash
|
|
@@ -34,7 +34,7 @@ Or in `.pi/settings.json` / `~/.pi/agent/config.json`:
|
|
|
34
34
|
|
|
35
35
|
## The workflow
|
|
36
36
|
|
|
37
|
-
You control each phase by invoking the skill. One folder per topic: `docs/plans/<date>-<topic>/` holds the topic's design doc, progress file, and review packet, and is the unit disposed at finalize. A design doc is one PR; a requirement is one testable slice within it. A requirement too big for one design doc but shipping as one PR is an **umbrella** — more than one leaf in that same folder, under one status-free overview, on one branch, finalized once:
|
|
37
|
+
You control each phase by invoking the skill. Requirements are grounded in evidence: a **PRD brief** opens brainstorm when source material exists, unknowns settle by **decide-by-experiment** (bounded sketch, proof clause), criteria pass the **probe test** (their `Then` names an outcome a command can observe), and the execution summary's **Evidence rows** pair plain words with a pointer — nothing is ✅ without one. One folder per topic: `docs/plans/<date>-<topic>/` holds the topic's design doc, progress file, and review packet, and is the unit disposed at finalize. A design doc is one PR; a requirement is one testable slice within it. A requirement too big for one design doc but shipping as one PR is an **umbrella** — more than one leaf in that same folder, under one status-free overview, on one branch, finalized once:
|
|
38
38
|
|
|
39
39
|
```
|
|
40
40
|
/skill:pwk-brainstorming → /skill:pwk-executing-tasks → /skill:pwk-finalizing
|
|
@@ -110,6 +110,23 @@ The destructive blacklist covers common file-mutating vectors (redirects, `tee`,
|
|
|
110
110
|
|
|
111
111
|
No configuration needed. It activates automatically after install.
|
|
112
112
|
|
|
113
|
+
## Sandboxed batch executors — known instances
|
|
114
|
+
|
|
115
|
+
Every skill treats its shell recipes as fallbacks: when the host grants a sandboxed batch executor (a tool that runs a script calling the agent's other tools, batching calls and filtering output before the model sees it), the skills prefer it. On pi ≥ 1.0.0 that executor is `codemode`, and the four discovery-sweep sites demonstrate the shape with a byte-pinned canonical script. Translate the shape, not the syntax: the scripts call tools by name, so they read correctly whether the host declares tools directly (pi's default) or hides them behind the executor (Claude Code's REPL mode hides its REPL-only tools; pi's `codemode.mode: only` does the same). Pinned command strings — the kit's `scripts/` helpers, plain `git`, the pinned `grep -m1 '^Feature phase:'` extraction — stay byte-exact even when batched inside one executor call; the pin protects the command string, not the vehicle.
|
|
116
|
+
|
|
117
|
+
Verified instances and absences, each dated so staleness is self-declaring rather than silently wrong:
|
|
118
|
+
|
|
119
|
+
| Host | Executor | Status (verified 2026-09-29) |
|
|
120
|
+
|------|----------|------------------------------|
|
|
121
|
+
| pi ≥ 1.0.0 | `codemode` | Shipped, opt-in via settings — see pi's "Enable codemode" documentation (verified 2026-09-29) |
|
|
122
|
+
| opencode v2 | `execute` ("Code Mode") | Shipped, gated by the `execute` permission (verified 2026-09-29) |
|
|
123
|
+
| Claude Platform API | Programmatic Tool Calling (`code_execution_20260120`+) | GA — code-execution container calling tools programmatically (verified 2026-09-29) |
|
|
124
|
+
| Claude Code CLI | REPL mode (`REPLTool`) | Experimental env-flag, source-verified, undocumented as of 2026-09-29 |
|
|
125
|
+
| zcode | — | Absent as of 2026-09-29 (CLI closed-source; docs silent) |
|
|
126
|
+
| commandcode | — | Absent as of 2026-09-29 (tool reference verified) |
|
|
127
|
+
|
|
128
|
+
A present instance names the concrete tool to prefer; an absent one means the bash recipes are the path — the skills read identically either way, and the dated rows tell a future reader when to re-verify.
|
|
129
|
+
|
|
113
130
|
## Test-first discipline
|
|
114
131
|
|
|
115
132
|
Design docs specify *what* (acceptance criteria + end-to-end scenarios); the executor writes the feature-acceptance E2E first (red), then implements to green. This keeps the spec stable — implementation details can change without invalidating the design.
|
package/docs/workflow-phases.md
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
Phase skills keep detailed contracts local to their skill directories:
|
|
4
4
|
`skills/pwk-brainstorming/references/umbrella.md`,
|
|
5
5
|
`skills/pwk-brainstorming/references/design-format.md`, and
|
|
6
|
-
`skills/pwk-brainstorming/scripts/validate-design.
|
|
6
|
+
`skills/pwk-brainstorming/scripts/validate-design.mjs`; plus
|
|
7
7
|
`skills/pwk-executing-tasks/references/progress-format.md`,
|
|
8
8
|
`skills/pwk-executing-tasks/references/resume.md`,
|
|
9
9
|
`skills/pwk-executing-tasks/references/review.md`, and
|
|
10
|
-
`skills/pwk-executing-tasks/scripts/build-review-packet.
|
|
10
|
+
`skills/pwk-executing-tasks/scripts/build-review-packet.mjs`.
|
|
11
11
|
|
|
12
12
|
The kit enforces a design → execute → finalize workflow. Each phase below names the skill that drives it:
|
|
13
13
|
|
|
@@ -26,7 +26,8 @@ brainstorm → executing-tasks → finalizing
|
|
|
26
26
|
/skill:pwk-brainstorming
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
- Explore requirements and shape the design. Interviews in **frontier rounds**: questions form a dependency tree seeded by a six-dimension checklist; each round asks the full frontier as numbered questions, each with a recommended answer; facts are looked up, only decisions asked; the interview ends when the frontier is empty — nothing left silently assumed — and an assumption gate sweeps the draft before the design is presented.
|
|
29
|
+
- Explore requirements and shape the design. Interviews in **frontier rounds**: questions form a dependency tree seeded by a six-dimension checklist; each round asks the full frontier as numbered questions, each with a recommended answer; facts are looked up, runnable unknowns settle by **decide-by-experiment** (a bounded sketch with a proof clause), only decisions asked; the interview ends when the frontier is empty — nothing left silently assumed — and an assumption gate sweeps the draft before the design is presented.
|
|
30
|
+
- Open with a **PRD brief** when source material exists (background / current situation / the delta — cited, zero-context, corrected by the human before any requirement is written); every criterion passes the **probe test**: its `Then` names an outcome a command can observe.
|
|
30
31
|
- Produce `docs/plans/<date>-<topic>/<leaf>-design.md` — descriptive, the **single buildable artifact**: a `## At a glance` digest for the human (2–4 sentence plain-language summary → **Key decisions**, one line each: decision + why, a `(rejected: …)` clause only when the fork was real → a `| R# | Requirement in one line | Risk |` table, one row per requirement) immediately before the `## Requirements` blocks — one `### R<n>:` block per requirement carrying its one-line behavior, **acceptance criteria** (Given/When/Then incl. edge/error cases) and Checkpoints/Review tags (no test-name lists, no separate plan doc) — ending with a `## Feature acceptance` section (end-to-end scenarios that prove the requirements compose into the feature — the feature's definition-of-done).
|
|
31
32
|
- May start an **umbrella** for a requirement too big for one design doc (human-approved): writes the status-free `docs/plans/<date>-<topic>/overview.md` (the same topic folder, now with more than one leaf; a `## Parts (build order)` roster of leaves + build order) and the **first** leaf's `<leaf>-design.md` beside it. Later leaves are brainstormed one by one against the overview + implemented predecessors.
|
|
32
33
|
- ADRs go to `docs/adr/` (permanent, never archived).
|
|
@@ -43,7 +44,7 @@ Write boundary: only `docs/plans/` is writable. Source files are hard-blocked.
|
|
|
43
44
|
- After the review passes, the executor writes a **code digest** into the progress file — plain-language summary, execution flow, gotchas, key files — derived from the review packet; it rides the existing disposal globs.
|
|
44
45
|
- Per-requirement checkpoints/reviews are **opt-in** — they fire only for requirements the design doc tags (default off); see [Proportionality](#proportionality).
|
|
45
46
|
- **Regression check after each commit** — run the full existing suite to catch cross-requirement regressions immediately. The feature E2E stays red until the last requirement and is gated only at the ship checkpoint (the old integration gate folds into it).
|
|
46
|
-
- Progress tracked in `docs/plans/<date>-<topic>/<leaf>-progress.md` (feature phase + requirement checklist).
|
|
47
|
+
- Progress tracked in `docs/plans/<date>-<topic>/<leaf>-progress.md` (feature phase + requirement checklist); the execution summary's **Evidence rows** pair plain words with a pointer — no requirement is ✅ without one.
|
|
47
48
|
|
|
48
49
|
No write restrictions. All tools available.
|
|
49
50
|
|
|
@@ -487,6 +487,46 @@ const PHASE_REMINDERS: Record<Exclude<Phase, null>, string> = {
|
|
|
487
487
|
"[pi-workflow-kit] DESIGN phase: read-only. No source edits; writes only under docs/plans/. No mutations.",
|
|
488
488
|
};
|
|
489
489
|
|
|
490
|
+
/** The one-line session visibility signal for a granted sandboxed batch executor.
|
|
491
|
+
* Informational only — the skills carry the actual preference; this line makes the
|
|
492
|
+
* host capability visible when work starts. */
|
|
493
|
+
const CODEMODE_HINT_LINE =
|
|
494
|
+
"codemode: active — prefer it for batched read-only exploration (one executor call beats N tool round-trips); the kit's shell recipes are fallbacks.";
|
|
495
|
+
|
|
496
|
+
/** A host that can report its tool registry (pi's ExtensionAPI can; minimal hosts and
|
|
497
|
+
* test harnesses may not — detection fails closed there). */
|
|
498
|
+
type ToolRegistryHost = {
|
|
499
|
+
getActiveTools?: () => unknown;
|
|
500
|
+
getAllTools?: () => unknown;
|
|
501
|
+
};
|
|
502
|
+
|
|
503
|
+
/** Does the host grant `codemode` (pi ≥ 1.0.0's sandboxed batch executor) to the model?
|
|
504
|
+
* The active tool set is authoritative when the host exposes one (`getAllTools` also
|
|
505
|
+
* reports registered-but-deferred tools); absent registries and unexpected entry
|
|
506
|
+
* shapes fail closed to false — the visibility line must never throw. */
|
|
507
|
+
export function detectCodeme(pi: ToolRegistryHost): boolean {
|
|
508
|
+
const grantsCodeme = (entries: unknown[]): boolean =>
|
|
509
|
+
entries.some((entry) =>
|
|
510
|
+
typeof entry === "string"
|
|
511
|
+
? entry === "codemode"
|
|
512
|
+
: typeof entry === "object" && entry !== null && (entry as { name?: unknown }).name === "codemode",
|
|
513
|
+
);
|
|
514
|
+
for (const source of [pi.getActiveTools, pi.getAllTools]) {
|
|
515
|
+
if (typeof source !== "function") continue;
|
|
516
|
+
try {
|
|
517
|
+
const entries = source.call(pi);
|
|
518
|
+
// Each registry that exists decides on its own answer — a container-shape
|
|
519
|
+
// surprise fails closed to false rather than falling through to the broader
|
|
520
|
+
// registry, which also reports deferred (not granted) tools.
|
|
521
|
+
return Array.isArray(entries) ? grantsCodeme(entries) : false;
|
|
522
|
+
} catch {
|
|
523
|
+
// Registry surprises fail closed; visibility never breaks the session.
|
|
524
|
+
return false;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
return false;
|
|
528
|
+
}
|
|
529
|
+
|
|
490
530
|
/** Determine if a write/edit to filePath should be blocked during the given phase.
|
|
491
531
|
* Only writes under docs/plans/ are allowed during the design phase.
|
|
492
532
|
*/
|
|
@@ -515,6 +555,13 @@ let pendingPhaseReminder = false;
|
|
|
515
555
|
*/
|
|
516
556
|
let guardOverride: "on" | "off" | null = null;
|
|
517
557
|
|
|
558
|
+
/** Codemode visibility (once per session): whether the host grants the executor,
|
|
559
|
+
* decided once at session_start, and whether the one-line hint has had its single
|
|
560
|
+
* emission window (the window never retries — a later /pwk-guard auto/on does not
|
|
561
|
+
* retro-add a suppressed line). */
|
|
562
|
+
let codemodeActive = false;
|
|
563
|
+
let codemodeAnnounced = false;
|
|
564
|
+
|
|
518
565
|
/** Is the guard actively enforcing read-only right now? */
|
|
519
566
|
function enforceActive(): boolean {
|
|
520
567
|
if (guardOverride === "off") return false;
|
|
@@ -542,6 +589,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
542
589
|
phase = null;
|
|
543
590
|
pendingPhaseReminder = false;
|
|
544
591
|
guardOverride = null;
|
|
592
|
+
codemodeActive = detectCodeme(pi);
|
|
593
|
+
codemodeAnnounced = false;
|
|
545
594
|
});
|
|
546
595
|
|
|
547
596
|
// --- Project role setup -------------------------------------------------
|
|
@@ -673,15 +722,29 @@ export default function (pi: ExtensionAPI) {
|
|
|
673
722
|
// return { block, reason }, not a message. So at bash time the reminder surfaces only when a
|
|
674
723
|
// destructive command is actually blocked (the reactive `reason` in the tool_call handler).
|
|
675
724
|
pi.on("before_agent_start", async () => {
|
|
676
|
-
|
|
725
|
+
// Codemode visibility: the line rides the first tail message of the session —
|
|
726
|
+
// appended to a phase reminder when one fires, emitted on its own when none
|
|
727
|
+
// does — once ever, and suppressed when the guard is pinned off.
|
|
728
|
+
let codemodeLine: string | null = null;
|
|
729
|
+
if (codemodeActive && !codemodeAnnounced) {
|
|
730
|
+
codemodeAnnounced = true;
|
|
731
|
+
if (guardOverride !== "off") codemodeLine = CODEMODE_HINT_LINE;
|
|
732
|
+
}
|
|
733
|
+
if (!phase || !pendingPhaseReminder) {
|
|
734
|
+
if (codemodeLine) return { message: { customType: "pwk-codemode-hint", content: codemodeLine, display: false } };
|
|
735
|
+
return {};
|
|
736
|
+
}
|
|
677
737
|
pendingPhaseReminder = false;
|
|
678
738
|
// Override states announce themselves via the /pwk-guard handler; this reminder
|
|
679
739
|
// is the auto-mode phase-entry cue only.
|
|
680
|
-
if (guardOverride !== null)
|
|
740
|
+
if (guardOverride !== null) {
|
|
741
|
+
if (codemodeLine) return { message: { customType: "pwk-codemode-hint", content: codemodeLine, display: false } };
|
|
742
|
+
return {};
|
|
743
|
+
}
|
|
681
744
|
return {
|
|
682
745
|
message: {
|
|
683
746
|
customType: "pwk-phase-reminder",
|
|
684
|
-
content: PHASE_REMINDERS[phase],
|
|
747
|
+
content: codemodeLine ? `${PHASE_REMINDERS[phase]}\n\n${codemodeLine}` : PHASE_REMINDERS[phase],
|
|
685
748
|
display: false,
|
|
686
749
|
},
|
|
687
750
|
};
|
package/package.json
CHANGED
|
@@ -5,15 +5,15 @@ description: "Use this before any creative work — creating features, building
|
|
|
5
5
|
|
|
6
6
|
# Brainstorming
|
|
7
7
|
|
|
8
|
-
Read-only exploration of source code; every file you create or edit goes under `docs/plans/`.
|
|
8
|
+
Read-only exploration of source code; every file you create or edit goes under `docs/plans/`. An approved ADR goes to `docs/adr/` — outside the writable boundary, so the human writes it or briefly runs `/pwk-guard off`, and the design phase never unlocks it. The design doc is the **single buildable artifact**: each requirement carries its own acceptance criteria and review tags, and the executor builds straight from it. Source-writing happens in `pwk-executing-tasks`.
|
|
9
9
|
|
|
10
|
-
Any command or tool recipe in this skill is an example, not the requirement — when your host grants a better tool for an operation (a sandboxed batch executor
|
|
10
|
+
Any command or tool recipe in this skill is an example, not the requirement — when your host grants a better tool for an operation (a sandboxed batch executor — e.g. `codemode` on pi ≥ 1.0.0 — a structured file API), use the better tool and treat the recipe as a fallback; the only exact exceptions are this kit's `scripts/` helpers and plain `git` invocations, whose deterministic output is the point.
|
|
11
11
|
|
|
12
12
|
## Proportionality: trivial vs non-trivial
|
|
13
13
|
|
|
14
14
|
Classify the change at the start.
|
|
15
15
|
|
|
16
|
-
- **Trivial** — typo or obvious bugfix with no open design questions, config
|
|
16
|
+
- **Trivial** — a typo or obvious bugfix with no open design questions, a config or version bump, a single-function change, or anything the human flags as trivial. Skip steps 3–6: read the design-format reference, run the validator in step 7, and write a **minimal** design doc in one turn — an `In short:` one-liner (what + why + approach), one `### R1:` block with criteria and tags, an optional `## Production-risk areas` line, and deliberately **no `## Feature acceptance`** (a trivial slice ships on the full existing suite; no E2E is manufactured). Hand off to `/skill:pwk-executing-tasks`. The guard still enforces read-only — trivial compresses the phase to one turn, it does not skip it.
|
|
17
17
|
- **Non-trivial** — open design questions, multiple approaches, cross-module impact, or new behavior. Run the full process below.
|
|
18
18
|
|
|
19
19
|
When unsure, ask: "This looks trivial — fast-path it, or full brainstorm?" Default to full.
|
|
@@ -22,39 +22,56 @@ When unsure, ask: "This looks trivial — fast-path it, or full brainstorm?" Def
|
|
|
22
22
|
|
|
23
23
|
**One design doc = one PR; one requirement = one testable slice within it.** Most work is a single design doc; several requirements serving one cohesive outcome do not force an umbrella.
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
A large request with distinct testable outcomes that need separate design/execute cycles becomes an **umbrella** of vertical slices with one-line scopes and a build order, approved before you write an overview or design. A layers-only split (database, API, UI) is not vertical — each slice delivers testable behavior. Design only the current slice, grounded in implemented code, not speculative sibling designs; the umbrella still ships as one PR on one branch, finalized once.
|
|
26
26
|
|
|
27
|
-
**One folder per topic:** `docs/plans/<date>-<topic>/`,
|
|
27
|
+
**One folder per topic:** `docs/plans/<date>-<topic>/`, holding `<leaf>-design.md`, `<leaf>-progress.md`, and `<leaf>-review-packet*.md`; `<leaf>` is `<topic>` for a single-part topic, and more than one leaf adds `overview.md`. The folder is the creation, discovery, and disposal unit.
|
|
28
28
|
|
|
29
|
-
**Umbrella trigger:** before proposing
|
|
29
|
+
**Umbrella trigger:** before proposing a new umbrella, or when discovery finds an `overview.md` beside this design, read [references/umbrella.md](references/umbrella.md) — it owns the status-free roster, the first/later-slice procedures, and header-only predecessor reporting. Build order is advisory, not a gate, and an existing roster means the split is already decided; design the current slice against it.
|
|
30
30
|
|
|
31
31
|
## Process
|
|
32
32
|
|
|
33
33
|
1. **Check git state** — `git status` + `git log --oneline -5`. Uncommitted work? Ask the user what to do first.
|
|
34
|
-
2. **Discovery** *(skip in a brand-new repo with no `docs/plans/`)* — first verify the repo root: run `pwd` (or your shell's equivalent) and `git rev-parse --show-toplevel`; mismatch → report both paths and stop; never `cd` (a worktree root counts). Then list `docs/plans` recursively, excluding docs/plans/completed/, for `*-design.md`, `*-progress.md`, and `overview.md` (topic docs live in `docs/plans/<date>-<topic>/` folders — archived work is not in flight). Use whatever recurses in your harness; one example: `find docs/plans -name '<suffix>' -not -path '*/completed/*'`; report in-flight topics and any active umbrella
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
2. **Discovery** *(skip in a brand-new repo with no `docs/plans/`)* — first verify the repo root: run `pwd` (or your shell's equivalent) and `git rev-parse --show-toplevel`; mismatch → report both paths and stop; never `cd` (a worktree root counts). Then list `docs/plans` recursively, excluding docs/plans/completed/, for `*-design.md`, `*-progress.md`, and `overview.md` (topic docs live in `docs/plans/<date>-<topic>/` folders — archived work is not in flight). Use whatever recurses in your harness; one example: `find docs/plans -name '<suffix>' -not -path '*/completed/*'`; report in-flight topics and any active umbrella, each topic’s `Feature phase:` line header-only (`grep -m1 '^Feature phase:' <file>`; design-only topics report `design` — no body ingest). With a sandboxed batch executor (e.g. `codemode` on pi ≥ 1.0.0) the listing and every phase extraction are one call, returning only the summary lines (adapt the paths to the verified root when your cwd differs):
|
|
35
|
+
|
|
36
|
+
```javascript
|
|
37
|
+
const designs = (await tools.bash({ command: "find docs/plans -name '*-design.md' -not -path '*/completed/*' | sort", timeout: 15 })).output.trim();
|
|
38
|
+
const files = designs ? designs.split('\n') : [];
|
|
39
|
+
const shellq = (s) => "'" + s.replace(/'/g, "'\\''") + "'";
|
|
40
|
+
const heads = await Promise.all(files.map(d =>
|
|
41
|
+
tools.bash({ command: "grep -m1 '^Feature phase:' " + shellq(d.replace('-design.md', '-progress.md')), timeout: 15 }).then(r => r.output.trim() || 'design')));
|
|
42
|
+
return text(files.map((d, i) => d + ' — ' + heads[i]).join('\n') || 'no in-flight topics');
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
If the idea continues an existing topic, ask whether to extend it or start fresh. An `overview.md` **beside the design doc** means the split is already decided — read it for the roster and design this part’s `<leaf>-design.md` against it.
|
|
46
|
+
3. **Understand the idea** — **PRD brief.** With source material (a PRD, ticket, or spec — pasted text, a path, a URL), open with a brief before any question: **Background** (the problem, why now, who is affected — each product claim cites its PRD section), **Current situation** (what the code does today — each claim cites `file:line`), **The delta** (what must change, each line naming a requirement candidate, and what stays untouched). Zero-context rule: plain meaning first, the pointer second — quote non-English domain terms with a plain-English gloss and mark anything uncited `(interpretation: …)`. Unreadable source material: report the blocker, ground on code only, name the gap. The human corrects the brief before frontier rounds; confirmed facts weave into the design doc, with no sidecar file. No source material, no brief. Then read only enough code, docs, and commits to ground the design, and **check `docs/lessons.md`**.
|
|
47
|
+
|
|
48
|
+
Ask questions in **frontier rounds** — the frontier is every question whose prerequisites are settled. Build the tree by walking every checklist dimension (*Goal & scope · Data & state · Behavior & edge cases · Errors & failure · Integration · Non-functional*), print `— nothing to ask` for empty groups, and ask the whole frontier in one round: number each question (`Q1`, `Q2`, …) with your recommended answer (`➡️ <recommendation>`) so the human confirms, strikes, or corrects each in one reply. A question that depends on another still-open one waits for a later round; recompute the frontier after each round.
|
|
49
|
+
|
|
50
|
+
**Facts vs. decisions:** anything answerable from the codebase, docs, or tools is looked up — recon scout or inline — never asked of the human; a pending lookup holds only its downstream questions while the rest of the frontier is asked now. **Runnable facts:** an unknown observable by running something — behavior, timing, output, layout — is settled by a bounded sketch, never asked of the human and never guessed: an inline interpreter or a file under `docs/plans/<topic>/`, no installs, no source writes. Record it where it lands as `(settled by sketch: <what ran> → <result>)` and list it in the round summary so the human can strike it; a sketch result that would set business behavior still passes the assumption gate; inconclusive or blocked → record `INCONCLUSIVE` plus one line of what ran, and the question returns to the human with the result attached. A cheaper read beats a run when reading can decide, and only decisions are asked.
|
|
51
|
+
|
|
52
|
+
Major approvals stay single-decision — one question each, never batched: approach selection (step 5), umbrella split, design approval, ADR offer. The interview ends when the frontier is empty — every branch visited, nothing left silently assumed — not when you feel you understand. Then present a short summary and ask: "Should I proceed, or is there more?" The human decides when to move on.
|
|
53
|
+
4. **(skipped on trivial changes)** **Codebase recon** — first **enumerate what this session actually grants** and name what you found: under a batch executor `Array.from(ALL_TOOLS)`, otherwise the tools and roles your host listed. Then request the host’s `codebase-recon` capability using the logical `pwk-recon-scout` role: a fresh-context, read-only, bounded worker given the topic, one-line intent, and repo root. Use its 5-section map (Relevant files, Existing patterns, Call sites, Test layout, Gotchas) as grounding for steps 5–6 instead of reading those files inline; the scout reports observations only, never design recommendations. No delegation capability among the tools you enumerated, or constraints it cannot enforce → report `Scout: unavailable` **with the enumeration result** and do the same recon inline, preserving the five-section map and `file:line` citations; never omit recon silently.
|
|
54
|
+
5. **Explore approaches** — propose 2–3, leading with your recommendation, and sketch the concrete interface (types, signatures, example caller) for each so the comparison is grounded in code rather than abstractions.
|
|
38
55
|
6. **Present the design** in one pass, organized into sections (architecture, components, data flow, error handling, testing) — the human comments on any section; re-present only revised sections.
|
|
39
56
|
|
|
40
|
-
**Assumptions to confirm first** — before presenting, sweep the drafted design: every assumption it would bake in
|
|
57
|
+
**Assumptions to confirm first** — before presenting, sweep the drafted design: every unconfirmed assumption it would bake in (business rules, defaults, edge-case resolutions) re-opens as a numbered question with your recommended answer, for one reply. An honest empty gate ("no unconfirmed assumptions") when the draft is clean — never invent items. Hard rule: no business behavior enters the design doc on the agent's assumption; confirmed facts are woven into existing sections, with no new template section.
|
|
41
58
|
|
|
42
|
-
Identified a significant architectural decision? Offer an ADR in `docs/adr
|
|
43
|
-
7. **Write the design doc** — validate its structure before handing off
|
|
59
|
+
Identified a significant architectural decision? Offer an ADR in `docs/adr/`, only when all three hold: **hard to reverse**, **surprising without context**, **a real trade-off**. Format: title + 1–3 sentences of context/decision/why. ADRs are permanent institutional memory — never archived or rotated. (Guard note: the human writes the approved ADR or briefly runs `/pwk-guard off`; you never write it while the design phase is gated.)
|
|
60
|
+
7. **Write the design doc** — validate its structure before handing off. Read [references/design-format.md](references/design-format.md) first for the exact format, tag defaults, risk/Setup rules, and audit; requirement blocks carry acceptance criteria plus `### Checkpoints` / `### Review` tags. Missing tags default to `none` / `skip`. Write `docs/plans/<date>-<topic>/<leaf>-design.md`, creating the topic folder when absent. It is descriptive, not a task list — the executor builds directly from it.
|
|
44
61
|
|
|
45
|
-
**Completion gate:** Test observable behavior through the public interface. Audit every requirement
|
|
62
|
+
**Completion gate:** Test observable behavior through the public interface. Audit every requirement’s criteria, tags, and risk notes — each appears exactly once. A criterion is ready only when its `Then` names an outcome a command can observe — a run, a grep, or an assertion; a criterion with no nameable probe sends the requirement back for splitting or rephrasing, and design-doc criteria never name tests — the probe materializes at execution. For non-trivial work, finish with an end-to-end `## Feature acceptance` as the primary enforced spec. If writing a scenario step would require inventing behavior, that invention goes back through the assumption gate: an unwritable step means an unspecified requirement, not permission to guess. Risk notes never set the tag — the written `### Review` value stays `skip` unless the human sets it, and only the human tags a slice for review. Keep designing until the requirements compose into a coherent feature and the human approves the design, including feature acceptance; trivial work keeps the compressed one-turn path above.
|
|
46
63
|
|
|
47
|
-
**
|
|
64
|
+
**Runtime prerequisite:** structural validation runs as a dependency-free Node script where commands execute, using only Node's standard library. Confirm `node --version` works before invoking the helper; if Node is missing, report the blocker and request a suitable runtime, then stop at this gate. Never auto-install a runtime, use a fallback implementation, or claim validation succeeded.
|
|
48
65
|
|
|
49
|
-
Resolve the helper from this installed skill
|
|
66
|
+
Resolve the helper from this installed skill’s directory and pass explicit paths, quoting paths with spaces:
|
|
50
67
|
|
|
51
68
|
```sh
|
|
52
|
-
|
|
69
|
+
node "<brainstorming-skill-dir>/scripts/validate-design.mjs" "<design-path>"
|
|
53
70
|
```
|
|
54
71
|
|
|
55
|
-
Nonzero means validation did not succeed: report file-specific diagnostics, correct structural errors, and rerun. A missing local reference or helper is a blocker before its dependent action;
|
|
72
|
+
Nonzero means validation did not succeed: report file-specific diagnostics, correct the structural errors, and rerun. A missing local reference or helper is a blocker before its dependent action; success verifies structure only — never semantic correctness, sound slicing, confirmed assumptions, or human approval.
|
|
56
73
|
|
|
57
|
-
The session stays read-only and uncommitted through brainstorm: branch creation and the design-doc commit happen at the start of `pwk-executing-tasks
|
|
74
|
+
The session stays read-only and uncommitted through brainstorm: branch creation and the design-doc commit happen at the start of `pwk-executing-tasks`.
|
|
58
75
|
|
|
59
76
|
## Principles
|
|
60
77
|
|
|
@@ -4,7 +4,7 @@ Read before writing any design doc. Keep the design descriptive, not a task list
|
|
|
4
4
|
|
|
5
5
|
## Trivial format
|
|
6
6
|
|
|
7
|
-
A trivial design has an `In short:` one-liner (what + why + approach
|
|
7
|
+
A trivial design has an `In short:` one-liner (what + why + approach), a single `### R1:` block with acceptance criteria and tags, and optional `## Production-risk areas`. It has no `## At a glance`, `## Requirements`, or `## Feature acceptance`; its ship gate is the full existing suite, not a manufactured E2E. The block rules below cover it.
|
|
8
8
|
|
|
9
9
|
```markdown
|
|
10
10
|
# Design: <topic>
|
|
@@ -23,7 +23,7 @@ In short: <what + why + approach>
|
|
|
23
23
|
|
|
24
24
|
## Non-trivial format
|
|
25
25
|
|
|
26
|
-
**Open with `## At a glance`** — the human's two-minute digest, immediately before `## Requirements
|
|
26
|
+
**Open with `## At a glance`** — the human's two-minute digest, immediately before `## Requirements`: (1) a 2–4 sentence plain-language summary of what is wrong or needed, what will be built, and the key approach; (2) **Key decisions** — one line each: decision + why, with a `(rejected: <alternative> — <reason>)` clause only when the fork was real (never manufactured); (3) a table `| R# | Requirement in one line | Risk |`, exactly one row per requirement, where **R# = the requirement's block number in the `## Requirements` section below** — the ID every later digest keys on. Plain language only: no jargon, no Given/When/Then — those live in the requirement blocks. An umbrella overview gains no at-a-glance section; its roster serves that role.
|
|
27
27
|
|
|
28
28
|
Then **`## Requirements`** — one `### R<n>: <name>` block per requirement, each one testable behavior:
|
|
29
29
|
|
|
@@ -49,18 +49,18 @@ Then **`## Requirements`** — one `### R<n>: <name>` block per requirement, eac
|
|
|
49
49
|
|
|
50
50
|
Block rules:
|
|
51
51
|
|
|
52
|
-
- **No test-name lists.** The criteria are the test spec
|
|
53
|
-
- **Tag every requirement** — `### Checkpoints` (
|
|
54
|
-
- **Nothing is tagged silently here; only the human tags a slice for review.** A requirement
|
|
55
|
-
- **No per-requirement spec stop, by design** — the
|
|
56
|
-
- **Production-risk notes** —
|
|
57
|
-
- **Ordering** — dependencies come earlier
|
|
52
|
+
- **No test-name lists.** The criteria are the test spec: the executor writes and names the tests red-green from them, so the doc holds no test-name lists and no R#-to-section map — the block structure is the map.
|
|
53
|
+
- **Tag every requirement** — `### Checkpoints` (`none` = no per-requirement stop, the default; `full` = tests + complete stops) and `### Review` (`skip` = the default; `parallel` = four delegated reviewers; `inline` = one `pwk-code-review` pass). Missing tags default to `none` / `skip`; flag `full` only where complex logic or the feature's main part makes a human look worth the stop.
|
|
54
|
+
- **Nothing is tagged silently here; only the human tags a slice for review.** A requirement touching a production-risk area carries its `### Production-risk notes` and is flagged `⚠ production-risk` in the At-a-glance Risk column — display-only, derived: `⚠ production-risk` if and only if the block carries non-empty notes, never an input; `auto` reads the underlying risk content, never the display column. Its written `### Review` value stays `skip` unless the human sets it — propose the tag in prose; an explicit human tag always wins, both ways.
|
|
55
|
+
- **No per-requirement spec stop, by design** — the criteria were approved at design time; re-checking mid-execution asks a question already answered.
|
|
56
|
+
- **Production-risk notes** — risks involving schema migrations, new dependencies, external APIs, or seed data also get a `## Setup` section (dependencies, migrations, seed data, and how to verify setup worked) between `## Requirements` and `## Feature acceptance`.
|
|
57
|
+
- **Ordering** — dependencies come earlier; the executor runs blocks in listed order with no dependency graph. Aim for vertical slices that merge cleanly on their own.
|
|
58
58
|
|
|
59
|
-
Then the narrative sections the executor reads as context — problem, approaches considered, architecture, components, data flow, error handling. Head the
|
|
59
|
+
Then the narrative sections the executor reads as context — problem, approaches considered, architecture, components, data flow, error handling. Head the fork record exactly `## Approaches considered` — finalizing's learning sweep reads it by that name — and **record every real fork and why each loser lost**; the executor needs the reasoning and finalize harvests it for ADRs.
|
|
60
60
|
|
|
61
|
-
Touches a production-risk area (DB schema/migrations, auth, external APIs, concurrency/batch, uploads/large data flows, Redis/caching/queues)? Add a brief `## Production-risk areas` **immediately after the last requirement block** — inside the `### R1 → ## Feature acceptance` span, so the review packet carries it
|
|
61
|
+
Touches a production-risk area (DB schema/migrations, auth, external APIs, concurrency/batch, uploads/large data flows, Redis/caching/queues)? Add a brief `## Production-risk areas` **immediately after the last requirement block** — inside the `### R1 → ## Feature acceptance` span, so the review packet carries it verbatim — and mirror the risks into each touched block's `### Production-risk notes`. `pwk-code-review` audits it (per reviewed slice, and always at the feature review); finalize's learning sweep reads it.
|
|
62
62
|
|
|
63
|
-
**End with `## Feature acceptance`** — one or more end-to-end `Given/When/Then` scenarios proving the requirements *compose* into the feature.
|
|
63
|
+
**End with `## Feature acceptance`** — one or more end-to-end `Given/When/Then` scenarios proving the requirements *compose* into the feature. It is the feature's definition-of-done and the **primary enforced spec**: `pwk-executing-tasks` writes it as the E2E test first and gates on it. The section carries the feature-level `### Feature review: auto | parallel | inline` tag — the one whole-feature review; default `auto`, which resolves on the design's own production-risk content to `parallel` (all four reviewers) when the design has any — a non-empty `## Production-risk areas` section, or a non-empty `### Production-risk notes` on any requirement — and to `inline` (one pass) otherwise. An explicit `parallel` or `inline` is written as-is, never resolved. If a scenario step would require inventing behavior, the invention goes back through the assumption gate — never silently into the scenario; an unwritable step means an unspecified requirement.
|
|
64
64
|
|
|
65
65
|
```markdown
|
|
66
66
|
## Feature acceptance
|
|
@@ -72,12 +72,12 @@ Touches a production-risk area (DB schema/migrations, auth, external APIs, concu
|
|
|
72
72
|
|
|
73
73
|
Example (rate limiting): "Given a new API consumer with no prior usage, When they exceed 100 requests/minute for 3 consecutive minutes, Then they're throttled, a `rate_limited` event is emitted, and further requests return 429."
|
|
74
74
|
|
|
75
|
-
**Audit before finishing:** every requirement block has acceptance criteria and both tags, and each requirement appears **exactly once** — none dropped, none duplicated.
|
|
75
|
+
**Audit before finishing:** every requirement block has acceptance criteria and both tags, and each requirement appears **exactly once** — none dropped, none duplicated. Non-trivial docs carry a `## Feature acceptance` section as the primary enforced spec; a trivial doc ends after its `### R1:` block and ships on the full suite. Production-risk areas appear in the blocks that touch them. The probe test: a criterion is ready only when its `Then` names an outcome a command can observe — a run, a grep, or an assertion; one with no nameable probe goes back for splitting or rephrasing, and criteria never name tests. A fact settled by a sketch carries its proof where it lands — `(settled by sketch: <what ran> → <result>)` — woven into the section it confirms, never a new template section.
|
|
76
76
|
|
|
77
77
|
## Structural validator contract
|
|
78
78
|
|
|
79
|
-
Run `scripts/validate-design.
|
|
79
|
+
Run `scripts/validate-design.mjs` as directed in the main skill. It reads UTF-8 Markdown without modifying it; headings, tags, and labels inside backtick or tilde fenced examples do not count, so close every fence. Real requirements use unique sequential `### R1: <name>`, `### R2: <name>`, … headings with nonempty names. Each block needs a standalone `**Acceptance criteria**` label in its main body, before any tag or risk-note heading (an explanatory suffix after an em dash, dash, or colon is allowed), with nonempty criteria before the next heading or bold label. A bare bullet or content borrowed from risk notes is not a criterion section.
|
|
80
80
|
|
|
81
81
|
Write each selected tag as one value, not the template's pipe-separated alternatives. Missing optional tags retain `Checkpoints: none`, `Review: skip`, and `Feature review: auto`. Non-trivial designs require nonempty `## Feature acceptance` scenarios before their feature-review tag. Only the minimal trivial shape above receives the no-Feature-acceptance exception.
|
|
82
82
|
|
|
83
|
-
The helper checks structure, not meaning: it does not prove Given/When/Then quality, testability,
|
|
83
|
+
The helper checks structure, not meaning: it does not prove Given/When/Then quality, testability, edge/error coverage, good slicing, risk classification, confirmed assumptions, or human approval. Those remain the agent's audit and the human's judgment. Structural success does not complete the design gate by itself.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# Umbrella mechanics
|
|
2
2
|
|
|
3
|
-
An umbrella splits one large requirement into multiple design docs
|
|
3
|
+
An umbrella splits one large requirement into multiple design docs shipping as **one PR**: one topic folder, more than one leaf, one branch, one `pwk-finalizing` at the end disposing the folder as one unit. Design only the current slice, grounded in implemented predecessor code.
|
|
4
4
|
|
|
5
5
|
**First brainstorm** (the requirement is too big for one design doc):
|
|
6
6
|
|
|
7
|
-
1. **Propose the split** — the parts, a one-line scope each, and build order
|
|
8
|
-
2. **Write the overview** — `docs/plans/<date>-<topic>/overview.md`, in the topic's own folder (every leaf lives beside it:
|
|
7
|
+
1. **Propose the split** — the parts, a one-line scope each, and build order; human approval before anything beyond discovery.
|
|
8
|
+
2. **Write the overview** — `docs/plans/<date>-<topic>/overview.md`, in the topic's own folder (every leaf lives beside it):
|
|
9
9
|
|
|
10
10
|
```markdown
|
|
11
11
|
# Overview: <topic>
|
|
@@ -17,10 +17,9 @@ An umbrella splits one large requirement into multiple design docs that ship tog
|
|
|
17
17
|
2. <leaf> — <one-line scope>
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
The `## Parts (build order)` heading and the `N. <leaf> — <one-line scope>` item shape
|
|
21
|
-
3. **Write the first part's design doc** — `docs/plans/<date>-<topic>/<leaf>-design.md`
|
|
20
|
+
The `## Parts (build order)` heading and the `N. <leaf> — <one-line scope>` item shape are the **roster contract**: `pwk-finalizing` and `pwk-status` read them, and both are lint-pinned. Goal, parts, build order — **no status column**; no skill mutates the overview before `pwk-finalizing` disposes it, and part-completion comes from each leaf's own `*-progress.md`.
|
|
21
|
+
3. **Write the first part's design doc** — `docs/plans/<date>-<topic>/<leaf>-design.md` beside the overview, then hand off to `/skill:pwk-executing-tasks`.
|
|
22
22
|
|
|
23
|
-
**Later parts** — re-run `/skill:pwk-brainstorming
|
|
24
|
-
|
|
25
|
-
The whole umbrella is one branch and one PR: `pwk-executing-tasks` creates the branch in its pre-flight and reuses it for later parts, and suggests the next part (or finalize after the last); `pwk-finalizing` disposes the whole folder — overview + every leaf — and ships one PR.
|
|
23
|
+
**Later parts** — re-run `/skill:pwk-brainstorming`. Read the overview for roster context, then report each prior leaf's `Feature phase:` line (`grep -m1 '^Feature phase:' <leaf>-progress.md` beside the overview; no progress file yet → `not started`) before designing the slice — prior parts are implemented code by then. Cross-slice decisions that must persist go in an ADR.
|
|
26
24
|
|
|
25
|
+
One branch and one PR: `pwk-executing-tasks` creates the branch in its pre-flight and reuses it for later parts; `pwk-finalizing` disposes the whole folder — overview and every leaf.
|