Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds a Visual Brainstorming Companion (Node.js server, browser helper, UI frame, shell utilities, tests), introduces Spec and Plan Document Reviewer prompts and review loops, moves plans/specs into Changes
Sequence Diagram(s)sequenceDiagram
participant Claude as Claude Instance
participant Server as Brainstorm Server
participant FileSystem as File System
participant Browser as Browser Helper
participant User as End User
Claude->>FileSystem: write screen.html to /tmp/brainstorm (or project dir)
FileSystem-->>Server: chokidar add/change event
Server->>FileSystem: read newest .html
Server->>Server: inject helper.js (wrap fragment in frame if needed)
Browser->>Server: WebSocket connect
User->>Browser: interact (click / form / input)
Browser->>Browser: capture, queue, debounce events
Browser->>Server: send event via WebSocket
Server->>Server: log event to stdout (JSON)
Claude->>Server: wait-for-feedback / poll .server.log
loop edits
Claude->>FileSystem: update .html
FileSystem-->>Server: change event
Server->>Browser: broadcast reload
Browser->>Browser: reload page
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord. Comment |
There was a problem hiding this comment.
Actionable comments posted: 9
🤖 Fix all issues with AI agents
In `@docs/README.opencode.md`:
- Around line 171-173: The fenced code blocks containing the examples "use skill
tool to list skills" and "use skill tool to load superpowers/brainstorming" are
missing language identifiers; update those backtick blocks to include a language
such as text (e.g., change ``` to ```text) for each occurrence (including the
second example referenced at 179-181) so markdownlint MD040 no longer flags
them. Ensure every fenced block that shows those exact example lines is updated
consistently to include the language identifier.
In `@docs/superpowers/specs/2026-01-22-document-review-system-design.md`:
- Around line 28-39: The fenced code block that starts with "## Spec Review" is
missing a language identifier (MD040); update both opening triple-backtick
fences to include a language (e.g., change ``` to ```text) for the block
containing "## Spec Review" and the later fenced block containing the workflow
line "brainstorming -> spec -> SPEC REVIEW LOOP -> writing-plans -> plan -> PLAN
REVIEW LOOP -> implementation" so markdownlint stops flagging them; ensure you
update the opening fences for the blocks referenced in the diff and the other
occurrence at the section noted as "Also applies to: 83-85".
In `@hooks/hooks.json`:
- Line 9: The command in hooks.json uses an unquoted expansion of
CLAUDE_PLUGIN_ROOT which can break when the path contains spaces; update the
"command" value from "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh" to use
single quotes around the expansion (i.e.,
'${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh') so the shell receives the path
as a single argument and the session-start.sh hook runs reliably.
In `@lib/brainstorm-server/helper.js`:
- Around line 15-20: The ws.onmessage handler currently calls
JSON.parse(msg.data) without protection; wrap the parse in a try/catch inside
the ws.onmessage function to prevent malformed JSON from throwing and breaking
the handler, e.g., try to parse msg.data, verify the resulting object exists and
has data.type === 'reload' before calling window.location.reload(), and in the
catch block log the parsing error (using console.error or a logger) and return
silently so the handler continues to run safely.
In `@lib/brainstorm-server/index.js`:
- Around line 55-63: The ws.on('message') handler currently calls JSON.parse
directly which can throw on malformed payloads and crash the server; update the
message handler inside the wss.on('connection' /* connection callback */) to
wrap the JSON.parse(data.toString()) call in a try/catch, handle parse errors by
logging the parse failure (include the raw data and error) via console.error or
process logger, and skip processing that message (optionally send an error
response over ws) instead of letting the exception bubble up and crash the
process; keep the rest of the successful-path behavior (building event and
console.log) unchanged.
In `@lib/brainstorm-server/package.json`:
- Around line 1-11: Update package.json to set "private": true at the top level
and bump the dependency versions: change "express" to a version >= 4.20.0 (or
latest 4.x/5.x) and "ws" to >= 8.17.1 in the "dependencies" object (leave
"chokidar" unchanged); after editing package.json run npm install (or yarn
install) to update package-lock.json/yarn.lock and verify no breaking changes.
In `@lib/brainstorm-server/start-server.sh`:
- Around line 33-45: The timeout branch currently exits without cleaning up the
background server and temporary directory; capture the background server PID
when launching it (e.g., assign $! to SERVER_PID where the server is started)
and on timeout kill that PID (first try kill "$SERVER_PID" then fallback to kill
-9 if needed), wait for it to exit, and remove the temp directory (e.g., rm -rf
"$TEMP_DIR" or "$TMP_DIR") before printing the JSON error and exiting with
status 1; also handle cases where SERVER_PID or the temp-dir variable may be
empty to avoid errors.
In `@tests/brainstorm-server/server.test.js`:
- Around line 8-10: The test is setting BRAINSTORM_SCREEN and a TEST_SCREEN path
but the server expects BRAINSTORM_DIR and the test does not create the screen
directory, causing ENOENT; update the test to export the correct env var (set
process.env.BRAINSTORM_DIR to the directory portion of TEST_SCREEN or adjust
SERVER_PATH usage) and ensure the test creates the directory for TEST_SCREEN
before any file writes (mkdir -p semantics) and clean it up after; apply the
same changes where TEST_SCREEN/port/env are used (the other occurrences around
the blocks referenced) so the server reads the right env and the directory
exists during reload tests.
In `@tests/claude-code/test-document-review-system.sh`:
- Around line 92-98: The failing exit code of the pipeline is overwritten by the
subsequent echo, so capture the exit status immediately after running the
command and before any other commands; assign the exit status of the `timeout
120 claude -p "$PROMPT" --permission-mode bypassPermissions 2>&1 | tee
"$OUTPUT_FILE"` pipeline (i.e., `$?`) to a local variable (e.g., EXIT_CODE)
right after it fails, then use that variable in the `echo "EXECUTION FAILED
(exit code: $EXIT_CODE)"` and the `exit $EXIT_CODE` calls; reference the
pipeline invocation and the `$?` usage in your fix.
🧹 Nitpick comments (9)
.gitattributes (1)
1-17: LGTM! Consider adding a default text normalization rule.The line-ending configuration is correct:
- LF for shell scripts ensures cross-platform compatibility
- LF for .cmd files is appropriate given their polyglot nature (parsed by both cmd and bash)
- Text and binary file coverage is comprehensive
Optional enhancement: Consider adding a default text normalization rule at the beginning of the file:
+# Auto-detect text files and normalize line endings +* text=auto + # Ensure shell scripts always have LF line endings *.sh text eol=lfThis provides defense-in-depth for file types not explicitly listed.
lib/brainstorm-server/stop-server.sh (1)
14-19: Consider validating SCREEN_DIR beforerm -rf.The script deletes
$SCREEN_DIRunconditionally when the PID file exists. If this script is ever invoked with an incorrect or malicious path argument,rm -rfcould cause unintended data loss.Consider adding a sanity check to ensure
SCREEN_DIRis within an expected parent directory (e.g., a temp directory or a known session root):Suggested safety check
if [[ -f "$PID_FILE" ]]; then pid=$(cat "$PID_FILE") kill "$pid" 2>/dev/null + # Safety: only remove if SCREEN_DIR looks like a session directory + if [[ "$SCREEN_DIR" == /tmp/* || "$SCREEN_DIR" == */brainstorm-session-* ]]; then # Clean up session directory rm -rf "$SCREEN_DIR" + else + echo '{"warning": "skipped cleanup - unexpected directory path"}' + fi echo '{"status": "stopped"}'skills/writing-plans/plan-document-reviewer-prompt.md (1)
9-9: Add language specifier to fenced code block.The code block lacks a language specifier. Since this contains a YAML-like task tool definition, consider adding
yamlfor syntax highlighting.Suggested fix
-``` +```yaml Task tool (general-purpose):lib/brainstorm-server/frame-template.html (2)
1-2: Addlangattribute to<html>element for accessibility.The
<html>element is missing thelangattribute, which is important for screen readers and accessibility compliance (WCAG 2.1 Success Criterion 3.1.1).Suggested fix
<!DOCTYPE html> -<html> +<html lang="en">
247-256: Add defensive check forbrainstormobject.The
send()function callsbrainstorm.sendToClaude(payload)without checking if thebrainstormobject exists. Ifhelper.jsfails to load or inject the global, this will throw a runtime error.Suggested fix
function send() { const feedbackEl = document.getElementById('feedback'); const feedback = feedbackEl.value.trim(); const payload = {}; if (selectedChoice) payload.choice = selectedChoice; if (feedback) payload.feedback = feedback; if (Object.keys(payload).length === 0) return; + if (typeof brainstorm === 'undefined' || !brainstorm.sendToClaude) { + console.error('Brainstorm helper not loaded'); + return; + } brainstorm.sendToClaude(payload); feedbackEl.value = ''; }lib/brainstorm-server/wait-for-feedback.sh (1)
16-27: Consider handling missing log file and adding a timeout.Two potential reliability concerns:
Missing log file: If
.server.logdoesn't exist when the script starts,wc -lreturns 0 (good), buttailwill silently fail on each poll iteration until the file is created. Consider adding an initial wait for the file.No timeout: The script polls indefinitely. If the server crashes or the user abandons the session, this script hangs forever. Consider adding an optional timeout parameter.
♻️ Suggested improvements
# Record current position in log file +# Wait for log file to exist (server may still be starting) +TIMEOUT=10 +while [[ ! -f "$LOG_FILE" ]] && (( TIMEOUT-- > 0 )); do + sleep 0.5 +done + LOG_POS=$(wc -l < "$LOG_FILE" 2>/dev/null || echo 0) +# Optional: Add max iterations for timeout (e.g., 1800 iterations = 6 minutes) +MAX_ITERATIONS=${2:-0} # 0 = no limit +ITERATION=0 + # Poll for new lines containing the event while true; do RESULT=$(tail -n +$((LOG_POS + 1)) "$LOG_FILE" 2>/dev/null | grep -m 1 "send-to-claude") if [[ -n "$RESULT" ]]; then echo "$RESULT" exit 0 fi + if [[ $MAX_ITERATIONS -gt 0 ]] && (( ++ITERATION >= MAX_ITERATIONS )); then + echo '{"error": "Timeout waiting for feedback"}' >&2 + exit 2 + fi sleep 0.2 doneskills/brainstorming/visual-companion.md (1)
22-30: Clarify the relationship between wait-for-feedback.sh and TaskOutput.The quick start shows two waiting mechanisms:
- Line 23:
wait-for-feedback.sh(shell-based polling)- Line 28:
TaskOutput(task_id, block=true, timeout=600000)(tool-based blocking)It's unclear how these interact. Does
TaskOutputread from the watcher's output, or are these alternative approaches? A brief note explaining the connection would help Claude (and developers) understand the workflow.skills/brainstorming/spec-document-reviewer-prompt.md (1)
9-9: Add a language identifier to the fenced code block.The static analysis tool flagged MD040 for missing language specification. Since this is a prompt template, consider using
textormarkdownas the language identifier.♻️ Suggested fix
-``` +```text Task tool (general-purpose):lib/brainstorm-server/helper.js (1)
72-88: Single debounce timer loses rapid cross-field input events.The shared
inputTimeoutvariable means typing in field A, then quickly switching to field B (within 500ms), cancels field A's event. If multiple form fields are expected, consider per-element debouncing.Per-element debounce alternative
// Auto-capture input changes (debounced) - let inputTimeout = null; + const inputTimeouts = new WeakMap(); document.addEventListener('input', (e) => { const target = e.target; if (!target.matches('input, textarea, select')) return; - clearTimeout(inputTimeout); - inputTimeout = setTimeout(() => { + clearTimeout(inputTimeouts.get(target)); + inputTimeouts.set(target, setTimeout(() => { send({ type: 'input', name: target.name || null, id: target.id || null, value: target.value, inputType: target.type || target.tagName.toLowerCase() }); - }, 500); // 500ms debounce + }, 500)); });
| ``` | ||
| use find_skills tool | ||
| use skill tool to list skills | ||
| ``` |
There was a problem hiding this comment.
Add fenced code block language identifiers (MD040).
Markdownlint will continue to flag these examples without a language.
🧹 Suggested fix
-```
+```text
use skill tool to list skills
```diff
-```
+```text
use skill tool to load superpowers/brainstorming
</details>
Also applies to: 179-181
<details>
<summary>🧰 Tools</summary>
<details>
<summary>🪛 markdownlint-cli2 (0.18.1)</summary>
171-171: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
</details>
</details>
<details>
<summary>🤖 Prompt for AI Agents</summary>
In @docs/README.opencode.md around lines 171 - 173, The fenced code blocks
containing the examples "use skill tool to list skills" and "use skill tool to
load superpowers/brainstorming" are missing language identifiers; update those
backtick blocks to include a language such as text (e.g., change totext)
for each occurrence (including the second example referenced at 179-181) so
markdownlint MD040 no longer flags them. Ensure every fenced block that shows
those exact example lines is updated consistently to include the language
identifier.
</details>
<!-- fingerprinting:phantom:poseidon:eagle -->
<!-- This is an auto-generated comment by CodeRabbit -->
| **Output format:** | ||
| ``` | ||
| ## Spec Review | ||
|
|
||
| **Status:** Approved | Issues Found | ||
|
|
||
| **Issues (if any):** | ||
| - [Section X]: [issue] - [why it matters] | ||
|
|
||
| **Recommendations (advisory):** | ||
| - [suggestions that don't block approval] | ||
| ``` |
There was a problem hiding this comment.
Add language identifiers to fenced code blocks (MD040).
markdownlint flags code fences without a language spec.
🔧 Proposed fix
-```
+```text
## Spec Review
**Status:** Approved | Issues Found
@@
-```
+```text
brainstorming -> spec -> SPEC REVIEW LOOP -> writing-plans -> plan -> PLAN REVIEW LOOP -> implementation</details>
Also applies to: 83-85
<details>
<summary>🧰 Tools</summary>
<details>
<summary>🪛 markdownlint-cli2 (0.18.1)</summary>
29-29: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
</details>
</details>
<details>
<summary>🤖 Prompt for AI Agents</summary>
In @docs/superpowers/specs/2026-01-22-document-review-system-design.md around
lines 28 - 39, The fenced code block that starts with "## Spec Review" is
missing a language identifier (MD040); update both opening triple-backtick
fences to include a language (e.g., change totext) for the block
containing "## Spec Review" and the later fenced block containing the workflow
line "brainstorming -> spec -> SPEC REVIEW LOOP -> writing-plans -> plan -> PLAN
REVIEW LOOP -> implementation" so markdownlint stops flagging them; ensure you
update the opening fences for the blocks referenced in the diff and the other
occurrence at the section noted as "Also applies to: 83-85".
</details>
<!-- fingerprinting:phantom:poseidon:eagle -->
<!-- This is an auto-generated comment by CodeRabbit -->
hooks/hooks.json
Outdated
| { | ||
| "type": "command", | ||
| "command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cmd\" session-start.sh" | ||
| "command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh" |
There was a problem hiding this comment.
Quote CLAUDE_PLUGIN_ROOT to avoid path splitting.
Claude Code expands variables before shell execution, so unquoted paths with spaces will break the hook. Please wrap the variable in single quotes. Based on learnings, this is required for reliable hook execution.
✅ Proposed fix
- "command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh"
+ "command": "'${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh'"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh" | |
| "command": "'${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh'" |
🤖 Prompt for AI Agents
In `@hooks/hooks.json` at line 9, The command in hooks.json uses an unquoted
expansion of CLAUDE_PLUGIN_ROOT which can break when the path contains spaces;
update the "command" value from "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh"
to use single quotes around the expansion (i.e.,
'${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh') so the shell receives the path
as a single argument and the session-start.sh hook runs reliably.
| ws.onmessage = (msg) => { | ||
| const data = JSON.parse(msg.data); | ||
| if (data.type === 'reload') { | ||
| window.location.reload(); | ||
| } | ||
| }; |
There was a problem hiding this comment.
Add error handling for WebSocket message parsing.
If the server sends malformed JSON, JSON.parse will throw and crash the handler silently. This could break the reload functionality.
Proposed fix
ws.onmessage = (msg) => {
- const data = JSON.parse(msg.data);
- if (data.type === 'reload') {
- window.location.reload();
+ try {
+ const data = JSON.parse(msg.data);
+ if (data.type === 'reload') {
+ window.location.reload();
+ }
+ } catch (e) {
+ console.warn('Invalid message from server:', e);
}
};📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ws.onmessage = (msg) => { | |
| const data = JSON.parse(msg.data); | |
| if (data.type === 'reload') { | |
| window.location.reload(); | |
| } | |
| }; | |
| ws.onmessage = (msg) => { | |
| try { | |
| const data = JSON.parse(msg.data); | |
| if (data.type === 'reload') { | |
| window.location.reload(); | |
| } | |
| } catch (e) { | |
| console.warn('Invalid message from server:', e); | |
| } | |
| }; |
🤖 Prompt for AI Agents
In `@lib/brainstorm-server/helper.js` around lines 15 - 20, The ws.onmessage
handler currently calls JSON.parse(msg.data) without protection; wrap the parse
in a try/catch inside the ws.onmessage function to prevent malformed JSON from
throwing and breaking the handler, e.g., try to parse msg.data, verify the
resulting object exists and has data.type === 'reload' before calling
window.location.reload(), and in the catch block log the parsing error (using
console.error or a logger) and return silently so the handler continues to run
safely.
| wss.on('connection', (ws) => { | ||
| clients.add(ws); | ||
| ws.on('close', () => clients.delete(ws)); | ||
|
|
||
| ws.on('message', (data) => { | ||
| // User interaction event - write to stdout for Claude | ||
| const event = JSON.parse(data.toString()); | ||
| console.log(JSON.stringify({ source: 'user-event', ...event })); | ||
| }); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Check file existence and view the specific lines with context
if [ -f lib/brainstorm-server/index.js ]; then
echo "=== Lines 50-70 of lib/brainstorm-server/index.js ==="
sed -n '50,70p' lib/brainstorm-server/index.js | cat -n
echo ""
echo "=== Checking for error handlers on ws/wss objects ==="
rg -n "ws\.on\('error'|wss\.on\('error'|\.on\('error'" lib/brainstorm-server/index.js
else
echo "File not found"
fiRepository: obra/superpowers
Length of output: 951
Guard against invalid JSON in WebSocket messages.
A malformed client payload will throw on JSON.parse and crash the server process.
🔧 Proposed fix
ws.on('message', (data) => {
// User interaction event - write to stdout for Claude
- const event = JSON.parse(data.toString());
- console.log(JSON.stringify({ source: 'user-event', ...event }));
+ let event;
+ try {
+ event = JSON.parse(data.toString());
+ } catch (err) {
+ console.warn(JSON.stringify({ type: 'invalid-user-event', error: err.message }));
+ return;
+ }
+ console.log(JSON.stringify({ source: 'user-event', ...event }));
});🤖 Prompt for AI Agents
In `@lib/brainstorm-server/index.js` around lines 55 - 63, The ws.on('message')
handler currently calls JSON.parse directly which can throw on malformed
payloads and crash the server; update the message handler inside the
wss.on('connection' /* connection callback */) to wrap the
JSON.parse(data.toString()) call in a try/catch, handle parse errors by logging
the parse failure (include the raw data and error) via console.error or process
logger, and skip processing that message (optionally send an error response over
ws) instead of letting the exception bubble up and crash the process; keep the
rest of the successful-path behavior (building event and console.log) unchanged.
| { | ||
| "name": "brainstorm-server", | ||
| "version": "1.0.0", | ||
| "description": "Visual brainstorming companion server for Claude Code", | ||
| "main": "index.js", | ||
| "dependencies": { | ||
| "chokidar": "^3.5.3", | ||
| "express": "^4.18.2", | ||
| "ws": "^8.14.2" | ||
| } | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
chokidar 3.5.3 security vulnerabilities CVE
💡 Result:
No CVEs are currently mapped as direct vulnerabilities in chokidar@3.5.3 in major vulnerability databases (i.e., no “package chokidar is vulnerable” CVE entries for that version). Snyk reports no direct vulnerabilities for chokidar (including the 3.x line). [1] Meterian likewise lists no known vulnerabilities for chokidar@3.5.3. [2]
Notes that often cause confusion:
- Older chokidar versions could pull in vulnerable dependencies (example: CVE-2020-28469 via
glob-parent), and upgrading away from older chokidar was cited as mitigation. [3] - Separate from CVEs, there have been typosquatting/malicious packages impersonating chokidar (e.g., look-alike package names). These are supply-chain threats, not CVEs in the legit
chokidarpackage. [4]
Sources: Snyk chokidar package page [1]; Meterian chokidar@3.5.3 page [2]; Drupal issue referencing CVE-2020-28469 via dependency chain [3]; Socket research on chokidar typosquatting packages [4].
🌐 Web query:
express 4.18.2 security vulnerabilities CVE
💡 Result:
Express 4.18.2 is affected by these published CVEs (directly and via its common bundled dependencies):
Express (core)
- CVE-2024-29041 – open redirect via malformed URLs in
res.location()/res.redirect()(affected < 4.19.2). Fix: upgrade to ≥ 4.19.2. [1] - CVE-2024-43796 – XSS / untrusted code execution risk when passing user input to
response.redirect()(affected < 4.20.0). Fix: upgrade to ≥ 4.20.0. [2]
Dependencies typically shipped with Express 4.18.x
- CVE-2024-43799 –
senduntrusted input toSendStream.redirect()(patched in send 0.19.0). Express 4.x updates this via later releases. [3] - CVE-2024-43800 –
serve-staticuntrusted input toredirect()(patched in serve-static 1.16.0). Express 4.x updates this via later releases. [4] - CVE-2024-45296 –
path-to-regexpReDoS (Express recommends upgrading the module; later Express 4.x releases update it). [5][6] - CVE-2024-47764 –
cookiecookie-field injection via crafted name/path/domain (patched in cookie 0.7.0; Express 4.21.1 updatescookie). [7][6]
Practical remediation
- If you must stay on Express 4.x, upgrade to the latest 4.x listed on Express’ security updates page (it includes dependency bumps for
send,serve-static,cookie, andpath-to-regexp). [6]
Sources: [1] [2] [3] [4] [5] [6] [7]
🌐 Web query:
ws 8.14.2 security vulnerabilities CVE
💡 Result:
For the Node.js ws (websockets/ws) library, version 8.14.2 falls in the affected range for:
- CVE-2024-37890 — Denial of Service (DoS): a request with too many HTTP headers (exceeding
server.maxHeadersCount) can crash awsserver. Affected versions includews>= 8.0.0 and < 8.17.1, so 8.14.2 is vulnerable. Fix: upgrade tows8.17.1+ (or use backports for older major versions). Sources: NVD and vendor advisory-derived databases. [1] [2]
Sources:
[1] https://nvd.nist.gov/vuln/detail/CVE-2024-37890
[2] https://cve.armis.com/cve-2024-37890
🏁 Script executed:
#!/bin/bash
# Check npm registry for current versions and basic info
echo "=== Checking npm registry for package information ==="
for pkg in "chokidar" "express" "ws"; do
echo ""
echo "--- $pkg ---"
npm view "$pkg" --json 2>/dev/null | jq '.version' 2>/dev/null || echo "Could not fetch from npm"
doneRepository: obra/superpowers
Length of output: 185
Upgrade express and ws for security fixes; add "private": true.
The package.json has known security vulnerabilities:
- express 4.18.2: affected by CVE-2024-29041 (open redirect), CVE-2024-43796 (XSS), and dependency vulnerabilities. Upgrade to ≥ 4.20.0 (or latest 4.x/5.x).
- ws 8.14.2: affected by CVE-2024-37890 (DoS via excessive HTTP headers). Upgrade to ≥ 8.17.1.
- chokidar 3.5.3: no known vulnerabilities.
Also add "private": true to prevent accidental npm publish of this internal tool.
🤖 Prompt for AI Agents
In `@lib/brainstorm-server/package.json` around lines 1 - 11, Update package.json
to set "private": true at the top level and bump the dependency versions: change
"express" to a version >= 4.20.0 (or latest 4.x/5.x) and "ws" to >= 8.17.1 in
the "dependencies" object (leave "chokidar" unchanged); after editing
package.json run npm install (or yarn install) to update
package-lock.json/yarn.lock and verify no breaking changes.
| # Wait for server-started message (check log file) | ||
| for i in {1..50}; do | ||
| if grep -q "server-started" "$LOG_FILE" 2>/dev/null; then | ||
| # Extract and output the server-started line | ||
| grep "server-started" "$LOG_FILE" | head -1 | ||
| exit 0 | ||
| fi | ||
| sleep 0.1 | ||
| done | ||
|
|
||
| # Timeout - server didn't start | ||
| echo '{"error": "Server failed to start within 5 seconds"}' | ||
| exit 1 |
There was a problem hiding this comment.
Clean up background server on startup timeout.
On timeout, the script exits but leaves the background server running and the temp dir behind, which can leak processes/ports across runs.
🔧 Proposed fix
# Timeout - server didn't start
-echo '{"error": "Server failed to start within 5 seconds"}'
-exit 1
+if kill -0 "$SERVER_PID" 2>/dev/null; then
+ kill "$SERVER_PID" 2>/dev/null
+fi
+rm -f "$PID_FILE"
+rm -rf "$SCREEN_DIR"
+echo '{"error": "Server failed to start within 5 seconds"}'
+exit 1📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| # Wait for server-started message (check log file) | |
| for i in {1..50}; do | |
| if grep -q "server-started" "$LOG_FILE" 2>/dev/null; then | |
| # Extract and output the server-started line | |
| grep "server-started" "$LOG_FILE" | head -1 | |
| exit 0 | |
| fi | |
| sleep 0.1 | |
| done | |
| # Timeout - server didn't start | |
| echo '{"error": "Server failed to start within 5 seconds"}' | |
| exit 1 | |
| # Wait for server-started message (check log file) | |
| for i in {1..50}; do | |
| if grep -q "server-started" "$LOG_FILE" 2>/dev/null; then | |
| # Extract and output the server-started line | |
| grep "server-started" "$LOG_FILE" | head -1 | |
| exit 0 | |
| fi | |
| sleep 0.1 | |
| done | |
| # Timeout - server didn't start | |
| if kill -0 "$SERVER_PID" 2>/dev/null; then | |
| kill "$SERVER_PID" 2>/dev/null | |
| fi | |
| rm -f "$PID_FILE" | |
| rm -rf "$SCREEN_DIR" | |
| echo '{"error": "Server failed to start within 5 seconds"}' | |
| exit 1 |
🧰 Tools
🪛 Shellcheck (0.11.0)
[warning] 34-34: i appears unused. Verify use (or export if used externally).
(SC2034)
🤖 Prompt for AI Agents
In `@lib/brainstorm-server/start-server.sh` around lines 33 - 45, The timeout
branch currently exits without cleaning up the background server and temporary
directory; capture the background server PID when launching it (e.g., assign $!
to SERVER_PID where the server is started) and on timeout kill that PID (first
try kill "$SERVER_PID" then fallback to kill -9 if needed), wait for it to exit,
and remove the temp directory (e.g., rm -rf "$TEMP_DIR" or "$TMP_DIR") before
printing the JSON error and exiting with status 1; also handle cases where
SERVER_PID or the temp-dir variable may be empty to avoid errors.
| echo "================================================================================" | ||
| cd "$SCRIPT_DIR/../.." && timeout 120 claude -p "$PROMPT" --permission-mode bypassPermissions 2>&1 | tee "$OUTPUT_FILE" || { | ||
| echo "" | ||
| echo "================================================================================" | ||
| echo "EXECUTION FAILED (exit code: $?)" | ||
| exit 1 | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n tests/claude-code/test-document-review-system.sh | sed -n '85,105p'Repository: obra/superpowers
Length of output: 984
Capture the failing exit code before running echo statements.
$? on line 96 reflects the exit code of the preceding echo command (which succeeds with 0), not the failed command on line 93. This logs "EXECUTION FAILED (exit code: 0)" regardless of the actual failure status.
🔧 Proposed fix
cd "$SCRIPT_DIR/../.." && timeout 120 claude -p "$PROMPT" --permission-mode bypassPermissions 2>&1 | tee "$OUTPUT_FILE" || {
+ status=$?
echo ""
echo "================================================================================"
- echo "EXECUTION FAILED (exit code: $?)"
+ echo "EXECUTION FAILED (exit code: $status)"
exit 1
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| echo "================================================================================" | |
| cd "$SCRIPT_DIR/../.." && timeout 120 claude -p "$PROMPT" --permission-mode bypassPermissions 2>&1 | tee "$OUTPUT_FILE" || { | |
| echo "" | |
| echo "================================================================================" | |
| echo "EXECUTION FAILED (exit code: $?)" | |
| exit 1 | |
| } | |
| echo "================================================================================" | |
| cd "$SCRIPT_DIR/../.." && timeout 120 claude -p "$PROMPT" --permission-mode bypassPermissions 2>&1 | tee "$OUTPUT_FILE" || { | |
| status=$? | |
| echo "" | |
| echo "================================================================================" | |
| echo "EXECUTION FAILED (exit code: $status)" | |
| exit 1 | |
| } |
🧰 Tools
🪛 Shellcheck (0.11.0)
[warning] 96-96: This $? refers to echo/printf, not a previous command. Assign to variable to avoid it being overwritten.
(SC2320)
🤖 Prompt for AI Agents
In `@tests/claude-code/test-document-review-system.sh` around lines 92 - 98, The
failing exit code of the pipeline is overwritten by the subsequent echo, so
capture the exit status immediately after running the command and before any
other commands; assign the exit status of the `timeout 120 claude -p "$PROMPT"
--permission-mode bypassPermissions 2>&1 | tee "$OUTPUT_FILE"` pipeline (i.e.,
`$?`) to a local variable (e.g., EXIT_CODE) right after it fails, then use that
variable in the `echo "EXECUTION FAILED (exit code: $EXIT_CODE)"` and the `exit
$EXIT_CODE` calls; reference the pipeline invocation and the `$?` usage in your
fix.
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In `@docs/plans/2026-01-17-visual-brainstorming.md`:
- Around line 37-122: The snippet uses a single SCREEN_FILE and watches it,
which is outdated; update it to use SCREEN_DIR, watch the directory for 'add'
and 'change' events, and replace the simple file-serving logic with a
getNewestScreen() implementation that picks the newest .html by mtime and serves
that file; specifically, remove references to SCREEN_FILE usage, switch to
SCREEN_DIR and SCREEN_DIR env var handling, add a getNewestScreen() helper used
by the express route, and update the chokidar watcher to watch SCREEN_DIR and
handle both additions and changes so behavior matches the current implementation
in getNewestScreen and the directory-watching logic.
In `@lib/brainstorm-server/start-server.sh`:
- Around line 20-25: The cleanup block using PID_FILE derived from SESSION_ID
(in start-server.sh) is ineffective because SESSION_ID is unique per run; change
the cleanup to target a stable PID location or scan for stale PID files: either
set PID_FILE to a fixed path (e.g., /tmp/brainstorm-server.pid) and use that in
the existing removal/killing logic, or implement a scan that iterates
/tmp/brainstorm-*/ directories to read and validate each PID file and kill stale
PIDs before removing them; update references to PID_FILE and SESSION_ID
accordingly and ensure the new logic safely checks process liveness before kill
to avoid false positives.
- Line 28: The script currently runs cd "$SCRIPT_DIR" without checking if it
succeeded, so if the chdir fails the subsequent node index.js runs from the
wrong directory; update the start-up logic to test the exit status of cd (or use
a conditional like cd "$SCRIPT_DIR" || { ... }) and on failure log an error
mentioning SCRIPT_DIR and exit with a non-zero status before invoking node
index.js so the server never starts from the wrong location.
In `@RELEASE-NOTES.md`:
- Around line 26-30: The unreleased changelog contains a duplicate breaking
change entry "OpenCode: Switched to native skills system" that already appears
in the v4.1.0 section; remove the duplicate from the unreleased section (or mark
it explicitly as intentionally carried forward) so the unreleased section only
lists new, unreleased changes; locate the entry by searching for the exact
heading/text "OpenCode: Switched to native skills system" in RELEASE-NOTES.md
and either delete that block under the Unreleased heading or add a clear note
that it’s intentionally repeated.
♻️ Duplicate comments (3)
lib/brainstorm-server/package.json (1)
2-9: Duplicate: verify dependency versions and consider"private": true.Same as the earlier review note: the versions at Line 6–9 should be verified for current advisories/updates, and adding
"private": truewould prevent accidental publish.Are there any published security advisories affecting express 4.18.2 or ws 8.14.2, and what are the latest secure versions in their current major lines?lib/brainstorm-server/start-server.sh (1)
43-45: Clean up background server on startup timeout.On timeout, the script exits but leaves the background server running and the temp directory behind. This can leak processes and ports across runs.
🔧 Proposed fix
# Timeout - server didn't start +if kill -0 "$SERVER_PID" 2>/dev/null; then + kill "$SERVER_PID" 2>/dev/null +fi +rm -f "$PID_FILE" +rm -rf "$SCREEN_DIR" echo '{"error": "Server failed to start within 5 seconds"}' exit 1tests/claude-code/test-document-review-system.sh (1)
92-98: Capture the failing exit code before running echo statements.
$?on line 96 reflects the exit code of the precedingechocommand (which succeeds with 0), not the failed command on line 93. This logs "EXECUTION FAILED (exit code: 0)" regardless of the actual failure status.🔧 Proposed fix
-cd "$SCRIPT_DIR/../.." && timeout 120 claude -p "$PROMPT" --permission-mode bypassPermissions 2>&1 | tee "$OUTPUT_FILE" || { +cd "$SCRIPT_DIR/../.." && timeout 120 claude -p "$PROMPT" --permission-mode bypassPermissions 2>&1 | tee "$OUTPUT_FILE" || { + status=$? echo "" echo "================================================================================" - echo "EXECUTION FAILED (exit code: $?)" + echo "EXECUTION FAILED (exit code: $status)" exit 1 }
🧹 Nitpick comments (6)
lib/brainstorm-server/stop-server.sh (1)
14-19: Validate path beforerm -rfand verify process termination.The script removes
$SCREEN_DIRbased on user input without path validation. Consider:
- Verifying
SCREEN_DIRstarts with/tmp/brainstorm-to prevent accidental deletion of unrelated directories- Waiting briefly for the process to terminate before cleanup
🔧 Proposed fix
if [[ -f "$PID_FILE" ]]; then pid=$(cat "$PID_FILE") + # Validate SCREEN_DIR is a brainstorm temp directory + if [[ ! "$SCREEN_DIR" =~ ^/tmp/brainstorm- ]]; then + echo '{"error": "Invalid screen directory path"}' + exit 1 + fi kill "$pid" 2>/dev/null + # Brief wait for process to terminate + sleep 0.1 # Clean up session directory rm -rf "$SCREEN_DIR" echo '{"status": "stopped"}'skills/writing-plans/plan-document-reviewer-prompt.md (1)
40-40: Minor inconsistency with spec reviewer status format.The status format here (
Approved | Issues Found) differs from the spec reviewer template which uses emoji (✅ Approved | ❌ Issues Found). Consider aligning the formats for consistency across reviewer outputs.🔧 Proposed fix
- **Status:** Approved | Issues Found + **Status:** ✅ Approved | ❌ Issues Foundtests/claude-code/test-document-review-system.sh (1)
141-150: Test 4 logic has ambiguous success path.Lines 148-149 report
[PASS]with message "ambiguous format but found issues" when neither the explicit rejection patterns (Issues Found,❌,not approved) nor the explicit approval patterns (Approved,✅without issues) are matched. This could mask cases where the reviewer output is malformed or doesn't follow the expected template at all.Consider tightening the verification to require explicit issue detection rather than falling through to a pass:
🔧 Proposed fix
# Test 4: Reviewer did NOT approve (found issues) echo "Test 4: Reviewer verdict..." if grep -qi "Issues Found\|❌\|not approved\|issues found" "$OUTPUT_FILE"; then echo " [PASS] Reviewer correctly found issues (not approved)" elif grep -qi "Approved\|✅" "$OUTPUT_FILE" && ! grep -qi "Issues Found\|❌" "$OUTPUT_FILE"; then echo " [FAIL] Reviewer incorrectly approved spec with errors" FAILED=$((FAILED + 1)) else - echo " [PASS] Reviewer identified problems (ambiguous format but found issues)" + echo " [WARN] Reviewer output format unclear - manual verification needed" + echo " Neither explicit approval nor explicit rejection found" + # Don't fail, but flag for attention fidocs/superpowers/plans/2026-01-22-document-review-system.md (1)
26-75: Verify the nested code block structure in the template.The embedded template contains a markdown code fence (lines 26-35) followed by the actual prompt content (lines 36-71) followed by another code fence marker (line 72). This nested structure might be confusing when implementing.
Consider clarifying whether:
- The entire content (lines 27-74) should be written to
spec-document-reviewer-prompt.mdas-is- The Task tool prompt is the section from lines 38-71
The current structure mixes the template documentation with the actual prompt content, which could lead to implementation errors.
💡 Suggested clarification
Consider restructuring to clearly separate:
- What the markdown file should contain (the template)
- What the Task tool prompt should be (extracted from the template)
For example:
- [ ] **Step 1:** Create the reviewer prompt template file The file should contain: - Purpose and dispatch timing - A template showing how to use the Task tool - The actual prompt text to send to the reviewer subagent Create `skills/brainstorming/spec-document-reviewer-prompt.md` with this content: ```markdown [template content here]</details> </blockquote></details> <details> <summary>docs/plans/2026-01-17-visual-brainstorming.md (2)</summary><blockquote> `545-545`: **Add language specifier to code fence.** The code fence at line 545 (showing .gitignore content) should specify a language for better syntax highlighting and markdown compliance. <details> <summary>💡 Suggested fix</summary> ```diff -``` +```gitignore lib/brainstorm-server/node_modules/</details> --- `1-11`: **Update the execution requirement header to match the newer pattern.** Line 3 uses "REQUIRED SUB-SKILL: Use superpowers:executing-plans" which is inconsistent with the newer pattern established in the document-review-system plan. Consider updating to the more flexible pattern: ```markdown > **For Claude:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan.This newer pattern supports both execution modes and is already adopted in the document-review-system plan (2026-01-22).
| # Kill any existing server | ||
| if [[ -f "$PID_FILE" ]]; then | ||
| old_pid=$(cat "$PID_FILE") | ||
| kill "$old_pid" 2>/dev/null | ||
| rm -f "$PID_FILE" | ||
| fi |
There was a problem hiding this comment.
Old server cleanup logic is ineffective.
This block attempts to kill any existing server, but PID_FILE is derived from SESSION_ID which is unique per invocation ($$-$(date +%s)). The PID file will never exist for a new session, so this cleanup is a no-op. If the intent is to clean up orphaned servers from crashed sessions, consider either:
- Using a fixed PID file location (e.g.,
/tmp/brainstorm-server.pid) - Or scanning for any
/tmp/brainstorm-*/directories with stale PID files
🤖 Prompt for AI Agents
In `@lib/brainstorm-server/start-server.sh` around lines 20 - 25, The cleanup
block using PID_FILE derived from SESSION_ID (in start-server.sh) is ineffective
because SESSION_ID is unique per run; change the cleanup to target a stable PID
location or scan for stale PID files: either set PID_FILE to a fixed path (e.g.,
/tmp/brainstorm-server.pid) and use that in the existing removal/killing logic,
or implement a scan that iterates /tmp/brainstorm-*/ directories to read and
validate each PID file and kill stale PIDs before removing them; update
references to PID_FILE and SESSION_ID accordingly and ensure the new logic
safely checks process liveness before kill to avoid false positives.
| fi | ||
|
|
||
| # Start server, capturing output to log file | ||
| cd "$SCRIPT_DIR" |
There was a problem hiding this comment.
Handle cd failure.
If cd "$SCRIPT_DIR" fails, the script continues and runs node index.js from the wrong directory.
🔧 Proposed fix
-cd "$SCRIPT_DIR"
+cd "$SCRIPT_DIR" || { echo '{"error": "Failed to change to script directory"}'; exit 1; }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| cd "$SCRIPT_DIR" | |
| cd "$SCRIPT_DIR" || { echo '{"error": "Failed to change to script directory"}'; exit 1; } |
🧰 Tools
🪛 Shellcheck (0.11.0)
[warning] 28-28: Use 'cd ... || exit' or 'cd ... || return' in case cd fails.
(SC2164)
🤖 Prompt for AI Agents
In `@lib/brainstorm-server/start-server.sh` at line 28, The script currently runs
cd "$SCRIPT_DIR" without checking if it succeeded, so if the chdir fails the
subsequent node index.js runs from the wrong directory; update the start-up
logic to test the exit status of cd (or use a conditional like cd "$SCRIPT_DIR"
|| { ... }) and on failure log an error mentioning SCRIPT_DIR and exit with a
non-zero status before invoking node index.js so the server never starts from
the wrong location.
| **OpenCode: Switched to native skills system** | ||
|
|
||
| Superpowers for OpenCode now uses OpenCode's native `skill` tool instead of custom `use_skill`/`find_skills` tools. This is a cleaner integration that works with OpenCode's built-in skill discovery. | ||
|
|
||
| **Migration required:** Skills must be symlinked to `~/.config/opencode/skills/superpowers/` (see updated installation docs). |
There was a problem hiding this comment.
Duplicate breaking change entry with v4.1.0.
The "OpenCode: Switched to native skills system" breaking change (lines 26-30) duplicates content from v4.1.0 (lines 105-109). If this is intentionally carried forward to unreleased for emphasis, consider removing it since it's already released. Otherwise, if v4.1.0 changes were already deployed, the unreleased section should only contain new changes.
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
26-26: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
🤖 Prompt for AI Agents
In `@RELEASE-NOTES.md` around lines 26 - 30, The unreleased changelog contains a
duplicate breaking change entry "OpenCode: Switched to native skills system"
that already appears in the v4.1.0 section; remove the duplicate from the
unreleased section (or mark it explicitly as intentionally carried forward) so
the unreleased section only lists new, unreleased changes; locate the entry by
searching for the exact heading/text "OpenCode: Switched to native skills
system" in RELEASE-NOTES.md and either delete that block under the Unreleased
heading or add a clear note that it’s intentionally repeated.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@lib/brainstorm-server/helper.js`:
- Around line 120-129: The send() function is building a payload object with
choice and feedback but calls sendToClaude(payload) while sendToClaude(event)
expects feedback as a string and assigns event.feedback directly; update
sendToClaude to accept a structured object (e.g., { choice, feedback }) and map
its fields to the event sent (or alternatively change send() to call
sendToClaude(feedback) and send choice separately). Locate the functions
window.send and sendToClaude and modify sendToClaude’s parameter handling so it
reads payload.feedback and payload.choice (and sets event.feedback and
event.choice) to preserve both fields.
In `@lib/brainstorm-server/index.js`:
- Around line 35-46: getNewestScreen reads SCREEN_DIR then calls fs.statSync for
each file which can throw if a file is removed (TOCTOU); wrap the stat call in a
try/catch inside getNewestScreen (or use fs.statSync guarded by fs.existsSync)
and skip files that throw or can't be stat'ed so the function returns the newest
existing .html file instead of crashing; update the mapping block that builds
the {name,path,mtime} entries to catch stat errors and filter out failed entries
before sorting.
🧹 Nitpick comments (2)
skills/brainstorming/SKILL.md (1)
41-45: Clarify the spec-document-reviewer-prompt.md location.The Spec Review Loop references
spec-document-reviewer-prompt.mdwithout specifying its location. For consistency with line 71's visual-companion reference, consider using the full path.📝 Proposed clarification
**Spec Review Loop:** After writing the spec document: -1. Dispatch spec-document-reviewer subagent (see spec-document-reviewer-prompt.md) +1. Dispatch spec-document-reviewer subagent (see `${CLAUDE_PLUGIN_ROOT}/skills/brainstorming/spec-document-reviewer-prompt.md`) 2. If Issues Found: fix, re-dispatch, repeat until Approved 3. If loop exceeds 5 iterations, surface to human for guidancelib/brainstorm-server/index.js (1)
27-32: Regex-based template injection is fragile.The
wrapInFramefunction uses a regex to find and replace content within the frame template. If the template structure changes (e.g., different whitespace, additional wrapper divs), the regex may fail silently and return malformed HTML.Consider using a more robust approach like a placeholder marker:
💡 Proposed improvement
In
frame-template.html, add a placeholder comment:<div id="claude-content"> <!-- CONTENT_PLACEHOLDER --> </div>Then in
index.js:function wrapInFrame(content) { - return frameTemplate.replace( - /(<div id="claude-content">)[\s\S]*?(<\/div>\s*<\/div>\s*<div class="feedback-footer">)/, - `$1\n ${content}\n $2` - ); + return frameTemplate.replace('<!-- CONTENT_PLACEHOLDER -->', content); }This is more maintainable and won't break if the template structure evolves.
lib/brainstorm-server/helper.js
Outdated
| window.send = function() { | ||
| const feedbackEl = document.getElementById('feedback'); | ||
| const feedback = feedbackEl ? feedbackEl.value.trim() : ''; | ||
| const payload = {}; | ||
| if (window.selectedChoice) payload.choice = window.selectedChoice; | ||
| if (feedback) payload.feedback = feedback; | ||
| if (Object.keys(payload).length === 0) return; | ||
| sendToClaude(payload); | ||
| if (feedbackEl) feedbackEl.value = ''; | ||
| }; |
There was a problem hiding this comment.
Parameter mismatch in sendToClaude call.
The send() function passes an object { choice, feedback } to sendToClaude() on line 127, but sendToClaude() (lines 92-96) expects a simple feedback parameter and assigns it directly to event.feedback. This means the choice is being sent as the feedback property, losing the structured data.
🔧 Proposed fix
window.send = function() {
const feedbackEl = document.getElementById('feedback');
const feedback = feedbackEl ? feedbackEl.value.trim() : '';
const payload = {};
if (window.selectedChoice) payload.choice = window.selectedChoice;
if (feedback) payload.feedback = feedback;
if (Object.keys(payload).length === 0) return;
- sendToClaude(payload);
+ sendEvent({
+ type: 'send-to-claude',
+ choice: payload.choice || null,
+ feedback: payload.feedback || null
+ });
+ // Show themed confirmation page
+ document.body.innerHTML = `
+ <div style="display: flex; align-items: center; justify-content: center; height: 100vh; font-family: system-ui, -apple-system, BlinkMacSystemFont, sans-serif; background: var(--bg-primary, `#f5f5f7`);">
+ <div style="text-align: center; color: var(--text-secondary, `#86868b`);">
+ <h2 style="color: var(--text-primary, `#1d1d1f`); margin-bottom: 0.5rem;">Sent to Claude</h2>
+ <p>Return to the terminal to see Claude's response.</p>
+ </div>
+ </div>
+ `;
if (feedbackEl) feedbackEl.value = '';
};Alternatively, update sendToClaude to accept an object:
- function sendToClaude(feedback) {
+ function sendToClaude(payload) {
sendEvent({
type: 'send-to-claude',
- feedback: feedback || null
+ choice: payload?.choice || null,
+ feedback: payload?.feedback || null
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| window.send = function() { | |
| const feedbackEl = document.getElementById('feedback'); | |
| const feedback = feedbackEl ? feedbackEl.value.trim() : ''; | |
| const payload = {}; | |
| if (window.selectedChoice) payload.choice = window.selectedChoice; | |
| if (feedback) payload.feedback = feedback; | |
| if (Object.keys(payload).length === 0) return; | |
| sendToClaude(payload); | |
| if (feedbackEl) feedbackEl.value = ''; | |
| }; | |
| window.send = function() { | |
| const feedbackEl = document.getElementById('feedback'); | |
| const feedback = feedbackEl ? feedbackEl.value.trim() : ''; | |
| const payload = {}; | |
| if (window.selectedChoice) payload.choice = window.selectedChoice; | |
| if (feedback) payload.feedback = feedback; | |
| if (Object.keys(payload).length === 0) return; | |
| sendEvent({ | |
| type: 'send-to-claude', | |
| choice: payload.choice || null, | |
| feedback: payload.feedback || null | |
| }); | |
| // Show themed confirmation page | |
| document.body.innerHTML = ` | |
| <div style="display: flex; align-items: center; justify-content: center; height: 100vh; font-family: system-ui, -apple-system, BlinkMacSystemFont, sans-serif; background: var(--bg-primary, `#f5f5f7`);"> | |
| <div style="text-align: center; color: var(--text-secondary, `#86868b`);"> | |
| <h2 style="color: var(--text-primary, `#1d1d1f`); margin-bottom: 0.5rem;">Sent to Claude</h2> | |
| <p>Return to the terminal to see Claude's response.</p> | |
| </div> | |
| </div> | |
| `; | |
| if (feedbackEl) feedbackEl.value = ''; | |
| }; |
🤖 Prompt for AI Agents
In `@lib/brainstorm-server/helper.js` around lines 120 - 129, The send() function
is building a payload object with choice and feedback but calls
sendToClaude(payload) while sendToClaude(event) expects feedback as a string and
assigns event.feedback directly; update sendToClaude to accept a structured
object (e.g., { choice, feedback }) and map its fields to the event sent (or
alternatively change send() to call sendToClaude(feedback) and send choice
separately). Locate the functions window.send and sendToClaude and modify
sendToClaude’s parameter handling so it reads payload.feedback and
payload.choice (and sets event.feedback and event.choice) to preserve both
fields.
| function getNewestScreen() { | ||
| const files = fs.readdirSync(SCREEN_DIR) | ||
| .filter(f => f.endsWith('.html')) | ||
| .map(f => ({ | ||
| name: f, | ||
| path: path.join(SCREEN_DIR, f), | ||
| mtime: fs.statSync(path.join(SCREEN_DIR, f)).mtime.getTime() | ||
| })) | ||
| .sort((a, b) => b.mtime - a.mtime); | ||
|
|
||
| return files.length > 0 ? files[0].path : null; | ||
| } |
There was a problem hiding this comment.
Potential TOCTOU race in getNewestScreen.
The function reads the directory, stats each file, and sorts by mtime. If a file is deleted between readdirSync and statSync, this will throw. Consider wrapping the stat call in a try/catch.
🛡️ Proposed fix
function getNewestScreen() {
const files = fs.readdirSync(SCREEN_DIR)
.filter(f => f.endsWith('.html'))
- .map(f => ({
- name: f,
- path: path.join(SCREEN_DIR, f),
- mtime: fs.statSync(path.join(SCREEN_DIR, f)).mtime.getTime()
- }))
+ .map(f => {
+ const filePath = path.join(SCREEN_DIR, f);
+ try {
+ return {
+ name: f,
+ path: filePath,
+ mtime: fs.statSync(filePath).mtime.getTime()
+ };
+ } catch {
+ return null;
+ }
+ })
+ .filter(Boolean)
.sort((a, b) => b.mtime - a.mtime);
return files.length > 0 ? files[0].path : null;
}🤖 Prompt for AI Agents
In `@lib/brainstorm-server/index.js` around lines 35 - 46, getNewestScreen reads
SCREEN_DIR then calls fs.statSync for each file which can throw if a file is
removed (TOCTOU); wrap the stat call in a try/catch inside getNewestScreen (or
use fs.statSync guarded by fs.existsSync) and skip files that throw or can't be
stat'ed so the function returns the newest existing .html file instead of
crashing; update the mapping block that builds the {name,path,mtime} entries to
catch stat errors and filter out failed entries before sorting.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@RELEASE-NOTES.md`:
- Around line 3-91: Release notes omission: add a new Unreleased subsection
documenting the "document review system and workflow enforcement" feature,
describing the spec and plan reviewer prompts and review loops; specifically
mention the new prompt files
skills/brainstorming/spec-document-reviewer-prompt.md and
skills/writing-plans/plan-document-reviewer-prompt.md, the addition of review
loops to the brainstorming and writing-plans skills, and the integration test
tests/claude-code/test-document-review-system.sh; keep the entry concise, mirror
the style of other entries (heading, short bullets), and include a one-line
migration/usage note indicating where reviewers live and how they are invoked.
🧹 Nitpick comments (4)
RELEASE-NOTES.md (1)
62-62: Remove trailing space inside code span.The code span contains a trailing space:
`bash `. The space should be outside the backticks for proper formatting.✨ Proposed fix
-Claude Code 2.1.x changed how hooks execute on Windows: it now auto-detects `.sh` files in commands and prepends `bash `. This broke the polyglot wrapper pattern because `bash "run-hook.cmd" session-start.sh` tries to execute the .cmd file as a bash script. +Claude Code 2.1.x changed how hooks execute on Windows: it now auto-detects `.sh` files in commands and prepends `bash`. This broke the polyglot wrapper pattern because `bash "run-hook.cmd" session-start.sh` tries to execute the .cmd file as a bash script.As per coding guidelines, markdownlint-cli2 flagged MD038 (no-space-in-code).
skills/writing-plans/plan-document-reviewer-prompt.md (1)
40-40: Minor inconsistency with status format.The output format shows
Approved | Issues Foundwithout emoji indicators, while the implementation plan atdocs/superpowers/plans/2026-01-22-document-review-system.md(lines 64, 184) uses✅ Approved | ❌ Issues Found. Consider aligning for consistency.📝 Suggested change
- **Status:** Approved | Issues Found + **Status:** ✅ Approved | ❌ Issues Foundlib/brainstorm-server/helper.js (1)
9-11: Address linting warning for forEach callback return value.The arrow function implicitly returns the result of
ws.send(), which is flagged by static analysis. While functionally harmless, using block syntax clarifies intent.📝 Suggested change
ws.onopen = () => { - eventQueue.forEach(e => ws.send(JSON.stringify(e))); + eventQueue.forEach(e => { ws.send(JSON.stringify(e)); }); eventQueue = []; };tests/brainstorm-server/server.test.js (1)
10-10: Hardcoded test directory may conflict with parallel test runs.
TEST_DIRis hardcoded to/tmp/brainstorm-test. If tests run in parallel (e.g., CI matrix), they could interfere with each other. Consider using a unique suffix ormkdtemp.📝 Suggested change
-const TEST_DIR = '/tmp/brainstorm-test'; +const TEST_DIR = `/tmp/brainstorm-test-${process.pid}`;
| ## Unreleased | ||
|
|
||
| ### Breaking Changes | ||
|
|
||
| **Specs and plans directory restructured** | ||
|
|
||
| - Specs (brainstorming output) now go to `docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md` | ||
| - Plans (writing-plans output) now go to `docs/superpowers/plans/YYYY-MM-DD-<feature-name>.md` | ||
| - User preferences for spec/plan locations override these defaults | ||
| - Migration: move existing files from `docs/plans/` to new locations if desired | ||
|
|
||
| **Brainstorming → writing-plans transition enforced** | ||
|
|
||
| - After design approval, brainstorming now requires using writing-plans skill | ||
| - Platform planning features (e.g., EnterPlanMode) should not be used | ||
| - Direct implementation without writing-plans is not allowed | ||
|
|
||
| **Subagent-driven development now mandatory on capable harnesses** | ||
|
|
||
| - On harnesses with subagent support (Claude Code), subagent-driven-development is now required after plan approval | ||
| - No longer offers a choice between subagent-driven and executing-plans | ||
| - Executing-plans is only used on harnesses without subagent capability | ||
|
|
||
| **OpenCode: Switched to native skills system** | ||
|
|
||
| Superpowers for OpenCode now uses OpenCode's native `skill` tool instead of custom `use_skill`/`find_skills` tools. This is a cleaner integration that works with OpenCode's built-in skill discovery. | ||
|
|
||
| **Migration required:** Skills must be symlinked to `~/.config/opencode/skills/superpowers/` (see updated installation docs). | ||
|
|
||
| ### Fixes | ||
|
|
||
| **OpenCode: Fixed agent reset on session start (#226)** | ||
|
|
||
| The previous bootstrap injection method using `session.prompt({ noReply: true })` caused OpenCode to reset the selected agent to "build" on first message. Now uses `experimental.chat.system.transform` hook which modifies the system prompt directly without side effects. | ||
|
|
||
| **OpenCode: Fixed Windows installation (#232)** | ||
|
|
||
| - Removed dependency on `skills-core.js` (eliminates broken relative imports when file is copied instead of symlinked) | ||
| - Added comprehensive Windows installation docs for cmd.exe, PowerShell, and Git Bash | ||
| - Documented proper symlink vs junction usage for each platform | ||
|
|
||
| ### New Features | ||
|
|
||
| **Visual companion for brainstorming skill** | ||
|
|
||
| Added optional browser-based visual companion for brainstorming sessions. When users have a browser available, brainstorming can display interactive screens showing current phase, questions, and design decisions in a more readable format than terminal output. | ||
|
|
||
| Components: | ||
| - `lib/brainstorm-server/` - WebSocket server for real-time updates | ||
| - `skills/brainstorming/visual-companion.md` - Integration guide | ||
| - Helper scripts for session management with proper isolation | ||
| - Browser helper library for event capture | ||
|
|
||
| The visual companion is opt-in and falls back gracefully to terminal-only operation. | ||
|
|
||
| ### Bug Fixes | ||
|
|
||
| **Fixed Windows hook execution for Claude Code 2.1.x** | ||
|
|
||
| Claude Code 2.1.x changed how hooks execute on Windows: it now auto-detects `.sh` files in commands and prepends `bash `. This broke the polyglot wrapper pattern because `bash "run-hook.cmd" session-start.sh` tries to execute the .cmd file as a bash script. | ||
|
|
||
| Fix: hooks.json now calls session-start.sh directly. Claude Code 2.1.x handles the bash invocation automatically. Also added .gitattributes to enforce LF line endings for shell scripts (fixes CRLF issues on Windows checkout). | ||
|
|
||
| **Brainstorming visual companion: reduced token cost and improved persistence** | ||
|
|
||
| The visual companion now generates much smaller HTML per screen. The server automatically wraps bare content fragments in the frame template (header, CSS theme, feedback footer, interactive JS), so Claude writes only the content portion (~30 lines instead of ~260). Full HTML documents are still served as-is when Claude needs complete control. | ||
|
|
||
| Other improvements: | ||
| - `toggleSelect`/`send`/`selectedChoice` moved from inline template script to `helper.js` (auto-injected) | ||
| - `start-server.sh --project-dir` persists mockups under `.superpowers/brainstorm/` instead of `/tmp` | ||
| - `stop-server.sh` only deletes ephemeral `/tmp` sessions, preserving persistent ones | ||
| - Dark mode fix: `sendToClaude` confirmation page now uses CSS variables instead of hardcoded colors | ||
| - Skill restructured: SKILL.md is minimal (prompt + pointer); all visual companion details in progressive disclosure doc (`visual-companion.md`) | ||
| - Prompt to user now notes the feature is new, token-intensive, and can be slow | ||
| - Deleted redundant `CLAUDE-INSTRUCTIONS.md` (content folded into `visual-companion.md`) | ||
| - Test fixes: correct env var (`BRAINSTORM_DIR`), polling-based startup wait, new tests for frame wrapping | ||
|
|
||
| ### Improvements | ||
|
|
||
| **Instruction priority clarified in using-superpowers** | ||
|
|
||
| Added explicit instruction priority hierarchy to prevent conflicts with user preferences: | ||
|
|
||
| 1. User's explicit instructions (CLAUDE.md, direct requests) — highest priority | ||
| 2. Superpowers skills — override default system behavior where they conflict | ||
| 3. Default system prompt — lowest priority | ||
|
|
||
| This ensures users remain in control. If CLAUDE.md says "don't use TDD" and a skill says "always use TDD," CLAUDE.md wins. | ||
|
|
There was a problem hiding this comment.
Main PR feature missing from release notes.
The PR title is "feat: document review system and workflow enforcement" and the PR objectives describe a document review system with spec and plan reviewers as the primary feature, but the Unreleased section does not document this feature at all.
According to PR objectives, the following should be documented:
- Document review system with spec and plan reviewer prompts
skills/brainstorming/spec-document-reviewer-prompt.mdskills/writing-plans/plan-document-reviewer-prompt.md- Review loops added to brainstorming and writing-plans skills
- Integration test
tests/claude-code/test-document-review-system.sh
The release notes only mention directory restructuring, workflow enforcement, and the visual companion. Users reading these notes won't understand the core functionality this PR adds.
🧰 Tools
🪛 markdownlint-cli2 (0.20.0)
[warning] 62-62: Spaces inside code span elements
(MD038, no-space-in-code)
🤖 Prompt for AI Agents
In `@RELEASE-NOTES.md` around lines 3 - 91, Release notes omission: add a new
Unreleased subsection documenting the "document review system and workflow
enforcement" feature, describing the spec and plan reviewer prompts and review
loops; specifically mention the new prompt files
skills/brainstorming/spec-document-reviewer-prompt.md and
skills/writing-plans/plan-document-reviewer-prompt.md, the addition of review
loops to the brainstorming and writing-plans skills, and the integration test
tests/claude-code/test-document-review-system.sh; keep the entry concise, mirror
the style of other entries (heading, short bullets), and include a one-line
migration/usage note indicating where reviewers live and how they are invoked.
Create the initial server for the visual brainstorming companion: - Express server with WebSocket support for browser communication - File watcher (chokidar) to detect screen.html changes - Auto-injects helper.js into served HTML for event capture - Binds to localhost only (127.0.0.1) for security - Outputs JSON events to stdout for Claude consumption
The spread operator order was causing incoming event types to overwrite the user-event type marker.
- Add sendToClaude() function to browser helper that shows confirmation - Add wait-for-event.sh script for watching server output (tail -f | grep -m 1) - Enables clean event-driven loop: background bash waits for event, completion triggers Claude's turn
Adds browser-based mockup display to replace ASCII art during brainstorming sessions. Key components: - Frame template with OS-aware light/dark theming - CSS helpers for options, cards, mockups, split views - Server lifecycle scripts (start/stop with random high port) - Event watcher using tail+grep for feedback loop - Claude instructions for using the visual companion The skill now asks users if they want browser mockups and only runs in Claude Code environments.
- Each session gets unique temp directory (/tmp/brainstorm-{pid}-{timestamp})
- Server outputs screen_dir and screen_file in startup JSON
- stop-server.sh takes screen_dir arg and cleans up session directory
- Document blocking TaskOutput pattern: 10-min timeouts, retry up to 3x,
then prompt user "let me know when you want to continue"
- New show-and-wait.sh combines write + wait into one command - Uses polling instead of tail -f (which hangs on macOS) - Docs updated: start watcher BEFORE writing screen to avoid race - Reduces terminal noise by consolidating operations
Scripts: - Rename show-and-wait.sh -> wait-for-feedback.sh (just waits, no HTML piping) - Remove wait-for-event.sh (used hanging tail -f) - Workflow now: Write tool for HTML, wait-for-feedback.sh to block Documentation rewrite: - Broader "when to use" (UI, architecture, complex choices, spatial) - Always ask user first before starting - Scale fidelity to the question being asked - Explain the question on each page - Iterate before moving on - validate changes address feedback - Use real content (Unsplash images) when it matters
- Never use cat/heredoc for HTML (dumps noise into terminal) - Read screen_file first before Write tool to avoid errors - Remind user of URL on every step, not just first - Give text summary of what's on screen before they look
Server now watches directory for new .html files instead of a single screen file. Claude writes to semantically named files like platform.html, style.html, layout.html - each screen is a new file. Benefits: - No need to read before write (files are always new) - Semantic filenames describe what's on screen - History preserved in directory for debugging - Server serves newest file by mtime automatically Updated: index.js, start-server.sh, and all documentation.
Clarifies that user instructions (CLAUDE.md, direct requests) always take precedence over Superpowers skills, which in turn override default system prompt behavior. Ensures users remain in control. Also updates RELEASE-NOTES.md with unreleased changes including the visual companion feature.
* fix use_skill agent context (#290) * fix: respect OPENCODE_CONFIG_DIR for personal skills lookup (#297) * fix: respect OPENCODE_CONFIG_DIR for personal skills lookup The plugin was hardcoded to look for personal skills in ~/.config/opencode/skills, ignoring users who set OPENCODE_CONFIG_DIR to a custom path (e.g., for dotfiles management). Now uses OPENCODE_CONFIG_DIR if set, falling back to the default path. * fix: update help text to use dynamic paths Use configDir and personalSkillsDir variables in help text so paths are accurate when OPENCODE_CONFIG_DIR is set. * fix: normalize OPENCODE_CONFIG_DIR before use Handle edge cases where the env var might be: - Empty or whitespace-only - Using ~ for home directory (common in .env files) - A relative path Now trims, expands ~, and resolves to absolute path. * feat(opencode): use native skills and fix agent reset bug (#226) - Replace custom use_skill/find_skills tools with OpenCode's native skill tool - Use experimental.chat.system.transform hook instead of session.prompt (fixes #226 agent reset on first message) - Symlink skills directory into ~/.config/opencode/skills/superpowers/ - Update installation docs with comprehensive Windows support: - Command Prompt, PowerShell, and Git Bash instructions - Proper symlink vs junction handling - Reinstall safety with cleanup steps - Verification commands for each shell * Add OpenCode native skills changes to release notes Documents: - Breaking change: switch to native skill tool - Fix for agent reset bug (#226) - Fix for Windows installation (#232) --------- Co-authored-by: Vinicius da Motta <viniciusmotta8@gmail.com> Co-authored-by: oribi <oribarilan@gmail.com>
* fix: convert shell scripts from CRLF to LF line endings Add .gitattributes to enforce LF line endings for shell scripts, preventing bash errors like "/usr/bin/bash: line 1: : command not found" when scripts are checked out on Windows with CRLF. Fixes #317 (SessionStart hook fails due to CRLF line endings) Files converted: - hooks/session-start.sh - lib/brainstorm-server/start-server.sh - lib/brainstorm-server/stop-server.sh - lib/brainstorm-server/wait-for-feedback.sh - skills/systematic-debugging/find-polluter.sh Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: update Windows hook execution for Claude Code 2.1.x Claude Code 2.1.x changed the Windows execution model: it now auto-detects .sh files in hook commands and prepends "bash " automatically. This broke the polyglot wrapper because: Before: "run-hook.cmd" session-start.sh (wrapper executes) After: bash "run-hook.cmd" session-start.sh (bash can't run .cmd) Changes: - hooks.json now calls session-start.sh directly (Claude Code handles bash) - Added deprecation comment to run-hook.cmd explaining the change - Updated RELEASE-NOTES.md Fixes #317, #313, #275, #292 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Specs (brainstorming output) now go to docs/superpowers/specs/ - Plans (writing-plans output) now go to docs/superpowers/plans/ - User preferences for locations override these defaults - Update all skill references and test files Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Make writing-plans REQUIRED after design approval - Explicitly forbid platform planning features (EnterPlanMode, etc.) - Forbid direct implementation without writing-plans skill Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Spec: docs/superpowers/specs/2026-01-22-document-review-system-design.md - Plan: docs/superpowers/plans/2026-01-22-document-review-system.md Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The `- [ ] ### Task N:` syntax was unusual and might not render correctly in all markdown parsers. Now only steps have checkboxes. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Tests verify: - Spec document reviewer checks (completeness, TODOs) - Plan document reviewer checks (spec alignment, task decomposition) - Review loops exist in brainstorming and writing-plans skills - Chunk-by-chunk review for plans with 1000-line limit - Iteration guidance (5 iterations, escalate to human) - Checkbox syntax on steps only (not task headings) - Correct directories (docs/superpowers/specs, docs/superpowers/plans) - Reviewers are advisory - Same agent fixes issues (preserves context) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Creates test project with spec containing intentional errors - Runs Claude to actually review using spec-document-reviewer template - Verifies reviewer catches TODO and "specified later" deferrals - Checks review format and verdict Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move toggleSelect/send/selectedChoice from frame-template.html inline script to helper.js so they're auto-injected. Server now detects bare HTML fragments (no DOCTYPE/html tag) and wraps them in the frame template automatically. Full documents pass through as before. Fix dark mode in sendToClaude confirmation (was using hardcoded colors). Fix test env var bug (BRAINSTORM_SCREEN -> BRAINSTORM_DIR). Add tests for fragment wrapping, full doc passthrough, and helper.js.
start-server.sh now accepts --project-dir to store session files under .superpowers/brainstorm/ instead of /tmp. stop-server.sh only deletes ephemeral /tmp sessions, keeping persistent ones for later review. Fix test race condition with polling-based server startup wait.
SKILL.md is now minimal: process, principles, and a prompt that notes the visual companion is new/token-intensive/slow. All visual companion details move to visual-companion.md as a progressive disclosure document read only when the user opts in. Delete CLAUDE-INSTRUCTIONS.md (content folded into visual-companion.md). Document fragment vs full-document behavior and --project-dir persistence.
…ills Brainstorming: design-for-isolation guidance and brownfield codebase awareness Writing-plans: file structure section requiring decomposition before task definition Implementer prompt: code organization awareness, structured escalation protocol (DONE/DONE_WITH_CONCERNS/BLOCKED/NEEDS_CONTEXT), explicit permission to stop Subagent-driven-development: provider-agnostic model selection tiers, escalation handling
- Define DONE_WITH_CONCERNS handling in SDD controller flow - Make implementer action explicit when file grows beyond plan intent - Reword writing-plans file size reasoning (avoid tooling-artifact language) - Add decomposition awareness to code quality reviewer prompt
Focus on whether this implementation grew or created large files, not pre-existing file sizes in brownfield codebases.
Spec reviewer now checks for unit decomposition with clear boundaries. Plan reviewer now checks file structure and whether files will grow too large to reason about.
Brainstorming now assesses whether a project is too large for a single spec and helps decompose into sub-projects. Spec reviewer checks scope. Writing-plans has a backstop if brainstorming missed it.
Testing showed the model skipped scope assessment when it was a separate step after "Understanding the idea." Inlining it as the first thing in understanding ensures it fires before detailed questions.
Claude Code spawns hook commands with shell:true + windowsHide:true, but on Windows the execution chain cmd.exe -> bash.exe causes Git Bash (MSYS2) to allocate its own console window, bypassing the hide flag. This creates visible terminal windows that steal focus on every SessionStart event (startup, resume, clear, compact). The fix: - Rename session-start.sh to session-start (no extension) so Claude Code's .sh auto-detection regex doesn't fire and prepend "bash" - Restore run-hook.cmd polyglot wrapper to control bash invocation on Windows (tries known Git Bash paths, then PATH, then exits silently if no bash found) - On Unix, the polyglot's shell portion runs the script directly This avoids Claude Code's broken .sh auto-prepend, gives us control over how bash is invoked on Windows, and gracefully handles missing bash instead of erroring. Addresses: #440, #414, #354, #417, #293 Upstream: anthropics/claude-code#14828
…ing table Codex subagents inherit filesystem access and can discover superpowers skills via native discovery. Without guidance, they activate the 1% rule and invoke full skill workflows instead of executing their assigned task. - Add SUBAGENT-STOP gate check above the 1% rule in using-superpowers - Add Codex dispatch routing table (spawn_agent/wait/close_agent) - Add scope directives to all 4 subagent dispatch templates Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace verbose scope explanations with a direct override statement that explicitly claims priority over prior guidance (i.e. the using-superpowers 1% rule injected by Codex's skill discovery). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Addresses Jesse's review feedback on PR #450: - Move inline routing table from using-superpowers to references/codex-tools.md, leveraging Codex's native progressive disclosure for companion files - Narrow SUBAGENT-STOP from "Do not invoke skills" to "Do not invoke superpowers skills" so subagents can still use non-superpowers skills Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Let the SUBAGENT-STOP gate in using-superpowers handle skill leakage instead of per-template directives. This avoids blocking non-superpowers skills that users may want subagents to use. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Drop 'top-level sessions only' which may cause the model to treat using-superpowers as a first-turn-only skill, breaking skill chaining on follow-up turns. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
) * Refactor visual brainstorming: browser displays, terminal commands Replaces the blocking TaskOutput/wait-for-feedback.sh pattern with a non-blocking model where the browser is an interactive display and the terminal stays available for conversation. Server changes: - Write user click events to .events JSONL file (per-screen, cleared on new screen push) so Claude reads them on its next turn - Replace regex-based wrapInFrame with <!-- CONTENT --> placeholder - Add --foreground flag to start-server.sh for sandbox environments - Harden startup with nohup/disown and liveness check UI changes: - Remove feedback footer (textarea + Send button) - Add selection indicator bar ("Option X selected — return to terminal") - Narrow click handler to [data-choice] elements only Skill changes: - Rewrite visual-companion.md for non-blocking loop - Fix visual companion being skipped on Codex (no browser tools needed) - Make visual companion offer a standalone question (one question rule) Deletes wait-for-feedback.sh entirely. * Add visual companion offer to brainstorming checklist for UX topics The visual companion was a disconnected section at the bottom of SKILL.md that agents never reached because it wasn't in the mandatory checklist. Now step 2 evaluates whether the topic involves visual/UX decisions and offers the companion if so. Non-visual topics (APIs, data models, etc.) skip the step entirely. * Add multi-select support to visual companion Containers with data-multiselect allow toggling multiple selections. Without it, behavior is unchanged (single-select). Indicator bar shows count when multiple items are selected.
Targeted edits to original skill (not a rewrite): scaling paragraph in Overview, hard gate reframed around confirmed understanding, anti-pattern refocused on understanding vs ceremony, scalable checklist with GATE wording, graphviz with decision diamonds at gates, and design doc marked as 'when warranted'. CSO fix removes workflow summary from description. Tested 5/5: all confirm understanding, none create rigid 6-task checklist.
Minimal additions: one paragraph in Overview about scaling effort to task, a graphviz process flow diagram with the review-loop gate as an explicit decision point, and GATE wording requiring permission before eliding the review loop. Tested 5/5 workers now explicitly ask before skipping review.
Two small additions based on tested findings: - Flowchart Usage: document that decision diamonds in process flows act as behavioral enforcement mechanisms (citing 2/5 → 5/5 compliance evidence) - Bulletproofing: add GATE marker technique for non-optional decision points Tested 3/3: workers correctly retrieve and apply both techniques.
- brainstorming: check in with user before transitioning to writing-plans - writing-plans: structured execution handoff (record context, advise compaction, give exact continuation prompt with subagent detection) - SDD: add scaling paragraph with GATE + orchestrator boundary, graphviz decision diamonds for review elision, check-in before finishing, replace TodoWrite with generic task list language, tighten Red Flags
Summary
docs/superpowers/specs/, plans todocs/superpowers/plans/Document Review System
skills/brainstorming/spec-document-reviewer-prompt.md) - reviews specs after brainstormingskills/writing-plans/plan-document-reviewer-prompt.md) - reviews plans chunk-by-chunkKey Files
skills/brainstorming/SKILL.md- added spec review loopskills/writing-plans/SKILL.md- added plan review loop, chunk boundaries, checkbox syntax on stepstests/claude-code/test-document-review-system.sh- integration test that creates spec with errors and verifies reviewer catches themTest plan
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation
Tests