@tianhai/pi-workflow-kit 2.7.0 → 2.8.1

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 CHANGED
@@ -80,6 +80,10 @@ A **design doc is one PR**; a **requirement is one testable slice within it**. *
80
80
  | **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
81
  | **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
82
 
83
+ ### ⚡ Batched tool calls (pi ≥ 1.0.0 `codemode`)
84
+
85
+ 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.
86
+
83
87
  ## The Workflow in Detail
84
88
 
85
89
  ### Phase Control
@@ -12,6 +12,8 @@ max_turns: 20
12
12
 
13
13
  You are a read-only code reviewer. Execute the task instructions below faithfully using the host’s read-only tools. **Report findings only — do not modify files.**
14
14
 
15
+ The `tools:` frontmatter is the minimum grant requested of the delegation provider, not a prescription — use any tool your host actually grants.
16
+
15
17
  ## Authority boundary
16
18
 
17
19
  The host must enforce read-only execution. Do not create, modify, delete, move, or copy files, and do not run commands that mutate system or repository state.
@@ -11,6 +11,8 @@ You are a codebase recon scout requested during brainstorming before design work
11
11
 
12
12
  **You are observations only.** No design recommendations, no preferred-approach opinion, no code beyond one-line excerpts. Every claim must cite a `file:line` so the main agent can drill in if it needs to.
13
13
 
14
+ The `tools:` frontmatter is the minimum grant requested of the delegation provider, not a prescription — use any tool your host actually grants.
15
+
14
16
  ## Authority boundary
15
17
 
16
18
  You are a read-only reporter. The host must enforce the requested read-only boundary; do not create, modify, delete, move, or copy files, and do not run commands that mutate system or repository state.
@@ -12,6 +12,8 @@ max_turns: 20
12
12
 
13
13
  You are a read-only code reviewer. Execute the task instructions below faithfully using the host’s read-only tools. **Report findings only — do not modify files.**
14
14
 
15
+ The `tools:` frontmatter is the minimum grant requested of the delegation provider, not a prescription — use any tool your host actually grants.
16
+
15
17
  ## Authority boundary
16
18
 
17
19
  The host must enforce read-only execution. Do not create, modify, delete, move, or copy files, and do not run commands that mutate system or repository state.
@@ -10,6 +10,8 @@ max_turns: 40
10
10
 
11
11
  You are a read-only code reviewer. Execute the task instructions below faithfully using the host’s read-only tools. **Report findings only — do not modify files.**
12
12
 
13
+ The `tools:` frontmatter is the minimum grant requested of the delegation provider, not a prescription — use any tool your host actually grants.
14
+
13
15
  ## Authority boundary
14
16
 
15
17
  The host must enforce read-only execution. Do not create, modify, delete, move, or copy files, and do not run commands that mutate system or repository state.
@@ -10,6 +10,8 @@ max_turns: 40
10
10
 
11
11
  You are a read-only code reviewer. Execute the task instructions below faithfully using the host’s read-only tools. **Report findings only — do not modify files.**
12
12
 
13
+ The `tools:` frontmatter is the minimum grant requested of the delegation provider, not a prescription — use any tool your host actually grants.
14
+
13
15
  ## Authority boundary
14
16
 
15
17
  The host must enforce read-only execution. Do not create, modify, delete, move, or copy files, and do not run commands that mutate system or repository state.
@@ -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.
@@ -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
- if (!phase || !pendingPhaseReminder) return {};
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) return {};
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tianhai/pi-workflow-kit",
3
- "version": "2.7.0",
3
+ "version": "2.8.1",
4
4
  "description": "Enforce structured design→execute→finalize workflow with TDD discipline in AI coding agents",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -7,6 +7,8 @@ description: "Use this before any creative work — creating features, building
7
7
 
8
8
  Read-only exploration of source code; every file you create or edit goes under `docs/plans/`. (An approved ADR goes to `docs/adr/`, which sits outside the writable boundary — the human writes it themselves or briefly runs `/pwk-guard off`; 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; nothing is re-derived into a second document later. 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 — 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
+
10
12
  ## Proportionality: trivial vs non-trivial
11
13
 
12
14
  Classify the change at the start.
@@ -29,7 +31,18 @@ Before drafting, assess whether a large request has distinct testable outcomes t
29
31
  ## Process
30
32
 
31
33
  1. **Check git state** — `git status` + `git log --oneline -5`. Uncommitted work? Ask the user what to do first.
32
- 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. For each in-flight topic with a progress file, report its `Feature phase:` line (matched header-only — `grep -m1 '^Feature phase:' <file>` — no body ingest); design-only topics report `design`. If the new idea continues an existing topic, ask whether to extend it or start fresh. Part of an umbrella? An existing `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 (read [references/umbrella.md](references/umbrella.md) before proceeding).
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 new idea continues an existing topic, ask whether to extend it or start fresh. Part of an umbrella? An existing `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 (read [references/umbrella.md](references/umbrella.md) before proceeding).
33
46
  3. **Understand the idea** — read only enough code/docs/commits to ground the design. **Check `docs/lessons.md`** — known constraints may shape it. Ask questions in **frontier rounds**: build a question tree seeded by the dimension checklist, then ask in rounds. The **frontier** is every question whose prerequisites are already settled — ask the whole frontier in one round; a question whose answer depends on another still-open question waits for a later round. Number each question (`Q1`, `Q2`, …) and attach your recommended answer (`➡️ <recommendation>`) — the recommendation is your assumption surfaced up front; the human confirms, strikes, or corrects each in one reply. Recompute the frontier after each round of answers. Seed the tree by walking every checklist dimension — *Goal & scope · Data & state · Behavior & edge cases · Errors & failure · Integration · Non-functional* — printing `— nothing to ask` for groups with no questions (never skip silently). **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 is an unsettled prerequisite that holds only its downstream questions, while the rest of the frontier is asked now. Only decisions are asked. 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.
34
47
  4. **(skipped on trivial changes)** **Codebase recon** — for non-trivial topics with prior art, request the host’s `codebase-recon` capability using the logical `pwk-recon-scout` role. Require a fresh-context, read-only, bounded worker and pass the topic, one-line intent, and repo root. Use the returned 5-section codebase map (Relevant files, Existing patterns, Call sites, Test layout, Gotchas) as the grounding context for the next two steps instead of reading those files inline. The scout is observations only — no design recommendations. Skip this step on trivial changes (typo, version bump, single-function edit per the proportionality rule). If no compatible capability is available or the provider cannot enforce the requested constraints, report `Scout: unavailable` and do the same recon inline, preserving the five-section map and `file:line` citations; do not silently omit recon.
35
48
  5. **Explore approaches** — propose 2–3, leading with your recommendation. Sketch the concrete interface (types, signatures, example caller) for each so the comparison is grounded in code, not abstractions.
@@ -7,6 +7,8 @@ description: "Review a completed requirement's code — trace the logic, check s
7
7
 
8
8
  Review the code just implemented — one tagged requirement, or the whole feature at the feature-level review. **Unlocked** — you may edit code to apply smell fixes; flag everything else as a follow-up.
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 — 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
+
10
12
  ## Process
11
13
 
12
14
  1. **Identify the scope** — in the feature-gate flow (the default), you review the **whole feature diff** at the feature-level review (`git diff $FEATURE_BASE...HEAD` — the parent of the first Commit-column entry; see the executing skill's packet recipe); all acceptance criteria in the design doc and the `## Feature acceptance` E2E are in scope. When invoked per-requirement (`Review: inline` on a tagged requirement — or inline-completing a missing delegated role when the tag is `parallel`), scope is just that requirement — read its acceptance criteria from the design doc, run `git log --oneline -5` and `git diff` to see what changed for it. Invoked standalone — no invoking skill, no design doc, no packet — review the span the user names (the working-tree diff, or the branch's commits against its parent branch): tracing, smell fixes, and the hazard check run as usual, while spec alignment has no acceptance criteria to key on — say so and judge the diff against its stated intent instead of manufacturing a coverage table. When the invoking skill already assembled a review packet (the feature packet, or the requirement-scoped `<leaf>-review-packet-r<N>.md`), work from the packet — it is the scope of record; re-derive nothing the packet already states.
@@ -7,6 +7,8 @@ description: "Implement a design doc via the feature-gate flow: write the featur
7
7
 
8
8
  Implement the design doc found under `docs/plans/` via the **feature-gate flow**. The design doc is the single buildable artifact — its `### R<n>` blocks carry each requirement's acceptance criteria and tags. The criteria define *what*, you decide *how*: structure, signatures, internals are yours.
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 — 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
+
10
12
  The feature-acceptance E2E test is the primary enforced gate and the primary enforced spec for the feature. The flow is always on: write the E2E first (red), implement the requirements back-to-back, then run the feature review and pause at the **ship checkpoint** — one fully-informed stop where you present the execution summary and the reviewer coverage table, with the full diff on request. Per-requirement checkpoints and reviews are **opt-in** — they fire only for requirements the design doc tags (default off); the feature gate covers everything else. A trivial design doc (no `## Feature acceptance`, per brainstorming's proportionality rule) skips the E2E steps and ships on the full suite; the one whole-feature review still runs at its ship checkpoint, its missing `### Feature review` tag defaulting to `auto`.
11
13
 
12
14
  ## Before you start
@@ -14,7 +16,18 @@ The feature-acceptance E2E test is the primary enforced gate and the primary enf
14
16
  Resolve local references and scripts from this installed skill directory. If a required resource is missing, report the blocker and stop before the affected action; do not silently skip its instructions.
15
17
 
16
18
  1. **Git state** — `git status` + `git log --oneline -5`; note uncommitted changes.
17
- 2. **Find the doc** — 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` (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/*'`. If no doc at all, ask the user to run `/skill:pwk-brainstorming` first; if several, ask which. Report one line, e.g. `Found: design "auth" — feature-gate execute (E2E written, implementing 2/5)`. A matching `*-progress.md` means this is a **resume** (see [Resume and progress](#resume-and-progress)). An umbrella part whose prior leaves are not all at `done`: surface their `Feature phase:` lines (matched header-only from each `<leaf>-progress.md`) as advisory context in the pre-flight report — no refusal, no reorder; build order stays advisory.
19
+ 2. **Find the doc** — 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` (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/*'`; take each topic’s `Feature phase:` line header-only (`grep -m1 '^Feature phase:' <file>`). 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):
20
+
21
+ ```javascript
22
+ const designs = (await tools.bash({ command: "find docs/plans -name '*-design.md' -not -path '*/completed/*' | sort", timeout: 15 })).output.trim();
23
+ const files = designs ? designs.split('\n') : [];
24
+ const shellq = (s) => "'" + s.replace(/'/g, "'\\''") + "'";
25
+ const heads = await Promise.all(files.map(d =>
26
+ tools.bash({ command: "grep -m1 '^Feature phase:' " + shellq(d.replace('-design.md', '-progress.md')), timeout: 15 }).then(r => r.output.trim() || 'design')));
27
+ return text(files.map((d, i) => d + ' — ' + heads[i]).join('\n') || 'no in-flight topics');
28
+ ```
29
+
30
+ If no doc at all, ask the user to run `/skill:pwk-brainstorming` first; if several, ask which. Report one line, e.g. `Found: design "auth" — feature-gate execute (E2E written, implementing 2/5)`. A matching `*-progress.md` means this is a **resume** (see [Resume and progress](#resume-and-progress)). An umbrella part whose prior leaves are not all at `done`: surface their `Feature phase:` lines (matched header-only from each `<leaf>-progress.md`) as advisory context in the pre-flight report — no refusal, no reorder; build order stays advisory.
18
31
  3. **Workspace — choose this topic’s branch/worktree.** Before creating, switching, or adopting one, read [Workspace and resume details](references/resume.md#workspace). Reuse this topic’s branch (one umbrella = one branch); a different topic’s branch never hosts these commits. Uncommitted planning docs do not cross a worktree boundary: commit this topic folder on its branch before a new worktree handoff; when adopting an existing checkout with uncommitted docs here, copy the topic folder there, verify it, then remove the source copy. Read the reference's command order before acting. Offer/adopt only after checking existing worktrees; wait for the user's choice.
19
32
 
20
33
  ## First run
@@ -7,11 +7,24 @@ description: "Use after all requirements are complete to archive or delete consu
7
7
 
8
8
  Ship the completed work.
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 — 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
+
10
12
  ## Pre-finalization checks
11
13
 
12
14
  1. **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).
13
15
  2. **Run the FULL test suite** — every test must pass, and only a green suite ships. Resume spans sessions; re-run the suite yourself rather than trust the previous session's ending state. Anything failing → send the user back to `/skill:pwk-executing-tasks`.
14
- 3. Read **every** relevant progress file — for a multi-leaf topic that's each leaf's progress file — discovered by listing `docs/plans` recursively, excluding docs/plans/completed/, for `*-progress.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/*'`. More than one topic in flight? Ask which one this finalize ships — finalizing touches only its own topic, and another topic still being designed or executed never blocks this run. Then match, in the chosen topic's file(s), the `Feature phase:` line (e.g. `grep -m1 '^Feature phase:' <file>`) and read only the matching ❌/⏭ verdict rows in the Requirements table (e.g. `sed -n '/^## Requirements/,/^## Execution summary/p' <file> | grep '^| [0-9].*❌'` / `sed -n '/^## Requirements/,/^## Execution summary/p' <file> | grep '^| [0-9].*⏭'` — scoped to Requirements-table rows because the Execution summary rows share the same row shape, with reasons); the sections after the tables carry nothing the gate needs. Apply the gates below to the chosen topic's file(s) and no others:
16
+ 3. Read **every** relevant progress file — for a multi-leaf topic that's each leaf's progress file — discovered by listing `docs/plans` recursively, excluding docs/plans/completed/, for `*-progress.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/*'`. With a sandboxed batch executor (e.g. `codemode` on pi ≥ 1.0.0) the listing and every topic’s `Feature phase:` extraction are one call, returning only the summary lines (adapt the paths to the verified root when your cwd differs):
17
+
18
+ ```javascript
19
+ const designs = (await tools.bash({ command: "find docs/plans -name '*-design.md' -not -path '*/completed/*' | sort", timeout: 15 })).output.trim();
20
+ const files = designs ? designs.split('\n') : [];
21
+ const shellq = (s) => "'" + s.replace(/'/g, "'\\''") + "'";
22
+ const heads = await Promise.all(files.map(d =>
23
+ tools.bash({ command: "grep -m1 '^Feature phase:' " + shellq(d.replace('-design.md', '-progress.md')), timeout: 15 }).then(r => r.output.trim() || 'design')));
24
+ return text(files.map((d, i) => d + ' — ' + heads[i]).join('\n') || 'no in-flight topics');
25
+ ```
26
+
27
+ More than one topic in flight? Ask which one this finalize ships — finalizing touches only its own topic, and another topic still being designed or executed never blocks this run. Then match, in the chosen topic's file(s), the `Feature phase:` line (e.g. `grep -m1 '^Feature phase:' <file>`) and read only the matching ❌/⏭ verdict rows in the Requirements table (e.g. `sed -n '/^## Requirements/,/^## Execution summary/p' <file> | grep '^| [0-9].*❌'` / `sed -n '/^## Requirements/,/^## Execution summary/p' <file> | grep '^| [0-9].*⏭'` — scoped to Requirements-table rows because the Execution summary rows share the same row shape, with reasons); the sections after the tables carry nothing the gate needs. Apply the gates below to the chosen topic's file(s) and no others:
15
28
  - **Any `❌ failed`** (in any leaf of the topic) → **block**. Present counts and reasons; continue only when the user sends the task back to executing-tasks, or explicitly types `--force-failed` to acknowledge shipping with incomplete requirements.
16
29
  - **Only `⏭ skipped`** → warn and confirm ("Requirement N was skipped. Continue, or go back?").
17
30
  - **`Feature phase` must be `done`** in every progress file of the topic — any other value (`e2e-written`, `implementing (k/N)`, `reviewing`, `ship-paused`) means that topic is still in flight: its ship checkpoint has not been approved. Send the user back to `/skill:pwk-executing-tasks` instead of finalizing.
@@ -33,6 +46,8 @@ Ship the completed work.
33
46
 
34
47
  - **Delete (default)** — code + tests are the source of truth; removing the scaffold prevents stale plan docs from misleading future sessions:
35
48
 
49
+ The invariant: the topic folder `docs/plans/<date>-<topic>/` is the disposal unit — delete it entirely, nothing more and nothing less; any single operation achieving exactly this is correct, and the bash below is one canonical example.
50
+
36
51
  ```bash
37
52
  # the topic folder goes as one unit (every leaf, plus overview.md if it has one).
38
53
  # The folder path is taken verbatim from discovery — never typed or
@@ -45,6 +60,8 @@ Ship the completed work.
45
60
 
46
61
  - **Archive** — keep the planning history for future readers (e.g. a complex design worth preserving) by moving the artifacts into `docs/plans/completed/`:
47
62
 
63
+ The invariant: the topic folder `docs/plans/<date>-<topic>/` moves whole into `docs/plans/completed/` and the destination is verified before committing; any single operation achieving exactly this is correct, and the bash below is one canonical example.
64
+
48
65
  ```bash
49
66
  mkdir -p docs/plans/completed
50
67
  # the topic folder goes as one unit (every leaf, plus overview.md if it has one).
@@ -68,7 +85,7 @@ Ship the completed work.
68
85
  3. **Squash & merge** — squash onto parent, push, delete branch.
69
86
  4. **Merge commit** — `--no-ff` merge, push parent, delete branch.
70
87
 
71
- For 2–4, confirm the detected parent branch before proceeding. When a worktree was used, the parent-side commands (merge onto parent, push parent, branch deletion) run from the main working tree — the topic worktree holds the feature-branch checkout, so the parent cannot be checked out there (`git -C ../<repo> …` drives the main side without moving the session; the root check's never-`cd` rule still holds) — and step 7's worktree removal comes **first**: a branch checked out in a worktree cannot be deleted.
88
+ For 2–4, confirm the detected parent branch before proceeding. When a worktree was used, the parent-side commands (merge onto parent, push parent, branch deletion) run from the main working tree — the topic worktree holds the feature-branch checkout, so the parent cannot be checked out there (`git -C ../<repo> …` drives the main side without moving the session; the root check's never-cd rule still holds) — and step 7's worktree removal comes **first**: a branch checked out in a worktree cannot be deleted.
72
89
  7. **Clean up** — if a worktree was used, verify presence first (`git worktree list`): when the topic's worktree exists, remove it (`git worktree remove ../<repo>-<topic>`, where `<topic>` is the folder slug — the same one `pwk-executing-tasks` created the branch under, never a leaf slug). The `../` path is written from the main working tree, and the removal runs from there — `git -C ../<repo> worktree remove ../<repo>-<topic>` when the session stands inside the worktree, which git refuses to remove under itself. When absent, cleanup is a silent no-op — never a failure.
73
90
 
74
91
  ## Principles
@@ -7,11 +7,23 @@ description: "Show all active pipeline topics and their phase/progress. Use when
7
7
 
8
8
  Report on in-flight pipelines in this working tree (a worktree has its own `docs/plans/`, so run status in each). Read-only. This skill **does not unlock the guard** — it needs no writes, so it runs fine inside the design read-only phase. If you want source edits after a status check, invoke the skill for the next phase yourself (the guard follows the skill).
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 — 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
+
10
12
  ## Process
11
13
 
12
14
  0. **Verify the 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).
13
- 1. **Discover** — 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) — this working tree only. Use whatever recurses in your harness; one example: `find docs/plans -name '<suffix>' -not -path '*/completed/*'`.
14
- 2. **State per topic/part — extract, never ingest.** For each progress file take the `Feature phase:` line by matching it (e.g. `grep -m1 '^Feature phase:' <file>` — wherever the template puts it); the body (execution summary, review reports, code digest) carries nothing status needs, and neither do design docs. A header reading `Setup: pending` renders the topic as **`awaiting setup`** — the setup checkpoint was never approved (the slot is only ever written when the design doc has a `## Setup` section, so the header alone decides — no design-doc read) — ahead of any phase-derived state below. Map the line to the displayed state:
15
+ 1. **Discover** — 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) — this working tree only; take each topic’s `Feature phase:` line header-only (`grep -m1 '^Feature phase:' <file>`). Use whatever recurses in your harness; one example: `find docs/plans -name '<suffix>' -not -path '*/completed/*'`. 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):
16
+
17
+ ```javascript
18
+ const designs = (await tools.bash({ command: "find docs/plans -name '*-design.md' -not -path '*/completed/*' | sort", timeout: 15 })).output.trim();
19
+ const files = designs ? designs.split('\n') : [];
20
+ const shellq = (s) => "'" + s.replace(/'/g, "'\\''") + "'";
21
+ const heads = await Promise.all(files.map(d =>
22
+ tools.bash({ command: "grep -m1 '^Feature phase:' " + shellq(d.replace('-design.md', '-progress.md')), timeout: 15 }).then(r => r.output.trim() || 'design')));
23
+ return text(files.map((d, i) => d + ' — ' + heads[i]).join('\n') || 'no in-flight topics');
24
+ ```
25
+
26
+ 2. **State per topic/part — map the header.** The body (execution summary, review reports, code digest) carries nothing status needs, and neither do design docs. A header reading `Setup: pending` renders the topic as **`awaiting setup`** — the setup checkpoint was never approved (the slot is only ever written when the design doc has a `## Setup` section, so the header alone decides — no design-doc read) — ahead of any phase-derived state below. Map the line to the displayed state:
15
27
  - `done` → **`done`** — terminal, never shown as in-flight; every row is resolved (`✅` passed, `❌` failed, `⏭` skipped — resolved, not necessarily passed). Append the tally as `N/N` when wanted — the Requirements-table row count, scoped to that table because the Execution summary rows share the same `| <n> |` row shape and a bare grep would double it (e.g. `sed -n '/^## Requirements/,/^## Execution summary/p' <file> | grep -c '^| [0-9]'`) — and when that same scoped range finds any — `sed -n '/^## Requirements/,/^## Execution summary/p' <file> | grep -c '^| [0-9].*❌'` / `sed -n '/^## Requirements/,/^## Execution summary/p' <file> | grep -c '^| [0-9].*⏭'` (the same scoping, so Execution-summary rows — which share the row shape — and prose mentions of the glyphs do not inflate the count) — render the counts, e.g. `done (1 ❌ · 1 ⏭)`, noting finalizing will require `--force-failed` while `❌` rows stand
16
28
  - `implementing (k/N)` → `execute k/N` (the tally rides on the line itself — no extra read)
17
29
  - `e2e-written` → `execute 0/N` (the E2E is written and the run continues into implementation — never shown as a paused state; N comes from the same Requirements-table-scoped row count as `done` — so no tally renders without a defined source)
@@ -7,6 +7,8 @@ description: "Generate a detailed, file-referenced walkthrough of a shipped feat
7
7
 
8
8
  Explain a shipped feature in code-level detail, for a human reading with the files open.
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 — 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
+
10
12
  **Not a pipeline phase** — never auto-run, never blocks anything. The skill is generated on demand and invoking it exits any gated design phase (it writes outside `docs/plans/`).
11
13
 
12
14
  Five sections, always: Summary / How it works / Key flows / Gotchas & invariants / Change map.