Skip to content

fix(writing-plans): commit the plan document so worktree cleanup can't destroy it#2016

Closed
jeongph wants to merge 1 commit into
obra:devfrom
jeongph:fix/commit-plan-document
Closed

fix(writing-plans): commit the plan document so worktree cleanup can't destroy it#2016
jeongph wants to merge 1 commit into
obra:devfrom
jeongph:fix/commit-plan-document

Conversation

@jeongph

@jeongph jeongph commented Jul 22, 2026

Copy link
Copy Markdown

Who is submitting this PR? (required)

Field Value
Your model + version Claude Fable 5 (claude-fable-5)
Harness + version Claude Code 2.1.217 (macOS)
All plugins installed superpowers 6.1.1, plus (unrelated to this change): Notion, context7, playwright, plugin-dev, pr-review-toolkit, feature-dev, hookify, commit-commands, code-review, skill-creator, remember, claude-okf, claude-intent, claude-md-management, claude-telemetry, agent-sdk-dev, mcp-server-dev, code-simplifier, claude-code-setup, frontend-design
Human partner who reviewed this diff JeongUk Park (@jeongph) — reviewed the complete diff and approved submission

What problem are you trying to solve?

My human partner lost superpowers-generated planning documents after finishing work in a worktree. The session followed the standard flow: brainstorming → writing-plans → execution in an isolated worktree → finishing-a-development-branch. After integration, the worktree was cleaned up — and the plan document under docs/superpowers/plans/ was gone.

Root cause, confirmed by reading the skills on dev:

  • brainstorming explicitly commits the spec ("Commit the design document to git").
  • writing-plans says "Save plans to: docs/superpowers/plans/..." but never instructs committing the plan document. The "Commit" steps in the skill are template content inside the generated plan (for the executor's implementation commits), not an action for the plan author. The plan therefore stays untracked for the entire lifetime of the branch — task commits git add only implementation files.
  • At finish time, finishing-a-development-branch Step 6 runs git worktree remove "$WORKTREE_PATH". With an untracked plan in the tree, git refuses (fatal: '<path>' contains modified or untracked files, use --force to delete it). The skill gives no guidance for that refusal, so the natural agent response is --force — which permanently deletes the untracked plan. Harness-owned workspace cleanup (workspace-exit tools) deletes untracked files the same way. Merge and PR paths don't help either: they only carry committed content.

Reproduction (pure git, no agent needed):

git worktree add .worktrees/feat -b feat
cd .worktrees/feat
mkdir -p docs/superpowers/plans && echo "PLAN" > docs/superpowers/plans/plan.md   # untracked, like writing-plans leaves it
echo impl > impl.txt && git add impl.txt && git commit -m impl                     # task commits touch only impl files
cd ../..
git worktree remove .worktrees/feat          # fatal: contains modified or untracked files
git worktree remove --force .worktrees/feat  # exit 0 — plan.md is gone, unrecoverable

The committed impl.txt survives on the branch; the plan does not survive anywhere.

What does this PR change?

Adds a "Commit the Plan" step to writing-plans immediately after Self-Review (mirroring the spec commit that brainstorming already mandates), and updates the Execution Handoff wording from "saved to" to "committed at" so the handoff message can't be satisfied without the commit having happened.

Is this change appropriate for the core library?

Yes. It touches only a core skill's own workflow gap — every superpowers user who runs the plan-in-a-worktree flow is exposed to this loss, regardless of project type, domain, or toolchain. No third-party dependency, no project-specific behavior.

What alternatives did you consider?

  1. Guard in finishing-a-development-branch Step 6 (refuse/rescue when the worktree is dirty, forbid --force): treats the symptom at cleanup time instead of the cause, and substantially overlaps open PR fix(finishing-a-development-branch): guard clean tree + handle linked-worktree cwd #1223 (Step 1 clean-tree guard). Even with a perfect guard, the plan would still be untracked and absent from merges and PRs — the guard can only stall, not preserve.
  2. Commit the plan at finish time: too late — subagent-driven execution reads and (per Plans and specs have no completion status after execution #1075's direction) may update the plan during execution, and a crash or discard before finish still loses it. Committing at creation matches when brainstorming commits the spec.
  3. Do nothing / rely on git's removal refusal: the refusal is exactly what pushes agents to --force; my human partner's session proves it doesn't protect in practice.

Does this PR contain multiple unrelated changes?

No. One file, one problem: the plan document's missing commit. The related-but-distinct cleanup-time hardening is left to #1223.

Existing PRs

Environment tested

Harness (e.g. Claude Code, Cursor) Harness version Model Model version/ID
Claude Code 2.1.217 Claude Fable 5 claude-fable-5

New harness support (required if this PR adds a new harness)

N/A — this PR does not add harness support.

Evaluation

  • Initial prompt: My human partner reported (in Korean): "superpowers 플러그인 사용시에 워크트리를 생성해서 작업하고 작업이 끝나서 워크트리를 종료하거나 삭제하면 superpowers가 생성한 문서들이 유실되는 버그가 있다" — i.e., documents generated by superpowers are lost when the worktree is closed/removed after work completes — and asked to verify and fix it.
  • Eval sessions after the change: 3 fresh-context sessions with the modified skill, against 3 fresh-context baseline sessions with the unmodified dev skill (micro-test methodology from writing-skills: fresh context per rep, no-guidance control, every response read manually). Scenario: end of writing-plans in a worktree, self-review passed; agent lists exact next actions before execution handoff.
  • Outcome change: Baseline 0/3 committed the plan — all three explicitly reasoned "the skill contains no instruction to commit the plan file" and proceeded straight to the handoff. Modified 3/3 ran git add docs/superpowers/plans/<file> + git commit before the handoff, with no variance in interpretation across reps. Plus the git-level reproduction above demonstrating the loss the commit prevents.

Honest scope note: these are fresh-context micro-tests per the writing-skills methodology, not multi-session tmux evals from superpowers-evals. The change is an additive workflow step (structural form for an omitted-element failure), not a rewording of tuned behavioral content.

Rigor

  • If this is a skills change: I used superpowers:writing-skills and completed adversarial pressure testing (paste results below)
  • This change was tested adversarially, not just on the happy path
  • I did not modify carefully-tuned content (Red Flags table, rationalizations, "human partner" language) without extensive evals showing the change is an improvement

Results: RED — baseline 0/3 commit (verbatim rationale: "The skill contains no instruction to commit the plan file"; "it does not instruct committing the plan file, so I run no git add/git commit"). GREEN — modified 3/3 commit before handoff, convergent behavior. Failure-path testing: the git reproduction above exercises the loss path (git worktree remove refusal → --force → permanent deletion) rather than only the happy path. No Red Flags tables, rationalization tables, or "human partner" language were touched — the change adds a new section and adjusts two handoff lines to be consistent with it.

Human review

  • A human has reviewed the COMPLETE proposed diff before submission

🤖 Generated with Claude Code

The plan file was saved to docs/superpowers/plans/ but never committed,
so it stayed untracked through execution. Worktree cleanup at finish
time (git worktree remove / harness workspace exit) then deleted it
permanently. brainstorming already commits the spec; this gives the
plan the same treatment so merge and PR both preserve it.
@obra

obra commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Thank you @jeongph — this is one of the best-constructed PRs this repo has received: real loss, correct three-part root-cause analysis (I verified all three legs against dev), a deterministic reproduction (which I ran — the plan is indeed unrecoverable after --force), honest eval scoping, and full disclosure. The diagnosis is accepted.

The fix is declined on design grounds, though, so I'm closing this. The maintainer's decision: not everyone wants superpowers plan documents committed into their repo history, so writing-plans won't gain an unconditional commit step. The loss path will instead be fixed where the destruction actually happens — finishing-a-development-branch's cleanup step will treat a refused git worktree remove as a stop-and-ask moment: it must never --force on its own initiative, and must show the human partner the untracked files (any untracked files, not just superpowers docs) and ask whether to commit, relocate, or delete them. A PR implementing that is coming shortly and will credit this report.

— Claude Fable 5 (AI assistant), Claude Code 2.1.218, doing PR triage for this repo. Decision by @obra.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants