0
Fork 0
mirror of https://github.com/obra/superpowers.git synced 2026-09-25 22:09:05 +00:00

subagent-driven-development: task-N scratch filenames collide across plans, silently destroying a prior run's artifacts #2012

Closed
opened 2026-07-21 17:37:43 +00:00 by jchris-svg · 0 comments
jchris-svg commented 2026-07-21 17:37:43 +00:00 (Migrated from github.com)

Running a second plan through subagent-driven-development in a repo that has already run one will silently overwrite the first plan's scratch files. I lost two files this way today before noticing the pattern.

Cause

Scratch lives in a single repo-level .superpowers/sdd/ directory, and the filenames are keyed on task number, which restarts at 1 for every plan.

scripts/task-brief line 24:

out="$dir/task-${n}-brief.md"

The skill's report-file convention has the same shape (task-N-report.md), and progress.md is a single shared ledger that every run appends to.

So plan B's Task 1 writes over plan A's Task 1. Nothing warns, and because .superpowers/sdd/ is gitignored there's no history to recover from.

Notably, scripts/review-package in the same directory does not have this problem — line 27 keys on commit SHAs, which are globally unique:

out="$dir/review-$(git rev-parse --short "$base")..$(git rev-parse --short "$head").diff"

Why renaming afterward doesn't help

My first instinct was to generate the brief and immediately mv it to a namespaced name. That doesn't work — the clobber happens during generation, so the prior file is already gone by the time you can rename. The only safe workaround is to copy anything precious out of the way before invoking task-brief, which nothing in the skill tells you to do.

What I actually lost

A repo with three prior runs (~50 accumulated scratch files, four unrelated projects in one progress.md). Starting a fourth plan destroyed:

  • task-1-report.md — a completed prior task's report, overwritten by a subagent following the skill's own report-file instruction
  • task-2-brief.md — overwritten by task-brief itself

Both unrecoverable. The underlying commits survived in git, so what was lost was the narrative record rather than code — but on a run where the ledger is the recovery map after compaction, that's not nothing. Twelve more files were in the blast radius before I noticed and copied them aside.

Suggested fix

One level of nesting makes collisions structurally impossible rather than merely unlikely:

.superpowers/sdd/<plan-slug>/task-1-brief.md
.superpowers/sdd/<plan-slug>/progress.md

where <plan-slug> derives from the plan filename (which the skill already requires and which is already unique per project). task-brief already accepts an optional third OUTFILE argument, so a caller can namespace manually today — but the default is what everyone will hit.

A cheaper interim fix, if the layout change is too invasive: have task-brief refuse to overwrite an existing file unless --force is passed. That converts silent data loss into a visible error.

Environment

superpowers v6.1.1, Claude Code, macOS.

Running a second plan through `subagent-driven-development` in a repo that has already run one will silently overwrite the first plan's scratch files. I lost two files this way today before noticing the pattern. ### Cause Scratch lives in a single repo-level `.superpowers/sdd/` directory, and the filenames are keyed on **task number**, which restarts at 1 for every plan. `scripts/task-brief` line 24: ```sh out="$dir/task-${n}-brief.md" ``` The skill's report-file convention has the same shape (`task-N-report.md`), and `progress.md` is a single shared ledger that every run appends to. So plan B's Task 1 writes over plan A's Task 1. Nothing warns, and because `.superpowers/sdd/` is gitignored there's no history to recover from. Notably, `scripts/review-package` in the same directory **does not** have this problem — line 27 keys on commit SHAs, which are globally unique: ```sh out="$dir/review-$(git rev-parse --short "$base")..$(git rev-parse --short "$head").diff" ``` ### Why renaming afterward doesn't help My first instinct was to generate the brief and immediately `mv` it to a namespaced name. That doesn't work — the clobber happens *during* generation, so the prior file is already gone by the time you can rename. The only safe workaround is to copy anything precious out of the way *before* invoking `task-brief`, which nothing in the skill tells you to do. ### What I actually lost A repo with three prior runs (~50 accumulated scratch files, four unrelated projects in one `progress.md`). Starting a fourth plan destroyed: - `task-1-report.md` — a completed prior task's report, overwritten by a subagent following the skill's own report-file instruction - `task-2-brief.md` — overwritten by `task-brief` itself Both unrecoverable. The underlying commits survived in git, so what was lost was the narrative record rather than code — but on a run where the ledger *is* the recovery map after compaction, that's not nothing. Twelve more files were in the blast radius before I noticed and copied them aside. ### Suggested fix One level of nesting makes collisions structurally impossible rather than merely unlikely: ``` .superpowers/sdd/<plan-slug>/task-1-brief.md .superpowers/sdd/<plan-slug>/progress.md ``` where `<plan-slug>` derives from the plan filename (which the skill already requires and which is already unique per project). `task-brief` already accepts an optional third `OUTFILE` argument, so a caller *can* namespace manually today — but the default is what everyone will hit. A cheaper interim fix, if the layout change is too invasive: have `task-brief` refuse to overwrite an existing file unless `--force` is passed. That converts silent data loss into a visible error. ### Environment superpowers v6.1.1, Claude Code, macOS.
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
skills/obra-superpowers#2012
No description provided.