@thebassclef/lite 1.0.4 → 1.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 (275) hide show
  1. package/dist/cli.cjs +65 -0
  2. package/dist/cli.js +65 -0
  3. package/dist/index.cjs +1 -1
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.js +1 -1
  6. package/dist/lite/.claude/agents/architect.md +70 -0
  7. package/dist/lite/.claude/agents/builder.md +114 -0
  8. package/dist/lite/.claude/agents/designer.md +156 -0
  9. package/dist/lite/.claude/agents/reviewer.md +88 -0
  10. package/dist/lite/.claude/hooks/bassclef-sync.sh +85 -27
  11. package/dist/lite/.claude/hooks/longrun-prep-compounding-axis-check.sh +492 -0
  12. package/dist/lite/.claude/hooks/longrun-prep-render-check.sh +236 -0
  13. package/dist/lite/.claude/hooks/persona-name-scrub-check.sh +105 -0
  14. package/dist/lite/.claude/hooks/skill-step-list-check.sh +171 -0
  15. package/dist/lite/.claude/luminaries/alan-cooper.md +170 -0
  16. package/dist/lite/.claude/luminaries/alistair-cockburn.md +140 -0
  17. package/dist/lite/.claude/luminaries/amazon-pr-faq.md +34 -0
  18. package/dist/lite/.claude/luminaries/andreas-zeller.md +74 -0
  19. package/dist/lite/.claude/luminaries/ash-maurya.md +121 -0
  20. package/dist/lite/.claude/luminaries/bill-buxton.md +210 -0
  21. package/dist/lite/.claude/luminaries/charles-sanders-peirce.md +150 -0
  22. package/dist/lite/.claude/luminaries/david-ogilvy.md +192 -0
  23. package/dist/lite/.claude/luminaries/don-norman.md +173 -0
  24. package/dist/lite/.claude/luminaries/edward-tufte.md +179 -0
  25. package/dist/lite/.claude/luminaries/eric-evans.md +160 -0
  26. package/dist/lite/.claude/luminaries/frederick-brooks.md +50 -0
  27. package/dist/lite/.claude/luminaries/gang-of-four.md +157 -0
  28. package/dist/lite/.claude/luminaries/glenford-myers.md +230 -0
  29. package/dist/lite/.claude/luminaries/hunt-thomas.md +115 -0
  30. package/dist/lite/.claude/luminaries/hyrum-wright.md +94 -0
  31. package/dist/lite/.claude/luminaries/jason-fried-dhh.md +46 -0
  32. package/dist/lite/.claude/luminaries/jesse-james-garrett.md +154 -0
  33. package/dist/lite/.claude/luminaries/john-ousterhout.md +94 -0
  34. package/dist/lite/.claude/luminaries/karl-popper.md +132 -0
  35. package/dist/lite/.claude/luminaries/kent-beck.md +168 -0
  36. package/dist/lite/.claude/luminaries/linus-torvalds.md +218 -0
  37. package/dist/lite/.claude/luminaries/martin-fowler.md +164 -0
  38. package/dist/lite/.claude/luminaries/michael-feathers.md +125 -0
  39. package/dist/lite/.claude/luminaries/michael-nygard.md +118 -0
  40. package/dist/lite/.claude/luminaries/robert-c-martin.md +164 -0
  41. package/dist/lite/.claude/luminaries/saltzer-schroeder.md +194 -0
  42. package/dist/lite/.claude/luminaries/sophia-prater.md +193 -0
  43. package/dist/lite/.claude/luminaries/stephen-toulmin.md +131 -0
  44. package/dist/lite/.claude/luminaries/tony-hoare.md +170 -0
  45. package/dist/lite/.claude/luminaries/vaughn-vernon.md +50 -0
  46. package/dist/lite/.claude/luminaries/w-edwards-deming.md +158 -0
  47. package/dist/lite/.claude/rules/accessor-library-discipline.md +110 -0
  48. package/dist/lite/.claude/rules/adr-discipline.md +96 -0
  49. package/dist/lite/.claude/rules/api-conventions.md +115 -0
  50. package/dist/lite/.claude/rules/artifact-ingestion.md +137 -0
  51. package/dist/lite/.claude/rules/assert-only-after-verify.md +111 -0
  52. package/dist/lite/.claude/rules/blocked-items.md +139 -0
  53. package/dist/lite/.claude/rules/bootstrap-pair-discipline.md +106 -0
  54. package/dist/lite/.claude/rules/branching.md +28 -0
  55. package/dist/lite/.claude/rules/cold-adopter-harness-discipline.md +93 -0
  56. package/dist/lite/.claude/rules/commit-conventions.md +22 -0
  57. package/dist/lite/.claude/rules/compounding-axis-fresh-analysis.md +173 -0
  58. package/dist/lite/.claude/rules/compounding-sequence-fresh-analysis.md +173 -0
  59. package/dist/lite/.claude/rules/context-engineering.md +155 -0
  60. package/dist/lite/.claude/rules/context-management.md +85 -0
  61. package/dist/lite/.claude/rules/defensive-bash.md +52 -0
  62. package/dist/lite/.claude/rules/deferred-actions.md +233 -0
  63. package/dist/lite/.claude/rules/destructive-operations.md +69 -0
  64. package/dist/lite/.claude/rules/diagnosis.md +38 -0
  65. package/dist/lite/.claude/rules/github-issue-flash-tweet.md +114 -0
  66. package/dist/lite/.claude/rules/guardrails.md +73 -0
  67. package/dist/lite/.claude/rules/hook-wire-on-author.md +77 -0
  68. package/dist/lite/.claude/rules/identifier-leak-prevention.md +73 -0
  69. package/dist/lite/.claude/rules/iteration-bet-brief-completeness.md +43 -0
  70. package/dist/lite/.claude/rules/lite-manifest-schema-change-discipline.md +79 -0
  71. package/dist/lite/.claude/rules/longrun-prep-plan-doc-compression.md +77 -0
  72. package/dist/lite/.claude/rules/loop-discipline.md +71 -0
  73. package/dist/lite/.claude/rules/manual-prod-approval.md +100 -0
  74. package/dist/lite/.claude/rules/marker-enrichment-discipline.md +72 -0
  75. package/dist/lite/.claude/rules/mobile-ephemeral-session.md +109 -0
  76. package/dist/lite/.claude/rules/new-dependency-check.md +44 -0
  77. package/dist/lite/.claude/rules/oo-ad-entry-point.md +95 -0
  78. package/dist/lite/.claude/rules/operator-facing-prose.md +177 -0
  79. package/dist/lite/.claude/rules/option-label-discipline.md +82 -0
  80. package/dist/lite/.claude/rules/pattern-annotation.md +83 -0
  81. package/dist/lite/.claude/rules/persona-name-leak-scrub.md +90 -0
  82. package/dist/lite/.claude/rules/plain-english-discipline.md +132 -0
  83. package/dist/lite/.claude/rules/plan-enumeration-needs-value-props.md +177 -0
  84. package/dist/lite/.claude/rules/pr-body-shape.md +195 -0
  85. package/dist/lite/.claude/rules/pr-strategy.md +142 -0
  86. package/dist/lite/.claude/rules/pr-title-shape.md +90 -0
  87. package/dist/lite/.claude/rules/prototype-workflow.md +53 -0
  88. package/dist/lite/.claude/rules/reserved-skill-names.md +103 -0
  89. package/dist/lite/.claude/rules/schema-management.md +42 -0
  90. package/dist/lite/.claude/rules/sdlc-gates.md +149 -0
  91. package/dist/lite/.claude/rules/security.md +37 -0
  92. package/dist/lite/.claude/rules/session-artifacts.md +236 -0
  93. package/dist/lite/.claude/rules/skill-composition-declarations.md +105 -0
  94. package/dist/lite/.claude/rules/skill-description-clarity.md +196 -0
  95. package/dist/lite/.claude/rules/skill-procedure-step-list.md +119 -0
  96. package/dist/lite/.claude/rules/sprint-prep-preset-picker.md +76 -0
  97. package/dist/lite/.claude/rules/state-schema-validation.md +156 -0
  98. package/dist/lite/.claude/rules/stuck-signal-diagnostic.md +111 -0
  99. package/dist/lite/.claude/rules/substrate-config-schema.md +85 -0
  100. package/dist/lite/.claude/rules/test-list-discipline.md +129 -0
  101. package/dist/lite/.claude/rules/test-sufficiency.md +186 -0
  102. package/dist/lite/.claude/rules/testing-tier-config.md +125 -0
  103. package/dist/lite/.claude/rules/testing.md +38 -0
  104. package/dist/lite/.claude/rules/turn-estimate-grounding.md +82 -0
  105. package/dist/lite/.claude/rules/visual-hierarchy.md +427 -0
  106. package/dist/lite/.claude/rules/we-dont-break-adopters.md +103 -0
  107. package/dist/lite/.claude/rules/whereami-load-bearing.md +184 -0
  108. package/dist/lite/.claude/rules/writing-craft-discipline.md +72 -0
  109. package/dist/lite/.claude/rules/wu-sequencing-compounds.md +119 -0
  110. package/dist/lite/.claude/skills/build/SKILL.md +640 -0
  111. package/dist/lite/.claude/skills/chronicle/SKILL.md +55 -0
  112. package/dist/lite/.claude/skills/clean-artifacts/SKILL.md +249 -0
  113. package/dist/lite/.claude/skills/decompose/SKILL.md +280 -0
  114. package/dist/lite/.claude/skills/diagnose/SKILL.md +297 -0
  115. package/dist/lite/.claude/skills/feynman/SKILL.md +90 -0
  116. package/dist/lite/.claude/skills/howdoi/SKILL.md +105 -0
  117. package/dist/lite/.claude/skills/ia-model/SKILL.md +108 -0
  118. package/dist/lite/.claude/skills/interaction-design/SKILL.md +112 -0
  119. package/dist/lite/.claude/skills/interpret-input/SKILL.md +180 -0
  120. package/dist/lite/.claude/skills/journal/SKILL.md +209 -0
  121. package/dist/lite/.claude/skills/kiss/SKILL.md +449 -0
  122. package/dist/lite/.claude/skills/launch/SKILL.md +915 -0
  123. package/dist/lite/.claude/skills/lean-canvas/SKILL.md +332 -0
  124. package/dist/lite/.claude/skills/longrun/SKILL.md +512 -0
  125. package/dist/lite/.claude/skills/luminary/SKILL.md +481 -0
  126. package/dist/lite/.claude/skills/ogilvy-writing-audit/SKILL.md +177 -0
  127. package/dist/lite/.claude/skills/onboard-repo/SKILL.md +1640 -0
  128. package/dist/lite/.claude/skills/pattern-review/SKILL.md +99 -0
  129. package/dist/lite/.claude/skills/personas/SKILL.md +207 -0
  130. package/dist/lite/.claude/skills/promote/SKILL.md +283 -0
  131. package/dist/lite/.claude/skills/requirement/SKILL.md +98 -0
  132. package/dist/lite/.claude/skills/retro/SKILL.md +117 -0
  133. package/dist/lite/.claude/skills/riff/SKILL.md +114 -0
  134. package/dist/lite/.claude/skills/roadmap-reconcile/SKILL.md +163 -0
  135. package/dist/lite/.claude/skills/session-end/SKILL.md +309 -0
  136. package/dist/lite/.claude/skills/session-log/SKILL.md +299 -0
  137. package/dist/lite/.claude/skills/skills/SKILL.md +228 -0
  138. package/dist/lite/.claude/skills/spec/SKILL.md +105 -0
  139. package/dist/lite/.claude/skills/sprint/SKILL.md +418 -0
  140. package/dist/lite/.claude/skills/stage/SKILL.md +384 -0
  141. package/dist/lite/.claude/skills/state-a-problem/SKILL.md +185 -0
  142. package/dist/lite/.claude/skills/temperance/SKILL.md +108 -0
  143. package/dist/lite/.claude/skills/use-case/SKILL.md +417 -0
  144. package/dist/lite/.claude/skills/user-stories/SKILL.md +268 -0
  145. package/dist/lite/.claude/skills/value-prop/SKILL.md +251 -0
  146. package/dist/lite/.claude/skills/verify/SKILL.md +160 -0
  147. package/dist/lite/.claude/skills/visual-review/SKILL.md +503 -0
  148. package/dist/lite/.claude/skills/whats-the-plan/SKILL.md +202 -0
  149. package/dist/lite/.claude/skills/whereami/SKILL.md +307 -0
  150. package/dist/lite/AGENTS.md +79 -0
  151. package/dist/lite/CLAUDE-lite.md +85 -0
  152. package/dist/lite/CODE_OF_CONDUCT.md +28 -0
  153. package/dist/lite/CONTRIBUTING.md +177 -0
  154. package/dist/lite/README.md +173 -0
  155. package/dist/lite/SECURITY.md +19 -0
  156. package/dist/lite/architecture/decisions/ADR-029-release-pipeline.md +79 -0
  157. package/dist/lite/architecture/decisions/ADR-031-non-breaking-changes-adopter-discipline.md +139 -0
  158. package/dist/lite/architecture/decisions/ADR-032-adopter-sync-dispatcher-architecture.md +192 -0
  159. package/dist/lite/architecture/decisions/ADR-039-release-tagging-scheme.md +145 -0
  160. package/dist/lite/architecture/decisions/ADR-040-planning-skill-vocabulary-and-lite-profile.md +155 -0
  161. package/dist/lite/architecture/decisions/ADR-044-unified-skill-body-template.md +162 -0
  162. package/dist/lite/lib/clean-artifacts-sweep.sh +112 -0
  163. package/dist/lite/lib/code-comment-discipline.sh +144 -0
  164. package/dist/lite/lib/composer-preflight.sh +459 -0
  165. package/dist/lite/lib/deferred-actions.sh +146 -0
  166. package/dist/lite/lib/hook-header-parser.sh +61 -0
  167. package/dist/lite/lib/hook-heartbeat.sh +152 -0
  168. package/dist/lite/lib/hook-inject.sh +255 -0
  169. package/dist/lite/lib/hook-installer.sh +195 -0
  170. package/dist/lite/lib/luminary-pick.sh +96 -0
  171. package/dist/lite/lib/output-discipline.sh +143 -0
  172. package/dist/lite/lib/prose-scan-boundary.sh +171 -0
  173. package/dist/lite/lib/rewrite-check.sh +214 -0
  174. package/dist/lite/lib/session-rescue.sh +151 -0
  175. package/dist/lite/lib/source-graph-walker.sh +277 -0
  176. package/dist/lite/lib/state.sh +1372 -0
  177. package/dist/lite/lib/telemetry.sh +205 -0
  178. package/dist/lite/lib/tier-check.sh +187 -0
  179. package/dist/lite/lib/tier-dependency-audit.sh +1088 -0
  180. package/dist/lite/presence/install/bassclef-hook-connect.sh +178 -0
  181. package/dist/lite/presence/install/bassclef-sync.dispatcher.template.sh +841 -0
  182. package/dist/lite/presence/install/bassclef-sync.template.sh +2278 -0
  183. package/dist/lite/presence/install/schedule-auto-save.cron.sh +88 -0
  184. package/dist/lite/presence/install/schedule-auto-save.taskscheduler.md +122 -0
  185. package/dist/lite/scripts/aggregate-telemetry.sh +217 -0
  186. package/dist/lite/scripts/analyze-tier-dependencies.sh +239 -0
  187. package/dist/lite/scripts/generate-lite-manifest.sh +505 -0
  188. package/dist/lite/scripts/generate-tier-manifest.sh +28 -0
  189. package/dist/lite/scripts/intent-drift-check.sh +456 -0
  190. package/dist/lite/scripts/lite-manifest-drift-check.sh +146 -0
  191. package/dist/lite/scripts/render-lite-manifest-doc.sh +150 -0
  192. package/dist/lite/standards/adr-template.md +86 -0
  193. package/dist/lite/standards/api-conventions/nextjs.md +84 -0
  194. package/dist/lite/standards/artifact-composition.md +209 -0
  195. package/dist/lite/standards/bash-hook-safety.md +246 -0
  196. package/dist/lite/standards/bassclef-configs-schema.md +232 -0
  197. package/dist/lite/standards/bassclef-evolution.md +143 -0
  198. package/dist/lite/standards/bassclef-internal-jargon.md +244 -0
  199. package/dist/lite/standards/bassclef-managed-sentinel.md +96 -0
  200. package/dist/lite/standards/bassclef-source-config.md +228 -0
  201. package/dist/lite/standards/branch-stacking.md +408 -0
  202. package/dist/lite/standards/code-safety-principles.md +176 -0
  203. package/dist/lite/standards/composer-prerequisites.md +155 -0
  204. package/dist/lite/standards/deferred-actions-schema.md +204 -0
  205. package/dist/lite/standards/dependency-discipline/cargo.md +39 -0
  206. package/dist/lite/standards/dependency-discipline/gem.md +43 -0
  207. package/dist/lite/standards/dependency-discipline/go-mod.md +41 -0
  208. package/dist/lite/standards/dependency-discipline/npm.md +42 -0
  209. package/dist/lite/standards/dependency-discipline/pip.md +42 -0
  210. package/dist/lite/standards/deployment-topology/ec2-tailscale.md +225 -0
  211. package/dist/lite/standards/deployment-topology.md +69 -0
  212. package/dist/lite/standards/docs-sync-allowlist.md +76 -0
  213. package/dist/lite/standards/domain-and-dns.md +145 -0
  214. package/dist/lite/standards/frontend-stack.md +67 -0
  215. package/dist/lite/standards/frontmatter-schema.md +154 -0
  216. package/dist/lite/standards/graceful-exit.md +227 -0
  217. package/dist/lite/standards/hook-idempotency.md +102 -0
  218. package/dist/lite/standards/hook-injection-discipline.md +202 -0
  219. package/dist/lite/standards/hook-install-class.md +215 -0
  220. package/dist/lite/standards/input-handler-interface.md +152 -0
  221. package/dist/lite/standards/lite-manifest-schema-changes.md +180 -0
  222. package/dist/lite/standards/lite-manifest.json +2797 -0
  223. package/dist/lite/standards/luminary-matching.md +105 -0
  224. package/dist/lite/standards/luminary-problem-patterns.md +481 -0
  225. package/dist/lite/standards/migration-discipline/active-record.md +50 -0
  226. package/dist/lite/standards/migration-discipline/alembic.md +43 -0
  227. package/dist/lite/standards/migration-discipline/gorm.md +50 -0
  228. package/dist/lite/standards/migration-discipline/prisma.md +53 -0
  229. package/dist/lite/standards/migration-discipline/sqlalchemy.md +51 -0
  230. package/dist/lite/standards/mobile-ephemeral-session.md +167 -0
  231. package/dist/lite/standards/model-routing-discipline.md +160 -0
  232. package/dist/lite/standards/ogilvy-writing-rules.md +225 -0
  233. package/dist/lite/standards/opener-discipline.md +96 -0
  234. package/dist/lite/standards/operator-facing-prose-discipline.md +201 -0
  235. package/dist/lite/standards/persona-schema.md +229 -0
  236. package/dist/lite/standards/pluggable-luminaries.md +323 -0
  237. package/dist/lite/standards/pr-body-discipline.md +115 -0
  238. package/dist/lite/standards/preview-state-schema.md +189 -0
  239. package/dist/lite/standards/project-directory-layout.md +276 -0
  240. package/dist/lite/standards/release-tagging.md +137 -0
  241. package/dist/lite/standards/reserved-skill-names.md +120 -0
  242. package/dist/lite/standards/scannable-multi-option-output.md +265 -0
  243. package/dist/lite/standards/sdlc-compliance.md +286 -0
  244. package/dist/lite/standards/sdlc-gates/typescript.md +57 -0
  245. package/dist/lite/standards/secrets-lifecycle.md +210 -0
  246. package/dist/lite/standards/security-scanner-adapter.md +145 -0
  247. package/dist/lite/standards/session-board.md +256 -0
  248. package/dist/lite/standards/skill-output-discipline.md +121 -0
  249. package/dist/lite/standards/state-spine-contract.md +255 -0
  250. package/dist/lite/standards/state-spine.md +511 -0
  251. package/dist/lite/standards/steering-hints/kiss-words.md +11 -0
  252. package/dist/lite/standards/substrate-config-schema.md +267 -0
  253. package/dist/lite/standards/tech-stack-config.md +109 -0
  254. package/dist/lite/standards/tier-dependency-analysis.md +167 -0
  255. package/dist/lite/standards/tier-runtime-deps/lite.md +57 -0
  256. package/dist/lite/standards/tier-tag-schema.md +155 -0
  257. package/dist/lite/standards/two-layer-config.md +99 -0
  258. package/dist/lite/standards/use-case-format.md +292 -0
  259. package/dist/lite/standards/user-story-invest.md +268 -0
  260. package/dist/lite/standards/velocity-and-appetite.md +229 -0
  261. package/dist/lite/standards/voice-input-pattern.md +119 -0
  262. package/dist/lite/standards/whereami-schema.md +301 -0
  263. package/dist/lite/standards/worktree-management.md +211 -0
  264. package/dist/lite/standards/writing-guide.md +213 -0
  265. package/dist/lite/templates/chronicle-template.md +75 -0
  266. package/dist/lite/templates/deferred-action-template.md +45 -0
  267. package/dist/lite/templates/memory-proposal-template.md +77 -0
  268. package/dist/lite/templates/persona-template.md +200 -0
  269. package/dist/lite/templates/pr-faq.md +45 -0
  270. package/dist/lite/templates/secret-rotation-template.md +162 -0
  271. package/dist/lite/templates/spec-template.md +131 -0
  272. package/dist/lite/templates/use-case-template.md +194 -0
  273. package/dist/lite/templates/user-story-template.md +107 -0
  274. package/dist/lite/templates/whereami-template.md +101 -0
  275. package/package.json +1 -1
@@ -0,0 +1,236 @@
1
+ #!/usr/bin/env bash
2
+ # tier: lite
3
+ # install-class: dual
4
+ # PostToolUse: Stop
5
+ #
6
+ # /longrun prep render check — closes ticket #1632.
7
+ #
8
+ # Fires four render-shape checks against the latest assistant message
9
+ # when the message carries a /longrun prep proposal:
10
+ #
11
+ # Symptom 1 — path label repetition. Every axis section repeating
12
+ # "Path A / Path B / Path C" as row prefixes = pure chart-junk per
13
+ # Tufte. Threshold: option labels appearing > 3 * option_count
14
+ # outside table header rows triggers BLOCK.
15
+ #
16
+ # Symptom 2 — no progressive disclosure. Recommend line declares
17
+ # Option X but multiple options carry full 6-axis blocks. Per
18
+ # Norman progressive disclosure + ADR-055 D3 recommended-only
19
+ # shape. Trigger: 2+ #### Option X sections beneath a
20
+ # "### Compounding value — recommended only" anchor when a
21
+ # Recommend line is present.
22
+ #
23
+ # Symptom 3 — TUI-unsafe table cells. Cells holding apostrophes,
24
+ # parens, or em-dashes fracture at Claude Code TUI render. Per
25
+ # .claude/rules/visual-hierarchy.md §12. Trigger: any markdown
26
+ # table row (starts and ends with |) carries [']()—] inside a cell
27
+ # (excluding header separator rows).
28
+ #
29
+ # Symptom 4 — "(Via /SKILL)" placeholder leak. Template placeholder
30
+ # text should be substituted with the dispatched skill name.
31
+ # Trigger: literal "(Via /SKILL)" appears in the message.
32
+ #
33
+ # Anchor luminaries:
34
+ # @luminary don-norman — progressive disclosure, signifier
35
+ # @luminary edward-tufte — data-ink ratio, chart-junk
36
+ # @luminary michael-feathers — characterization tests
37
+ # @luminary kent-beck — Tier 0 strict-TDD
38
+ #
39
+ # Toggle (default advisory; flip strict after calibration cycle):
40
+ # LONGRUN_PREP_RENDER_CHECK_TOGGLE=strict → exit 2 on any finding
41
+ # LONGRUN_PREP_RENDER_CHECK_TOGGLE=advisory → exit 0, findings to stderr (default)
42
+ # LONGRUN_PREP_RENDER_CHECK_TOGGLE=silent → exit 0, no output
43
+ #
44
+ # Override per-call:
45
+ # SKIP_LONGRUN_PREP_RENDER_CHECK=1
46
+
47
+ set -uo pipefail
48
+
49
+ # Override — skip and log
50
+ if [ "${SKIP_LONGRUN_PREP_RENDER_CHECK:-0}" = "1" ]; then
51
+ echo "[longrun-prep-render-check: SKIPPED via SKIP_LONGRUN_PREP_RENDER_CHECK=1]" >&2
52
+ exit 0
53
+ fi
54
+
55
+ TOGGLE="${LONGRUN_PREP_RENDER_CHECK_TOGGLE:-advisory}"
56
+
57
+ # Silent mode — exit clean
58
+ if [ "$TOGGLE" = "silent" ]; then
59
+ exit 0
60
+ fi
61
+
62
+ # Fixture-mode override (tests) — checked FIRST so fixture content is
63
+ # the source of truth when the env var is set. Skips the transcript
64
+ # extraction entirely.
65
+ if [ -n "${LONGRUN_PREP_RENDER_FIXTURE:-}" ] && [ -f "${LONGRUN_PREP_RENDER_FIXTURE}" ]; then
66
+ MESSAGE_TEXT="$(cat "${LONGRUN_PREP_RENDER_FIXTURE}")"
67
+ else
68
+ # Normal runtime path — read stdin JSON + extract latest assistant message
69
+ STDIN_JSON="$(cat 2>/dev/null || echo '{}')"
70
+ TRANSCRIPT_PATH="$(echo "$STDIN_JSON" | jq -r '.transcript_path // empty' 2>/dev/null || echo "")"
71
+
72
+ if [ -z "$TRANSCRIPT_PATH" ] || [ ! -f "$TRANSCRIPT_PATH" ]; then
73
+ exit 0
74
+ fi
75
+
76
+ MESSAGE_TEXT="$(jq -r '
77
+ select(.type == "assistant")
78
+ | .message.content[]?
79
+ | select(.type == "text")
80
+ | .text
81
+ ' "$TRANSCRIPT_PATH" 2>/dev/null | tail -c 32000)"
82
+ fi
83
+
84
+ if [ -z "$MESSAGE_TEXT" ]; then
85
+ exit 0
86
+ fi
87
+
88
+ # Only fire on messages that look like /longrun prep proposals.
89
+ # Anchor patterns per SKILL body Step 1.5-1.7:
90
+ # - "### Compare options" — the scan-table anchor
91
+ # - "### Compounding value" — the axis block anchor
92
+ # - "**Recommend:**" — the recommendation opener
93
+ # If none of these appear, this is not a prep proposal; skip.
94
+ if ! echo "$MESSAGE_TEXT" | grep -qE '(### Compare options|### Compounding value|\*\*Recommend:\*\*)'; then
95
+ exit 0
96
+ fi
97
+
98
+ FINDINGS=""
99
+ FINDING_COUNT=0
100
+
101
+ # =========================================================================
102
+ # Symptom 1 — Path label repetition (Tufte chart-junk)
103
+ # =========================================================================
104
+ #
105
+ # Count occurrences of "Option [a-z]" or "Path [A-Z]" or "Shape [a-c]" in
106
+ # non-comment / non-fenced-code lines. Deduct one occurrence per option
107
+ # for the header row + one for the Recommend line + one for the card
108
+ # section header. If remaining count > 0, we have per-option axis
109
+ # repetition — the chart-junk pattern.
110
+ #
111
+ # Threshold: per-option axis repetition means 6+ extra label rows per
112
+ # option. If the total residual count is > 3, the anti-pattern is present.
113
+ LABEL_TOTAL=$(echo "$MESSAGE_TEXT" | \
114
+ grep -vE '^[[:space:]]*```' | \
115
+ grep -oE '\b(Option [a-z]|Path [A-Z]|Shape [a-c])\b' | wc -l | tr -d ' ')
116
+ OPTION_COUNT=$(echo "$MESSAGE_TEXT" | \
117
+ grep -vE '^[[:space:]]*```' | \
118
+ grep -oE '\b(Option [a-z]|Path [A-Z]|Shape [a-c])\b' | sort -u | wc -l | tr -d ' ')
119
+
120
+ # Baseline: header row + card section + recommend line + one summary sentence.
121
+ # Estimate ~4 legitimate uses per option label.
122
+ BASELINE=$((OPTION_COUNT * 4))
123
+
124
+ if [ "$LABEL_TOTAL" -gt "$BASELINE" ] && [ "$OPTION_COUNT" -ge 2 ]; then
125
+ EXCESS=$((LABEL_TOTAL - BASELINE))
126
+ FINDINGS="${FINDINGS}
127
+ Symptom 1 — path label repetition (Tufte chart-junk):
128
+ ${LABEL_TOTAL} option-label mentions across ${OPTION_COUNT} options
129
+ (baseline ~${BASELINE}; excess ~${EXCESS})
130
+ Cure — collapse per-axis 'Option A / B / C' rows into ONE header naming
131
+ options once, then rows carry values without re-labeling."
132
+ FINDING_COUNT=$((FINDING_COUNT + 1))
133
+ fi
134
+
135
+ # =========================================================================
136
+ # Symptom 2 — no progressive disclosure (Norman)
137
+ # =========================================================================
138
+ #
139
+ # Fires when Recommend line declares Option X AND non-recommended options
140
+ # ALSO carry full 6-axis "#### Option Y" cards beneath the
141
+ # "### Compounding value — recommended only" anchor. Per bassclef-upstream
142
+ # #1376 + ADR-055 D3, only the recommended option gets a full card.
143
+ RECOMMENDED=$(echo "$MESSAGE_TEXT" | \
144
+ grep -oE '\*\*Recommend[^*]*\*\*[[:space:]]*(Option [a-z]|Path [A-Z]|Shape [a-c])' | \
145
+ head -1 | grep -oE '(Option [a-z]|Path [A-Z]|Shape [a-c])' | head -1)
146
+
147
+ if [ -n "$RECOMMENDED" ]; then
148
+ # Count #### Option X headers under the recommended-only anchor
149
+ CARD_HEADERS_UNDER_ANCHOR=$(echo "$MESSAGE_TEXT" | awk '
150
+ /^### Compounding value/ { in_anchor=1; next }
151
+ /^### / && in_anchor { in_anchor=0 }
152
+ in_anchor && /^#### (Option [a-z]|Path [A-Z]|Shape [a-c])/ { print }
153
+ ' | wc -l | tr -d ' ')
154
+
155
+ if [ "$CARD_HEADERS_UNDER_ANCHOR" -ge 2 ]; then
156
+ FINDINGS="${FINDINGS}
157
+ Symptom 2 — no progressive disclosure (Norman):
158
+ Recommend declared '${RECOMMENDED}' but ${CARD_HEADERS_UNDER_ANCHOR}
159
+ #### Option cards appear under '### Compounding value — recommended only'
160
+ Cure — render ONE card for the recommended option only. Non-recommended
161
+ options carry axes as one-liner cells in the scan-table row above.
162
+ See .claude/rules/compounding-sequence-fresh-analysis.md postcondition."
163
+ FINDING_COUNT=$((FINDING_COUNT + 1))
164
+ fi
165
+ fi
166
+
167
+ # =========================================================================
168
+ # Symptom 3 — TUI-unsafe table cells (visual-hierarchy §12)
169
+ # =========================================================================
170
+ #
171
+ # Detect markdown table rows (start and end with |, not separator rows)
172
+ # that carry apostrophes, parens, or em-dashes inside cell text.
173
+ # Per .claude/rules/visual-hierarchy.md §12 — card format is the cure.
174
+ UNSAFE_CELL_LINES=$(echo "$MESSAGE_TEXT" | \
175
+ grep -E '^\|.*\|[[:space:]]*$' | \
176
+ grep -vE '^\|[[:space:]:-]+\|' | \
177
+ grep -E "['()—]" | head -3)
178
+
179
+ if [ -n "$UNSAFE_CELL_LINES" ]; then
180
+ UNSAFE_COUNT=$(echo "$UNSAFE_CELL_LINES" | wc -l | tr -d ' ')
181
+ FINDINGS="${FINDINGS}
182
+ Symptom 3 — TUI-unsafe table cells (visual-hierarchy §12):
183
+ ${UNSAFE_COUNT} table row(s) carry apostrophes / parens / em-dashes
184
+ in cell text. First offending row:
185
+ $(echo "$UNSAFE_CELL_LINES" | head -1 | cut -c1-120)
186
+ Cure — move affected content to card format (bullets under a heading)
187
+ or replace ' with U+2019, replace () with plain prose, replace — with
188
+ HTML entity or backticks."
189
+ FINDING_COUNT=$((FINDING_COUNT + 1))
190
+ fi
191
+
192
+ # =========================================================================
193
+ # Symptom 4 — "(Via /SKILL)" placeholder leak
194
+ # =========================================================================
195
+ #
196
+ # Detect literal "(Via /SKILL)" or "(via /SKILL)" or "(/SKILL)" in the
197
+ # message. These are template placeholders that should have been
198
+ # substituted with the actual dispatched skill name.
199
+ LEAK_COUNT=$(echo "$MESSAGE_TEXT" | grep -cE '\((Via|via) /SKILL\)|\(/SKILL\)' 2>/dev/null | tr -d '[:space:]' || echo 0)
200
+ LEAK_COUNT="${LEAK_COUNT:-0}"
201
+
202
+ if [ "$LEAK_COUNT" -gt 0 ]; then
203
+ FINDINGS="${FINDINGS}
204
+ Symptom 4 — '(Via /SKILL)' placeholder leak:
205
+ ${LEAK_COUNT} literal placeholder(s) in message. Should be substituted
206
+ with the dispatched skill name (e.g., 'via /state-a-problem brief').
207
+ Cure — replace each '(Via /SKILL)' with 'via /<actual-skill>' or drop
208
+ the citation if no skill fired."
209
+ FINDING_COUNT=$((FINDING_COUNT + 1))
210
+ fi
211
+
212
+ # =========================================================================
213
+ # Emit + exit per toggle
214
+ # =========================================================================
215
+
216
+ if [ "$FINDING_COUNT" -eq 0 ]; then
217
+ exit 0
218
+ fi
219
+
220
+ case "$TOGGLE" in
221
+ strict)
222
+ echo "🛑 LONGRUN-PREP-RENDER — BLOCKED (${FINDING_COUNT} finding(s); ticket #1632)" >&2
223
+ echo "$FINDINGS" >&2
224
+ echo "" >&2
225
+ echo "Override: SKIP_LONGRUN_PREP_RENDER_CHECK=1" >&2
226
+ exit 2
227
+ ;;
228
+ *)
229
+ # Default: advisory
230
+ echo "⚠ LONGRUN-PREP-RENDER — ADVISORY (${FINDING_COUNT} finding(s); ticket #1632)" >&2
231
+ echo "$FINDINGS" >&2
232
+ echo "" >&2
233
+ echo "Flip to strict via LONGRUN_PREP_RENDER_CHECK_TOGGLE=strict" >&2
234
+ exit 0
235
+ ;;
236
+ esac
@@ -0,0 +1,105 @@
1
+ #!/bin/bash
2
+ # tier: lite
3
+ # install-class: dual
4
+ # persona-name-scrub-check — PreToolUse hook that scans SKILL descriptions,
5
+ # SKILL bodies, rule bodies, luminary bodies, and adopter-facing docs
6
+ # (docs/**/*.md, docs-site/content/**/*.{md,mdx}) for bassclef persona
7
+ # proper nouns (Sam, Louis, Jamie, Morgan).
8
+ #
9
+ # V1 (bassclef-web#327): description-only scope.
10
+ # V2 (bassclef-web#339): body scope + adopter-facing docs paths.
11
+ #
12
+ # Per .claude/rules/persona-name-leak-scrub.md.
13
+ # V1+V2 ADVISORY per ADR-031 grace window. Exit 0 with stderr finding.
14
+ # V3 BLOCK deferred pending calibration cycle.
15
+ #
16
+ # Exit codes:
17
+ # 0 — allow (non-matching path, non-Edit/Write, clean content, or override)
18
+ #
19
+ # Override: SKIP_PERSONA_NAME_SCRUB=1
20
+
21
+ set +e
22
+
23
+ INPUT=$(cat 2>/dev/null)
24
+ TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // ""' 2>/dev/null)
25
+ FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // ""' 2>/dev/null)
26
+
27
+ # Only fire on Edit or Write or MultiEdit
28
+ case "$TOOL_NAME" in
29
+ Edit|Write|MultiEdit) ;;
30
+ *) exit 0 ;;
31
+ esac
32
+
33
+ # Override path
34
+ if [ "${SKIP_PERSONA_NAME_SCRUB:-}" = "1" ]; then
35
+ exit 0
36
+ fi
37
+
38
+ # Path scope decision — V2 broadened per bassclef-web#339
39
+ # Order matters: skip docs/personas/*.md BEFORE the docs/*.md general match
40
+ case "$FILE_PATH" in
41
+ */docs/personas/*.md)
42
+ exit 0 ;;
43
+ */.claude/skills/*/SKILL.md) ;;
44
+ */.claude/rules/*.md) ;;
45
+ */.claude/luminaries/*.md) ;;
46
+ */docs-site/content/*.md|*/docs-site/content/*.mdx) ;;
47
+ */docs/*.md) ;;
48
+ *) exit 0 ;;
49
+ esac
50
+
51
+ # Extract content — Write → content; Edit → new_string; MultiEdit → concat edits[].new_string
52
+ CONTENT=""
53
+ if [ "$TOOL_NAME" = "Write" ]; then
54
+ CONTENT=$(echo "$INPUT" | jq -r '.tool_input.content // ""' 2>/dev/null)
55
+ elif [ "$TOOL_NAME" = "MultiEdit" ]; then
56
+ CONTENT=$(echo "$INPUT" | jq -r '[.tool_input.edits[]? | .new_string] | join("\n")' 2>/dev/null)
57
+ else
58
+ CONTENT=$(echo "$INPUT" | jq -r '.tool_input.new_string // ""' 2>/dev/null)
59
+ fi
60
+
61
+ [ -z "$CONTENT" ] && exit 0
62
+
63
+ # Strip false-positive sources BEFORE regex scan (R4 + R12 mitigations):
64
+ # 1. Fenced code blocks (``` ... ```)
65
+ # 2. Inline backtick spans (`...`)
66
+ # awk + sed pipeline. Order: fenced first (multi-line), then inline (single-line).
67
+ STRIPPED=$(echo "$CONTENT" | awk '
68
+ BEGIN { in_block = 0 }
69
+ /^```/ { in_block = !in_block; next }
70
+ { if (!in_block) print }
71
+ ' | sed 's/`[^`]*`//g')
72
+
73
+ # Word-boundary case-sensitive regex for persona proper nouns.
74
+ # grep -E for extended regex, -o extracts matches for the ADVISORY report.
75
+ MATCHES=$(echo "$STRIPPED" | grep -oE '\b(Sam|Louis|Jamie|Morgan)\b' 2>/dev/null | sort -u | tr '\n' ' ')
76
+
77
+ if [ -n "$MATCHES" ]; then
78
+ # Determine scope label for the ADVISORY (description vs body vs docs)
79
+ SCOPE_LABEL="body"
80
+ if echo "$STRIPPED" | grep -qE '^description:.*\b(Sam|Louis|Jamie|Morgan)\b'; then
81
+ SCOPE_LABEL="description"
82
+ fi
83
+ case "$FILE_PATH" in
84
+ */docs/*|*/docs-site/*) SCOPE_LABEL="adopter-facing content" ;;
85
+ esac
86
+
87
+ cat >&2 <<EOF
88
+ ⚠ PERSONA-NAME-SCRUB — ADVISORY (V2)
89
+
90
+ File: $FILE_PATH
91
+ Scope: $SCOPE_LABEL
92
+ Match: $MATCHES
93
+
94
+ Adopters read SKILL bodies + rules + luminaries + docs. They have
95
+ no context on bassclef persona names. Substitute role words —
96
+ writer, picker, reviewer, operator, adopter.
97
+
98
+ Or backtick the name if it names a variable / quoted external ref.
99
+
100
+ Per .claude/rules/persona-name-leak-scrub.md
101
+ Override (logged): SKIP_PERSONA_NAME_SCRUB=1
102
+ EOF
103
+ fi
104
+
105
+ exit 0
@@ -0,0 +1,171 @@
1
+ #!/bin/bash
2
+ # tier: lite
3
+ # install-class: dual
4
+ # Skill-step-list check — Stop hook that scans the transcript for a Skill tool
5
+ # dispatch followed by an assistant response without a step-list block.
6
+ #
7
+ # Per sunj-labs/bassclef-upstream#1119: closes the SKILL-step-skip class caught
8
+ # in session 2026-08-05a. Rule at .claude/rules/skill-procedure-step-list.md.
9
+ # Ships as pair per bootstrap-pair-discipline.md.
10
+ #
11
+ # Sibling pattern: .claude/hooks/turn-prose-kiss-check.sh (Stop hook + transcript scan).
12
+ #
13
+ # Input (stdin): JSON with transcript_path + session_id
14
+ # {"transcript_path": "/path/to/transcript.jsonl", "session_id": "..."}
15
+ #
16
+ # Toggle (env or .claude/bassclef-configs.jsonc):
17
+ # SKILL_STEP_LIST_TOGGLE=true — advisory (exit 0, findings to stderr) [DEFAULT]
18
+ # SKILL_STEP_LIST_TOGGLE=strict — strict (exit 2, blocks stop, forces rewrite)
19
+ # SKILL_STEP_LIST_TOGGLE=false — silent (exit 0, no scan)
20
+ #
21
+ # Override per-call:
22
+ # SKIP_SKILL_STEP_LIST=1 — skip scan, exit 0
23
+ #
24
+ # Exit codes:
25
+ # 0 — pass (no findings, advisory mode, toggle off, override set, or no Skill dispatched)
26
+ # 2 — block stop (strict mode + Skill dispatched + no step-list in response)
27
+ #
28
+ # Reads:
29
+ # - $TRANSCRIPT_PATH (JSONL, one event per line)
30
+ # - .claude/bassclef-configs.jsonc (toggle when env not set)
31
+
32
+ set +e
33
+
34
+ # === Override path ===
35
+ if [ "${SKIP_SKILL_STEP_LIST:-0}" = "1" ]; then
36
+ exit 0
37
+ fi
38
+
39
+ # === Source install-class resolver ===
40
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
41
+
42
+ # Hook liveness heartbeat (silent-fail)
43
+ {
44
+ for _hb_c in "${SCRIPT_DIR}/../../lib/hook-heartbeat.sh" "${HOME:-/}/lib/hook-heartbeat.sh"; do
45
+ [ -f "$_hb_c" ] && source "$_hb_c" && heartbeat_mark "skill-step-list-check" && break
46
+ done
47
+ unset _hb_c
48
+ } 2>/dev/null || true
49
+
50
+ for _candidate in \
51
+ "${SCRIPT_DIR}/../../lib/hook-inject.sh" \
52
+ "${HOME_OVERRIDE:-${HOME:-/}}/lib/hook-inject.sh"; do
53
+ if [ -f "$_candidate" ]; then
54
+ # shellcheck disable=SC1090
55
+ source "$_candidate"
56
+ break
57
+ fi
58
+ done
59
+ unset _candidate
60
+
61
+ # === Parse stdin JSON ===
62
+ STDIN_JSON=$(cat 2>/dev/null || echo '{}')
63
+ TRANSCRIPT_PATH=$(echo "$STDIN_JSON" | jq -r '.transcript_path // ""' 2>/dev/null)
64
+
65
+ # Graceful skip if no transcript path
66
+ if [ -z "$TRANSCRIPT_PATH" ]; then
67
+ exit 0
68
+ fi
69
+
70
+ # Graceful skip if transcript file missing
71
+ if [ ! -f "$TRANSCRIPT_PATH" ]; then
72
+ exit 0
73
+ fi
74
+
75
+ # === Resolve config file ===
76
+ if declare -f resolve_config_path >/dev/null 2>&1; then
77
+ CONFIG_FILE=$(resolve_config_path 2>/dev/null) || CONFIG_FILE=""
78
+ else
79
+ CONFIG_FILE="${SCRIPT_DIR}/../bassclef-configs.jsonc"
80
+ fi
81
+
82
+ # === Resolve toggle ===
83
+ TOGGLE="${SKILL_STEP_LIST_TOGGLE:-}"
84
+ if [ -z "$TOGGLE" ]; then
85
+ if [ -n "$CONFIG_FILE" ] && [ -f "$CONFIG_FILE" ]; then
86
+ TOGGLE=$(sed 's|//.*||g' "$CONFIG_FILE" 2>/dev/null \
87
+ | jq -r '.skill_step_list.toggle // "true"' 2>/dev/null)
88
+ fi
89
+ TOGGLE="${TOGGLE:-true}"
90
+ fi
91
+
92
+ case "$TOGGLE" in
93
+ true|"true") MODE="advisory" ;;
94
+ strict|"strict") MODE="strict" ;;
95
+ false|"false") exit 0 ;;
96
+ *) MODE="advisory" ;;
97
+ esac
98
+
99
+ # === Scan transcript for a Skill tool_use ===
100
+ # We scan the last 200 lines to keep the hook fast.
101
+ LAST_LINES=$(tail -200 "$TRANSCRIPT_PATH" 2>/dev/null)
102
+
103
+ # Find lines with Skill tool_use
104
+ SKILL_LINE_NUM=$(echo "$LAST_LINES" | grep -n '"type":"tool_use"' 2>/dev/null | grep '"name":"Skill"' | tail -1 | cut -d: -f1)
105
+
106
+ if [ -z "$SKILL_LINE_NUM" ]; then
107
+ # No Skill dispatched in recent transcript — silent pass
108
+ exit 0
109
+ fi
110
+
111
+ # === Find the assistant text_content event AFTER the Skill line ===
112
+ # The response we care about is the one after the Skill tool_result comes back.
113
+ AFTER_SKILL=$(echo "$LAST_LINES" | tail -n +"$((SKILL_LINE_NUM + 1))" 2>/dev/null)
114
+
115
+ # Get the latest assistant text_content in that portion
116
+ LAST_ASSISTANT_AFTER=$(echo "$AFTER_SKILL" | grep '"type":"assistant"' | tail -1)
117
+
118
+ if [ -z "$LAST_ASSISTANT_AFTER" ]; then
119
+ # Skill dispatched but no response yet — silent pass
120
+ exit 0
121
+ fi
122
+
123
+ # Extract text content from the assistant message
124
+ MESSAGE_TEXT=$(echo "$LAST_ASSISTANT_AFTER" \
125
+ | jq -r '.message.content[]? |
126
+ if .type == "text" then
127
+ .text
128
+ else
129
+ empty
130
+ end' 2>/dev/null)
131
+
132
+ if [ -z "$MESSAGE_TEXT" ]; then
133
+ # Assistant message had no text content (tool_use only) — silent pass
134
+ exit 0
135
+ fi
136
+
137
+ # === Check for step-list pattern ===
138
+ # Pattern: two markers must both appear:
139
+ # 1. A "Step N" reference (Step + digit)
140
+ # 2. At least one "[x]" or "[~]" bracket status marker
141
+ HAS_STEP=$(echo "$MESSAGE_TEXT" | grep -cE 'Step[[:space:]]+[0-9]+' 2>/dev/null)
142
+ HAS_MARKER=$(echo "$MESSAGE_TEXT" | grep -cE '\[[x~]\]' 2>/dev/null)
143
+
144
+ if [ "$HAS_STEP" -gt 0 ] && [ "$HAS_MARKER" -gt 0 ]; then
145
+ # Step-list present — silent pass
146
+ exit 0
147
+ fi
148
+
149
+ # === Missing step-list — emit finding ===
150
+ NOTICE="SKILL step-list check: recent Skill dispatch response lacks a step-list block."
151
+ NOTICE="$NOTICE Per .claude/rules/skill-procedure-step-list.md,"
152
+ NOTICE="$NOTICE write each SKILL procedure step with [x] done+source OR [~] deferred+reason."
153
+
154
+ # Trace log if trace-helper available
155
+ if [ -f "${SCRIPT_DIR}/../../lib/trace-helper.sh" ]; then
156
+ source "${SCRIPT_DIR}/../../lib/trace-helper.sh" 2>/dev/null
157
+ if declare -f trace_record >/dev/null 2>&1; then
158
+ trace_record "skill-step-list-check" "advisory-fired" "$NOTICE" 2>/dev/null
159
+ fi
160
+ fi
161
+
162
+ if [ "$MODE" = "strict" ]; then
163
+ echo "🛑 BLOCKED: $NOTICE" >&2
164
+ echo "" >&2
165
+ echo "To resolve: rewrite the response with a step list at the top." >&2
166
+ echo "Override: SKIP_SKILL_STEP_LIST=1 <command> (logged)" >&2
167
+ exit 2
168
+ else
169
+ echo "⚠ ADVISORY: $NOTICE" >&2
170
+ exit 0
171
+ fi
@@ -0,0 +1,170 @@
1
+ ---
2
+ tier: lite
3
+ name: Alan Cooper
4
+ slug: alan-cooper
5
+ claimed_by: [designer]
6
+ referenced_by_skills: [ia-model, jtbd-tasks, task-scenarios]
7
+ primary_domain: ux
8
+ depth: full
9
+ sources:
10
+ - type: book
11
+ title: "About Face: The Essentials of Interaction Design (4th edition)"
12
+ authors: ["Alan Cooper", "Robert Reimann", "David Cronin", "Christopher Noessel"]
13
+ year: 2014
14
+ url: "https://www.wiley.com/en-us/About+Face%3A+The+Essentials+of+Interaction+Design%2C+4th+Edition-p-9781118766576"
15
+ isbn: "9781118766576"
16
+ methodology_covered:
17
+ - "Goal-Directed Design — design starts from user goals, not features or tasks"
18
+ - "Personas as design tools — composite archetypes derived from user research"
19
+ - "Scenarios — narrative descriptions of personas using the product to achieve goals"
20
+ - "Three categories of users: novice + intermediate + expert; design for the perpetual intermediate"
21
+ - type: book
22
+ title: "The Inmates Are Running the Asylum: Why High-Tech Products Drive Us Crazy and How to Restore the Sanity"
23
+ authors: ["Alan Cooper"]
24
+ year: 1999
25
+ url: "https://www.pearson.com/en-us/subject-catalog/p/inmates-are-running-the-asylum-the-why-high-tech-products-drive-us-crazy-and-how-to-restore-the-sanity/P200000009296"
26
+ isbn: "9780672326141"
27
+ methodology_covered:
28
+ - "Programmer-driven design produces hostile interfaces"
29
+ - "Interaction designers as a distinct discipline, separate from engineering"
30
+ - "Persona origin — Cooper's first published articulation of the persona methodology"
31
+ verification_status: verified
32
+ solves_problems_brownfield:
33
+ - "Existing UI exposes the system's structure when users want their workflow"
34
+ - "Power users keep retracing the same multi-step path through the current UI"
35
+ - "Persona research surfaces a goal but the existing UI optimizes for novice exploration"
36
+ - "App is feature-rich but each user wants only one slice for their job"
37
+ solves_problems_greenfield:
38
+ - "Designing a workflow-heavy app for returning users with named goals"
39
+ - "Building a product where personas + scenarios should drive the UI before any screen sketch"
40
+ - "Planning a tool for power users who need their job-specific slice surfaced from day one"
41
+ - "Mid-complexity product where personas keep early design decisions grounded in real users"
42
+ anti_patterns:
43
+ - "Truly simple consumer apps — Cooper overweights workflow modeling"
44
+ - "First-launch novelty experiences — goal-directed assumes a returning user"
45
+ - "Pure marketing or storytelling surfaces"
46
+ description: "\"Personas are precision tools — each one a research-grounded behavioral archetype, not a fictional user."
47
+ ---
48
+
49
+ # Alan Cooper
50
+
51
+ ## Signature
52
+
53
+ *"Personas are precision tools — each one a research-grounded behavioral archetype, not a fictional user. Start with user goals and let personas carry you there."*
54
+
55
+ "Father of Visual Basic"; founder of Cooper (the consultancy); author of
56
+ **About Face** and **The Inmates Are Running the Asylum**. The bassclef
57
+ voice on **Goal-Directed Design** and the proper use of personas as
58
+ research artifacts.
59
+
60
+ ## Core methods
61
+
62
+ - **Goal-Directed Design** — Start with user goals (what they want to
63
+ accomplish, at life/experience/end levels), then derive tasks, then
64
+ derive interface. Feature-first design inverts this and produces
65
+ feature-dense, goal-incoherent products.
66
+ - **Personas as behavioral archetypes** — Built from interview pattern
67
+ analysis, not invented. Each persona represents a distinct goal set +
68
+ mental model + behavior pattern. A good product serves a primary
69
+ persona ruthlessly; secondary personas are served if it doesn't
70
+ compromise the primary.
71
+ - **Three levels of goals** — Life goals (long-term aspirations),
72
+ experience goals (how the interaction should feel), end goals (what
73
+ they want to accomplish in this session). Life goals shape brand;
74
+ experience goals shape interaction; end goals shape task flow.
75
+ - **Scenarios over requirements** — Describe the user in their context
76
+ pursuing their goal. A list of requirements decomposes; a scenario
77
+ holds the context that makes requirements make sense.
78
+ - **Dancing bear anti-pattern** — When something is remarkable *that it
79
+ works at all*, we accept it despite being difficult to use. Enterprise
80
+ software especially. Cooper's insight: don't accept the dancing bear.
81
+
82
+ ## When to channel this luminary
83
+
84
+ When the biggest risk is building the wrong thing for the wrong person.
85
+ Cooper dominates when you have a target user population with distinct
86
+ behavior patterns, when goals (not features) should drive the product,
87
+ and when the risk of serving-everyone-badly is real. Think: operator
88
+ tools where the primary user does this job all day, specialist tools
89
+ where casual users will never be the target, B2B products with clear
90
+ user roles.
91
+
92
+ Do NOT channel Cooper as primary for: consumer products with vague
93
+ personas, rapid prototyping where persona rigor is premature, projects
94
+ where research budget doesn't support proper persona development (use
95
+ lightweight JTBD instead).
96
+
97
+ ## Stack translation
98
+
99
+ In a Next.js + Prisma operator tool:
100
+
101
+ - **User goals → top-level nav** — If the primary persona's goal is
102
+ "move deals through pipeline efficiently," nav centers on deal flow,
103
+ not on feature taxonomy.
104
+ - **Personas → role-based access + UI variants** — Actual personas
105
+ often map to auth roles (Operator vs Broker vs Viewer). Each role
106
+ gets a goal-optimized surface, not a feature-subset of a generic UI.
107
+ - **Scenarios → key path tests** — Each scenario becomes an end-to-end
108
+ test that walks through the persona's goal. If the scenario breaks,
109
+ the product breaks for that persona.
110
+ - **Primary persona dominance** — When Primary Persona and Secondary
111
+ Persona needs conflict, Primary wins. Tailwind variants, conditional
112
+ rendering, feature flags — all serve this.
113
+
114
+ ## Anti-patterns it prevents
115
+
116
+ - **Self-referential design** — designing for ourselves because we're
117
+ easy to imagine. Cooper's rigor demands research-grounded personas.
118
+ - **Generic "the user"** — vague singular user that's really an
119
+ amalgam of all users. Produces features for all, good-fit for none.
120
+ - **Feature-driven roadmap** — building because the feature was
121
+ requested, not because it serves a persona's goal. Accumulates
122
+ feature bloat without coherent direction.
123
+ - **Persona gallery** — fictional marketing personas dressed as UX
124
+ personas. Names, photos, and hobbies without behavioral grounding.
125
+ Useless for design decisions.
126
+ - **Goal conflation** — treating "user wants to export to CSV" as a
127
+ goal. That's a task. The goal is "report to their manager." The task
128
+ could be replaced by a better path to the goal.
129
+
130
+ ## Worked example
131
+
132
+ For POA's deal pipeline, Cooper's approach starts with:
133
+
134
+ **Primary persona**: "Operator" — the person whose full-time job is
135
+ managing deal flow. Life goal: become a successful PE operator.
136
+ Experience goal: feel in control of their pipeline at a glance. End
137
+ goals per session: advance stuck deals, respond to broker inbound, log
138
+ new conversations, identify stalled opportunities.
139
+
140
+ **Secondary persona**: "Broker" — external contact. Life goal: maximize
141
+ commissions. Experience goal: trust the platform. End goals per session:
142
+ submit new listings, see status on submitted deals, communicate with
143
+ Operator.
144
+
145
+ **Primary wins**: the main surface is optimized for Operator. Broker
146
+ access is a narrow, focused interface (not the Operator UI with fewer
147
+ permissions). Dashboards emphasize stuck/stalled deals (end-goal
148
+ triggers) over total-deals-count (vanity metric).
149
+
150
+ What Cooper would NOT produce: a generic "deal management platform"
151
+ designed for "users." A feature-grid home page. A Broker UI that's
152
+ just Operator UI with most nav items hidden.
153
+
154
+ ## Sources
155
+
156
+ - *About Face: The Essentials of Interaction Design* — Cooper,
157
+ Reimann, Cronin, Noessel, Wiley (4th ed 2014) — the foundational text
158
+ - *The Inmates Are Running the Asylum* — Cooper (1999, rev. 2004)
159
+ - cooper.com — Cooper consultancy (now part of Designit)
160
+
161
+ ## Related luminaries
162
+
163
+ - **Kim Goodwin** — Goodwin provides the operational method for
164
+ Cooper's Goal-Directed Design; pair them always.
165
+ - **Sophia Prater** — OOUX starts with objects; Cooper with goals. Both
166
+ reject feature-first. Complementary at different layers.
167
+ - **Teresa Torres** — Continuous Discovery updates Cooper's research
168
+ rigor for weekly cadence.
169
+ - **Indi Young** — Mental models research at the thinking layer below
170
+ Cooper's behavioral archetypes.