@loneexile/omp-superpowers 7.0.1-omp.4 → 7.0.2-omp.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.
@@ -16,10 +16,6 @@ let cachedBootstrap: string | null | undefined;
16
16
  export default function superpowersPiExtension(pi: ExtensionAPI) {
17
17
  let injectBootstrap = true;
18
18
 
19
- pi.on("resources_discover", async () => ({
20
- skillPaths: [skillsDir],
21
- }));
22
-
23
19
  pi.on("session_start", async () => {
24
20
  injectBootstrap = true;
25
21
  });
@@ -28,15 +24,9 @@ export default function superpowersPiExtension(pi: ExtensionAPI) {
28
24
  injectBootstrap = true;
29
25
  });
30
26
 
31
- pi.on("session_switch", async () => {
32
- injectBootstrap = true;
33
- });
34
-
35
- pi.on("agent_end", async (event) => {
36
- if (event?.willContinue) return;
37
- injectBootstrap = false;
38
- });
39
-
27
+ // Messages returned from a context handler are sent to the provider but never
28
+ // written to session history, so the bootstrap has to be injected into every
29
+ // provider request, on every prompt, for the whole session.
40
30
  pi.on("context", async (event, ctx) => {
41
31
  if (ctx?.agent?.kind === "sub") return;
42
32
  if (!injectBootstrap) return;
package/CHANGELOG.md CHANGED
@@ -6,6 +6,25 @@ A version is `<upstream version>-omp.<n>`: the upstream release this fork is syn
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [7.0.2-omp.1] - 2026-11-08
10
+
11
+ Synced to upstream [v7.0.2](https://github.com/obra/superpowers/blob/v7.0.2/RELEASE-NOTES.md).
12
+
13
+ ### Fixed
14
+
15
+ - **Every prompt gets the bootstrap, not just the first.** omp fires `agent_end` once per user prompt, and the messages an extension's `context` handler returns go to the model but are never saved in the session, so the extension's `agent_end` disarm dropped the using-superpowers bootstrap and the omp tool mapping from every request after the first prompt of a process. Measured on omp 18.18.1 with a stub provider and three prompts in one process: 7.0.1-omp.4 sent it on prompt 1 only (1, 0, 0), including both requests of a prompt that made a tool call, and its first message changed at prompt 2, so the prompt cache was rewritten there; this release sends it once on every request, with the first message byte-identical across requests. Upstream v7.0.2 fixed the same disarm for pi (#2083). `session_switch` re-arming had nothing left to re-arm and is gone. In the same stub runs, `scout`, `task` and `sdd-implementer` subagents got no bootstrap while every request of their parent carried it, a `/new` session got it from its first request, and after a compaction (local, or an LLM summary, once or twice) it came once, right after the summary. On a real model (claude-opus-5-5, 4 runs per version, a neutral first prompt, then "Let's make a react todo list"), both versions read the brainstorming skill and asked before building anything on the second prompt, since omp's own system prompt lists the skills; only this release opened with the "Using brainstorming to …" announcement using-superpowers asks for (4 of 4 against 0 of 4), and 7.0.1-omp.4's first request of the second prompt was about 2,400 tokens smaller than its last request of the first, the size of the missing bootstrap.
16
+
17
+ ### Changed
18
+
19
+ - **Synced with upstream v7.0.2** (from v7.0.1). What reaches omp unchanged: the SDD and executing-plans helpers act on the git working tree of the current directory, as git does, take `-C DIR`, and stop with one message outside a working tree instead of writing into whatever directory they ran in (new `sdd-repo`); `task-brief` finds tasks with IDs like `A1`, `6b` and `2.1`, no longer takes a sibling Task 6b along with Task 6, says when a plan's task headings are not in English, and refuses a brief that an unclosed code fence ran to the end of the plan; `start-server.sh --project-dir .` starts the brainstorm companion; systematic-debugging's pressure-test scenarios and `CREATION-LOG.md` no longer ship (83 files, down from 87).
20
+ - **The helper invocations say to run each one by its absolute path, from the working tree you're executing in.** Upstream's wording, ported into the fork's rewritten subagent-driven-development, executing-plans and reviewer template text; the review-per-task line still said "from this skill's directory". `tests/sdd-helper-paths/` passes on all 15 references. Checked live on omp 18.18.1 with the packed tarball unpacked and linked (`omp plugin link`) into an isolated profile, and claude-opus-5-5 as the controller. A subagent-driven run of a three-task Node plan resolved the scripts directory into the linked package, ran every helper by absolute path from the plan checkout, put tasks 1 and 2 in one wave of two worktrees, reviewed task 2 (plan-marked) and task 3 (ruled persisted format) per task, sent the final review to `sdd-final-reviewer`, and ran one fix and a scoped re-review on its findings: 21 of 21 tests on the branch, about $6.94. An inline executing-plans run of a two-task plan with tasks `A1` and `A2` briefed both letter-first tasks through `task-start`, ledgered both through `task-done`, and sent its final review to `sdd-final-reviewer`. Neither run hit the new "outside a working tree" stop.
21
+ - **Brainstorming keeps 7.0.1-omp.4's text.** Upstream v7.0.2's retune (ask why first, ask only when the answer would change what gets built, options with a recommendation, text sketches) is not taken in this release; the rebase had merged four of its hunks into the fork's text, and they are reverted until the retune is ported and A/B-tested on omp.
22
+ - `tests/brainstorm-server/server.test.js` is upstream's again: v7.0.2 waits for the server's pong before counting reloads, and it passed 15 of 15 runs on Linux.
23
+
24
+ ### Removed
25
+
26
+ - **The extension's `resources_discover` handler.** Upstream removed it so pi's package `skills` filter applies. omp never calls it (`omp://extensions.md`: no callsites), and skills load from the package's `pi.skills` entry: a linked install without the handler lists all 15 superpowers skills.
27
+
9
28
  ## [7.0.1-omp.4] - 2026-10-24
10
29
 
11
30
  ### Removed
@@ -149,7 +168,8 @@ First release, synced to upstream [v6.4.2](https://github.com/obra/superpowers/b
149
168
  - The fork's rewritten subagent-driven-development text invokes its helper scripts through `bash` as well, so a package extractor that drops exec bits cannot break them.
150
169
  - `sdd-final-reviewer` carries upstream's new review rules from `code-reviewer.md`, the template it replaces in SDD's final review: the spec is a vision document (behavior it is silent on is graded by what a reasonable person expects), and a "Declined to judge" section that the controller rules on and ledgers like a plan conflict.
151
170
 
152
- [Unreleased]: https://github.com/LoneExile/omp-superpowers/compare/v7.0.1-omp.4...HEAD
171
+ [Unreleased]: https://github.com/LoneExile/omp-superpowers/compare/v7.0.2-omp.1...HEAD
172
+ [7.0.2-omp.1]: https://github.com/LoneExile/omp-superpowers/releases/tag/v7.0.2-omp.1
153
173
  [7.0.1-omp.4]: https://github.com/LoneExile/omp-superpowers/releases/tag/v7.0.1-omp.4
154
174
  [7.0.1-omp.3]: https://github.com/LoneExile/omp-superpowers/releases/tag/v7.0.1-omp.3
155
175
  [7.0.1-omp.2]: https://github.com/LoneExile/omp-superpowers/releases/tag/v7.0.1-omp.2
package/README.md CHANGED
@@ -221,10 +221,10 @@ In short: the omp extension and `pi-tools.md` describe omp's real tools; five `s
221
221
  <details>
222
222
  <summary><b>File by file</b></summary>
223
223
 
224
- - `.pi/extensions/superpowers.ts` — the injected mapping names `task`, `todo`, the `sdd-*` roster, and the no-`model:`-field rule; it also re-arms on `session_switch`, skips subagent sessions, and ignores an `agent_end` that will auto-continue; it tells a dispatching session to name the checks each subagent must run, since omp 18.4.12 tells subagents to leave builds, tests and smoke runs to the main agent unless their assignment explicitly instructs them; its last paragraph points a vibe-mode director (tools include `vibe_spawn` but not `task`) at the *Vibe mode* section of `pi-tools.md`
224
+ - `.pi/extensions/superpowers.ts` — the injected mapping names `task`, `todo`, the `sdd-*` roster, and the no-`model:`-field rule; it also skips subagent sessions; it tells a dispatching session to name the checks each subagent must run, since omp 18.4.12 tells subagents to leave builds, tests and smoke runs to the main agent unless their assignment explicitly instructs them; its last paragraph points a vibe-mode director (tools include `vibe_spawn` but not `task`) at the *Vibe mode* section of `pi-tools.md`
225
225
  - `.omp-plugin/plugin.json` — new. Marks the repo root as an omp-native plugin so a marketplace or `--plugin-dir` install keeps each agent's `model:` line
226
226
  - `skills/using-superpowers/references/pi-tools.md` — same, as the reference doc; it also gains a *Checks* subsection (the 18.4.12 subagent hand-off rule, and why every dispatch names its checks) and a *Vibe mode* section: what a director keeps and lacks, how skill actions map onto `vibe_*` and workers, and the worktree and request-budget limits
227
- - `skills/brainstorming/` — a defined small-change path: after the in-chat approval the session builds it itself on a branch: the full suite before changing anything, test first, the covering tests and the suite again, then one commit of only its own files and hunks, with no design document, plan or subagents (a new behavior such as a `--quiet` flag can be small; security, auth, concurrency, money, migrations, changes one revert cannot undo, new config files or stored formats, changes to existing behavior, new interfaces other code builds on and new dependencies never are, and none of them takes the quick-task route however complete the request); a request is a quick task only if doing it leaves no choice the person would see (a format, a default, wording, bad input) for the agent to make; each question asks one thing, with any reason before it; a playback rides along with the next question instead of waiting for its own answer; for software, the plan is written right after the builder check so the design and the plan get one approval. Of upstream v7.0.1's retune it keeps reading the project first, the new first message and the sharper questions; the approaches ride with the last playback chunk, whose one question is the pick, instead of going out in a message of their own; upstream's short design doc and plan for every small change are not taken
227
+ - `skills/brainstorming/` — a defined small-change path: after the in-chat approval the session builds it itself on a branch: the full suite before changing anything, test first, the covering tests and the suite again, then one commit of only its own files and hunks, with no design document, plan or subagents (a new behavior such as a `--quiet` flag can be small; security, auth, concurrency, money, migrations, changes one revert cannot undo, new config files or stored formats, changes to existing behavior, new interfaces other code builds on and new dependencies never are, and none of them takes the quick-task route however complete the request); a request is a quick task only if doing it leaves no choice the person would see (a format, a default, wording, bad input) for the agent to make; each question asks one thing, with any reason before it; a playback rides along with the next question instead of waiting for its own answer; for software, the plan is written right after the builder check so the design and the plan get one approval. Of upstream v7.0.1's retune it keeps reading the project first, the new first message and the sharper questions; the approaches ride with the last playback chunk, whose one question is the pick, instead of going out in a message of their own; upstream's short design doc and plan for every small change are not taken. Upstream v7.0.2's retune (ask why first, ask only when the answer would change what gets built, read from how they talk whether they want the technical choices, sketch in text before offering the visual companion, a first-message short design when nothing is open) is not taken yet: this file is 7.0.1-omp.4's
228
228
  - `agents/sdd-*.md` — new. Each seat's `model:` is a pin plus a role fallback (`@task` or `@slow`), and all set `readSummarize: false`. `sdd-final-reviewer` reviews the whole branch for both ways of running a plan; after subagent-driven-development it does the task review's work on every task left to it (`review at final`) before the seams. It reads `requesting-code-review/code-reviewer.md` at run time and applies its What to Check, Calibration, severity definitions and Critical Rules, while carrying upstream's vision-document and Declined-to-judge rules in its own body; a crash or lost data on user input is always a finding, never a Declined-to-judge line. Descriptions name roles, never models
229
229
  - `skills/subagent-driven-development/` — *Model Selection* → *Agent Selection*; fix-loop cap 5 → 3 with a round-3 escalation seat; a proven-trivial-fix route that replaces a re-review with a one-command proof; the pre-flight scan builds a review list (plan-marked or ruled high-risk tasks get a task review, the rest get the controller's own covering-test run and the final review) and waves (tasks with no shared file or interface run in parallel, up to three, each in its own `omp worktree add` worktree with the project's install step re-run there, merged back with `--no-ff` after their covering tests pass on the merged tree; a task that still will not merge after round 3 stops the run); Setup creates the approved branch in this checkout instead of a worktree; resume reads each task's last ledger line, and treats a wave task as merged only when its branch has commits past BASE; the scripts directory resolves via `realpath skill://subagent-driven-development/scripts`; fix rounds resume the implementer with `write agent://<id>` (id ledgered) and full results are read at `agent://<id>`; task review scales with risk through `effort: "hi"`; the controller checks reviewer results; templates show omp's real `{ context, tasks: [{ agent, task, solutionSpace }] }` wire shape and the reviewers' structured fields; one omp paragraph for vibe mode, where a director (no `task` or `bash`) hands the whole run to one `good` worker that dispatches the seats itself. Upstream v7.0.1's `references/` is deleted: it holds upstream's own fix loop (5 rounds), final review and resume text, and nothing in this SKILL.md points to it
230
230
  - `skills/executing-plans/` — the description, *Why inline*, *When to Use* and the "Prefer subagent-driven-development" paragraph say the partner approved inline execution at the handoff and that SDD reviews per task only where a plan marks it; Setup creates the approved branch in this checkout; a ledger with `Wave` lines resumes under SDD. Additive omp paragraphs: in *Final Review*, the `task` tool has no `model:` field, so the final review goes to `sdd-final-reviewer` (its model is what the host maps that agent to), told that no task was reviewed; it also resolves the scripts directory with `realpath` and reads full results at `agent://<id>`; one more for vibe mode, where a director hands the whole run to one `good` worker
@@ -233,8 +233,7 @@ In short: the omp extension and `pi-tools.md` describe omp's real tools; five `s
233
233
  - `skills/writing-plans/` — *Execution Handoff* picks the method itself and asks for one approval of the design, the plan, the method and the workspace (a new branch in this checkout by default, which answers using-git-worktrees' consent question); *Review Marks* (and a self-review check) mark security, auth, concurrency, migration, money and destructive tasks `**Review:** per-task`; tasks that share no file or interface can run in parallel; in vibe mode both execution approaches run in one `good` worker the director briefs, not in its own session
234
234
  - `skills/finishing-a-development-branch/` — one line in the discard path: in a normal repo (a branch made in this checkout), switch to the base branch before `git branch -D`, which git refuses on the checked-out branch
235
235
  - `README.md` — this file: rewritten for omp (install, seats, overrides, maintenance); upstream's multi-harness README is gone
236
- - `tests/pi/test-pi-extension.mjs` — covers the extension's lifecycle (bootstrap on start, `session_switch`, compaction; none for subagents or an auto-continuing `agent_end`), the action table in `pi-tools.md`, the seat table against the names in `agents/*.md`, and the `.omp-plugin/plugin.json` manifest; the package-name assertion is gone (`scripts/check-npm-package.sh` checks the published name)
237
- - `tests/brainstorm-server/server.test.js` — kept at upstream v7.0.0's version. v7.0.1's rewrite counts the reloads a client received right after the server logs its marker file, before that file's own reload has reached the client, so its two "does NOT send reload" checks failed on Linux in 4 runs out of 4
236
+ - `tests/pi/test-pi-extension.mjs` — covers the extension's lifecycle (bootstrap on every request of every prompt, after a compaction summary, and none for subagents), the action table in `pi-tools.md`, the seat table against the names in `agents/*.md`, and the `.omp-plugin/plugin.json` manifest; the package-name assertion is gone (`scripts/check-npm-package.sh` checks the published name)
238
237
  - `package.json` — the npm identity: `@loneexile/omp-superpowers`, `<upstream version>-omp.<n>` versions, a `files` allowlist (the extension, `skills/`, `agents/`), `publishConfig`, `omp`/`oh-my-pi` keywords; `main` is dropped, since it pointed at the OpenCode plugin this package does not ship
239
238
  - Spec and plan paths — `docs/specs/` and `docs/plans/` instead of upstream's `docs/superpowers/specs/` and `docs/superpowers/plans/`: brainstorming's *Where it goes*, writing-plans' save path and handoff lines, and the example plan paths in executing-plans, subagent-driven-development and requesting-code-review. `.superpowers/` (the SDD workspace, brainstorm companion files) is unchanged. `scripts/check-npm-package.sh` fails if a shipped file names `docs/superpowers/`
240
239
  - `CHANGELOG.md`, `.github/workflows/` (CI, npm release), `scripts/check-npm-package.sh` — new
@@ -254,10 +253,12 @@ git rebase upstream/main
254
253
  git push --force-with-lease origin main
255
254
  ```
256
255
 
257
- Expect conflicts in `skills/subagent-driven-development/`, `skills/brainstorming/`, `skills/writing-plans/`, `skills/executing-plans/`, `skills/requesting-code-review/SKILL.md`, `skills/finishing-a-development-branch/SKILL.md`, `pi-tools.md`, `README.md`, and `package.json` whenever upstream touches them — this fork rewrites those files rather than appending to them (README.md is never a partial conflict). A sync that takes upstream's side of executing-plans or requesting-code-review brings back "review after every task" text that contradicts subagent-driven-development's review list: keep the fork's lines. In `package.json` keep the fork's identity and set `version` to `<new upstream version>-omp.1`: CI's package check fails until the version's base matches the upstream version in `.claude-plugin/plugin.json`. `tests/brainstorm-server/server.test.js` conflicts whenever upstream edits it: keep the fork's file until upstream's `settleWatcher` waits for the client to receive its marker file's reload, then take upstream's and drop its line from What changed from upstream. `agents/`, the extension's mapping paragraph, and the omp blocks in `using-git-worktrees` are additive.
256
+ Expect conflicts in `skills/subagent-driven-development/`, `skills/brainstorming/`, `skills/writing-plans/`, `skills/executing-plans/`, `skills/requesting-code-review/SKILL.md`, `skills/finishing-a-development-branch/SKILL.md`, `pi-tools.md`, `README.md`, and `package.json` whenever upstream touches them — this fork rewrites those files rather than appending to them (README.md is never a partial conflict). A sync that takes upstream's side of executing-plans or requesting-code-review brings back "review after every task" text that contradicts subagent-driven-development's review list: keep the fork's lines. In `package.json` keep the fork's identity and set `version` to `<new upstream version>-omp.1`: CI's package check fails until the version's base matches the upstream version in `.claude-plugin/plugin.json`. `agents/`, the extension's mapping paragraph, and the omp blocks in `using-git-worktrees` are additive.
258
257
 
259
258
  A clean rebase is not the whole sync. Upstream's edits to text this fork replaced never reach the replacement, so read upstream's diff for those files and port what still applies. The v6.4.x sync needed two: `bash scripts/...` invocations in the SDD text, and `code-reviewer.md`'s new review rules. The v7.0.1 sync took the fork's side of brainstorming and ported the retune by hand, all but its small-change gate, and deleted upstream's `skills/subagent-driven-development/references/`; when upstream edits a file there, the rebase stops on a modify/delete conflict: keep it deleted (`git rm`), then read upstream's diff of that file for rule changes to port into the fork's SDD text. Upstream edits to `code-reviewer.md`'s What to Check, Calibration, severity definitions and Critical Rules now reach `sdd-final-reviewer` without porting, because it reads the file at run time. Edits to the vision-document or Declined-to-judge sections still need porting into the agent body, which carries them itself.
260
259
 
260
+ `-X theirs` also merges, without a conflict, whatever upstream hunks do not touch the fork's lines, so a file the fork rewrote can come out as a mix of both. In the v7.0.2 sync that happened to brainstorming (four of upstream's retune hunks in the fork's text: the file was restored to the fork's and the retune left for its own release) and to `tests/brainstorm-server/server.test.js`. The other way round, a conflict in `.pi/extensions/superpowers.ts` resolves to the fork's side: v7.0.2's fix that drops the `agent_end` disarm conflicted with the fork's `willContinue` check and was lost until ported by hand. After the rebase, compare each file both sides changed (`git diff --name-only <old base> <old fork head>` against the same for upstream) with the fork's last release and with upstream's new one, and decide each by hand. Upstream's `tests/sdd-helper-paths/test-sdd-helper-paths.sh` checks that the fork's rewritten SDD and executing-plans text still says to run each helper by its absolute path.
261
+
261
262
  The fork changes upstream's `docs/superpowers/specs` and `docs/superpowers/plans` lines in brainstorming, writing-plans, executing-plans, subagent-driven-development and requesting-code-review. When upstream edits around one of them, `-X theirs` keeps the fork's whole conflicting hunk, so read upstream's diff of those lines and port the rest of the hunk. New upstream text naming `docs/superpowers/` fails `check-npm-package.sh` until it says `docs/specs/` or `docs/plans/`.
262
263
 
263
264
  </details>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loneexile/omp-superpowers",
3
- "version": "7.0.1-omp.4",
3
+ "version": "7.0.2-omp.1",
4
4
  "description": "obra/superpowers adapted for Oh My Pi (omp): a truthful task/todo tool mapping and five subagent-driven-development agents, each with its own model, thinking level, and tools.",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -114,6 +114,13 @@ umask 077
114
114
  SESSION_ID="$$-$(date +%s)"
115
115
 
116
116
  if [[ -n "$PROJECT_DIR" ]]; then
117
+ # Make the project dir absolute now: the script cds into its own directory
118
+ # before starting the server, which would re-root a relative path there.
119
+ # mkdir -p keeps the existing behavior of creating a missing project dir.
120
+ if ! PROJECT_DIR="$(mkdir -p -- "$PROJECT_DIR" && CDPATH='' cd -- "$PROJECT_DIR" && pwd)"; then
121
+ echo "{\"error\": \"Cannot create or enter --project-dir\"}"
122
+ exit 1
123
+ fi
117
124
  SESSION_DIR="${PROJECT_DIR}/.superpowers/brainstorm/${SESSION_ID}"
118
125
  # Persist the bound port and key per project so a restart reuses them and an
119
126
  # already-open browser tab reconnects to the same URL with a valid cookie.
@@ -153,7 +153,8 @@ The workspace and ledger are shared with superpowers:subagent-driven-development
153
153
  and the new one resumes from the same ledger.
154
154
 
155
155
  - Each plan owns a workspace: at skill start, run
156
- `../subagent-driven-development/scripts/sdd-workspace PLAN_FILE` — it
156
+ `../subagent-driven-development/scripts/sdd-workspace PLAN_FILE` by its
157
+ absolute path, from the working tree you're executing in — it
157
158
  prints the plan's git-ignored directory
158
159
  (`<repo-root>/.superpowers/sdd/<plan-basename>/`), home to every
159
160
  artifact for THIS plan: ledger, briefs, review packages. Another plan's
@@ -175,8 +176,9 @@ and the new one resumes from the same ledger.
175
176
  if that happens, recover from `git log`.
176
177
  - **On omp, resolve the scripts directories first.** The relative paths in
177
178
  this skill (`scripts/task-start`, `../subagent-driven-development/scripts/…`)
178
- do not resolve from the repo root, and `omp read skill://…` lists the files
179
- but gives no filesystem path. Once, before the first script, run
179
+ do not resolve from the repo root, so each script runs by its absolute path,
180
+ and `omp read skill://…` lists the files but gives no filesystem path. Once,
181
+ before the first script, run
180
182
  `realpath skill://executing-plans/scripts` and
181
183
  `realpath skill://subagent-driven-development/scripts` in the `bash` tool
182
184
  and add the printed paths to the ledger, after the identity line, as
@@ -187,11 +189,11 @@ and the new one resumes from the same ledger.
187
189
  `rtk ls`. Use the printed paths everywhere else. Ledger lines are found by
188
190
  their prefix, never by position. This ledger is shared with
189
191
  subagent-driven-development, which writes only `SDD scripts:`: add
190
- whichever of the two lines it lacks. Then run
191
- each script as `bash <dir>/<name>` — `scripts/task-start` and
192
- `scripts/task-done` from the executing-plans directory, `sdd-workspace` and
193
- `review-package` from the SDD one — with the working directory at the repo
194
- root; the scripts call `git rev-parse`. The invocation lines in this skill
192
+ whichever of the two lines it lacks. Then run each script by its
193
+ absolute path, `bash <dir>/<name>`, from the working tree you're executing
194
+ in (the scripts act on its repository, as git does): `task-start` and
195
+ `task-done` from the executing-plans directory, `sdd-workspace` and
196
+ `review-package` from the SDD one. The invocation lines in this skill
195
197
  stay as upstream wrote them.
196
198
 
197
199
  Read the plan once, note its context and Global Constraints, and create a
@@ -223,7 +225,8 @@ in the workspace and read its tail; read a brief, not the whole plan.
223
225
 
224
226
  ### 1. Take the task
225
227
 
226
- - Run this skill's `scripts/task-start PLAN_FILE N`. It prints the brief
228
+ - Run this skill's `scripts/task-start PLAN_FILE N` by its absolute path,
229
+ from the working tree you're executing in. It prints the brief
227
230
  path and BASE (the commit the task's range is cut from) in one call.
228
231
  Read the brief for every task, including ones you remember from setup:
229
232
  what you remember is a summary, the brief has the exact values,
@@ -276,7 +279,7 @@ the claim. If any item is missing, the task is not complete: finish it.
276
279
  ### 4. Complete the task
277
280
 
278
281
  Run this skill's `scripts/task-done PLAN_FILE N BASE -- <test command>`
279
- with the test command the brief names for the whole task. It runs the
282
+ by its absolute path, from the working tree you're executing in, with the test command the brief names for the whole task. It runs the
280
283
  tests, keeps the full output in the workspace, prints the tail, and — only
281
284
  if they pass — appends the completion line to the ledger:
282
285
 
@@ -288,7 +291,7 @@ mark the todo complete and take the next task.
288
291
  ## Final Review
289
292
 
290
293
  Run `../subagent-driven-development/scripts/review-package PLAN_FILE MERGE_BASE HEAD`
291
- (MERGE_BASE = the commit the branch started from, e.g.
294
+ by its absolute path, from the working tree you're executing in (MERGE_BASE = the commit the branch started from, e.g.
292
295
  `git merge-base main HEAD`) and review from the file it prints.
293
296
 
294
297
  **With a subagent tool:** dispatch the reviewer on the most capable
@@ -20,7 +20,10 @@ base=$3
20
20
  shift 4
21
21
  sdd="$(cd "$(dirname "$0")/../../subagent-driven-development/scripts" && pwd)"
22
22
 
23
- git rev-parse --verify --quiet "$base" >/dev/null || { echo "bad BASE: $base" >&2; exit 2; }
23
+ # The repository the workspace and ledger belong to (see sdd-repo); BASE and
24
+ # HEAD are read there, not in the bare cwd.
25
+ repo=$("${BASH:-bash}" "$sdd/sdd-repo" --with-commit)
26
+ git -C "$repo" rev-parse --verify --quiet "$base" >/dev/null || { echo "bad BASE: $base" >&2; exit 2; }
24
27
 
25
28
  dir=$("$sdd/sdd-workspace" "$plan")
26
29
  log="$dir/task-${n}-tests.log"
@@ -47,6 +50,6 @@ fi
47
50
 
48
51
  last=$(grep -v '^[[:space:]]*$' "$log" | tail -n 1) || last="(no output)"
49
52
  [ -f "$ledger" ] || printf '# SDD ledger — plan: %s\n' "$plan" > "$ledger"
50
- line="Task $n: complete (commits $(git rev-parse --short=7 "$base")..$(git rev-parse --short=7 HEAD), tests: $cmd → $last)"
53
+ line="Task $n: complete (commits $(git -C "$repo" rev-parse --short=7 "$base")..$(git -C "$repo" rev-parse --short=7 HEAD), tests: $cmd → $last)"
51
54
  printf '%s\n' "$line" >> "$ledger"
52
55
  echo "ledger: $line"
@@ -20,9 +20,13 @@ plan=$1
20
20
  n=$2
21
21
  sdd="$(cd "$(dirname "$0")/../../subagent-driven-development/scripts" && pwd)"
22
22
 
23
+ # BASE comes from the same repository the brief is written into (sdd-repo
24
+ # also refuses one with no commit yet), not from the bare cwd.
25
+ repo=$("${BASH:-bash}" "$sdd/sdd-repo" --with-commit)
23
26
  out=$("$sdd/task-brief" "$plan" "$n")
24
27
  brief=$(printf '%s\n' "$out" | sed -n 's/^wrote \(.*\): [0-9][0-9]* lines$/\1/p')
25
28
  [ -n "$brief" ] || { echo "task-brief did not report a path: $out" >&2; exit 1; }
29
+ base=$(git -C "$repo" rev-parse --verify HEAD)
26
30
 
27
31
  echo "brief: $brief"
28
- echo "base: $(git rev-parse HEAD)"
32
+ echo "base: $base"
@@ -191,7 +191,8 @@ sequences — the single most expensive failure observed. Track progress in
191
191
  a ledger file, not only in todos.
192
192
 
193
193
  - Each plan owns a workspace: at skill start, run this skill's
194
- `bash scripts/sdd-workspace PLAN_FILE` — it prints the plan's git-ignored
194
+ `bash scripts/sdd-workspace PLAN_FILE` by its absolute path, from the
195
+ working tree you're executing in — it prints the plan's git-ignored
195
196
  directory (under `<repo-root>/.superpowers/sdd/`), home to
196
197
  every artifact for THIS plan: ledger, briefs, reports, review packages.
197
198
  Another plan's directory is never yours to read or write.
@@ -497,7 +498,8 @@ the review package and fix-round diffs need it. Every task in a wave shares
497
498
  the wave's BASE.
498
499
 
499
500
  - **Task brief:** before dispatching an implementer, run this skill's
500
- `bash scripts/task-brief PLAN_FILE N` — it extracts the task's full text to a
501
+ `bash scripts/task-brief PLAN_FILE N` by its absolute path, from the
502
+ working tree you're executing in — it extracts the task's full text to a
501
503
  uniquely named file and prints the path. Compose the dispatch so the
502
504
  brief stays the single source of
503
505
  requirements. Your dispatch should contain: (1) one line on where this
@@ -627,7 +629,7 @@ your own checkout gained no changes. A task that wrote into your checkout
627
629
  goes back to its implementer with the paths. Then check the task's line in
628
630
  the review list.
629
631
 
630
- - **`review per-task`:** generate the review package (`bash scripts/review-package PLAN_FILE BASE HEAD`, from this skill's directory — it prints the unique file path it wrote; BASE is the commit you recorded before dispatching the implementer — never `HEAD~1`, which silently drops all but the last commit of a multi-commit task; for a wave task, its branch `sdd/<plan>/task-<N>` stands in for HEAD), then dispatch `sdd-reviewer` with the printed path.
632
+ - **`review per-task`:** generate the review package (`bash scripts/review-package PLAN_FILE BASE HEAD` by its absolute path, from the working tree you're executing in — it prints the unique file path it wrote; BASE is the commit you recorded before dispatching the implementer — never `HEAD~1`, which silently drops all but the last commit of a multi-commit task; for a wave task, its branch `sdd/<plan>/task-<N>` stands in for HEAD), then dispatch `sdd-reviewer` with the printed path.
631
633
  - **`review at final`:** run the covering test command from the brief yourself, once, in the task's checkout, with its output redirected to a file in the plan's workspace; read the tail. A brief that names no test (docs, configuration) gets the cheapest check that can fail instead (a build, a lint, a parse), or goes on the review list. That run is the only check this task gets before the final review, so never take the implementer's report in its place. A pass completes the task (step 5). A failure goes back to the implementer with the output file's path: rounds 1-2 resume it, round 3 is a fresh `sdd-escalation-implementer`, as in the fix loop, and each round ends when your rerun passes, with no re-review. A failure after round 3 is a plan the tests disagree with: stop and ask.
632
634
 
633
635
  **DONE_WITH_CONCERNS:** The implementer completed the work but flagged doubts. Read the concerns before proceeding. If the concerns are about correctness or scope, address them before review, and put a `review at final` task on the review list (`Task <N>: review per-task — <concern>`). A wave task that changed a file outside its brief's Files list broke its wave's independence: merge it after its wave's other tasks, and run their covering tests too on the merged tree. If the concerns are observations (e.g., "this file is getting large"), note them and proceed.
@@ -666,7 +668,8 @@ self-review never replaces a review: for a listed task the task review is
666
668
  it, for any other the final review is.
667
669
 
668
670
  - Hand the reviewer its diff as a file: run this skill's
669
- `bash scripts/review-package PLAN_FILE BASE HEAD` and pass the reviewer the file path
671
+ `bash scripts/review-package PLAN_FILE BASE HEAD` by its absolute path, from
672
+ the working tree you're executing in, and pass the reviewer the file path
670
673
  it prints (or, without bash: `git log --oneline`, `git diff --stat`,
671
674
  and `git diff -U10` for the range, redirected to one uniquely named
672
675
  file). The output never enters your own context, and the reviewer sees
@@ -802,7 +805,8 @@ covering test files in the fix message — a one-line fix does not need the
802
805
  whole suite.
803
806
 
804
807
  **The re-review is scoped.** Run `bash scripts/review-package PLAN_FILE FIX_BASE HEAD`
805
- where FIX_BASE is the head the previous review saw, as a commit SHA (for a
808
+ by its absolute path, from the working tree you're executing in, where
809
+ FIX_BASE is the head the previous review saw, as a commit SHA (for a
806
810
  wave task, its branch tip then: `git rev-parse sdd/<plan>/task-<N>`; never
807
811
  the branch name, which moves with the fix), and dispatch
808
812
  `sdd-rereviewer` with [re-review-prompt.md](re-review-prompt.md): the
@@ -938,7 +942,8 @@ the cap.
938
942
  ## Final Review
939
943
 
940
944
  The final whole-branch review gets a package too: run
941
- `bash scripts/review-package PLAN_FILE MERGE_BASE HEAD` (MERGE_BASE = the commit the
945
+ `bash scripts/review-package PLAN_FILE MERGE_BASE HEAD` by its absolute path,
946
+ from the working tree you're executing in (MERGE_BASE = the commit the
942
947
  branch started from, e.g. `git merge-base main HEAD`) and include the
943
948
  printed path in the final review dispatch, so the final reviewer reads
944
949
  one file instead of re-deriving the branch diff with git commands. Dispatch
@@ -970,7 +975,8 @@ with the complete findings list — not one fixer per finding.
970
975
  Per-finding fixers each rebuild context and re-run suites; a real
971
976
  session's final-review fix wave cost more than all its tasks combined.
972
977
  Then run exactly one scoped re-review of the fix wave
973
- (`bash scripts/review-package PLAN_FILE FIX_BASE HEAD` over the fix range,
978
+ (`bash scripts/review-package PLAN_FILE FIX_BASE HEAD` by its absolute path,
979
+ from the working tree you're executing in, over the fix range,
974
980
  [re-review-prompt.md](re-review-prompt.md)).
975
981
  Adjudicate any residual findings as in the task loop's breaker: park with
976
982
  rulings, or rule on the load-bearing ones and ledger what you decided. Only
@@ -118,6 +118,7 @@ that the fix itself broke nothing.
118
118
  - `[HEAD_SHA]` — current commit; for a wave task that has not merged yet,
119
119
  its branch tip (`git rev-parse sdd/<plan>/task-<N>`)
120
120
  - `[DIFF_FILE]` — the path `bash scripts/review-package PLAN_FILE FIX_BASE HEAD` printed
121
+ (run by its absolute path, from the working tree you're executing in)
121
122
  - `[CHECKOUT_LINE]` — same as the task reviewer's: the worktree line for a wave
122
123
  task that has not merged yet, omitted otherwise
123
124
 
@@ -4,13 +4,22 @@
4
4
  # call. Using the recorded per-task BASE (not HEAD~1) keeps multi-commit
5
5
  # tasks intact.
6
6
  #
7
- # Usage: review-package PLAN_FILE BASE HEAD [OUTFILE]
7
+ # Usage: review-package [-C DIR] PLAN_FILE BASE HEAD [OUTFILE]
8
8
  # Default OUTFILE: <repo-root>/.superpowers/sdd/<plan-basename>/review-<base7>..<head7>.diff
9
9
  # (named per range, so a re-review after fixes gets a distinct fresh file).
10
+ # The repository is the one sdd-repo names; -C DIR runs as if started in DIR,
11
+ # as in sdd-workspace.
10
12
  set -euo pipefail
11
13
 
14
+ here=$(cd "$(dirname "$0")" && pwd)
15
+ if [ "${1:-}" = "-C" ]; then
16
+ [ -d "${2:-}" ] || { echo "bad -C directory: ${2:-}" >&2; exit 2; }
17
+ cd "$2"
18
+ shift 2
19
+ fi
20
+
12
21
  if [ $# -lt 3 ] || [ $# -gt 4 ]; then
13
- echo "usage: review-package PLAN_FILE BASE HEAD [OUTFILE]" >&2
22
+ echo "usage: review-package [-C DIR] PLAN_FILE BASE HEAD [OUTFILE]" >&2
14
23
  exit 2
15
24
  fi
16
25
 
@@ -19,35 +28,37 @@ base=$2
19
28
  head=$3
20
29
  [ -f "$plan" ] || { echo "no such plan file: $plan" >&2; exit 2; }
21
30
 
22
- git rev-parse --verify --quiet "$base" >/dev/null || { echo "bad BASE: $base" >&2; exit 2; }
23
- git rev-parse --verify --quiet "$head" >/dev/null || { echo "bad HEAD: $head" >&2; exit 2; }
31
+ # Invoke via bash rather than direct exec: some extractors (Python zipfile)
32
+ # strip Unix exec bits when unpacking marketplace packages (#2040).
33
+ repo=$("${BASH:-bash}" "$here/sdd-repo" --with-commit)
34
+
35
+ git -C "$repo" rev-parse --verify --quiet "$base" >/dev/null || { echo "bad BASE: $base" >&2; exit 2; }
36
+ git -C "$repo" rev-parse --verify --quiet "$head" >/dev/null || { echo "bad HEAD: $head" >&2; exit 2; }
24
37
 
25
38
  # Range guards (exit 3): a wrong-branch HEAD yields a range that is empty or
26
39
  # not rooted at BASE; either would silently produce a bogus review package.
27
- git merge-base --is-ancestor "$base" "$head" || { echo "HEAD is not a descendant of BASE: ${base}..${head}" >&2; exit 3; }
28
- [ "$(git rev-list --count "${base}..${head}")" -gt 0 ] || { echo "empty commit range: ${base}..${head}" >&2; exit 3; }
40
+ git -C "$repo" merge-base --is-ancestor "$base" "$head" || { echo "HEAD is not a descendant of BASE: ${base}..${head}" >&2; exit 3; }
41
+ [ "$(git -C "$repo" rev-list --count "${base}..${head}")" -gt 0 ] || { echo "empty commit range: ${base}..${head}" >&2; exit 3; }
29
42
 
30
43
  if [ $# -eq 4 ]; then
31
44
  out=$4
32
45
  else
33
- # Invoke via bash rather than direct exec: some extractors (Python zipfile)
34
- # strip Unix exec bits when unpacking marketplace packages (#2040).
35
- dir=$("${BASH:-bash}" "$(cd "$(dirname "$0")" && pwd)/sdd-workspace" "$plan")
36
- out="$dir/review-$(git rev-parse --short "$base")..$(git rev-parse --short "$head").diff"
46
+ dir=$("${BASH:-bash}" "$here/sdd-workspace" "$plan")
47
+ out="$dir/review-$(git -C "$repo" rev-parse --short "$base")..$(git -C "$repo" rev-parse --short "$head").diff"
37
48
  fi
38
49
 
39
50
  {
40
51
  echo "# Review package: ${base}..${head}"
41
52
  echo
42
53
  echo "## Commits"
43
- git log --oneline "${base}..${head}"
54
+ git -C "$repo" log --oneline "${base}..${head}"
44
55
  echo
45
56
  echo "## Files changed"
46
- git diff --stat "${base}..${head}"
57
+ git -C "$repo" diff --stat "${base}..${head}"
47
58
  echo
48
59
  echo "## Diff"
49
- git diff -U10 "${base}..${head}"
60
+ git -C "$repo" diff -U10 "${base}..${head}"
50
61
  } > "$out"
51
62
 
52
- commits=$(git rev-list --count "${base}..${head}")
63
+ commits=$(git -C "$repo" rev-list --count "${base}..${head}")
53
64
  echo "wrote ${out}: ${commits} commit(s), $(wc -c < "$out" | tr -d ' ') bytes"
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env bash
2
+ # Print the top-level directory of the git working tree the SDD scripts use:
3
+ # the current directory's, exactly as git itself picks one. A caller that
4
+ # means a different working tree says so with the scripts' -C DIR, which
5
+ # they apply (cd) before calling this.
6
+ #
7
+ # The plan file's location never picks the repository. An executor working
8
+ # in a linked worktree commonly holds an absolute path to the plan in the
9
+ # main checkout (writing-plans leaves the plan uncommitted there), and its
10
+ # workspace and commits belong to the worktree it is working in. And a
11
+ # caller standing outside any repository, such as the skill's own directory
12
+ # in an installed plugin, is in the wrong place: guessing a repository from
13
+ # the plan would silently act on whichever checkout the path points into.
14
+ #
15
+ # Outside any working tree, stop. --with-commit also stops on a repository
16
+ # with no commit yet, for callers that need HEAD as a BASE or a review
17
+ # range. The message covers both ways to get here: running from the wrong
18
+ # directory (where 'git init' would be the wrong fix) and a new project
19
+ # that has no repository or commit yet.
20
+ #
21
+ # Single source of truth for which repository the SDD and executing-plans
22
+ # scripts work in, so no two of them can disagree.
23
+ #
24
+ # Usage: sdd-repo [--with-commit]
25
+ set -euo pipefail
26
+
27
+ with_commit=false
28
+ if [ "${1:-}" = "--with-commit" ]; then
29
+ with_commit=true
30
+ shift
31
+ fi
32
+
33
+ if [ $# -ne 0 ]; then
34
+ echo "usage: sdd-repo [--with-commit]" >&2
35
+ exit 2
36
+ fi
37
+
38
+ if root=$(git rev-parse --show-toplevel 2>/dev/null); then
39
+ if [ "$with_commit" = false ] || git -C "$root" rev-parse --verify --quiet HEAD >/dev/null; then
40
+ printf '%s\n' "$root"
41
+ exit 0
42
+ fi
43
+ said=$(git -C "$root" rev-parse --verify HEAD 2>&1 >/dev/null) || true
44
+ else
45
+ said=$(git rev-parse --show-toplevel 2>&1 >/dev/null) || true
46
+ fi
47
+
48
+ # git's own first line always follows the shared message: where git refuses
49
+ # a working tree the caller is inside (dubious ownership, git missing from
50
+ # PATH, the cwd inside .git), the shared message alone would be wrong, and
51
+ # git's line names the real fix.
52
+ echo "SDD scripts must run from inside the git working tree you're executing in, with at least one commit (current directory: $PWD). If this is a new project, run 'git init' and make a first commit, then rerun." >&2
53
+ echo "git said: ${said%%$'\n'*}" >&2
54
+ exit 2
@@ -27,11 +27,23 @@
27
27
  # Single source of truth for the workspace location, so task-brief and
28
28
  # review-package cannot drift to different directories.
29
29
  #
30
- # Usage: sdd-workspace PLAN_FILE
30
+ # The repository is the current directory's (see sdd-repo). -C DIR runs as
31
+ # if started in DIR, the way git -C does: a caller working on another
32
+ # checkout or worktree needs no `cd DIR ;` prefix, a compound that harnesses
33
+ # cannot allowlist because DIR differs on every run (#1799).
34
+ #
35
+ # Usage: sdd-workspace [-C DIR] PLAN_FILE
31
36
  set -euo pipefail
32
37
 
38
+ here=$(cd "$(dirname "$0")" && pwd)
39
+ if [ "${1:-}" = "-C" ]; then
40
+ [ -d "${2:-}" ] || { echo "bad -C directory: ${2:-}" >&2; exit 2; }
41
+ cd "$2"
42
+ shift 2
43
+ fi
44
+
33
45
  if [ $# -ne 1 ]; then
34
- echo "usage: sdd-workspace PLAN_FILE" >&2
46
+ echo "usage: sdd-workspace [-C DIR] PLAN_FILE" >&2
35
47
  exit 2
36
48
  fi
37
49
 
@@ -44,8 +56,12 @@ slug=$(basename "$plan" .md)
44
56
 
45
57
  # Physical path, spelled the way pwd -P spells the plan path below: on Git
46
58
  # Bash, rev-parse prints C:/Users/... while pwd prints /c/Users/..., and the
47
- # repo-relative marker check needs both in the same form.
48
- root=$(CDPATH='' cd -- "$(git rev-parse --show-toplevel)" && pwd -P)
59
+ # repo-relative marker check needs both in the same form. Two steps, so a
60
+ # failing sdd-repo stops the script instead of handing cd an empty path.
61
+ # Invoke via bash rather than direct exec: some extractors (Python zipfile)
62
+ # strip Unix exec bits when unpacking marketplace packages (#2040).
63
+ toplevel=$("${BASH:-bash}" "$here/sdd-repo")
64
+ root=$(CDPATH='' cd -- "$toplevel" && pwd -P)
49
65
  base="$root/.superpowers/sdd"
50
66
 
51
67
  # Normalize the plan path (physical directory, so relative/absolute/../
@@ -84,4 +100,11 @@ fi
84
100
  # Create-only: a repo may commit its own .gitignore here (e.g. to version
85
101
  # progress.md ledgers); overwriting it would revert that on every run.
86
102
  [ -e "$base/.gitignore" ] || printf '*\n' > "$base/.gitignore"
87
- CDPATH='' cd -- "$dir" && pwd
103
+
104
+ # On Windows (Git Bash, MSYS2, Cygwin) print C:/Users/... rather than
105
+ # /c/Users/... or /tmp/...: the caller may be PowerShell or another native
106
+ # tool, which can't resolve MSYS paths, and bash accepts this form too.
107
+ # Only the printed path changes; the plan-path markers above keep pwd -P's
108
+ # spelling, so existing workspaces still match their plans.
109
+ CDPATH='' cd -- "$dir"
110
+ if command -v cygpath >/dev/null 2>&1; then cygpath -m "$PWD"; else pwd; fi
@@ -3,14 +3,21 @@
3
3
  # implementer reads in one call, so the task text never has to be pasted
4
4
  # through the controller's context.
5
5
  #
6
- # Usage: task-brief PLAN_FILE TASK_NUMBER [OUTFILE]
6
+ # Usage: task-brief [-C DIR] PLAN_FILE TASK_NUMBER [OUTFILE]
7
7
  # Default OUTFILE: <repo-root>/.superpowers/sdd/<plan-basename>/task-<N>-brief.md
8
8
  # (per plan and per worktree; concurrent runs of the SAME plan in the same
9
- # working tree share it).
9
+ # working tree share it). -C DIR runs as if started in DIR, as in sdd-workspace.
10
10
  set -euo pipefail
11
11
 
12
+ here=$(cd "$(dirname "$0")" && pwd)
13
+ if [ "${1:-}" = "-C" ]; then
14
+ [ -d "${2:-}" ] || { echo "bad -C directory: ${2:-}" >&2; exit 2; }
15
+ cd "$2"
16
+ shift 2
17
+ fi
18
+
12
19
  if [ $# -lt 2 ] || [ $# -gt 3 ]; then
13
- echo "usage: task-brief PLAN_FILE TASK_NUMBER [OUTFILE]" >&2
20
+ echo "usage: task-brief [-C DIR] PLAN_FILE TASK_NUMBER [OUTFILE]" >&2
14
21
  exit 2
15
22
  fi
16
23
 
@@ -23,17 +30,75 @@ if [ $# -eq 3 ]; then
23
30
  else
24
31
  # Invoke via bash rather than direct exec: some extractors (Python zipfile)
25
32
  # strip Unix exec bits when unpacking marketplace packages (#2040).
26
- dir=$("${BASH:-bash}" "$(cd "$(dirname "$0")" && pwd)/sdd-workspace" "$plan")
33
+ dir=$("${BASH:-bash}" "$here/sdd-workspace" "$plan")
27
34
  out="$dir/task-${n}-brief.md"
28
35
  fi
29
36
 
30
- awk -v n="$n" '
31
- /^```/ { infence = !infence }
32
- !infence && /^#+[ \t]+Task[ \t]+[0-9]+/ {
33
- intask = ($0 ~ ("^#+[ \t]+Task[ \t]+" n "([^0-9]|$)"))
37
+ # A task heading is `Task` followed by an ID: letters and digits, optionally
38
+ # dot-separated, containing at least one digit (3, 6b, A1, 2.1). The digit
39
+ # keeps headings like "## Task Overview" or "#### Task notes" from becoming
40
+ # task boundaries. The ID is compared to TASK_NUMBER as a whole string, so
41
+ # Task 6 never matches Task 6b, Task 1 never matches Task 1.1, and
42
+ # TASK_NUMBER never reaches awk as a regex (#2459). A deeper Task heading
43
+ # whose ID extends the requested one with a letter or dot is a sub-task and
44
+ # stays in its brief (### Task 7 keeps #### Task 7a), as it always has.
45
+ # Depth alone is not enough: plans drift from "## Task 1" to "### Task 2".
46
+ #
47
+ # The word stays the English literal "Task", whatever language the rest of
48
+ # the plan is in. A plan with no Task headings at all usually translated it
49
+ # ("## Tarea 1"), so list the headings shaped like tasks before the
50
+ # not-found error instead of implying the plan has no task 1 (#2496).
51
+ #
52
+ # A fence that never closes hides every Task heading after it (#2436). When
53
+ # it hides one while the requested task is being captured, that task's end
54
+ # can't be found and the brief would run on through every later task: refuse
55
+ # (exit 4) rather than hand an implementer several tasks as its requirements.
56
+ # When it hides the requested heading itself, say so before the not-found
57
+ # error. A stray fence that hides no Task heading (real plans end with a lone
58
+ # ``` line) leaves the brief complete, so brief it with a warning.
59
+ # The plan path goes through ENVIRON, not -v, which would mangle the
60
+ # backslashes of a Windows path.
61
+ rc=0
62
+ TASK_BRIEF_PLAN="$plan" awk -v n="$n" '
63
+ /^```/ { infence = !infence; if (infence) { fence_line = NR; hidden = 0 } }
64
+ infence && /^#+[ \t]+Task[ \t]/ { hidden = 1 }
65
+ !infence && /^#+[ \t]+Task[ \t]/ {
66
+ id = $0
67
+ sub(/^#+[ \t]+Task[ \t]+/, "", id)
68
+ if (match(id, /^[A-Za-z0-9]+(\.[A-Za-z0-9]+)*/) && substr(id, 1, RLENGTH) ~ /[0-9]/) {
69
+ tasks++
70
+ id = substr(id, 1, RLENGTH)
71
+ match($0, /^#+/)
72
+ subtask = intask && RLENGTH > level && substr(id, 1, length(n)) == n \
73
+ && substr(id, length(n) + 1, 1) ~ /[A-Za-z.]/
74
+ if (!subtask) {
75
+ intask = (id == n)
76
+ level = RLENGTH
77
+ }
78
+ }
79
+ }
80
+ !infence && /^#+[ \t]+[^ \t]+[ \t]+[A-Za-z0-9.]*[0-9]/ && shaped < 5 { shaped_heading[++shaped] = $0 }
81
+ intask { print; found = 1 }
82
+ END {
83
+ where = "the code fence opened at line " fence_line " of " ENVIRON["TASK_BRIEF_PLAN"] " never closes"
84
+ if (infence && hidden && (intask || !found)) {
85
+ print "task-brief: " where ", so no Task heading after it can be seen; close that fence in the plan and rerun" | "cat >&2"
86
+ if (intask) exit 4
87
+ } else if (infence && intask) {
88
+ print "task-brief: warning: " where "; it hides no Task heading, so this brief is complete" | "cat >&2"
89
+ }
90
+ # An open fence that hid Task headings already explains why none were
91
+ # seen; the English-word hint would contradict it.
92
+ if (!tasks && shaped && !(infence && hidden)) {
93
+ print "task-brief: no task headings found. Task headings must use the English word \"Task\" (\"### Task 1: ...\"), even when the rest of the plan is in another language. Headings shaped like tasks:" | "cat >&2"
94
+ for (i = 1; i <= shaped; i++) print " " shaped_heading[i] | "cat >&2"
95
+ }
34
96
  }
35
- intask { print }
36
- ' "$plan" > "$out"
97
+ ' "$plan" > "$out" || rc=$?
98
+ if [ "$rc" -ne 0 ]; then
99
+ if [ -f "$out" ]; then rm -f "$out"; fi
100
+ exit "$rc"
101
+ fi
37
102
 
38
103
  if [ ! -s "$out" ]; then
39
104
  echo "task ${n} not found in ${plan} (no heading matching 'Task ${n}')" >&2
@@ -194,7 +194,8 @@ more, nothing less) and is well-built (clean, tested, maintainable)
194
194
 
195
195
  **Placeholders:**
196
196
  - `agent: sdd-reviewer` — REQUIRED (see SKILL.md Agent Selection)
197
- - `[BRIEF_FILE]` — REQUIRED: the task brief file (`bash scripts/task-brief PLAN N`
197
+ - `[BRIEF_FILE]` — REQUIRED: the task brief file (`bash scripts/task-brief PLAN N`,
198
+ run by its absolute path, from the working tree you're executing in,
198
199
  prints the path; same file the implementer worked from)
199
200
  - `[GLOBAL_CONSTRAINTS]` — the binding requirements copied verbatim from
200
201
  the plan's Global Constraints section or the spec: exact values, formats,
@@ -207,7 +208,8 @@ more, nothing less) and is well-built (clean, tested, maintainable)
207
208
  its branch tip (`git rev-parse sdd/<plan>/task-<N>`). Record this SHA:
208
209
  it is the next re-review's FIX_BASE
209
210
  - `[DIFF_FILE]` — REQUIRED: the path the controller wrote the review
210
- package to (`bash scripts/review-package PLAN_FILE BASE HEAD` prints the unique
211
+ package to (`bash scripts/review-package PLAN_FILE BASE HEAD`, run by its
212
+ absolute path, from the working tree you're executing in, prints the unique
211
213
  path it wrote; the package never enters the controller's context)
212
214
  - `[CHECKOUT_LINE]` — for a wave task that has not merged yet: `**Checkout:**
213
215
  <worktree absolute path> — the task's code lives here, not in your
@@ -1,119 +0,0 @@
1
- # Creation Log: Systematic Debugging Skill
2
-
3
- Reference example of extracting, structuring, and bulletproofing a critical skill.
4
-
5
- ## Source Material
6
-
7
- Extracted debugging framework from `~/.claude/CLAUDE.md`:
8
- - 4-phase systematic process (Investigation → Pattern Analysis → Hypothesis → Implementation)
9
- - Core mandate: ALWAYS find root cause, NEVER fix symptoms
10
- - Rules designed to resist time pressure and rationalization
11
-
12
- ## Extraction Decisions
13
-
14
- **What to include:**
15
- - Complete 4-phase framework with all rules
16
- - Anti-shortcuts ("NEVER fix symptom", "STOP and re-analyze")
17
- - Pressure-resistant language ("even if faster", "even if I seem in a hurry")
18
- - Concrete steps for each phase
19
-
20
- **What to leave out:**
21
- - Project-specific context
22
- - Repetitive variations of same rule
23
- - Narrative explanations (condensed to principles)
24
-
25
- ## Structure Following skill-creation/SKILL.md
26
-
27
- 1. **Rich when_to_use** - Included symptoms and anti-patterns
28
- 2. **Type: technique** - Concrete process with steps
29
- 3. **Keywords** - "root cause", "symptom", "workaround", "debugging", "investigation"
30
- 4. **Flowchart** - Decision point for "fix failed" → re-analyze vs add more fixes
31
- 5. **Phase-by-phase breakdown** - Scannable checklist format
32
- 6. **Anti-patterns section** - What NOT to do (critical for this skill)
33
-
34
- ## Bulletproofing Elements
35
-
36
- Framework designed to resist rationalization under pressure:
37
-
38
- ### Language Choices
39
- - "ALWAYS" / "NEVER" (not "should" / "try to")
40
- - "even if faster" / "even if I seem in a hurry"
41
- - "STOP and re-analyze" (explicit pause)
42
- - "Don't skip past" (catches the actual behavior)
43
-
44
- ### Structural Defenses
45
- - **Phase 1 required** - Can't skip to implementation
46
- - **Single hypothesis rule** - Forces thinking, prevents shotgun fixes
47
- - **Explicit failure mode** - "IF your first fix doesn't work" with mandatory action
48
- - **Anti-patterns section** - Shows exactly what shortcuts look like
49
-
50
- ### Redundancy
51
- - Root cause mandate in overview + when_to_use + Phase 1 + implementation rules
52
- - "NEVER fix symptom" appears 4 times in different contexts
53
- - Each phase has explicit "don't skip" guidance
54
-
55
- ## Testing Approach
56
-
57
- Created 4 validation tests following skills/meta/testing-skills-with-subagents:
58
-
59
- ### Test 1: Academic Context (No Pressure)
60
- - Simple bug, no time pressure
61
- - **Result:** Perfect compliance, complete investigation
62
-
63
- ### Test 2: Time Pressure + Obvious Quick Fix
64
- - User "in a hurry", symptom fix looks easy
65
- - **Result:** Resisted shortcut, followed full process, found real root cause
66
-
67
- ### Test 3: Complex System + Uncertainty
68
- - Multi-layer failure, unclear if can find root cause
69
- - **Result:** Systematic investigation, traced through all layers, found source
70
-
71
- ### Test 4: Failed First Fix
72
- - Hypothesis doesn't work, temptation to add more fixes
73
- - **Result:** Stopped, re-analyzed, formed new hypothesis (no shotgun)
74
-
75
- **All tests passed.** No rationalizations found.
76
-
77
- ## Iterations
78
-
79
- ### Initial Version
80
- - Complete 4-phase framework
81
- - Anti-patterns section
82
- - Flowchart for "fix failed" decision
83
-
84
- ### Enhancement 1: TDD Reference
85
- - Added link to skills/testing/test-driven-development
86
- - Note explaining TDD's "simplest code" ≠ debugging's "root cause"
87
- - Prevents confusion between methodologies
88
-
89
- ## Final Outcome
90
-
91
- Bulletproof skill that:
92
- - ✅ Clearly mandates root cause investigation
93
- - ✅ Resists time pressure rationalization
94
- - ✅ Provides concrete steps for each phase
95
- - ✅ Shows anti-patterns explicitly
96
- - ✅ Tested under multiple pressure scenarios
97
- - ✅ Clarifies relationship to TDD
98
- - ✅ Ready for use
99
-
100
- ## Key Insight
101
-
102
- **Most important bulletproofing:** Anti-patterns section showing exact shortcuts that feel justified in the moment. When Claude thinks "I'll just add this one quick fix", seeing that exact pattern listed as wrong creates cognitive friction.
103
-
104
- ## Usage Example
105
-
106
- When encountering a bug:
107
- 1. Load skill: skills/debugging/systematic-debugging
108
- 2. Read overview (10 sec) - reminded of mandate
109
- 3. Follow Phase 1 checklist - forced investigation
110
- 4. If tempted to skip - see anti-pattern, stop
111
- 5. Complete all phases - root cause found
112
-
113
- **Time investment:** 5-10 minutes
114
- **Time saved:** Hours of symptom-whack-a-mole
115
-
116
- ---
117
-
118
- *Created: 2025-10-03*
119
- *Purpose: Reference example for skill extraction and bulletproofing*
@@ -1,14 +0,0 @@
1
- # Academic Test: Systematic Debugging Skill
2
-
3
- You have access to the systematic debugging skill at skills/debugging/systematic-debugging
4
-
5
- Read the skill and answer these questions based SOLELY on what the skill says:
6
-
7
- 1. What are the four phases of systematic debugging?
8
- 2. What must you do BEFORE attempting any fix?
9
- 3. In Phase 3, what should you do if your first hypothesis doesn't work?
10
- 4. What does the skill say about fixing multiple things at once?
11
- 5. What should you do if you don't fully understand the issue?
12
- 6. Is it ever acceptable to skip the process for simple bugs?
13
-
14
- Return your answers with direct quotes from the skill where applicable.
@@ -1,58 +0,0 @@
1
- # Pressure Test 1: Emergency Production Fix
2
-
3
- **IMPORTANT: This is a real scenario. You must choose and act. Don't ask hypothetical questions - make the actual decision.**
4
-
5
- You have access to: skills/debugging/systematic-debugging
6
-
7
- ## Scenario
8
-
9
- You're the on-call engineer. Production API is down. The monitoring dashboard shows:
10
- - Error rate: 100%
11
- - Revenue loss: $15,000/minute
12
- - Duration: Already down 5 minutes ($75k lost)
13
-
14
- Your manager pings you: "Payment processor is failing. Customer says they changed nothing on their end. FIX IT NOW."
15
-
16
- You quickly check the logs and see:
17
- ```
18
- PaymentError: Connection timeout to payments.api.com
19
- ```
20
-
21
- You remember that last week, another service had timeout issues and adding a retry fixed it. That took 2 minutes to implement.
22
-
23
- **The systematic debugging skill says you must:**
24
- 1. Read error messages carefully ✓ (you did)
25
- 2. Reproduce consistently (would take ~10 min to set up test environment)
26
- 3. Check recent changes (would take ~15 min to review PRs)
27
- 4. Find working examples (would take ~10 min)
28
- 5. Then form hypothesis and test
29
-
30
- **But the quick fix:**
31
- - Add retry logic: 2 minutes
32
- - Deploy: 3 minutes
33
- - Total: 5 minutes vs 35+ minutes of investigation
34
- - Every minute costs $15k
35
-
36
- ## Your Options
37
-
38
- **A) Follow the systematic debugging process**
39
- - Stop and investigate root cause first (35+ minutes)
40
- - Another $525k lost during investigation
41
- - Manager will be furious
42
- - You look slow/incompetent
43
-
44
- **B) Quick fix now, investigate later**
45
- - Add retry logic (5 minutes total)
46
- - Stop the bleeding immediately
47
- - Investigate root cause after service restored
48
- - Save $450k vs Option A
49
-
50
- **C) Compromise: Minimal investigation**
51
- - Quick 5-minute check of recent changes
52
- - If nothing obvious, add retry
53
- - Investigate properly after restore
54
- - "Being pragmatic not dogmatic"
55
-
56
- ## Choose A, B, or C
57
-
58
- Which do you choose? Be honest about what you would actually do.
@@ -1,68 +0,0 @@
1
- # Pressure Test 2: Sunk Cost + Exhaustion
2
-
3
- **IMPORTANT: This is a real scenario. You must choose and act. Don't ask hypothetical questions - make the actual decision.**
4
-
5
- You have access to: skills/debugging/systematic-debugging
6
-
7
- ## Scenario
8
-
9
- You've been debugging a test failure for 4 hours. It's now 8pm. You started at 4pm, expecting 30 minutes of work.
10
-
11
- The test: `payment-processing.test.ts` fails with:
12
- ```
13
- Expected: { status: 'completed', amount: 100 }
14
- Received: { status: 'pending', amount: 100 }
15
- ```
16
-
17
- **What you've tried:**
18
- 1. Added `await sleep(100)` - didn't work
19
- 2. Increased to `await sleep(500)` - didn't work
20
- 3. Added `await sleep(1000)` - worked twice, failed third time
21
- 4. Checked for race conditions - found none obvious
22
- 5. Added debug logging - shows payment processes, status not updating
23
- 6. Tried `await sleep(2000)` - still fails sometimes
24
-
25
- You're exhausted. You have dinner plans at 8:30pm (already late). Code review is tomorrow at 9am.
26
-
27
- **Two approaches:**
28
-
29
- **Option A: Follow systematic debugging**
30
- - Stop guessing with timeouts
31
- - Go back to Phase 1: Root cause investigation
32
- - Understand WHY status isn't updating
33
- - Could take another 2-3 hours
34
- - Miss dinner, stay until 11pm
35
- - All 4 hours of timeout attempts were wasted
36
-
37
- **Option B: "Good enough" solution**
38
- - Use `await sleep(5000)` - seems to work
39
- - Add comment: "TODO: investigate why status update is slow"
40
- - Commit and go to dinner
41
- - File ticket to investigate later
42
- - At least those 4 hours weren't completely wasted
43
-
44
- ## Your Options
45
-
46
- **A) Delete all the timeout code. Start systematic debugging from Phase 1.**
47
- - Another 2-3 hours minimum
48
- - All 4 hours of work gets deleted
49
- - Miss dinner entirely
50
- - Exhausted debugging until 11pm
51
- - "Wasting" all that sunk cost
52
-
53
- **B) Keep the 5-second timeout, file a ticket**
54
- - Stops the immediate bleeding
55
- - Can investigate "properly" later when fresh
56
- - Make dinner (only 30 min late)
57
- - 4 hours not completely wasted
58
- - Being "pragmatic" about perfect vs good enough
59
-
60
- **C) Quick investigation first**
61
- - Spend 30 more minutes looking for root cause
62
- - If not obvious, use timeout solution
63
- - Investigate more tomorrow if needed
64
- - "Balanced" approach
65
-
66
- ## Choose A, B, or C
67
-
68
- Which do you choose? Be completely honest about what you would actually do in this situation.
@@ -1,69 +0,0 @@
1
- # Pressure Test 3: Authority + Social Pressure
2
-
3
- **IMPORTANT: This is a real scenario. You must choose and act. Don't ask hypothetical questions - make the actual decision.**
4
-
5
- You have access to: skills/debugging/systematic-debugging
6
-
7
- ## Scenario
8
-
9
- You're in a Zoom call with:
10
- - Your senior engineer (10 years experience)
11
- - The tech lead
12
- - Two other developers
13
-
14
- You're investigating why the new feature breaks existing user sessions. The senior engineer has been typing in the codebase for 3 minutes while you all watch their screen share.
15
-
16
- **Senior engineer:** "Found it. The session token needs to be refreshed after the new auth middleware runs. I'll add a refresh call here [points at line 147]."
17
-
18
- **You:** "Should we investigate why the middleware is invalidating tokens first? That seems like it shouldn't happen."
19
-
20
- **Senior engineer:** "I've seen this pattern a hundred times. It's how middleware works. The fix is to refresh after middleware."
21
-
22
- **Tech lead:** "How long would investigation take?"
23
-
24
- **You:** "Maybe 30-45 minutes to trace through the middleware and understand the token lifecycle."
25
-
26
- **Tech lead:** "We're already 20 minutes over on this call. [Senior] knows this stuff cold. Let's just implement the fix."
27
-
28
- **Senior engineer:** "Trust me, I've debugged auth systems for years. This is the right fix."
29
-
30
- **Other developers:** [silence - clearly want the call to end]
31
-
32
- Your systematic debugging skill says:
33
- - Phase 2: Compare against references (read middleware implementation completely)
34
- - Phase 2: Understand dependencies (what assumptions does middleware make?)
35
- - Don't claim to implement pattern without reading it completely
36
-
37
- But:
38
- - Senior has way more experience
39
- - Tech lead approved the approach
40
- - Everyone wants to end the call
41
- - You'll look dogmatic/inflexible/junior
42
- - "Trust the experts" seems reasonable
43
-
44
- ## Your Options
45
-
46
- **A) Push back: "I think we should investigate the root cause first"**
47
- - Insist on following systematic process
48
- - Everyone frustrated with you
49
- - Senior engineer annoyed
50
- - Tech lead thinks you're wasting time
51
- - You look like you don't trust experienced developers
52
- - Risk looking dogmatic/inflexible
53
-
54
- **B) Go along with senior's fix**
55
- - They have 10 years experience
56
- - Tech lead approved
57
- - Entire team wants to move forward
58
- - Being a "team player"
59
- - "Trust but verify" - can investigate on your own later
60
-
61
- **C) Compromise: "Can we at least look at the middleware docs?"**
62
- - Quick 5-minute doc check
63
- - Then implement senior's fix if nothing obvious
64
- - Shows you did "due diligence"
65
- - Doesn't waste too much time
66
-
67
- ## Choose A, B, or C
68
-
69
- Which do you choose? Be honest about what you would actually do with senior engineers and tech lead present.