@friedbotstudio/create-baseline 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +222 -0
  3. package/bin/cli.js +247 -0
  4. package/obj/template/.claude/agents/swarm-worker.md +52 -0
  5. package/obj/template/.claude/bin/LICENSE +201 -0
  6. package/obj/template/.claude/bin/NOTICE +48 -0
  7. package/obj/template/.claude/commands/approve-spec.md +29 -0
  8. package/obj/template/.claude/commands/approve-swarm.md +27 -0
  9. package/obj/template/.claude/commands/grant-commit.md +19 -0
  10. package/obj/template/.claude/commands/init-project.md +191 -0
  11. package/obj/template/.claude/hooks/artifact_template_guard.sh +141 -0
  12. package/obj/template/.claude/hooks/consent_gate_grant.sh +89 -0
  13. package/obj/template/.claude/hooks/destructive_cmd_guard.sh +42 -0
  14. package/obj/template/.claude/hooks/env_guard.sh +36 -0
  15. package/obj/template/.claude/hooks/git_commit_guard.sh +93 -0
  16. package/obj/template/.claude/hooks/harness_continuation.sh +121 -0
  17. package/obj/template/.claude/hooks/lib/__pycache__/resume_writer.cpython-314.pyc +0 -0
  18. package/obj/template/.claude/hooks/lib/common.sh +328 -0
  19. package/obj/template/.claude/hooks/lib/resume_writer.py +341 -0
  20. package/obj/template/.claude/hooks/lint_runner.sh +55 -0
  21. package/obj/template/.claude/hooks/memory_pre_compact.sh +36 -0
  22. package/obj/template/.claude/hooks/memory_session_start.sh +244 -0
  23. package/obj/template/.claude/hooks/memory_stop.sh +173 -0
  24. package/obj/template/.claude/hooks/plantuml_syntax_guard.sh +161 -0
  25. package/obj/template/.claude/hooks/process_lifecycle_guard.sh +89 -0
  26. package/obj/template/.claude/hooks/setup_guard.sh +50 -0
  27. package/obj/template/.claude/hooks/spec_approval_guard.sh +81 -0
  28. package/obj/template/.claude/hooks/spec_design_calls_guard.sh +183 -0
  29. package/obj/template/.claude/hooks/spec_diagram_presence_guard.sh +141 -0
  30. package/obj/template/.claude/hooks/swarm_approval_guard.sh +39 -0
  31. package/obj/template/.claude/hooks/swarm_boundary_guard.sh +136 -0
  32. package/obj/template/.claude/hooks/tdd_order_guard.sh +176 -0
  33. package/obj/template/.claude/hooks/test_runner.sh +75 -0
  34. package/obj/template/.claude/hooks/tests/fixtures/ac008_byte_equal_reference.txt +12 -0
  35. package/obj/template/.claude/hooks/tests/memory_session_start_test.sh +285 -0
  36. package/obj/template/.claude/hooks/track_guard.sh +127 -0
  37. package/obj/template/.claude/hooks/verify_pass_guard.sh +88 -0
  38. package/obj/template/.claude/memory/README.md +108 -0
  39. package/obj/template/.claude/memory/_pending.md +15 -0
  40. package/obj/template/.claude/memory/_resume.md +12 -0
  41. package/obj/template/.claude/memory/conventions.md +26 -0
  42. package/obj/template/.claude/memory/decisions.md +29 -0
  43. package/obj/template/.claude/memory/landmarks.md +26 -0
  44. package/obj/template/.claude/memory/landmines.md +27 -0
  45. package/obj/template/.claude/memory/libraries.md +27 -0
  46. package/obj/template/.claude/memory/pending-questions.md +28 -0
  47. package/obj/template/.claude/project.json +221 -0
  48. package/obj/template/.claude/settings.json +110 -0
  49. package/obj/template/.claude/skills/archive/SKILL.md +48 -0
  50. package/obj/template/.claude/skills/archive/archive.sh +145 -0
  51. package/obj/template/.claude/skills/audit-baseline/SKILL.md +80 -0
  52. package/obj/template/.claude/skills/audit-baseline/audit.sh +919 -0
  53. package/obj/template/.claude/skills/brd/SKILL.md +44 -0
  54. package/obj/template/.claude/skills/brd/template.md +83 -0
  55. package/obj/template/.claude/skills/chore/SKILL.md +99 -0
  56. package/obj/template/.claude/skills/claude-automation-recommender/LICENSE +202 -0
  57. package/obj/template/.claude/skills/claude-automation-recommender/NOTICE +69 -0
  58. package/obj/template/.claude/skills/claude-automation-recommender/SKILL.md +358 -0
  59. package/obj/template/.claude/skills/claude-automation-recommender/references/hooks-patterns.md +226 -0
  60. package/obj/template/.claude/skills/claude-automation-recommender/references/mcp-servers.md +263 -0
  61. package/obj/template/.claude/skills/claude-automation-recommender/references/plugins-reference.md +98 -0
  62. package/obj/template/.claude/skills/claude-automation-recommender/references/skills-reference.md +408 -0
  63. package/obj/template/.claude/skills/claude-automation-recommender/references/subagent-templates.md +181 -0
  64. package/obj/template/.claude/skills/code-structure/SKILL.md +204 -0
  65. package/obj/template/.claude/skills/commit/SKILL.md +21 -0
  66. package/obj/template/.claude/skills/copywriting/SKILL.md +252 -0
  67. package/obj/template/.claude/skills/copywriting/evals/evals.json +111 -0
  68. package/obj/template/.claude/skills/copywriting/references/ai-writing-detection.md +200 -0
  69. package/obj/template/.claude/skills/copywriting/references/copy-frameworks.md +344 -0
  70. package/obj/template/.claude/skills/copywriting/references/natural-transitions.md +272 -0
  71. package/obj/template/.claude/skills/design-ui/SKILL.md +175 -0
  72. package/obj/template/.claude/skills/design-ui/references/design-vs-development.md +89 -0
  73. package/obj/template/.claude/skills/design-ui/references/intent-table.md +64 -0
  74. package/obj/template/.claude/skills/design-ui/references/orchestration.md +121 -0
  75. package/obj/template/.claude/skills/design-ui/references/state-machine.md +125 -0
  76. package/obj/template/.claude/skills/document/SKILL.md +66 -0
  77. package/obj/template/.claude/skills/documentation/SKILL.md +50 -0
  78. package/obj/template/.claude/skills/harness/SKILL.md +169 -0
  79. package/obj/template/.claude/skills/humanizer/SKILL.md +489 -0
  80. package/obj/template/.claude/skills/humanizer/references/ai-writing-detection.md +208 -0
  81. package/obj/template/.claude/skills/impeccable/PROJECT_NOTES.md +22 -0
  82. package/obj/template/.claude/skills/impeccable/SKILL.md +153 -0
  83. package/obj/template/.claude/skills/impeccable/agents/openai.yaml +4 -0
  84. package/obj/template/.claude/skills/impeccable/reference/adapt.md +190 -0
  85. package/obj/template/.claude/skills/impeccable/reference/animate.md +173 -0
  86. package/obj/template/.claude/skills/impeccable/reference/audit.md +134 -0
  87. package/obj/template/.claude/skills/impeccable/reference/bolder.md +113 -0
  88. package/obj/template/.claude/skills/impeccable/reference/brand.md +104 -0
  89. package/obj/template/.claude/skills/impeccable/reference/clarify.md +174 -0
  90. package/obj/template/.claude/skills/impeccable/reference/cognitive-load.md +106 -0
  91. package/obj/template/.claude/skills/impeccable/reference/color-and-contrast.md +105 -0
  92. package/obj/template/.claude/skills/impeccable/reference/colorize.md +154 -0
  93. package/obj/template/.claude/skills/impeccable/reference/craft.md +138 -0
  94. package/obj/template/.claude/skills/impeccable/reference/critique.md +213 -0
  95. package/obj/template/.claude/skills/impeccable/reference/delight.md +302 -0
  96. package/obj/template/.claude/skills/impeccable/reference/distill.md +111 -0
  97. package/obj/template/.claude/skills/impeccable/reference/document.md +427 -0
  98. package/obj/template/.claude/skills/impeccable/reference/extract.md +70 -0
  99. package/obj/template/.claude/skills/impeccable/reference/harden.md +347 -0
  100. package/obj/template/.claude/skills/impeccable/reference/heuristics-scoring.md +234 -0
  101. package/obj/template/.claude/skills/impeccable/reference/interaction-design.md +195 -0
  102. package/obj/template/.claude/skills/impeccable/reference/layout.md +141 -0
  103. package/obj/template/.claude/skills/impeccable/reference/live.md +513 -0
  104. package/obj/template/.claude/skills/impeccable/reference/motion-design.md +99 -0
  105. package/obj/template/.claude/skills/impeccable/reference/onboard.md +234 -0
  106. package/obj/template/.claude/skills/impeccable/reference/optimize.md +258 -0
  107. package/obj/template/.claude/skills/impeccable/reference/overdrive.md +130 -0
  108. package/obj/template/.claude/skills/impeccable/reference/personas.md +178 -0
  109. package/obj/template/.claude/skills/impeccable/reference/polish.md +232 -0
  110. package/obj/template/.claude/skills/impeccable/reference/product.md +62 -0
  111. package/obj/template/.claude/skills/impeccable/reference/quieter.md +99 -0
  112. package/obj/template/.claude/skills/impeccable/reference/responsive-design.md +114 -0
  113. package/obj/template/.claude/skills/impeccable/reference/shape.md +136 -0
  114. package/obj/template/.claude/skills/impeccable/reference/spatial-design.md +100 -0
  115. package/obj/template/.claude/skills/impeccable/reference/teach.md +137 -0
  116. package/obj/template/.claude/skills/impeccable/reference/typeset.md +124 -0
  117. package/obj/template/.claude/skills/impeccable/reference/typography.md +159 -0
  118. package/obj/template/.claude/skills/impeccable/reference/ux-writing.md +107 -0
  119. package/obj/template/.claude/skills/impeccable/scripts/cleanup-deprecated.mjs +284 -0
  120. package/obj/template/.claude/skills/impeccable/scripts/command-metadata.json +94 -0
  121. package/obj/template/.claude/skills/impeccable/scripts/design-parser.mjs +820 -0
  122. package/obj/template/.claude/skills/impeccable/scripts/detect-csp.mjs +198 -0
  123. package/obj/template/.claude/skills/impeccable/scripts/is-generated.mjs +69 -0
  124. package/obj/template/.claude/skills/impeccable/scripts/live-accept.mjs +465 -0
  125. package/obj/template/.claude/skills/impeccable/scripts/live-browser.js +4684 -0
  126. package/obj/template/.claude/skills/impeccable/scripts/live-inject.mjs +436 -0
  127. package/obj/template/.claude/skills/impeccable/scripts/live-poll.mjs +187 -0
  128. package/obj/template/.claude/skills/impeccable/scripts/live-server.mjs +679 -0
  129. package/obj/template/.claude/skills/impeccable/scripts/live-wrap.mjs +395 -0
  130. package/obj/template/.claude/skills/impeccable/scripts/live.mjs +247 -0
  131. package/obj/template/.claude/skills/impeccable/scripts/load-context.mjs +93 -0
  132. package/obj/template/.claude/skills/impeccable/scripts/modern-screenshot.umd.js +14 -0
  133. package/obj/template/.claude/skills/impeccable/scripts/pin.mjs +214 -0
  134. package/obj/template/.claude/skills/implement/SKILL.md +83 -0
  135. package/obj/template/.claude/skills/intake/SKILL.md +46 -0
  136. package/obj/template/.claude/skills/intake/template.md +61 -0
  137. package/obj/template/.claude/skills/integrate/SKILL.md +62 -0
  138. package/obj/template/.claude/skills/memory-flush/SKILL.md +172 -0
  139. package/obj/template/.claude/skills/memory-flush/sweep.py +286 -0
  140. package/obj/template/.claude/skills/memory-flush/tests/run.sh +327 -0
  141. package/obj/template/.claude/skills/prose/SKILL.md +119 -0
  142. package/obj/template/.claude/skills/rca/SKILL.md +42 -0
  143. package/obj/template/.claude/skills/rca/template.md +83 -0
  144. package/obj/template/.claude/skills/research/SKILL.md +75 -0
  145. package/obj/template/.claude/skills/scenario/SKILL.md +64 -0
  146. package/obj/template/.claude/skills/scout/SKILL.md +72 -0
  147. package/obj/template/.claude/skills/security/SKILL.md +75 -0
  148. package/obj/template/.claude/skills/simplify/SKILL.md +67 -0
  149. package/obj/template/.claude/skills/spec/SKILL.md +69 -0
  150. package/obj/template/.claude/skills/spec/template.md +274 -0
  151. package/obj/template/.claude/skills/spec-diagram-review/SKILL.md +81 -0
  152. package/obj/template/.claude/skills/spec-lint/SKILL.md +55 -0
  153. package/obj/template/.claude/skills/spec-lint/lint.sh +218 -0
  154. package/obj/template/.claude/skills/spec-render/SKILL.md +45 -0
  155. package/obj/template/.claude/skills/spec-render/render.sh +109 -0
  156. package/obj/template/.claude/skills/spec-traceability-review/SKILL.md +72 -0
  157. package/obj/template/.claude/skills/swarm-dispatch/SKILL.md +212 -0
  158. package/obj/template/.claude/skills/swarm-dispatch/swarm_merge.sh +154 -0
  159. package/obj/template/.claude/skills/swarm-plan/SKILL.md +90 -0
  160. package/obj/template/.claude/skills/swarm-plan/validate.sh +181 -0
  161. package/obj/template/.claude/skills/tdd/SKILL.md +100 -0
  162. package/obj/template/.claude/skills/technical-tutorials/SKILL.md +569 -0
  163. package/obj/template/.claude/skills/technical-tutorials/references/audience-context-README.md +53 -0
  164. package/obj/template/.claude/skills/technical-tutorials/references/audience-context.md +246 -0
  165. package/obj/template/.claude/skills/technical-tutorials/references/audience-example.md +175 -0
  166. package/obj/template/.claude/skills/technical-tutorials/references/audience-template.md +152 -0
  167. package/obj/template/.claude/skills/triage/SKILL.md +55 -0
  168. package/obj/template/.claude/skills/verify/SKILL.md +74 -0
  169. package/obj/template/.mcp.json +24 -0
  170. package/obj/template/CLAUDE.md +327 -0
  171. package/obj/template/docs/init/seed.md +585 -0
  172. package/obj/template/manifest.json +214 -0
  173. package/package.json +48 -0
  174. package/src/.mcp.template.json +24 -0
  175. package/src/.npmrc.template +2 -0
  176. package/src/CLAUDE.template.md +327 -0
  177. package/src/agents/swarm-worker.template.md +51 -0
  178. package/src/cli/conflict.js +31 -0
  179. package/src/cli/doctor.js +152 -0
  180. package/src/cli/install.js +93 -0
  181. package/src/cli/io.js +27 -0
  182. package/src/cli/manifest.js +38 -0
  183. package/src/cli/mcp.js +54 -0
  184. package/src/cli/merge.js +107 -0
  185. package/src/cli/plantuml.js +121 -0
  186. package/src/cli/util.js +10 -0
  187. package/src/memory/_pending.template.md +15 -0
  188. package/src/memory/_resume.template.md +12 -0
  189. package/src/memory/conventions.template.md +26 -0
  190. package/src/memory/decisions.template.md +29 -0
  191. package/src/memory/landmarks.template.md +26 -0
  192. package/src/memory/landmines.template.md +27 -0
  193. package/src/memory/libraries.template.md +27 -0
  194. package/src/memory/pending-questions.template.md +28 -0
  195. package/src/project.template.json +221 -0
  196. package/src/seed.template.md +585 -0
  197. package/src/settings.template.json +110 -0
@@ -0,0 +1,327 @@
1
+ #!/usr/bin/env bash
2
+ # Fixture-based integration tests for the memory-flush Step 0 SOP.
3
+ # Covers AC-001, AC-002, AC-004, AC-006 from docs/specs/memory-lifecycle-closure.md
4
+ #
5
+ # The SKILL.md SOP is markdown; the executable contract lives in
6
+ # `.claude/skills/memory-flush/sweep.py`, a deterministic helper the SOP
7
+ # invokes for the sweep-and-classify portion of Step 0. Each test builds a
8
+ # stubbed memory tree, invokes sweep.py with a stubbed reply stream, and
9
+ # asserts on the resulting file state + JSON action report.
10
+ #
11
+ # Until sweep.py exists, every flush test fails RED (correct TDD state).
12
+ # AC-006 regression-traps stay green from day one and must stay green.
13
+
14
+ set -uo pipefail
15
+
16
+ HERE="$(cd "$(dirname "$0")" && pwd)"
17
+ REPO_ROOT="$(cd "$HERE/../../../.." && pwd)"
18
+ SWEEP="$REPO_ROOT/.claude/skills/memory-flush/sweep.py"
19
+
20
+ PASS=0; FAIL=0; FAILED=()
21
+
22
+ # --- assertion helpers --------------------------------------------------------
23
+
24
+ fail() { echo " FAIL: $*"; return 1; }
25
+
26
+ assert_file_contains() {
27
+ local path="$1" needle="$2" msg="$3"
28
+ if grep -qF "$needle" "$path" 2>/dev/null; then return 0; fi
29
+ fail "$msg :: file $path missing: $needle"
30
+ }
31
+
32
+ assert_file_not_contains() {
33
+ local path="$1" needle="$2" msg="$3"
34
+ if grep -qF "$needle" "$path" 2>/dev/null; then
35
+ fail "$msg :: file $path should NOT contain: $needle"
36
+ return 1
37
+ fi
38
+ }
39
+
40
+ assert_contains() {
41
+ local haystack="$1" needle="$2" msg="$3"
42
+ case "$haystack" in
43
+ *"$needle"*) return 0 ;;
44
+ *) fail "$msg :: expected to contain: $needle" ;;
45
+ esac
46
+ }
47
+
48
+ # Invoke sweep.py against a fixture memory dir.
49
+ # $1 = mode (auto-close | prose-scan | stale-sweep)
50
+ # $2 = memory dir
51
+ # $3 = reply stream (newline-separated; piped to stdin)
52
+ # Stdout = JSON report from sweep.py; exit 0 success, non-zero error.
53
+ sweep() {
54
+ local mode="$1" mem="$2" replies="${3:-}"
55
+ if [ ! -x "$SWEEP" ] && [ ! -f "$SWEEP" ]; then
56
+ echo "{\"error\":\"sweep.py missing\"}"
57
+ return 127
58
+ fi
59
+ printf '%s' "$replies" | python3 "$SWEEP" --mode "$mode" --memory-dir "$mem"
60
+ }
61
+
62
+ seed_skel() {
63
+ local mem="$1"
64
+ mkdir -p "$mem"
65
+ for f in landmarks libraries decisions landmines conventions pending-questions; do
66
+ cat > "$mem/$f.md" <<EOF
67
+ ---
68
+ owners: [test]
69
+ size-cap: 500
70
+ key: test
71
+ ---
72
+
73
+ # Fixture
74
+ EOF
75
+ done
76
+ }
77
+
78
+ # Append an entry block to a canonical file.
79
+ add() {
80
+ local mem="$1" file="$2"; shift 2
81
+ printf '\n%s\n' "$*" >> "$mem/$file.md"
82
+ }
83
+
84
+ days_ago() {
85
+ local n="$1"
86
+ if date -u -d "$n days ago" +%Y-%m-%d 2>/dev/null; then return; fi
87
+ date -u -v "-${n}d" +%Y-%m-%d
88
+ }
89
+
90
+ today() { date -u +%Y-%m-%d; }
91
+
92
+ run() {
93
+ local name="$1"
94
+ echo "RUN $name"
95
+ if "$name"; then
96
+ PASS=$((PASS+1)); echo "PASS $name"
97
+ else
98
+ FAIL=$((FAIL+1)); FAILED+=("$name"); echo "FAIL $name"
99
+ fi
100
+ }
101
+
102
+ # --- AC-001 -------------------------------------------------------------------
103
+
104
+ test_when_resolved_at_present_on_pending_then_flush_removes_block() {
105
+ local mem; mem="$(mktemp -d)"; trap "rm -rf $mem" RETURN
106
+ seed_skel "$mem"
107
+ add "$mem" "pending-questions" "## Q-100
108
+
109
+ - Question: stub
110
+ - verified-at: HEAD
111
+ - last-touched: $(today)
112
+ - resolved-at: 2026-05-01"
113
+ local report; report="$(sweep auto-close "$mem")" || { fail "AC-001 sweep crashed"; return 1; }
114
+ assert_file_not_contains "$mem/pending-questions.md" "## Q-100" "AC-001 expected Q-100 block removed" || return 1
115
+ assert_contains "$report" '"closed": 1' "AC-001 expected closed count 1 in report (got: $report)" || return 1
116
+ }
117
+
118
+ test_when_superseded_at_present_on_landmarks_then_flush_removes_block() {
119
+ local mem; mem="$(mktemp -d)"; trap "rm -rf $mem" RETURN
120
+ seed_skel "$mem"
121
+ add "$mem" "landmarks" "## src/old.js:42
122
+
123
+ - role: legacy entrypoint
124
+ - verified-at: HEAD
125
+ - last-touched: $(today)
126
+ - superseded-at: 2026-05-01"
127
+ local report; report="$(sweep auto-close "$mem")" || { fail "AC-001 sweep crashed"; return 1; }
128
+ assert_file_not_contains "$mem/landmarks.md" "## src/old.js:42" "AC-001 expected superseded block removed" || return 1
129
+ assert_contains "$report" '"closed": 1' "AC-001 expected closed count 1 in report" || return 1
130
+ }
131
+
132
+ test_when_resolved_at_malformed_then_entry_remains_open() {
133
+ local mem; mem="$(mktemp -d)"; trap "rm -rf $mem" RETURN
134
+ seed_skel "$mem"
135
+ add "$mem" "pending-questions" "## Q-200
136
+
137
+ - Question: stub
138
+ - verified-at: HEAD
139
+ - last-touched: $(today)
140
+ - resolved-at: 2026-13-99"
141
+ local report; report="$(sweep auto-close "$mem")" || { fail "AC-001 sweep crashed on malformed"; return 1; }
142
+ assert_file_contains "$mem/pending-questions.md" "## Q-200" "AC-001 malformed date must NOT delete entry" || return 1
143
+ assert_contains "$report" '"malformed":' "AC-001 expected malformed flag in report" || return 1
144
+ }
145
+
146
+ test_when_resolved_at_on_wrong_file_then_skill_flags_violation() {
147
+ local mem; mem="$(mktemp -d)"; trap "rm -rf $mem" RETURN
148
+ seed_skel "$mem"
149
+ # resolved-at on landmarks.md is a per-file invariant violation.
150
+ add "$mem" "landmarks" "## src/x.js:1
151
+
152
+ - role: test
153
+ - verified-at: HEAD
154
+ - last-touched: $(today)
155
+ - resolved-at: 2026-05-01"
156
+ local report; report="$(sweep auto-close "$mem")" || { fail "AC-001 sweep crashed"; return 1; }
157
+ assert_file_contains "$mem/landmarks.md" "## src/x.js:1" "AC-001 invariant-violation entry must NOT be deleted" || return 1
158
+ assert_contains "$report" '"invariant_violation":' "AC-001 expected invariant_violation flag in report" || return 1
159
+ }
160
+
161
+ # --- AC-002 -------------------------------------------------------------------
162
+
163
+ test_when_pending_entry_has_resolution_prose_and_y_then_block_removed() {
164
+ local mem; mem="$(mktemp -d)"; trap "rm -rf $mem" RETURN
165
+ seed_skel "$mem"
166
+ add "$mem" "pending-questions" "## Q-300
167
+
168
+ - Question: stub
169
+ **Resolution path taken (2026-04-29):** decided in spec.
170
+ - verified-at: HEAD
171
+ - last-touched: $(today)"
172
+ # Reply stream: 'y' to confirm removal.
173
+ local report; report="$(sweep prose-scan "$mem" "y")" || { fail "AC-002 sweep crashed"; return 1; }
174
+ assert_file_not_contains "$mem/pending-questions.md" "## Q-300" "AC-002 'y' must delete block" || return 1
175
+ assert_contains "$report" '"closed_by_confirm": 1' "AC-002 expected closed_by_confirm 1 (got: $report)" || return 1
176
+
177
+ # 'n' keeps the entry.
178
+ rm -rf "$mem"; mem="$(mktemp -d)"; seed_skel "$mem"
179
+ add "$mem" "pending-questions" "## Q-301
180
+
181
+ - Question: stub
182
+ **Resolution path taken (2026-04-29):** decided in spec.
183
+ - verified-at: HEAD
184
+ - last-touched: $(today)"
185
+ sweep prose-scan "$mem" "n" >/dev/null || { fail "AC-002 sweep crashed on 'n'"; return 1; }
186
+ assert_file_contains "$mem/pending-questions.md" "## Q-301" "AC-002 'n' must keep block" || return 1
187
+
188
+ # 'skip' keeps the entry and marks for next-run reconsideration.
189
+ rm -rf "$mem"; mem="$(mktemp -d)"; seed_skel "$mem"
190
+ add "$mem" "pending-questions" "## Q-302
191
+
192
+ - Question: stub
193
+ **Resolution path taken (2026-04-29):** decided.
194
+ - verified-at: HEAD
195
+ - last-touched: $(today)"
196
+ report="$(sweep prose-scan "$mem" "skip")"
197
+ assert_file_contains "$mem/pending-questions.md" "## Q-302" "AC-002 'skip' must keep block" || return 1
198
+ assert_contains "$report" '"deferred":' "AC-002 'skip' should produce deferred marker" || return 1
199
+ }
200
+
201
+ test_when_body_has_resolved_by_alice_anchored_then_surfaced() {
202
+ local mem; mem="$(mktemp -d)"; trap "rm -rf $mem" RETURN
203
+ seed_skel "$mem"
204
+ add "$mem" "pending-questions" "## Q-310
205
+
206
+ - Question: who decides
207
+ Resolved by Alice 2026-05-01
208
+ - verified-at: HEAD
209
+ - last-touched: $(today)"
210
+ local report; report="$(sweep prose-scan "$mem" "y")" || { fail "AC-002 sweep crashed"; return 1; }
211
+ assert_file_not_contains "$mem/pending-questions.md" "## Q-310" "AC-002 R3 anchored should surface and delete on 'y'" || return 1
212
+ assert_contains "$report" '"closed_by_confirm": 1' "AC-002 expected closed_by_confirm 1" || return 1
213
+ }
214
+
215
+ test_when_body_has_resolved_midsentence_then_not_surfaced() {
216
+ local mem; mem="$(mktemp -d)"; trap "rm -rf $mem" RETURN
217
+ seed_skel "$mem"
218
+ add "$mem" "pending-questions" "## Q-320
219
+
220
+ - Question: we resolved most of this last week but still need a date.
221
+ - verified-at: HEAD
222
+ - last-touched: $(today)"
223
+ # No replies; if a prompt surfaces unexpectedly the sweep will hang or pick a default.
224
+ local report; report="$(sweep prose-scan "$mem" "")" || { fail "AC-002 sweep crashed"; return 1; }
225
+ assert_file_contains "$mem/pending-questions.md" "## Q-320" "AC-002 mid-sentence must NOT surface" || return 1
226
+ assert_contains "$report" '"surfaced": 0' "AC-002 expected surfaced 0 for mid-sentence (got: $report)" || return 1
227
+ }
228
+
229
+ # --- AC-004 -------------------------------------------------------------------
230
+
231
+ test_when_2_stale_then_flush_offers_reverify_then_delete_prompts() {
232
+ local mem; mem="$(mktemp -d)"; trap "rm -rf $mem" RETURN
233
+ seed_skel "$mem"
234
+ add "$mem" "landmarks" "## src/keep.js:1
235
+
236
+ - role: test
237
+ - verified-at: HEAD
238
+ - last-touched: $(days_ago 120)"
239
+ add "$mem" "landmarks" "## src/drop.js:1
240
+
241
+ - role: test
242
+ - verified-at: HEAD
243
+ - last-touched: $(days_ago 130)"
244
+ # Replies: re-verify (keep+restamp) then delete.
245
+ local report; report="$(sweep stale-sweep "$mem" "re-verify
246
+ delete")" || { fail "AC-004 sweep crashed"; return 1; }
247
+ # First entry kept with refreshed last-touched.
248
+ assert_file_contains "$mem/landmarks.md" "## src/keep.js:1" "AC-004 reverify must keep" || return 1
249
+ assert_file_contains "$mem/landmarks.md" "last-touched: $(today)" "AC-004 reverify must restamp last-touched" || return 1
250
+ # Second entry deleted.
251
+ assert_file_not_contains "$mem/landmarks.md" "## src/drop.js:1" "AC-004 delete must remove" || return 1
252
+ assert_contains "$report" '"reverified": 1' "AC-004 expected reverified 1" || return 1
253
+ assert_contains "$report" '"deleted": 1' "AC-004 expected deleted 1" || return 1
254
+ }
255
+
256
+ test_when_stale_mark_closed_on_pending_then_resolved_at_added_not_deleted() {
257
+ local mem; mem="$(mktemp -d)"; trap "rm -rf $mem" RETURN
258
+ seed_skel "$mem"
259
+ add "$mem" "pending-questions" "## Q-400
260
+
261
+ - Question: stub
262
+ - verified-at: HEAD
263
+ - last-touched: $(days_ago 120)"
264
+ sweep stale-sweep "$mem" "mark-closed" >/dev/null || { fail "AC-004 sweep crashed"; return 1; }
265
+ assert_file_contains "$mem/pending-questions.md" "## Q-400" "AC-004 mark-closed must NOT delete this run" || return 1
266
+ assert_file_contains "$mem/pending-questions.md" "resolved-at:" "AC-004 mark-closed must add resolved-at on pending-questions" || return 1
267
+ }
268
+
269
+ # --- AC-006 (regression traps — start green, stay green) ----------------------
270
+
271
+ test_when_no_closure_no_prose_no_stale_then_entry_survives_all_paths() {
272
+ local mem; mem="$(mktemp -d)"; trap "rm -rf $mem" RETURN
273
+ seed_skel "$mem"
274
+ add "$mem" "landmarks" "## src/normal.js:1
275
+
276
+ - role: ordinary entry, no closure, no prose match
277
+ - verified-at: HEAD
278
+ - last-touched: $(today)"
279
+ local before; before="$(cat "$mem/landmarks.md")"
280
+ # Step 0a auto-close.
281
+ sweep auto-close "$mem" >/dev/null
282
+ # Step 0b prose-scan with no replies (nothing should be surfaced).
283
+ sweep prose-scan "$mem" "" >/dev/null
284
+ # Step 0c stale-sweep (entry is not stale; nothing to do).
285
+ sweep stale-sweep "$mem" "" >/dev/null
286
+ local after; after="$(cat "$mem/landmarks.md")"
287
+ if [ "$before" = "$after" ]; then return 0; fi
288
+ fail "AC-006 entry mutated through Step 0 a/b/c"
289
+ diff <(printf '%s' "$before") <(printf '%s' "$after") || true
290
+ return 1
291
+ }
292
+
293
+ test_when_pre_spec_entry_no_source_no_verbatim_then_grandfathered() {
294
+ local mem; mem="$(mktemp -d)"; trap "rm -rf $mem" RETURN
295
+ seed_skel "$mem"
296
+ # Legacy shape: no `source:`, no `verbatim:` block.
297
+ add "$mem" "conventions" "## legacy-entry
298
+
299
+ - pattern: legacy
300
+ - verified-at: HEAD
301
+ - last-touched: $(today)"
302
+ sweep auto-close "$mem" >/dev/null || { fail "AC-006 sweep crashed"; return 1; }
303
+ sweep prose-scan "$mem" "" >/dev/null
304
+ assert_file_contains "$mem/conventions.md" "## legacy-entry" "AC-006 grandfathered legacy entry survives" || return 1
305
+ }
306
+
307
+ # --- runner -------------------------------------------------------------------
308
+
309
+ run test_when_resolved_at_present_on_pending_then_flush_removes_block
310
+ run test_when_superseded_at_present_on_landmarks_then_flush_removes_block
311
+ run test_when_resolved_at_malformed_then_entry_remains_open
312
+ run test_when_resolved_at_on_wrong_file_then_skill_flags_violation
313
+ run test_when_pending_entry_has_resolution_prose_and_y_then_block_removed
314
+ run test_when_body_has_resolved_by_alice_anchored_then_surfaced
315
+ run test_when_body_has_resolved_midsentence_then_not_surfaced
316
+ run test_when_2_stale_then_flush_offers_reverify_then_delete_prompts
317
+ run test_when_stale_mark_closed_on_pending_then_resolved_at_added_not_deleted
318
+ run test_when_no_closure_no_prose_no_stale_then_entry_survives_all_paths
319
+ run test_when_pre_spec_entry_no_source_no_verbatim_then_grandfathered
320
+
321
+ echo "----"
322
+ echo "Passed: $PASS Failed: $FAIL"
323
+ if [ "$FAIL" -gt 0 ]; then
324
+ echo "Failed tests:"
325
+ for t in "${FAILED[@]}"; do echo " - $t"; done
326
+ fi
327
+ exit $((FAIL > 0))
@@ -0,0 +1,119 @@
1
+ ---
2
+ name: prose
3
+ owner: baseline
4
+ description: Draft or revise English prose for any brief — documentation body, intake problem statements, spec context, RCA summaries, marketing copy, README sections, PR descriptions. Mandatorily invokes `Skill(humanizer)` as the final pass on every draft. Conditionally invokes `copywriting` for persuasive register, `documentation` for reference docs, `technical-tutorials` for tutorials. Used when any phase needs human-readable prose written or rewritten. Composition only — research and register-picking happen in the caller's context.
5
+ ---
6
+
7
+ You are executing a **decision the main context has already made**: "produce this specific prose, for this audience, in this register, grounded in this source material." You compose. You do not invent facts, pick the register, or expand scope.
8
+
9
+ # The skill is invalid without an explicit `Skill(humanizer)` tool call
10
+
11
+ This is the load-bearing rule. The other rules support it.
12
+
13
+ - Every prose deliverable produced by this skill must end with the model issuing a `Skill(humanizer)` tool call against the draft, and using humanizer's output **verbatim** as the final text.
14
+ - Reading humanizer's patterns from memory and rewriting "in humanizer's spirit" does not satisfy this rule. The Skill tool call must occur in the same turn as the prose.
15
+ - "I know these patterns, I'll skip the call to save tokens" is the exact failure this rule prevents. Skip is forbidden even for a single sentence.
16
+ - The receipt line at the end of your output must reference the turn-local humanizer Skill tool call. If you cannot honestly write that line, the deliverable is not done.
17
+
18
+ # Before you draft — load this checklist
19
+
20
+ Hold these patterns in active context for the whole drafting pass. Drafting against the checklist is cheaper than rewriting after.
21
+
22
+ **Forbidden in human-facing prose:**
23
+
24
+ - **Em-dash overuse.** Treat the em dash as expensive. Maximum one em dash per paragraph. Two em dashes in the same paragraph is always wrong; stacking em dashes around a parenthetical (`A — X — B`) is always wrong.
25
+ - **Sentence-fragment stacking.** Three or more short fragments in a row read as AI rhythm. "Skills run here. One worker there. Discipline through composition." — that pattern is the tell. Vary length. Break the rhythm.
26
+ - **Sloganeering in body copy.** "Placement is policy." "The audit is the contract." "Discipline through composition." Headline rhythms in paragraph copy are AI signatures. State the claim plainly and move on.
27
+ - **Tagline echo.** If the headline contains a phrase, the body paragraph should not repeat that phrase. Echoing reinforces the slogan and feels engineered.
28
+ - **Negative parallelism.** "It's not just X, it's Y." "What this is not: …. It is also not …." Cut these structures unless one specific instance is genuinely the cleanest expression.
29
+ - **Rule of three.** Forced triplets that round out a list to three items for cadence. If you have two real items, write two.
30
+ - **AI vocabulary.** *crucial, pivotal, leverage, robust, comprehensive, seamless, holistic, foster, navigate, journey, harness (verb), unleash, cutting-edge, game-changing, paradigm, synergy, delve, tapestry, testament, underscore, landscape (abstract), vibrant, in the heart of, nestled.*
31
+ - **Vague attributions.** "Industry experts believe", "research suggests", "many would argue".
32
+ - **Filler hedges.** "It is important to note that", "in order to", "at this point in time", "due to the fact that".
33
+ - **Generic positive endings.** "Exciting times ahead." "The future looks bright." "A major step forward."
34
+ - **Bolded inline-header lists** (`- **User Experience:** …`) and emoji decoration. Cut both.
35
+ - **Curly quotes** (`“”` `‘’`). ASCII straight quotes only.
36
+
37
+ The full pattern set with examples lives in `humanizer/SKILL.md`. The list above is the high-frequency subset; the Skill tool call below loads the full set.
38
+
39
+ # Conditional skills the caller specifies
40
+
41
+ Run **before** humanizer. The caller names which one applies. Do not pick more than one.
42
+
43
+ - `Skill(copywriting)` — when register is persuasive (landing/pricing/feature/hero/CTA/tagline).
44
+ - `Skill(documentation)` — when register is technical reference.
45
+ - `Skill(technical-tutorials)` — when register is step-by-step walkthrough.
46
+
47
+ # Inputs the caller must provide
48
+
49
+ Stop and ask if any are unclear.
50
+
51
+ - **Brief**: what to write. Length. What it's for.
52
+ - **Source material**: facts, links, quotes, diff slices, spec excerpts. Anything you'd otherwise be tempted to invent must be in here.
53
+ - **Audience**: internal engineer, external user, mixed.
54
+ - **Register**: reference doc · tutorial · summary · marketing/product · PR description · runbook intro · etc. The caller picks; you execute.
55
+ - **Output target**: a file path, a section to edit, or "return inline."
56
+
57
+ # Method
58
+
59
+ 1. **Draft from source material only.** Vary sentence length and rhythm. Use first person when register supports it. Acknowledge complexity where real. Be specific — real numbers, real names, real behaviors.
60
+ 2. **Run the pre-draft checklist over your draft.** Read the draft once with the forbidden-pattern list active. Cut every hit before moving to step 3. This is the cheap pass; it removes 80% of what humanizer would otherwise reject.
61
+ 3. **Apply the conditional skill the caller named** via `Skill(...)`. Use its output as your working draft.
62
+ 4. **Invoke `Skill(humanizer)` with the entire working draft.** Use humanizer's output verbatim. Do not paraphrase; do not cherry-pick its suggestions. If humanizer changes something you intended to keep, you may either accept the change or invoke humanizer again with explicit guidance — you may not silently revert.
63
+ 5. **Self-audit grep the final text.** Apply these mechanical checks in your head before declaring done:
64
+ - Em-dash count per paragraph: 0 or 1, never 2+.
65
+ - Three-fragment-in-a-row patterns: count and break any you find.
66
+ - Slogan-in-body-paragraph patterns: any sentence under 6 words that sits alone in a paragraph and could be a headline → rewrite into the surrounding sentence.
67
+ - AI-vocabulary scan: re-grep the forbidden word list above. Any hit that survived humanizer → fix manually.
68
+ - Headline-tagline echo: search the body for any phrase repeated from the H1/H2.
69
+ If any check fails, fix and re-invoke `Skill(humanizer)` on the corrected draft. Do not ship a draft that fails self-audit.
70
+ 6. **Land the output** at the caller's target.
71
+
72
+ # Output
73
+
74
+ - **File target given** → write/edit the file.
75
+ - **Section edit given** → edit the referenced section in place.
76
+ - **Inline return** → put the finished prose in your response.
77
+
78
+ Always close with one line stating evidence:
79
+
80
+ ```
81
+ Invoked: Skill(humanizer) on the draft this turn. Conditional: <copywriting | documentation | technical-tutorials | none>. Self-audit: passed.
82
+ ```
83
+
84
+ If you cannot honestly write that exact line — because you didn't issue a `Skill(humanizer)` tool call this turn, or because self-audit found a hit you didn't fix — the deliverable is not complete. Re-do the pass before returning to the caller.
85
+
86
+ # Hard scope: never humanize Claude-instructional prose
87
+
88
+ The humanizer pass is for prose meant for **human readers**. Some markdown files in this repo look like prose but are contracts Claude reads to decide behavior. Rewriting those for "natural rhythm" can soften imperatives, drop precision, or break load-bearing repetition.
89
+
90
+ **Refuse to humanize, even on explicit caller request:**
91
+
92
+ - `CLAUDE.md` — session constitution.
93
+ - `docs/init/seed.md` — rebuild prompt.
94
+ - `.claude/skills/*/SKILL.md` — skill prompts. Imperatives are load-bearing.
95
+ - `.claude/agents/*.md` — subagent prompts.
96
+ - `.claude/commands/*.md` — command prompts.
97
+ - `.claude/skills/*/template.md` — canonical structures downstream guards check.
98
+ - Any file whose primary reader is Claude rather than a human.
99
+
100
+ Detection rule: if the file is read into Claude's context as instructions, it is **out of scope**. If unsure, ask the caller.
101
+
102
+ **In scope:**
103
+
104
+ - `README.md` user-facing sections (intro, quickstart, "what you get") — layout-tree and config tables stay untouched.
105
+ - `site/**` (or whichever rendered-site path the project uses — check `project.json → workflow.artifacts.document`) — rendered site for human readers. Marketing copy inside JSX/TSX strings is in scope; surrounding code is not.
106
+ - Intake / spec Context / RCA Summary narrative blocks — prose that conveys reasoning to a human reviewer.
107
+ - Commit message bodies (when caller asks).
108
+ - Onboarding / migration / how-to docs.
109
+
110
+ When humanizing prose blocks inside a mostly-instructional file (e.g., the user-facing intro of `README.md`), surgically scope edits to the prose blocks. Never run a whole-file pass on a mixed file.
111
+
112
+ # Constraints
113
+
114
+ - **`Skill(humanizer)` is mandatory, always.** No exceptions for short, polished, or "obviously fine" passages.
115
+ - **Don't invent facts.** If the source material doesn't support a claim, drop the claim.
116
+ - **Match the caller's voice when specified.** A migration runbook sounds different from a hero section.
117
+ - **Start terse.** Length bloat is a top humanizer pattern. Expand only when the brief explicitly asks for depth.
118
+ - **Don't over-hedge.** "It could potentially possibly be the case that..." gets cut.
119
+ - **Code and code comments are out of scope.** If the brief is "write a function" or "fix this bug", decline and route to `implement`.
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: rca
3
+ owner: baseline
4
+ description: Draft a Root Cause Analysis for an incident, outage, or repeated test failure. Unlike intake/spec/brd, RCA is not a workflow phase — it's a standalone postmortem artifact that often precedes a bugfix intake. Output lives at `docs/rca/<slug>.md`.
5
+ ---
6
+
7
+ # RCA — Root Cause Analysis
8
+
9
+ You are drafting an **RCA**. It is a narrative of what went wrong, why, and what will change so it doesn't recur. Unlike the other artifact skills in this workflow, RCA is **not** part of the linear phase chain — it's a separate document that often feeds into a bugfix intake (`/triage` → `/intake` → …).
10
+
11
+ **Use an RCA when:**
12
+ - A production incident occurred (outage, data corruption, security breach).
13
+ - A test that previously passed now fails intermittently and the cause is non-obvious.
14
+ - A `verify` skill verdict has been `FAIL` across multiple attempts and the team needs a blameless record.
15
+ - The user explicitly says "postmortem", "RCA", "incident review", or equivalent.
16
+
17
+ **Don't use an RCA for:** a bug reported in a ticket, a missing feature, or a normal TDD failure. Those belong in intake/spec/tdd.
18
+
19
+ ## Inputs
20
+
21
+ - The incident's observable facts: timeline, alerts, logs, user reports, metrics screenshots (paths or URLs).
22
+ - The commits, deploys, or config changes in the suspect window.
23
+ - `template.md` in this skill directory.
24
+
25
+ ## Steps
26
+
27
+ 1. Read `template.md`. Every heading must appear in the output.
28
+ 2. Assemble the **Timeline** from raw evidence (logs, alert history, chat transcripts, deploy log). Wall-clock times in a single timezone. Do NOT paraphrase events — record what happened.
29
+ 3. State the **Root cause** as a single sentence. If you have multiple candidate causes and cannot distinguish them from the evidence, list them under **Contributing factors** and put "not conclusively identified" as the Root cause. Do not guess.
30
+ 4. **Impact must be quantified.** Users affected: count or estimate with method. Duration: precise. Business impact: dollars, SLA minutes, or "none measurable" — never a vague "significant".
31
+ 5. **Action items have owners and due dates.** Unassigned action items are placeholder; delete them or assign.
32
+ 6. Write to `docs/rca/<slug>.md`. Slug: `YYYY-MM-DD-<short-name>` so the file sorts chronologically in the directory.
33
+ 7. Tell the user: "RCA drafted at `docs/rca/<slug>.md`. Action items: N, owners assigned: M. If this warrants a fix, run `/triage` with a bugfix description referencing this RCA."
34
+
35
+ ## Drafting rules
36
+
37
+ - **Blameless.** Describe what a system or process allowed, not who is at fault. "The deploy ran without a staging rehearsal" — not "Alice deployed without testing".
38
+ - **Evidence links trump prose.** Where possible, cite the log line, the commit SHA, the dashboard URL. Prose that isn't traceable is speculation.
39
+ - **What went well matters.** Most RCAs omit this. Include it — it reinforces practices that should persist.
40
+ - **Action items are specific.** "Improve monitoring" is not an action item; "Add alarm on upstream 5xx rate > 1% for 2m, paging to #oncall-payments, owner: Priya, due 2026-05-15" is.
41
+ - **Do not self-commit to a timeline you can't honor.** If action item ETAs are uncertain, mark them "tentative".
42
+ - **Don't mix RCA and spec.** The RCA says what broke and why. The fix spec (separate, via `/spec`) says how to repair it.
@@ -0,0 +1,83 @@
1
+ # RCA: <short incident name>
2
+
3
+ <!--
4
+ Root Cause Analysis. Produced by the `rca` skill.
5
+ Required sections (enforced by artifact_template_guard): Summary, Timeline,
6
+ Impact, Root cause, Action items.
7
+ Blameless by convention: describe systems and processes, not individuals.
8
+ -->
9
+
10
+ ## Summary
11
+
12
+ <Two sentences. What broke, when, and whether it's resolved as of writing.>
13
+
14
+ ## Timeline
15
+
16
+ <Wall-clock, one timezone (state which). Sourced from evidence. Every entry
17
+ links to a log / alert / commit / chat where possible.>
18
+
19
+ - `YYYY-MM-DD HH:MM TZ` — <event>. <link/evidence>
20
+ - `YYYY-MM-DD HH:MM TZ` — <event>. <link/evidence>
21
+ - `YYYY-MM-DD HH:MM TZ` — <event>. <link/evidence>
22
+
23
+ ## Impact
24
+
25
+ <Quantified. Users affected with counting method. Duration precise.
26
+ Business/SLA/dollar impact or "none measurable".>
27
+
28
+ - **Users affected**: <count/estimate + method>
29
+ - **Duration**: <start → end, total minutes>
30
+ - **SLA impact**: <e.g., 23 minutes against 99.9% monthly error budget>
31
+ - **Business impact**: <dollars, or "none measurable">
32
+ - **Data impact**: <loss? corruption? none?>
33
+
34
+ ## Detection
35
+
36
+ <How did we notice? Who/what raised the alarm? Was the detection time
37
+ acceptable? What would have made detection faster?>
38
+
39
+ ## Root cause
40
+
41
+ <Single sentence. What was the underlying condition that, removed, would
42
+ have prevented this incident? If inconclusive, state so here and enumerate
43
+ candidates under Contributing factors.>
44
+
45
+ ## Contributing factors
46
+
47
+ <Conditions that worsened the incident but are not the single root cause.>
48
+
49
+ - <factor>
50
+ - <factor>
51
+
52
+ ## Resolution
53
+
54
+ <What was done to resolve it. Commands run, configs reverted, deploys. Link
55
+ the fix commit(s) if any.>
56
+
57
+ ## What went well
58
+
59
+ <Behaviours/tools/practices that limited the blast radius or sped recovery.
60
+ These should persist.>
61
+
62
+ - <item>
63
+
64
+ ## What could be improved
65
+
66
+ <Process gaps exposed by the incident.>
67
+
68
+ - <item>
69
+
70
+ ## Action items
71
+
72
+ <Each has: a description, an owner (named person), a due date (absolute,
73
+ YYYY-MM-DD), and a status.>
74
+
75
+ - [ ] **AI-01** — <description>. Owner: <name>. Due: <YYYY-MM-DD>. Status: open.
76
+ - [ ] **AI-02** — <description>. Owner: <name>. Due: <YYYY-MM-DD>. Status: open.
77
+
78
+ ## Links
79
+
80
+ <Incident ticket, deploy logs, dashboards, related commits, prior RCAs if
81
+ this is a recurrence.>
82
+
83
+ - <label>: <url>
@@ -0,0 +1,75 @@
1
+ ---
2
+ name: research
3
+ owner: baseline
4
+ description: Workflow Phase 3 — Research and Solution Exploration. Surfaces 2–4 candidate solution approaches with concrete tradeoffs, grounded in current library docs via context7 MCP — never in training-data recall. Output lives at `docs/research/<slug>.md`. Executes in main context.
5
+ ---
6
+
7
+ You are surfacing a small set of candidate approaches to a task, with honest tradeoffs, so the spec author can pick one. Decisions are not made here — the human reviewer decides at `/spec`. Your job is to lay out the option space.
8
+
9
+ # Prereqs
10
+
11
+ - `scout` in `completed` OR in `exceptions`.
12
+
13
+ # Inputs
14
+
15
+ - The intake at `docs/intake/<slug>.md` — **Constraints** and **Acceptance criteria** sections filter which approaches are viable.
16
+ - The scout report at `docs/scout/<slug>.md` — patterns in use, touchpoints, landmines.
17
+ - The BRD at `docs/brd/<slug>.md` if present — NFR-### requirements (latency, compliance, etc.).
18
+ - The existing tech stack — read `package.json`, `pyproject.toml`, `go.mod`, lockfiles.
19
+
20
+ # Mandatory: context7 MCP for library APIs
21
+
22
+ For any library you intend to cite:
23
+
24
+ 1. `mcp__plugin_context7_context7__resolve-library-id`
25
+ 2. `mcp__plugin_context7_context7__query-docs`
26
+
27
+ **Never cite an API from memory.** Record the version present in the lockfile and confirm the docs match that major version. If context7 has no coverage, fall back to `WebFetch` against the library's official docs and note that.
28
+
29
+ # Method
30
+
31
+ 1. **Identify libraries and frameworks** the solution would likely touch.
32
+ 2. **Verify each library API** via context7 (above).
33
+ 3. **For each candidate**, evaluate against:
34
+ - Fit with existing patterns (per scout report).
35
+ - YAGNI: does it need abstractions beyond what this task requires?
36
+ - Test-ability: can it be driven by tests seed.md permits — no internal mocks, no mocked DB?
37
+ - Reversibility: if it proves wrong post-implementation, what is the blast radius?
38
+ 4. **Rank candidates.** State your recommendation. Name what would flip the decision.
39
+
40
+ # Output
41
+
42
+ Write the memo to `docs/research/<slug>.md`. Format:
43
+
44
+ ```
45
+ # Pattern Research — <task>
46
+
47
+ ## Candidate A: <short name>
48
+ - **Summary**: <1–2 sentences>
49
+ - **API references (current)**:
50
+ - `<lib>@<version>` — <specific API> — <context7 or doc URL>
51
+ - **Fits**: <yes/no — anchored to a Scout observation>
52
+ - **Tests it enables**: <kinds of tests>
53
+ - **Tradeoffs**: <honest, not marketing>
54
+
55
+ ## Candidate B: ...
56
+
57
+ ## Recommendation
58
+ <Which candidate, and what would flip the decision.>
59
+
60
+ ## Open questions
61
+ <Things a human reviewer must decide before the spec is written.>
62
+ ```
63
+
64
+ After writing the file, append `"research"` to `workflow.json → completed`.
65
+
66
+ Tell the user: `Research memo at <path>. Next: /spec.`
67
+
68
+ # Constraints
69
+
70
+ - **No code generation.** Memo only.
71
+ - **No API assertion without a context7/docs reference.** "Unable to verify" is the honest answer when you hit a gap; do not guess.
72
+ - **No reimplementing what an approved dependency provides** (YAGNI, per seed.md).
73
+ - **Prefer 2–3 candidates over 6+.** Half-baked options are noise.
74
+ - **The recommendation is a recommendation.** The human reviewer decides at `/spec`.
75
+ - **Project source is read-only.** The only write is to `docs/research/<slug>.md`.