Compare commits

...

8 Commits

Author SHA1 Message Date
Drew Ritter
f2bbe9ff92 docs: describe the :; label-line wrapper mechanism (#571) 2026-08-05 15:16:30 -07:00
Drew Ritter
d80fc1808a fix(hooks): replace run-hook.cmd heredoc with :; label lines (#571)
bash >= 5.1 writes heredocs into a pipe pre-fork; under macOS pipe
pressure the kernel hands out 512-byte pipes and the wrapper's 1.4KB
CMDBLOCK heredoc deadlocks every hook. Label lines parse nowhere:
cmd.exe skips them as labels, POSIX shells exec away before the batch
block. Also: silent fail-open when bash or the script name is missing,
and CDPATH-proof directory resolution.
2026-08-05 15:12:47 -07:00
Drew Ritter
431915accb test(hooks): fence against heredocs in the hook chain (red; #571) 2026-08-05 15:08:33 -07:00
Kattni
fb518edf7b Moves Community up, and adds ToC. 2026-08-04 20:16:46 -07:00
Drew Ritter
05c2393b82 Merge pull request #2078 from obra/fix/x6a-sdd-batch-small-tasks
fix(sdd): batch small same-shape tasks into one dispatch
2026-08-04 14:26:31 -07:00
Drew Ritter
78cc189244 fix(sdd): batch reviews check the diff against the brief's file list
Batching moves N edits under one review, which changes the review's
failure profile: an implementer that silently skips one file of twelve
produces a diff full of correct, uniform edits — nothing conspicuous is
missing, and no seat in the pipeline was assigned to notice. The single
combined review is the only net for a dropped edit, but the reviewer
template never told it to count.

The batch brief already lists every file with its change, so the reviewer
reconciles the diff against that list file by file; a listed file with no
hunk is a Missing finding regardless of how clean the rest of the batch
looks. Conditional on a multi-file brief, so single-task reviews are
unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-04 14:25:40 -07:00
Drew Ritter
be76350536 Merge pull request #2080 from obra/fix/x7a-sdd-evidence-bearing-preflight
fix(sdd): preflight emits its checks as a ledger table and rules on what it surfaces
2026-08-04 14:22:57 -07:00
Jesse Vincent
e7a4285985 fix(sdd): batch small same-shape tasks into one dispatch
Plans sometimes enumerate many tiny, same-shape edits (one-line fixes,
constant changes, a field added across files) as separate tasks. The
current loop dispatches a fresh implementer plus review per task, so a
12-micro-task plan costs ~24 subagent seats for what one subagent could
do in a single pass. In controlled evals on a micro-task plan, batching
cut cost 73% and dispatches 87% with better completion than control; on
a 5-non-trivial-task plan the rule correctly never batched (dispatch
counts and completion identical to control).

Claude-Session: https://claude.ai/code/session_0185AJr98gHx5EmwqNeft4Sy
2026-08-02 19:36:55 -07:00
8 changed files with 116 additions and 28 deletions

View File

@@ -2,6 +2,31 @@
Superpowers is a complete software development methodology for your coding agents, built on top of a set of composable skills and some initial instructions that make sure your agent uses them.
## Table of Contents
- [Quickstart](#quickstart)
- [How it works](#how-it-works)
- [Commercial Services](#commercial-services)
- [Installation](#installation)
- [Claude Code](#claude-code)
- [Antigravity](#antigravity)
- [Codex App](#codex-app)
- [Codex CLI](#codex-cli)
- [Cursor](#cursor)
- [Factory Droid](#factory-droid)
- [Gemini CLI](#gemini-cli)
- [GitHub Copilot CLI](#github-copilot-cli)
- [Kimi Code](#kimi-code)
- [OpenCode](#opencode)
- [Pi](#pi)
- [The Basic Workflow](#the-basic-workflow)
- [Community](#community)
- [What's Inside](#whats-inside)
- [Philosophy](#philosophy)
- [Contributing](#contributing)
- [Updating](#updating)
- [License](#license)
- [Visual companion telemetry](#visual-companion-telemetry)
## Quickstart
@@ -211,6 +236,14 @@ The Pi package loads the Superpowers skills and a small extension that injects t
**The agent checks for relevant skills before any task.** Mandatory workflows, not suggestions.
## Community
Superpowers is built by [Jesse Vincent](https://blog.fsck.com) and the rest of the folks at [Prime Radiant](https://primeradiant.com).
- **Discord**: [Join us](https://discord.gg/35wsABTejz) for community support, questions, and sharing what you're building with Superpowers
- **Issues**: https://github.com/obra/superpowers/issues
- **Release announcements**: [Sign up](https://primeradiant.com/superpowers/) to get notified about new versions
## What's Inside
### Skills Library
@@ -271,11 +304,3 @@ MIT License - see LICENSE file for details
## Visual companion telemetry
Because skills and plugins don't provide any feedback to creators, we have no idea how many of you are using Superpowers. By default, the Prime Radiant logo on brainstorming's optional visual companion feature is loaded from our website. It includes the version of Superpowers in use. It does not include any details about your project, prompt, or coding agent. We don't see your clicks or anything about what you're building. This helps us have a rough idea of how many folks are using Superpowers and which version of Superpowers they're using. It's 100% optional. To disable this, set the environment variable `SUPERPOWERS_DISABLE_TELEMETRY` to any true value. Superpowers also honors Claude Code's `DISABLE_TELEMETRY` and `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` opt-outs.
## Community
Superpowers is built by [Jesse Vincent](https://blog.fsck.com) and the rest of the folks at [Prime Radiant](https://primeradiant.com).
- **Discord**: [Join us](https://discord.gg/35wsABTejz) for community support, questions, and sharing what you're building with Superpowers
- **Issues**: https://github.com/obra/superpowers/issues
- **Release announcements**: [Sign up](https://primeradiant.com/superpowers/) to get notified about new versions

View File

@@ -745,8 +745,10 @@ single file that's valid as both a Windows batch script and a Unix shell script.
On Windows, `cmd.exe` runs the batch portion, which locates `bash` (Git for
Windows, then `bash` on PATH) and runs the named hook script; if no bash is
found it exits cleanly so the harness still works, just without injection. On
Unix, the leading `:` makes the batch block a no-op and the shell runs the
script directly.
Unix, the shell executes the leading `:;` lines and `exec`s the hook script
before reaching the batch block (cmd.exe skips those lines as labels).
Heredocs are banned throughout hooks/ — see issue #571 and the fence test
`tests/hooks/test-no-heredocs-in-hooks.sh`.
Two rules this enforces, which you must respect:

View File

@@ -65,9 +65,9 @@ The path is quoted because `${CLAUDE_PLUGIN_ROOT}` may contain spaces.
## How `run-hook.cmd` Works at a High Level
`run-hook.cmd` is a polyglot script: Windows treats the first block as batch
commands, while Unix shells treat that block as a no-op heredoc and continue
after it.
`run-hook.cmd` is a polyglot script: its first lines start with `:;`, which
cmd.exe skips as labels and Unix shells execute — the shell execs the hook
before ever reaching the batch block that Windows runs.
Do not copy an implementation from this document. Read `hooks/run-hook.cmd`
directly when changing the dispatcher, and run `tests/hooks/test-session-start.sh`
@@ -89,10 +89,14 @@ afterward.
### How it works on Unix (bash/sh)
1. `: << 'CMDBLOCK'` opens a heredoc on a no-op command.
2. The entire CMD batch block is consumed by the heredoc and ignored.
3. After `CMDBLOCK`, bash resolves the script directory and `exec`s the named
extensionless script directly.
1. Each leading `:;` line is a no-op label to cmd.exe but real commands to a
POSIX shell.
2. The shell checks bash exists (silent exit 0 if not), resolves the script
directory CDPATH-proof, and `exec`s the named extensionless script — it
never reads the batch block at all.
3. Heredocs are banned in this file and all hooks/ executables (issue #571:
bash >= 5.1 pre-fork pipe writes deadlock on macOS under pipe pressure);
`tests/hooks/test-no-heredocs-in-hooks.sh` enforces the ban.
### Key design decisions

View File

@@ -1,8 +1,20 @@
: << 'CMDBLOCK'
:; command -v bash >/dev/null 2>&1 || exit 0
:; [ $# -ge 1 ] || exit 0
:; SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
:; SCRIPT_NAME="$1"; shift; exec bash "${SCRIPT_DIR}/${SCRIPT_NAME}" "$@"
@echo off
REM Cross-platform polyglot wrapper for hook scripts.
REM On Windows: cmd.exe runs the batch portion, which finds and calls bash.
REM On Unix: the shell interprets this as a script (: is a no-op in bash).
REM On Unix: POSIX shells execute the ":;" lines above and exec away before
REM reaching this batch block (":" is a no-op; cmd.exe treats lines starting
REM with ":" as labels and skips them). If bash or the script name is
REM missing, the wrapper exits 0 silently - hooks are optional context, never
REM a session breaker.
REM On Windows: cmd.exe runs this batch portion, which finds and calls bash.
REM
REM Heredocs are banned in this file and every hooks/ executable: bash 5.1+
REM delivers them via a pre-fork pipe write that deadlocks on macOS under
REM pipe pressure (issue #571). tests/hooks/test-no-heredocs-in-hooks.sh is
REM the fence.
REM
REM Hook scripts use extensionless filenames (e.g. "session-start" not
REM "session-start.sh") so Claude Code's Windows auto-detection -- which
@@ -35,12 +47,4 @@ if %ERRORLEVEL% equ 0 (
)
REM No bash found - exit silently rather than error
REM (plugin still works, just without SessionStart context injection)
exit /b 0
CMDBLOCK
# Unix: run the named script directly
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
SCRIPT_NAME="$1"
shift
exec bash "${SCRIPT_DIR}/${SCRIPT_NAME}" "$@"

View File

@@ -217,6 +217,14 @@ that implementer. Single-file mechanical fixes also take the cheapest tier.
## The Task Loop
**Batch small same-shape work.** When the plan lists several tasks that are
each a small, independent edit of the same kind — the same one-line fix,
constant change, or field addition repeated across files — do not dispatch
one subagent per task. Compose ONE dispatch brief listing every file and
its change, send the whole batch to a single subagent, and review its diff
as one unit. Reserve one-dispatch-per-task for work that needs its own
judgment, its own tests, or its own review surface.
Everything you paste into a dispatch prompt — and everything a subagent
prints back — stays resident in your context for the rest of the session
and is re-read on every later turn. Hand artifacts over as files.

View File

@@ -95,6 +95,12 @@ Subagent (general-purpose):
- **Misunderstood:** right feature built the wrong way, wrong problem
solved
If the brief lists several files each with its own change (a batched
dispatch), check the diff against that list file by file: every listed
file must have its corresponding hunk. A listed file the diff never
touches is a Missing finding, no matter how clean the rest of the
batch looks.
If a requirement cannot be verified from this diff alone (it lives in
unchanged code or spans tasks), report it as a ⚠️ item instead of
broadening your search.

View File

@@ -0,0 +1,30 @@
#!/usr/bin/env bash
set -euo pipefail
# Heredocs are banned from the hook delivery chain: bash >= 5.1 delivers
# them through a pre-fork pipe write that deadlocks on macOS under pipe
# pressure (issue #571; the #571 class). This fence fails the moment one
# returns. The operator is spelled out of a variable so this file does not
# trip its own check.
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
OP='<''<'
FAILURES=0
for f in "$REPO_ROOT"/hooks/*; do
case "$f" in *.json) continue;; esac
[ -f "$f" ] || continue
if hits="$(grep -nE "$OP" "$f")"; then
echo " [FAIL] heredoc operator in ${f#"$REPO_ROOT"/}:"
printf '%s\n' "$hits" | sed 's/^/ /'
FAILURES=$((FAILURES + 1))
else
echo " [PASS] ${f#"$REPO_ROOT"/} is heredoc-free"
fi
done
if [ "$FAILURES" -gt 0 ]; then
echo "STATUS: FAILED ($FAILURES file(s))"
exit 1
fi
echo "STATUS: PASSED"

View File

@@ -184,6 +184,15 @@ assert_command_output \
CLAUDE_PLUGIN_ROOT="$REPO_ROOT" \
bash "$WRAPPER_UNDER_TEST" session-start
# With no bash available, the wrapper must fail open: silent, exit 0.
if output="$(env -i PATH=/nonexistent /bin/sh "$WRAPPER_UNDER_TEST" session-start 2>&1)" \
&& [ -z "$output" ]; then
pass "wrapper with no bash on PATH is silent and exits 0"
else
fail "wrapper with no bash on PATH is silent and exits 0"
printf '%s\n' "$output" | head -3 | sed 's/^/ /'
fi
cursor_home="$(make_home cursor)"
assert_command_output \
"Cursor emits top-level additional_context only" \