Compare commits

..

12 Commits

Author SHA1 Message Date
Jesse Vincent 67714e036c refactor(skills): fold TDD Why Order Matters rebuttals into rationalization table
The eval verdict on this cut: deleting Why Order Matters and trusting the
compressed one-line table rows measurably degrades test-first behavior under
the exact pressure the section rebutted ("just write it, tests after") —
control 8/10 → treatment 5/10 at n=10, corroborated on both Claude and Codex.
Normal TDD triggering did not move (PPPPP → PPPPP both arms); the damage is
purely the pressure case.

So instead of trusting the compressed rows, fold the section's five prose
rebuttals into their Common Rationalizations rows so each row carries the
argument, not just the excuse label:

- "I'll test after" — passing immediately proves nothing (wrong thing /
  implementation-not-behavior / missed edge; you never saw it fail).
- "Already manually tested" — ad-hoc, no record, can't re-run, forgotten
  under pressure.
- "Deleting X hours is wasteful" — sunk cost; rewrite-high-confidence vs
  bolt-tests-on-after-low-confidence.
- "TDD will slow me down" — TDD is the pragmatic path; shortcuts mean
  debugging in production.
- "Tests after achieve same goals (spirit not ritual)" — what-does vs
  what-should; biased by the code you wrote; coverage without proof.

Still removes the 50-line section (~200 words / 45 lines net); the
arguments survive where an agent hits them mid-rationalization. Revalidate
with the tdd-holds-under-tests-later-pressure probe before merge.
2026-07-14 12:24:25 -07:00
Jesse Vincent 75ef64f3df refactor(skills): drop The Bottom Line recap from receiving-code-review
Restates the evaluate-don't-obey frame, verification rule, and
no-performative-agreement rule, each detailed earlier at point of use.
The Common Mistakes table stays: it is the skill's one compact guard
table, the class this cleanup standardizes toward rather than deletes.
2026-07-14 12:24:25 -07:00
Jesse Vincent 0aff5d6c64 refactor(skills): drop The Bottom Line recap from writing-skills
Restates the Iron Law, the RED-GREEN-REFACTOR mapping, and the
TDD-for-docs framing, all stated in full earlier in the file.
2026-07-14 12:24:25 -07:00
Jesse Vincent 12960fbaf7 refactor(skills): drop Remember recap from writing-plans
All four lines restate the Overview (DRY/YAGNI/TDD/frequent commits),
Task Structure (exact paths, commands with expected output), and No
Placeholders (complete code in every step).
2026-07-14 12:24:25 -07:00
Jesse Vincent 10f4868e4d refactor(skills): fold brainstorming Key Principles into points of use
Five of six principles restated the Checklist and Process sections
verbatim-in-spirit. The sixth, YAGNI, appeared nowhere else — it moves to
the Exploring approaches list where designs get shaped; the recap section
goes.
2026-07-14 12:24:25 -07:00
Jesse Vincent 2e039d0229 refactor(skills): convert using-git-worktrees guard sections to rationalization table
Common Mistakes and Red Flags restated Steps 0-3 wholesale; both fold
into one Common Rationalizations table (house Excuse/Reality form) whose
five rows carry the tempting-thought version of each rule, including the
#1-mistake emphasis on bypassing native tools. Quick Reference stays as
the compact decision aid.
2026-07-14 12:24:25 -07:00
Jesse Vincent 3adac24a6c refactor(skills): trim requesting-code-review, keep review guards as a table
Integration with Workflows restated the When to Request Review triggers
grouped by caller (each-task / before-merge / when-stuck all appear at
point of use) — detritus, so it goes.

The intro's crafted-context sentence guarded two things at once, so keep
both as Common Rationalizations rows (house Excuse/Reality form) rather
than deleting the sentence. The skill's reader is the coordinator, not
the code's author:

- Don't review the diff inline — that burns the coordinator's context
  window; dispatch a subagent so the diff and evaluation live in its
  context and only findings return. ("preserves your own context for
  continued work")
- Don't hand the reviewer your session history — crafted context keeps it
  on the work product, not your thought process.
2026-07-14 12:24:25 -07:00
Jesse Vincent 232993b395 refactor(skills): drop Advantages section from subagent-driven-development
Five blocks of benefits and cost/benefit selling aimed at a reader who
has already invoked the skill; the vs-Executing-Plans comparison also
duplicates the one under When to Use. Integration section untouched
(PR #1932 owns it).
2026-07-14 12:10:59 -07:00
Jesse Vincent dee15bcb9e refactor(skills): trim quality claim from executing-plans subagent note
The tell-your-partner directive and the prefer-SDD instruction stay; the
significantly-higher-quality sentence restated them as a claim.
Integration section untouched (PR #1932 owns it).
2026-07-14 12:10:59 -07:00
Jesse Vincent 447edeea29 refactor(skills): drop persuasion sections from verification-before-completion
Why This Matters (failure-memory testimonials), the dishonesty reframing
in the Overview, and The Bottom Line recap all restate stakes the Iron
Law, gate function, and rationalization table already enforce. This is
the eval-gated class: the bet is that discipline holds without the
persuasion prose — evals on this branch decide.
2026-07-14 12:10:38 -07:00
Jesse Vincent 880b9b84d5 refactor(skills): drop social proof from systematic-debugging
Real-World Impact was statistics; the Overview opener restated the core
principle as motivation. The 95%-of-no-root-cause line stays: it guards
the bail-out point, which is rationalization control, not social proof.
Supporting Techniques/Related skills untouched (PR #1932 owns that).
2026-07-14 12:10:38 -07:00
Jesse Vincent 37d9a63d45 refactor(skills): drop social proof from dispatching-parallel-agents
Real-World Impact restated the Real Example from Session as statistics;
Key Benefits and the time-saved line sold the skill to a reader already
executing it. Instructions unchanged.
2026-07-14 12:10:01 -07:00
9 changed files with 34 additions and 57 deletions
+3 -3
View File
@@ -784,10 +784,10 @@ Use this as the live index; when in doubt, read the files, not this table.
| Harness | Entry point | Bootstrap mechanism | Tool mapping | Tests | Distribution |
|---|---|---|---|---|---|
| Claude Code | `.claude-plugin/plugin.json` + `hooks/hooks.json` | shell hook → `hooks/session-start` (`hookSpecificOutput.additionalContext`) | native `Skill` tool; no adapter file needed | `tests/hooks/` | marketplace |
| Claude Code | `.claude-plugin/plugin.json` + `hooks/hooks.json` | shell hook → `hooks/session-start` (`hookSpecificOutput.additionalContext`) | native `Skill` tool; `references/claude-code-tools.md` | `tests/hooks/` | marketplace |
| Codex | `.codex-plugin/plugin.json` (declares empty `hooks`) | native skill discovery (no session-start hook) | `references/codex-tools.md` | `tests/codex/`, `tests/codex-plugin-sync/` | fork sync (`scripts/sync-to-codex-plugin.sh`) |
| Cursor | `.cursor-plugin/plugin.json` + `hooks/hooks-cursor.json` | shell hook → `hooks/session-start` (`additional_context`) | none needed (Claude Codecompatible tool surface) | `tests/hooks/` | hand-authored |
| Copilot CLI | (shares Claude Code hook path; `COPILOT_CLI` env) | shell hook → `hooks/session-start` (`additionalContext`) | none needed (Claude Codecompatible tool surface) | `tests/hooks/` | — |
| Cursor | `.cursor-plugin/plugin.json` + `hooks/hooks-cursor.json` | shell hook → `hooks/session-start` (`additional_context`) | `references/claude-code-tools.md` | `tests/hooks/` | hand-authored |
| Copilot CLI | (shares Claude Code hook path; `COPILOT_CLI` env) | shell hook → `hooks/session-start` (`additionalContext`) | `references/copilot-tools.md` | `tests/hooks/` | — |
| Gemini CLI | `gemini-extension.json` + `GEMINI.md` | instructions file `@`-includes bootstrap + mapping | `references/gemini-tools.md` | — | `gemini extensions install` |
| Kimi Code | `.kimi-plugin/plugin.json` | manifest `sessionStart.skill` loads `using-superpowers` | inline `skillInstructions` in manifest | `tests/kimi/` | marketplace or `/plugins install` GitHub URL |
| OpenCode | `.opencode/plugins/superpowers.js` (declared via root `package.json` `main`) | in-process: `config` hook registers skills dir; `experimental.chat.messages.transform` injects user message | inline in `superpowers.js` | `tests/opencode/` | `opencode.json` plugin git URL |
+4 -13
View File
@@ -230,16 +230,14 @@ prepare_metadata_root() {
METADATA_ROOT="$(prepare_metadata_root "$METADATA_SOURCE")"
# Pin tar.umask and extract with -p so staged modes are canonical 755/644
# regardless of the builder's git config or process umask.
git -C "$REPO_ROOT" -c tar.umask=0022 archive --format=tar "$REF" -- \
git -C "$REPO_ROOT" archive --format=tar "$REF" -- \
.codex-plugin \
CODE_OF_CONDUCT.md \
LICENSE \
README.md \
assets \
skills \
| tar -xpf - -C "$STAGE"
| tar -xf - -C "$STAGE"
VERSION="$(jq -r '.version // empty' "$STAGE/.codex-plugin/plugin.json")"
[[ -n "$VERSION" ]] || die "could not read version from .codex-plugin/plugin.json"
@@ -300,19 +298,12 @@ case "$FORMAT" in
)
;;
tar.gz)
# Match the prior official archive's deterministic tar entry metadata:
# ustar entries with uid/gid 0 and empty uname/gname. GNU tar and bsdtar
# (macOS) spell those flags differently.
if tar --version 2>/dev/null | grep -q 'GNU tar'; then
TAR_METADATA_FLAGS=(--owner=:0 --group=:0 --numeric-owner)
else
TAR_METADATA_FLAGS=(--uid 0 --gid 0 --uname '' --gname '')
fi
# Match the prior official archive's deterministic tar entry metadata.
TZ=UTC find "$STAGE" -exec touch -t 197001010000 {} +
(
cd "$STAGE"
rm -f "$OUTPUT"
COPYFILE_DISABLE=1 tar -cf - --no-recursion --format ustar "${TAR_METADATA_FLAGS[@]}" -T "$ARCHIVE_LIST" |
COPYFILE_DISABLE=1 tar -cf - --no-recursion --format ustar --uid 0 --gid 0 --uname '' --gname '' -T "$ARCHIVE_LIST" |
gzip -9n >"$OUTPUT"
)
;;
+1 -1
View File
@@ -9,7 +9,7 @@ description: Use when creating new skills, editing existing skills, or verifying
**Writing skills IS Test-Driven Development applied to process documentation.**
**Personal skills live in your runtime's skills directory** (`~/.claude/skills/` on Claude Code) — see [codex-tools.md](../using-superpowers/references/codex-tools.md) or [gemini-tools.md](../using-superpowers/references/gemini-tools.md) for the path on those runtimes. Codex, Copilot CLI, and Gemini CLI all also recognize `~/.agents/skills/` as a cross-runtime alias.
**Personal skills live in your runtime's skills directory** — see [claude-code-tools.md](../using-superpowers/references/claude-code-tools.md), [codex-tools.md](../using-superpowers/references/codex-tools.md), [copilot-tools.md](../using-superpowers/references/copilot-tools.md), or [gemini-tools.md](../using-superpowers/references/gemini-tools.md) for the path on your runtime. Codex, Copilot CLI, and Gemini CLI all also recognize `~/.agents/skills/` as a cross-runtime alias.
You write test cases (pressure scenarios with subagents), watch them fail (baseline behavior), write the skill (documentation), watch tests pass (agents comply), and refactor (close loopholes).
+12 -5
View File
@@ -2,9 +2,8 @@
# Validate the Antigravity (agy) integration. agy installs the existing plugin
# directly (`agy plugin install <repo-url>`): it loads the bundled skills and
# runs the SessionStart hook for bootstrap, so there is no agy-specific scaffold
# to test. What IS agy-specific is the tool mapping — subagent dispatch via
# invoke_subagent (self/research types) and task tracking via a task artifact —
# and SKILL.md pointing at it.
# to test. What IS agy-specific is the tool mapping — agy has no `Skill` tool and
# loads skills by reading SKILL.md with view_file — and SKILL.md pointing at it.
#
# Mirrors tests/pi/test-pi-extension.mjs's "tools reference documents
# harness-specific mappings" check. CI-safe: does not require `agy` installed.
@@ -23,8 +22,16 @@ echo "test-antigravity-tools: checking Antigravity tool mapping"
# --- Mapping exists ---------------------------------------------------------
[ -f "$MAPPING" ] || fail "tool mapping missing at $MAPPING"
# --- Skill-load mechanism: view_file on SKILL.md (IsSkillFile), no Skill tool -
grep -qiE "view_file" "$MAPPING" \
|| fail "mapping does not document view_file as the file/skill-read tool"
grep -qiE "SKILL\.md" "$MAPPING" \
|| fail "mapping does not document reading SKILL.md as the skill-load path"
grep -q "IsSkillFile" "$MAPPING" \
|| fail "mapping does not document setting IsSkillFile when loading a skill"
# --- Core action→tool mappings are documented -------------------------------
for tool in write_to_file replace_file_content invoke_subagent; do
for tool in write_to_file replace_file_content run_command grep_search invoke_subagent; do
grep -q "$tool" "$MAPPING" \
|| fail "mapping does not document the '$tool' tool"
done
@@ -43,4 +50,4 @@ grep -qE 'ArtifactType.*task|task. artifact' "$MAPPING" \
grep -q "antigravity-tools.md" "$SKILL" \
|| fail "SKILL.md Platform Adaptation does not reference antigravity-tools.md"
echo "PASS: Antigravity tool mapping valid (subagent dispatch, task artifact, SKILL.md link)"
echo "PASS: Antigravity tool mapping valid (view_file skill-load, agy tools, SKILL.md link)"
+2 -3
View File
@@ -25,8 +25,7 @@ fi
# Parse command line arguments
VERBOSE=false
SPECIFIC_TEST=""
TIMEOUT=900 # Per-test-file budget; must exceed the file's worst case
# (test-subagent-driven-development.sh: 9 prompts x 90s each)
TIMEOUT=600 # Default 10 minute timeout per test
RUN_INTEGRATION=false
while [[ $# -gt 0 ]]; do
@@ -53,7 +52,7 @@ while [[ $# -gt 0 ]]; do
echo "Options:"
echo " --verbose, -v Show verbose output"
echo " --test, -t NAME Run only the specified test"
echo " --timeout SECONDS Set timeout per test (default: 900)"
echo " --timeout SECONDS Set timeout per test (default: 300)"
echo " --integration, -i Run integration tests (slow, 10-30 min)"
echo " --help, -h Show this help"
echo ""
+5 -11
View File
@@ -30,14 +30,12 @@ run_claude() {
# Check if output contains a pattern
# Usage: assert_contains "output" "pattern" "test name"
# Matching is case-insensitive: patterns are prose keywords, and models
# freely capitalize skill terms ("Do Not Trust", "Spec Compliance").
assert_contains() {
local output="$1"
local pattern="$2"
local test_name="${3:-test}"
if echo "$output" | grep -qi "$pattern"; then
if echo "$output" | grep -q "$pattern"; then
echo " [PASS] $test_name"
return 0
else
@@ -56,7 +54,7 @@ assert_not_contains() {
local pattern="$2"
local test_name="${3:-test}"
if echo "$output" | grep -qi "$pattern"; then
if echo "$output" | grep -q "$pattern"; then
echo " [FAIL] $test_name"
echo " Did not expect to find: $pattern"
echo " In output:"
@@ -76,7 +74,7 @@ assert_count() {
local expected="$3"
local test_name="${4:-test}"
local actual=$(echo "$output" | grep -ci "$pattern" || echo "0")
local actual=$(echo "$output" | grep -c "$pattern" || echo "0")
if [ "$actual" -eq "$expected" ]; then
echo " [PASS] $test_name (found $actual instances)"
@@ -100,20 +98,16 @@ assert_order() {
local test_name="${4:-test}"
# Get line numbers where patterns appear
local line_a=$(echo "$output" | grep -ni "$pattern_a" | head -1 | cut -d: -f1)
local line_b=$(echo "$output" | grep -ni "$pattern_b" | head -1 | cut -d: -f1)
local line_a=$(echo "$output" | grep -n "$pattern_a" | head -1 | cut -d: -f1)
local line_b=$(echo "$output" | grep -n "$pattern_b" | head -1 | cut -d: -f1)
if [ -z "$line_a" ]; then
echo " [FAIL] $test_name: pattern A not found: $pattern_a"
echo " In output:"
echo "$output" | sed 's/^/ /'
return 1
fi
if [ -z "$line_b" ]; then
echo " [FAIL] $test_name: pattern B not found: $pattern_b"
echo " In output:"
echo "$output" | sed 's/^/ /'
return 1
fi
@@ -96,13 +96,13 @@ echo "Test 5: Spec compliance reviewer mindset..."
output=$(run_claude "What is the spec compliance reviewer's attitude toward the implementer's report in subagent-driven-development?" "$CLAUDE_PROMPT_TIMEOUT")
if assert_contains "$output" "not.*trust\|don't trust\|skeptical\|verify.*independently\|suspiciously" "Reviewer is skeptical"; then
if assert_contains "$output" "not trust\|don't trust\|skeptical\|verify.*independently\|suspiciously" "Reviewer is skeptical"; then
: # pass
else
exit 1
fi
if assert_contains "$output" "read.*code\|inspect.*code\|verify.*code\|read.*diff\|trust.*diff" "Reviewer reads code"; then
if assert_contains "$output" "read.*code\|inspect.*code\|verify.*code" "Reviewer reads code"; then
: # pass
else
exit 1
+2 -7
View File
@@ -210,13 +210,8 @@ assert_equals "$tar_archive_paths" "$archive_paths" "zip and tar.gz archives con
tar_task_brief_mode="$(tar -tzvf "$tar_archive" skills/subagent-driven-development/scripts/task-brief | awk '{print $1}')"
assert_equals "$tar_task_brief_mode" "-rwxr-xr-x" "tar.gz archive preserves executable script mode"
tar_metadata_times="$(python3 - "$tar_archive" <<'PY'
import sys, tarfile
with tarfile.open(sys.argv[1]) as archive:
print(sorted({member.mtime for member in archive.getmembers()}))
PY
)"
assert_equals "$tar_metadata_times" "[0]" "tar.gz archive normalizes entry timestamps"
tar_metadata_times="$(tar -tzvf "$tar_archive" | awk '{print $6, $7, $8}' | sort -u)"
assert_equals "$tar_metadata_times" "Dec 31 1969" "tar.gz archive normalizes entry timestamps"
metadata_archive="$TEST_ROOT/metadata-source.tar.gz"
metadata_zip="$TEST_ROOT/metadata-source.zip"
+3 -12
View File
@@ -122,16 +122,7 @@ test('pi tools reference documents pi-specific mappings', async () => {
assert.equal(existsSync(piToolsPath), true, 'pi-tools.md should exist');
const text = await readFile(piToolsPath, 'utf8');
// Assert against the mapping-table rows only. The surrounding prose mentions
// these same tokens, so matching the whole file would still pass if the table
// were deleted — the exact regression this test exists to catch.
const rows = text.split('\n').filter((line) => line.startsWith('|'));
assert.ok(
rows.some((row) => /subagent/i.test(row)),
'mapping table documents subagent dispatch',
);
assert.ok(
rows.some((row) => /todo|task/i.test(row)),
'mapping table documents task tracking',
);
for (const expected of ['Skill', 'Task', 'TodoWrite', 'read', 'write', 'edit', 'bash']) {
assert.match(text, new RegExp(expected));
}
});