---
name: superpowers-sprint
description: Structured sprint workflow built only on officially-distributed Claude Code skills (superpowers, code-review, plainly). Drives an eight-phase chain — worktree → brainstorm → plan → implement → verify → code review → land → final status — with every phase resolved to a skill that ships in `~/.claude/skills/` or the official plugin marketplaces. Use on installs that do not carry the `gstack` plugin. Triggers include "superpowers sprint", "sprint without gstack", or invoking against a `.tasks/NNN-*.md` file on a maxy-code install.
---

# Superpowers Sprint

A structured workflow for executing development work — features, bug fixes, refactors, any scoped unit of work — using only skills that ship with the official Claude Code distribution. No `gstack`, no custom plugin required.

This skill is the maxy-code counterpart to `sprint`. The phase chain is identical in spirit; the difference is the skill at each phase. If both `gstack` and superpowers are installed and the project is set up for it, prefer `sprint` — its plan reviews are richer. Use this skill when `gstack` is not available.

## Output discipline (applies to every emission in this skill)

Every message the sprint writes — plan summaries, change logs, status tables, the final summary — is written `/plainly`. That means:

- Plain English, spoken register, short sentences. Read it aloud; if it doesn't parse in conversation, rewrite it.
- Only pertinent information. The operator needs to know: the outcome was achieved, how it was achieved, where the agent deviated, and what they must do to verify. Anything that does not serve one of those four is cut.
- No filler, no inflation vocabulary, no em-dashes, no AI tells (see the `plainly` skill catalogue). No re-stating the brief back to the user.
- Tables and checklists stay only when they carry information the operator will act on. A table with one row of "✅" everywhere is replaced by one sentence.

Bloat in any phase's output is a defect, not a style choice.

## Phase markers

Every phase emits exactly one marker line to stdout when it begins, in the form:

```
[sprint] phase <N> — <name> — invoking <skill>
```

If a phase invokes no skill (internal-only steps like Plan Conformity or Debrief), the marker names the internal step instead: `[sprint] phase <N> — <name> — internal`. Markers exist so the operator and any transcript reader can confirm which phases ran and in what order. A missing marker is a phase that did not run.

## Workflow

### Phase 0: Worktree Isolation — `superpowers:using-git-worktrees`

Invoke `superpowers:using-git-worktrees`. The skill creates an isolated git worktree on a fresh branch named for the task (e.g. `task-537-superpowers-sprint`). Without isolation, parallel sessions share one HEAD and one working directory — a branch switch in one session silently disrupts every other active session.

After entering the worktree, install dependencies before building. Worktrees only contain tracked files, so `node_modules`, build artifacts, and untracked configuration are absent. Run `npm install` in every directory you plan to build from.

`getmaxy` is one repo with two parallel installer trees living as plain directories — `packages/create-maxy/` ships `@rubytech/create-maxy`, and `maxy-code/packages/create-maxy-code/` ships `@rubytech/create-maxy-code`. Neither is a submodule, subtree, or sibling repo. Build only the tree the sprint touches; if a build needs `platform/` deps, install in the matching tree (`platform/` at the root for legacy work, `maxy-code/platform/` for Maxy Code work). If the sprint depends on recent main-branch work, merge main into the worktree branch at the start.

If already in a worktree (resuming a sprint), skip — but verify `node_modules` is present.

If the only repo-side artifact of the sprint is the task-file archive plus the LANES.md sync (the deliverable lives outside the repo entirely — e.g. an operator-side `~/.claude/skills/...` file), the worktree is still required: the archive commit must land on a feature branch and merge to main like any other change.

### Phase 1: Brainstorm — `superpowers:brainstorming`

Invoke `superpowers:brainstorming`. The skill explores user intent, requirements, and design before any code is written. It is the forcing function that prevents starting implementation against an unclear brief.

Read the task file or operator brief first, then enter brainstorming with what you understood. The skill's questions surface implicit assumptions, unstated constraints, and scope ambiguity. The output of this phase is a shared understanding of *what* is being built and *why*, not yet *how*.

If the operator hands over a fully-formed plan that is already broken into specific files and behaviours, brainstorming can be a fast confirmation rather than an open exploration — but it still runs, because skipping it is the failure mode the phase exists to prevent.

### Phase 2: Plan — `superpowers:writing-plans`

Invoke `superpowers:writing-plans` against the brainstorm output. The skill produces a single written plan: the files to touch, the behaviours to add or change, the edge cases, the test coverage, the deployment story. This is the artefact Phase 6 (Plan Conformity) checks the implementation against.

This is a deliberate downgrade from `sprint`'s separate CEO and Eng reviews — multi-approach architecture review is out of scope for the superpowers chain. One reviewed plan is the baseline.

Present the final plan to the operator and get explicit confirmation before writing any production code.

### Phase 3: Implement — `superpowers:executing-plans` + `superpowers:test-driven-development`

Invoke `superpowers:executing-plans` to drive execution against the Phase 2 plan. Within each step, follow `superpowers:test-driven-development` — RED-GREEN-REFACTOR for every behaviour change.

Tests are ephemeral: design and run them to prove the implementation works during the sprint, then discard them. They are not committed to the repository unless the project's own test suite already lives in the tree and the new behaviour belongs in it. Their purpose is to enforce thinking through behaviour before writing production code, not to build a permanent regression suite.

- **Test first.** Write a failing test for each behaviour before implementing it. Watch it fail. Write minimal code to pass. Refactor.
- **Track progress.** Use TaskCreate/TaskUpdate for multi-step work. Mark tasks in_progress before starting, completed when done.
- **Build incrementally.** Make changes file by file. Verify as you go with build scripts to catch errors early, not at the end.
- **Follow project conventions.** Read CLAUDE.md rules.
- **Multi-surface sync.** On a maxy-code sprint, when adding or removing MCP tools, all registration surfaces must be updated in the same commit: tool server `index.ts`, `PLUGIN.md` declarations, `ADMIN_CORE_TOOLS`, and specialist agent templates under `platform/templates/specialists/agents/`. Grep for a sibling tool name to find affected files.
- **Don't over-engineer.** Only make changes that are directly needed. No speculative abstractions, no cleanup of surrounding code, no extra error handling for impossible scenarios.
- **Debug with discipline.** When something breaks and the cause isn't immediately obvious, invoke `superpowers:systematic-debugging`. It enforces root-cause-first: hypothesis → evidence → fix. No fixes without root cause. This replaces the instinct to chain speculative fixes.

### Phase 4: Verify — `superpowers:verification-before-completion`

Invoke `superpowers:verification-before-completion`. The skill blocks any "it works" claim until an explicit verification command has been run and its output observed. Evidence before assertions, always.

Minimum verification surface:

1. Build — no TypeScript errors. Build success does not imply boot success. When the change touches dependencies, the build pipeline, or plugin entry points, also run the bundle command for the matching tree and confirm no runtime errors in the assembled payload.
2. Lint — no new lint errors in changed files.
3. Tests — the ephemeral tests from Phase 3 pass, plus any pre-existing test surface that covers the changed code.
4. **UI sprints.** Drive the change in a real browser via the `chrome-devtools-mcp:chrome-devtools` MCP, or the `playwright` MCP if that is what the project is set up for. Walk the user-visible flow that the sprint changed and confirm the expected state. Console messages and network requests are part of the verification surface, not optional polish.
5. **Pi signal verification (for sprints touching hooks or MCP tool input handling).** Local tests validate hook logic but cannot verify that test inputs match what production actually sends. After deploying to the Pi, trigger the relevant flow via admin chat. SSH in and read the diagnostic log (`/tmp/maxy-gate.log` for gate hooks, or the relevant log for other hooks). Compare the actual `tool_input` field names and structure against what the local tests pipe as JSON. If they diverge, the tests are wrong — fix them before proceeding. The Pi is the only environment where the real Claude Code hook protocol runs.

If verification fails, return to Phase 3.

### Phase 5: Code Review — `superpowers:requesting-code-review` → `code-review:code-review` → `superpowers:receiving-code-review`

Invoke `superpowers:requesting-code-review` to frame the review request. Then run `code-review:code-review` against the sprint's diff. Process the response through `superpowers:receiving-code-review`, which gates whether each finding is accepted, contested, or filed as follow-up.

Findings that are accepted and trivial are fixed before proceeding. Findings that are accepted but out-of-scope for this sprint become new `.tasks/NNN-*.md` files (the same deferral rule as Phase 6 — prose deferrals are banned). Findings that are contested get a one-line rebuttal in the debrief.

### Phase 6: Land

Land has four internal steps in fixed order: Plan Conformity, Debrief, Task Archive + LANES sync, then worktree teardown via `superpowers:finishing-a-development-branch`.

**Gating model — fixed, not per-sprint.** The boundary between automatic and command-gated steps is the same on every sprint, so the user never has to remember which kind of sprint this was:

| Step | When |
|------|------|
| Commit, archive task file, merge to local `main`, worktree + branch cleanup | **Automatic** once the user confirms the task is done in this phase |
| `git push`, `npm publish` | **Always await explicit command** — never auto-run, never offer as a menu |

No "Want me to push, or hold?" phrasings. The rule above is the answer; restating it as a question is a menu-phrasing violation. If the user wants to push, they say so; otherwise the final-status block makes the pending state visible.

#### 6a. Plan Conformity

Compare the implementation against the approved Phase 2 plan. Every plan item must appear in exactly one section of the conformity report:

```
## Plan Conformity

### Implemented as planned
- [item] — matches plan: [brief evidence]

### Deviations
- [item] — DEVIATED: [what the plan said] → [what was actually built] — Reason: [why]
  → Follow-up: [.tasks/NNN-*.md path] — REQUIRED if the deviation drops any plan commitment

### Omissions
- [item] — NOT IMPLEMENTED — Follow-up: [.tasks/NNN-*.md path] — REQUIRED, no exceptions

### Additions
- [item] — NOT IN PLAN: [what was added and why it was necessary]
```

**100% coverage required.** Silent omissions — items that were in the plan but neither implemented nor flagged — are the failure mode this step exists to prevent.

**Deferrals require task files, never prose.** Any plan item moved out of this sprint must point to a concrete `.tasks/NNN-*.md` file created here, before the debrief. "Deferred because X" without a task file becomes a silent regression. Binary rule: either pull the item back into scope and finish it, or file a task.

If deviations or omissions are found, present them to the operator for acknowledgement before the debrief.

#### 6b. Debrief

**Change log.** For every file modified:

```
### `path/to/file.ts`
**What changed:** [concise description of the change]
**Why:** [the reason this change was needed]
**Implication:** [what this change means for the system — behavior change, new capability, dependency, etc.]
```

Group related changes logically.

**Commit table.** Run `git log --oneline <base-branch>..HEAD` and present it as a table of hash, message, files. Nothing uncommitted at debrief time without an explanation.

**Testing instructions.** Specific UI steps the operator runs to exercise the feature, what to look for, what should NOT happen. "Test it" is not an instruction. "Open `/setup`, click the iMessage refresh button, verify the status shows Connected" is.

**Known limitations.** Every intentionally-deferred or out-of-scope item links to a `.tasks/NNN-*.md` file. No prose-only deferrals.

#### 6c. Task Archive and LANES Sync

Close the loop against the original task file. For every requirement in the task:

- **Complete** — implemented and verified during this sprint.
- **Deferred** — deliberately excluded; a new `.tasks/NNN-*.md` captures what remains and why.
- **Missing** — should have been done but wasn't. Fix it now before archiving.

Present the assessment and wait for operator confirmation. Do not archive until every requirement is accounted for.

Once confirmed, archive the task file. The recipe branches on whether the source is tracked, because `git mv` errors with `fatal: not under version control` on an untracked source:

```bash
if git ls-files --error-unmatch .tasks/<task-file>.md >/dev/null 2>&1; then
  git mv .tasks/<task-file>.md .tasks/archive/
else
  mv .tasks/<task-file>.md .tasks/archive/<task-file>.md
  git add .tasks/archive/<task-file>.md
fi
```

Two post-conditions hold for both branches; a third holds only for tracked sources:

```bash
# 1. No file remains at the live path.
[ ! -e .tasks/<task-file>.md ] || { echo "ERROR: live source still on disk"; exit 1; }

# 2. The archive add is staged.
git diff --cached --name-only | grep -qx ".tasks/archive/<task-file>.md" \
  || { echo "ERROR: archive add not staged"; exit 1; }

# 3. (Tracked branch only) Confirm the rename was atomic.
if git ls-files --error-unmatch .tasks/<task-file>.md >/dev/null 2>&1; then
  git diff --cached --name-status | grep -E "^R[0-9]+\s+\.tasks/<task-file>\.md\s+\.tasks/archive/<task-file>\.md$" \
    || { echo "ERROR: tracked source not renamed atomically — re-run with git mv"; exit 1; }
fi
```

Pre-archive safety net: if `.tasks/archive/<task-file>.md` already exists on disk, stop. A duplicate basename in archive is never a silent overwrite — investigate the prior archive cycle first.

**Update `.tasks/LANES.md` in the same commit as the archive move.** Three invariants hold after the LANES edit:

1. **No Ready row references the archived task.** Verify: `grep -F "<task-file>.md" .tasks/LANES.md` returns zero hits inside the Ready section.
2. **The archive sentence names the archived task number.** Verify: the regex `\b<NNN>\b` matches at least once inside the archive sentence.
3. **Any new task file created for deferred work gets a Ready row in the same edit.** Otherwise the next sprint inherits an open file with no tracker entry.

Commit the archive move, the LANES update, and any new task files for deferred work as a single commit:

```
chore: archive <task-name>
```

#### 6d. Worktree Teardown — `superpowers:finishing-a-development-branch`

Invoke `superpowers:finishing-a-development-branch` to present the integration options (merge, PR, cleanup). On this sprint chain the default action is merge-to-local-main, because the gating model says push and publish await explicit operator command — the skill should be driven toward that outcome, not toward a PR.

The cleanup sequence after the operator confirms is order-sensitive:

1. Return to the main working directory (the superpowers skill drives this via its worktree teardown action).
2. Merge the feature branch into `main`: `git merge <branch-name>`.
3. **Sweep post-merge debris in `.tasks/`.** When the worktree archived a task file that was never tracked on `main` (created in a prior session at the open path but never committed), the merge brings in the archive add but cannot delete the untracked open-path copy on main. Walk every `chore: archive` commit in the merged range and remove untracked open-path twins:

   ```bash
   MERGED_RANGE="$(git merge-base HEAD~ HEAD)..HEAD"
   git log --format=%H --grep='^chore: archive' "$MERGED_RANGE" | while read -r sha; do
     git show --name-only --format= "$sha" | grep -E '\.tasks/archive/.+\.md$' | while read -r archived; do
       bn="$(basename "$archived")"
       open="${archived%/archive/$bn}/$bn"
       if [ -e "$open" ] && ! git ls-files --error-unmatch "$open" >/dev/null 2>&1; then
         rm -f "$open"
         echo "[sprint] post-merge debris removed: $open"
       fi
     done
   done
   ```

4. Remove the worktree: `git worktree remove .claude/worktrees/<name>`.
5. Force-delete the branch: `git branch -D <branch-name>` (capital `-D`; lowercase `-d` fails when `refs/remotes/origin/main` is behind local `main`).

If not in a worktree, merge and force-delete the branch directly, still running the debris sweep between them.

### Phase 7: Final Status — `plainly`

The sprint's last emission has two parts in fixed order: (1) the live status table, computed from the working tree right now; (2) a three-sentence plain-English summary, written under the `plainly` skill rules.

Every sprint ends with this block as its final output, regardless of how it went.

#### 7a. Status table

Compute each row from a deterministic check, then render:

```
## Sprint Status

| Artifact | State | Detail |
|----------|-------|--------|
| Committed | ✅ / ❌ | `git status --porcelain` empty? |
| Merged to local main | ✅ / ❌ | `git branch --contains <sha> \| grep -q '^[* ] main$'` |
| Pushed to origin/main | ⏳ awaiting command / ✅ / N/A | `git rev-list main..origin/main --count` is 0 and HEAD == origin/main |
| Published (every brand) | ⏳ awaiting command / ✅ / N/A — no shipped files changed | one row per brand directory under `$BRANDS_DIR`; ✅ only when `npm view <pkg> version` returns the bumped version for ALL of them |
| Task archived | ✅ / ❌ | task file lives under `.tasks/archive/` |
| LANES synced | ✅ / ❌ | `.tasks/LANES.md` has no Ready row for the archived task, and the archive sentence names `<NNN>` |
```

Rules:

- **Always emitted**, even if every row is ✅. Skipping it is the failure mode this phase prevents.
- **No menu phrasings.** Never end with "Want me to push, or hold?" or any variant.
- **States are computed, not narrated.** Don't write "I think it's pushed"; run the check and render ✅ or ⏳.
- **N/A is required when applicable.** A skill-only sprint (deliverable outside the published packages) shows publish rows as `N/A — no shipped files changed`, not ⏳.
- **The pending-commands block (below) is omitted entirely** if no row is ⏳.

#### 7b. Pending commands

If any row is ⏳, render the commands the operator runs when ready. Publish-tree detection picks the installer tree from the sprint's diff against the merge base — never from `basename` of the working directory; both trees live in the one `getmaxy` repo:

| Installer tree | Installer directory | Brands directory | Default brand | Default package |
|---|---|---|---|---|
| Repo root (legacy Maxy) | `packages/create-maxy/` | `brands/` | `maxy` | `@rubytech/create-maxy` |
| `maxy-code/` (Maxy Code) | `maxy-code/packages/create-maxy-code/` | `maxy-code/brands/` | `maxy-code` | `@rubytech/create-maxy-code` |

```bash
git push
# (publish block — only if any Published row is ⏳; iterates every brand directory)
REPO_ROOT=$(git rev-parse --show-toplevel)
CHANGED=$(git diff --name-only "$(git merge-base HEAD main)" HEAD)
if echo "$CHANGED" | grep -q '^maxy-code/'; then
  INSTALLER_DIR=maxy-code/packages/create-maxy-code
  BRANDS_DIR=maxy-code/brands
  DEFAULT_BRAND=maxy-code
else
  INSTALLER_DIR=packages/create-maxy
  BRANDS_DIR=brands
  DEFAULT_BRAND=maxy
fi
cd "$REPO_ROOT/$INSTALLER_DIR" && npm run bundle && npm publish
cd "$REPO_ROOT/$INSTALLER_DIR" && for b in $(ls "$REPO_ROOT/$BRANDS_DIR" | grep -v "^${DEFAULT_BRAND}$"); do
  npm run bundle -- --brand="$b" && npm publish --ignore-scripts
done
cd "$REPO_ROOT/$INSTALLER_DIR" && npm run bundle
```

A diff that touches both trees is two sprints, not one — split it before publishing. A diff that touches neither tree is a docs/tooling sprint and publishes nothing; mark every Published row N/A. Every brand under `$BRANDS_DIR` ships a separate npm package and all of them must publish in lockstep at the same version — every new deployment of any brand pulls its own `@rubytech/create-<brand>` from npm, so a brand left behind silently regresses on the next install. `--ignore-scripts` on every non-default brand prevents `prepublishOnly` from re-bundling as the default brand and republishing under the wrong name. The final `npm run bundle` restores `package.json` to the default brand.

After publishing, verify every brand landed at the new version on npm:

```bash
for pkg in $(for b in $(ls "$BRANDS_DIR"); do
  python3 -c "import json; print(json.load(open('$BRANDS_DIR/'+'$b'+'/brand.json'))['npm']['packageName'])"
done); do
  echo "$pkg: $(npm view "$pkg" version)"
done
```

Every line must show the version just bumped — a lagging entry means the publish loop missed that brand and a manual `cd "$REPO_ROOT/$INSTALLER_DIR" && npm run bundle -- --brand=<that-brand> && npm publish --ignore-scripts` is required.

A version bump applies once to the default installer package and propagates to every brand at bundle time — there is no per-brand version. Bump once, publish all brands at that version, every time.

#### 7c. Plain summary (the literal last words of the sprint)

After the status block, write exactly three short sentences, under the `plainly` skill rules. Nothing follows them. The three sentences cover, in order:

1. **Outcome** — what was achieved, in the operator's words. One sentence.
2. **How / deviation** — the single most important thing the operator needs to know about how it was done, or where the work deviated from the brief. If there was no meaningful deviation, use this sentence for the one mechanism that matters. One sentence.
3. **Verify** — the one concrete thing the operator does to confirm the outcome landed. One sentence, imperative.

Hard rules:

- Three sentences total. Not four. Not "three sentences plus a bullet list".
- No jargon, no acronyms, no file paths, no commit hashes, no em-dashes.
- No restating what the table already said.
- No follow-up offer, no "let me know if…", no `/schedule` tail.

If the sprint deferred work to a task file, the deviation sentence names that fact in plain English (e.g. "the retry cap is filed as a follow-up task"). The task number lives in the table or the conformity report, not in this summary.

---

## Commits

Every commit made during a sprint must include a `Session:` trailer linking it to the Claude Code session that produced it.

Derive the session ID from the most recently modified JSONL in the project's session directory:

```bash
ls -t ~/.claude/projects/$(pwd | tr '/' '-')/*.jsonl | head -1 | xargs basename | sed 's/.jsonl//'
```

Include it as a trailer:

```
feat: implement feature X

Co-Authored-By: Claude <model> <noreply@anthropic.com>
Session: <session-id>
```

---

## Principles

- **Ship complete.** A sprint is not done until the debrief and the final-status block are delivered. Code without documentation is unfinished work.
- **Explain the why.** Every change has a reason. "Refactored for clarity" is not a reason. "Extracted to avoid duplicate route derivation across WhatsApp and iMessage" is.
- **Operator perspective.** Testing instructions are written for the person running the product. If the operator is non-technical, instructions are UI-based.
- **No surprises.** If a change has side effects, non-obvious implications, or touches shared infrastructure, call it out explicitly.
- **Iterative by default.** Scope to what's achievable, and defer the rest by filing a `.tasks/NNN-*.md` for each unfinished piece before the sprint ends. Prose-only deferrals are banned.
- **Always close with status.** Every sprint, without exception, ends on the Phase 7 Final Status block. Same gating rule on every sprint (commit/merge automatic, push/publish await command), same final emission shape, no menu-phrasing tail.
