Compare commits

..

7 Commits

Author SHA1 Message Date
Drew Ritter
935de5d5ec Simplify Codex hook entrypoint 2026-05-14 15:51:53 -07:00
Drew Ritter
f5c43d6055 test: add Codex native hook drill coverage 2026-05-13 18:21:55 -07:00
Drew Ritter
51514f86c8 feat: support Codex native plugin hooks 2026-05-13 18:21:07 -07:00
Drew Ritter
a57b6c5dc1 docs: plan Codex native hooks implementation 2026-05-13 18:19:42 -07:00
Drew Ritter
de320dce01 docs: record Codex hook contract spike 2026-05-13 18:19:42 -07:00
Drew Ritter
62b64d1674 docs: refine Codex hooks spec after review 2026-05-13 18:19:42 -07:00
Drew Ritter
09f3871be2 docs: specify Codex native hooks parity 2026-05-13 18:19:42 -07:00
8 changed files with 44 additions and 79 deletions

2
evals

Submodule evals updated: e2b37138c8...29957de826

View File

@@ -37,13 +37,13 @@ session_context="<EXTREMELY_IMPORTANT>\nYou have superpowers.\n\n**Below is the
# See: https://github.com/obra/superpowers/issues/571 # See: https://github.com/obra/superpowers/issues/571
if [ -n "${CURSOR_PLUGIN_ROOT:-}" ]; then if [ -n "${CURSOR_PLUGIN_ROOT:-}" ]; then
# Cursor sets CURSOR_PLUGIN_ROOT (may also set CLAUDE_PLUGIN_ROOT) # Cursor sets CURSOR_PLUGIN_ROOT (may also set CLAUDE_PLUGIN_ROOT)
printf '{\n "additional_context": "%s"\n}\n' "$session_context" | cat printf '{\n "additional_context": "%s"\n}\n' "$session_context"
elif [ -n "${CLAUDE_PLUGIN_ROOT:-}" ] && [ -z "${COPILOT_CLI:-}" ]; then elif [ -n "${CLAUDE_PLUGIN_ROOT:-}" ] && [ -z "${COPILOT_CLI:-}" ]; then
# Claude Code sets CLAUDE_PLUGIN_ROOT without COPILOT_CLI # Claude Code sets CLAUDE_PLUGIN_ROOT without COPILOT_CLI
printf '{\n "hookSpecificOutput": {\n "hookEventName": "SessionStart",\n "additionalContext": "%s"\n }\n}\n' "$session_context" | cat printf '{\n "hookSpecificOutput": {\n "hookEventName": "SessionStart",\n "additionalContext": "%s"\n }\n}\n' "$session_context"
else else
# Copilot CLI (sets COPILOT_CLI=1) or unknown platform — SDK standard format # Copilot CLI (sets COPILOT_CLI=1) or unknown platform — SDK standard format
printf '{\n "additionalContext": "%s"\n}\n' "$session_context" | cat printf '{\n "additionalContext": "%s"\n}\n' "$session_context"
fi fi
exit 0 exit 0

View File

@@ -21,6 +21,6 @@ escape_for_json() {
using_superpowers_escaped=$(escape_for_json "$using_superpowers_content") using_superpowers_escaped=$(escape_for_json "$using_superpowers_content")
session_context="<EXTREMELY_IMPORTANT>\nYou have superpowers.\n\n**Below is the full content of your 'superpowers:using-superpowers' skill - your introduction to using skills. For all other skills, follow the Codex skill-loading instructions in that skill:**\n\n${using_superpowers_escaped}\n</EXTREMELY_IMPORTANT>" session_context="<EXTREMELY_IMPORTANT>\nYou have superpowers.\n\n**Below is the full content of your 'superpowers:using-superpowers' skill - your introduction to using skills. For all other skills, follow the Codex skill-loading instructions in that skill:**\n\n${using_superpowers_escaped}\n</EXTREMELY_IMPORTANT>"
printf '{\n "hookSpecificOutput": {\n "hookEventName": "SessionStart",\n "additionalContext": "%s"\n }\n}\n' "$session_context" | cat printf '{\n "hookSpecificOutput": {\n "hookEventName": "SessionStart",\n "additionalContext": "%s"\n }\n}\n' "$session_context"
exit 0 exit 0

View File

@@ -14,26 +14,22 @@ Subagent (general-purpose):
## What Was Implemented ## What Was Implemented
[DESCRIPTION] {DESCRIPTION}
## Requirements / Plan ## Requirements / Plan
[PLAN_OR_REQUIREMENTS] {PLAN_OR_REQUIREMENTS}
## Git Range to Review ## Git Range to Review
**Base:** [BASE_SHA] **Base:** {BASE_SHA}
**Head:** [HEAD_SHA] **Head:** {HEAD_SHA}
```bash ```bash
git diff --stat [BASE_SHA]..[HEAD_SHA] git diff --stat {BASE_SHA}..{HEAD_SHA}
git diff [BASE_SHA]..[HEAD_SHA] git diff {BASE_SHA}..{HEAD_SHA}
``` ```
## Read-Only Review
Your review is read-only on this checkout. Do not mutate the working tree, the index, HEAD, or branch state in any way. Use tools like `git show`, `git diff`, and `git log` to inspect history. If you need a working copy of a different revision, check it out into a separate temporary directory (e.g. `git worktree add /tmp/review-[SHA] [SHA]`) — never move HEAD on this checkout.
## What to Check ## What to Check
**Plan alignment:** **Plan alignment:**
@@ -126,10 +122,10 @@ Subagent (general-purpose):
``` ```
**Placeholders:** **Placeholders:**
- `[DESCRIPTION]` — brief summary of what was built - `{DESCRIPTION}` — brief summary of what was built
- `[PLAN_OR_REQUIREMENTS]` — what it should do (plan file path, task text, or requirements) - `{PLAN_OR_REQUIREMENTS}` — what it should do (plan file path, task text, or requirements)
- `[BASE_SHA]` — starting commit - `{BASE_SHA}` — starting commit
- `[HEAD_SHA]` — ending commit - `{HEAD_SHA}` — ending commit
**Reviewer returns:** Strengths, Issues (Critical / Important / Minor), Recommendations, Assessment **Reviewer returns:** Strengths, Issues (Critical / Important / Minor), Recommendations, Assessment

View File

@@ -18,22 +18,6 @@ Subagent (general-purpose):
[From implementer's report] [From implementer's report]
## Git Range to Review
**Base:** [BASE_SHA — commit before this task]
**Head:** [HEAD_SHA — current commit]
```bash
git diff --stat [BASE_SHA]..[HEAD_SHA]
git diff [BASE_SHA]..[HEAD_SHA]
```
Only read files in this diff. Do not crawl the broader codebase.
## Read-Only Review
Your review is read-only on this checkout. Do not mutate the working tree, the index, HEAD, or branch state in any way. Use tools like `git show`, `git diff`, and `git log` to inspect history. If you need a working copy of a different revision, check it out into a separate temporary directory (e.g. `git worktree add /tmp/review-[SHA] [SHA]`) — never move HEAD on this checkout.
## CRITICAL: Do Not Trust the Report ## CRITICAL: Do Not Trust the Report
The implementer finished suspiciously quickly. Their report may be incomplete, The implementer finished suspiciously quickly. Their report may be incomplete,

View File

@@ -237,7 +237,7 @@ If you catch yourself thinking:
- "Is that not happening?" - You assumed without verifying - "Is that not happening?" - You assumed without verifying
- "Will it show us...?" - You should have added evidence gathering - "Will it show us...?" - You should have added evidence gathering
- "Stop guessing" - You're proposing fixes without understanding - "Stop guessing" - You're proposing fixes without understanding
- "Ultra-think this" - Question fundamentals, not just symptoms - "Ultrathink this" - Question fundamentals, not just symptoms
- "We're stuck?" (frustrated) - Your approach isn't working - "We're stuck?" (frustrated) - Your approach isn't working
**When you see these:** STOP. Return to Phase 1. **When you see these:** STOP. Return to Phase 1.

View File

@@ -102,15 +102,15 @@ These thoughts mean STOP—you're rationalizing:
When multiple skills could apply, use this order: When multiple skills could apply, use this order:
1. **Process skills first** (brainstorming, systematic-debugging) - these determine HOW to approach the task 1. **Process skills first** (brainstorming, debugging) - these determine HOW to approach the task
2. **Implementation skills second** (frontend-design, mcp-builder) - these guide execution 2. **Implementation skills second** (frontend-design, mcp-builder) - these guide execution
"Let's build X" → brainstorming first, then implementation skills. "Let's build X" → brainstorming first, then implementation skills.
"Fix this bug" → systematic-debugging first, then domain-specific skills. "Fix this bug" → debugging first, then domain-specific skills.
## Skill Types ## Skill Types
**Rigid** (TDD, systematic-debugging): Follow exactly. Don't adapt away discipline. **Rigid** (TDD, debugging): Follow exactly. Don't adapt away discipline.
**Flexible** (patterns): Adapt principles to context. **Flexible** (patterns): Adapt principles to context.

View File

@@ -1,11 +1,9 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Windows lifecycle tests for the brainstorm server. # Windows lifecycle tests for the brainstorm server.
# #
# Verifies brainstorm server lifecycle behavior, including: # Verifies that the brainstorm server survives the 60-second lifecycle
# - Windows/MSYS2 foreground mode and empty OWNER_PID handling # check on Windows, where OWNER_PID monitoring is disabled because the
# - Server survival past the 60-second lifecycle check window # MSYS2 PID namespace is invisible to Node.js.
# - Dead-at-startup OWNER_PID validation (logged, monitoring disabled)
# - Clean stop-server.sh shutdown
# #
# Requirements: # Requirements:
# - Node.js in PATH # - Node.js in PATH
@@ -22,7 +20,7 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="${SUPERPOWERS_ROOT:-$(cd "$SCRIPT_DIR/../.." && pwd)}" REPO_ROOT="${SUPERPOWERS_ROOT:-$(cd "$SCRIPT_DIR/../.." && pwd)}"
START_SCRIPT="$REPO_ROOT/skills/brainstorming/scripts/start-server.sh" START_SCRIPT="$REPO_ROOT/skills/brainstorming/scripts/start-server.sh"
STOP_SCRIPT="$REPO_ROOT/skills/brainstorming/scripts/stop-server.sh" STOP_SCRIPT="$REPO_ROOT/skills/brainstorming/scripts/stop-server.sh"
SERVER_SCRIPT="$REPO_ROOT/skills/brainstorming/scripts/server.cjs" SERVER_JS="$REPO_ROOT/skills/brainstorming/scripts/server.js"
TEST_DIR="${TMPDIR:-/tmp}/brainstorm-win-test-$$" TEST_DIR="${TMPDIR:-/tmp}/brainstorm-win-test-$$"
@@ -66,7 +64,7 @@ skip() {
wait_for_server_info() { wait_for_server_info() {
local dir="$1" local dir="$1"
for _ in $(seq 1 50); do for _ in $(seq 1 50); do
if [[ -f "$dir/state/server-info" ]]; then if [[ -f "$dir/.server-info" ]]; then
return 0 return 0
fi fi
sleep 0.1 sleep 0.1
@@ -75,9 +73,9 @@ wait_for_server_info() {
} }
get_port_from_info() { get_port_from_info() {
# Read the port from state/server-info. Use grep/sed instead of Node.js # Read the port from .server-info. Use grep/sed instead of Node.js
# to avoid MSYS2-to-Windows path translation issues. # to avoid MSYS2-to-Windows path translation issues.
grep -o '"port":[0-9]*' "$1/state/server-info" | head -1 | sed 's/"port"://' grep -o '"port":[0-9]*' "$1/.server-info" | head -1 | sed 's/"port"://'
} }
http_check() { http_check() {
@@ -216,11 +214,11 @@ BRAINSTORM_HOST="127.0.0.1" \
BRAINSTORM_URL_HOST="localhost" \ BRAINSTORM_URL_HOST="localhost" \
BRAINSTORM_OWNER_PID="" \ BRAINSTORM_OWNER_PID="" \
BRAINSTORM_PORT=$((49152 + RANDOM % 16383)) \ BRAINSTORM_PORT=$((49152 + RANDOM % 16383)) \
node "$SERVER_SCRIPT" > "$TEST_DIR/survival/.server.log" 2>&1 & node "$SERVER_JS" > "$TEST_DIR/survival/.server.log" 2>&1 &
SERVER_PID=$! SERVER_PID=$!
if ! wait_for_server_info "$TEST_DIR/survival"; then if ! wait_for_server_info "$TEST_DIR/survival"; then
fail "Server starts successfully" "Server did not write state/server-info within 5 seconds" fail "Server starts successfully" "Server did not write .server-info within 5 seconds"
kill "$SERVER_PID" 2>/dev/null || true kill "$SERVER_PID" 2>/dev/null || true
SERVER_PID="" SERVER_PID=""
else else
@@ -256,15 +254,10 @@ else
SERVER_PID="" SERVER_PID=""
fi fi
# ========== Test 5: Dead-at-startup OWNER_PID is logged but does not kill the server ========== # ========== Test 5: Bad OWNER_PID causes shutdown (control) ==========
#
# The server validates BRAINSTORM_OWNER_PID at startup. If it's already dead,
# the PID resolution was wrong (common on WSL, Tailscale SSH, cross-user
# scenarios). The server logs 'owner-pid-invalid', disables owner monitoring,
# and continues running. The idle timeout becomes the only shutdown trigger.
echo "" echo ""
echo "--- Dead-at-startup OWNER_PID: server survives, logs owner-pid-invalid ---" echo "--- Control: Bad OWNER_PID causes shutdown ---"
mkdir -p "$TEST_DIR/control" mkdir -p "$TEST_DIR/control"
@@ -279,41 +272,33 @@ BRAINSTORM_HOST="127.0.0.1" \
BRAINSTORM_URL_HOST="localhost" \ BRAINSTORM_URL_HOST="localhost" \
BRAINSTORM_OWNER_PID="$BAD_PID" \ BRAINSTORM_OWNER_PID="$BAD_PID" \
BRAINSTORM_PORT=$((49152 + RANDOM % 16383)) \ BRAINSTORM_PORT=$((49152 + RANDOM % 16383)) \
node "$SERVER_SCRIPT" > "$TEST_DIR/control/.server.log" 2>&1 & node "$SERVER_JS" > "$TEST_DIR/control/.server.log" 2>&1 &
CONTROL_PID=$! CONTROL_PID=$!
if ! wait_for_server_info "$TEST_DIR/control"; then if ! wait_for_server_info "$TEST_DIR/control"; then
fail "Control server starts" "Server did not write state/server-info within 5 seconds" fail "Control server starts" "Server did not write .server-info within 5 seconds"
kill "$CONTROL_PID" 2>/dev/null || true kill "$CONTROL_PID" 2>/dev/null || true
CONTROL_PID="" CONTROL_PID=""
else else
pass "Control server starts with dead-at-startup OWNER_PID=$BAD_PID" pass "Control server starts with bad OWNER_PID=$BAD_PID"
echo " Waiting ~75s to verify server survives past lifecycle check..." echo " Waiting ~75s for lifecycle check to kill server..."
sleep 75 sleep 75
if kill -0 "$CONTROL_PID" 2>/dev/null; then if kill -0 "$CONTROL_PID" 2>/dev/null; then
pass "Server survives with dead-at-startup OWNER_PID (owner monitoring disabled)" fail "Control server self-terminates with bad OWNER_PID" \
"Server is still alive (expected it to die)"
kill "$CONTROL_PID" 2>/dev/null || true
else else
fail "Server survives with dead-at-startup OWNER_PID" \ pass "Control server self-terminates with bad OWNER_PID"
"Server died unexpectedly. Log tail: $(tail -5 "$TEST_DIR/control/.server.log" 2>/dev/null)"
fi
if grep -q "owner-pid-invalid" "$TEST_DIR/control/.server.log" 2>/dev/null; then
pass "Server logs 'owner-pid-invalid' for dead-at-startup PID"
else
fail "Server logs 'owner-pid-invalid' for dead-at-startup PID" \
"Log tail: $(tail -5 "$TEST_DIR/control/.server.log" 2>/dev/null)"
fi fi
if grep -q "owner process exited" "$TEST_DIR/control/.server.log" 2>/dev/null; then if grep -q "owner process exited" "$TEST_DIR/control/.server.log" 2>/dev/null; then
fail "No spurious 'owner process exited' log" \ pass "Control server logs 'owner process exited'"
"Found 'owner process exited' but owner monitoring should be disabled"
else else
pass "No spurious 'owner process exited' log" fail "Control server logs 'owner process exited'" \
"Log tail: $(tail -5 "$TEST_DIR/control/.server.log" 2>/dev/null)"
fi fi
kill "$CONTROL_PID" 2>/dev/null || true
fi fi
wait "$CONTROL_PID" 2>/dev/null || true wait "$CONTROL_PID" 2>/dev/null || true
@@ -324,16 +309,16 @@ CONTROL_PID=""
echo "" echo ""
echo "--- Clean Shutdown ---" echo "--- Clean Shutdown ---"
mkdir -p "$TEST_DIR/stop-test/state" mkdir -p "$TEST_DIR/stop-test"
BRAINSTORM_DIR="$TEST_DIR/stop-test" \ BRAINSTORM_DIR="$TEST_DIR/stop-test" \
BRAINSTORM_HOST="127.0.0.1" \ BRAINSTORM_HOST="127.0.0.1" \
BRAINSTORM_URL_HOST="localhost" \ BRAINSTORM_URL_HOST="localhost" \
BRAINSTORM_OWNER_PID="" \ BRAINSTORM_OWNER_PID="" \
BRAINSTORM_PORT=$((49152 + RANDOM % 16383)) \ BRAINSTORM_PORT=$((49152 + RANDOM % 16383)) \
node "$SERVER_SCRIPT" > "$TEST_DIR/stop-test/.server.log" 2>&1 & node "$SERVER_JS" > "$TEST_DIR/stop-test/.server.log" 2>&1 &
STOP_TEST_PID=$! STOP_TEST_PID=$!
echo "$STOP_TEST_PID" > "$TEST_DIR/stop-test/state/server.pid" echo "$STOP_TEST_PID" > "$TEST_DIR/stop-test/.server.pid"
if ! wait_for_server_info "$TEST_DIR/stop-test"; then if ! wait_for_server_info "$TEST_DIR/stop-test"; then
fail "Stop-test server starts" "Server did not start" fail "Stop-test server starts" "Server did not start"