@thebassclef/lite 1.1.1 → 1.2.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 (135) hide show
  1. package/dist/cli.cjs +23 -6
  2. package/dist/cli.js +23 -6
  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/bassclef-configs.jsonc +56 -0
  7. package/dist/lite/.claude/bassclef-orientation.md +120 -0
  8. package/dist/lite/.claude/hooks/adr-discipline-check.sh +132 -0
  9. package/dist/lite/.claude/hooks/atomic-pr-check.sh +169 -0
  10. package/dist/lite/.claude/hooks/auto-save-idle.sh +51 -0
  11. package/dist/lite/.claude/hooks/bassclef-sync.sh +51 -13
  12. package/dist/lite/.claude/hooks/bet-doc-gate.sh +283 -0
  13. package/dist/lite/.claude/hooks/bug-diagnosis.sh +64 -0
  14. package/dist/lite/.claude/hooks/destructive-command-guard.sh +136 -0
  15. package/dist/lite/.claude/hooks/file-rename-discipline-check.sh +147 -0
  16. package/dist/lite/.claude/hooks/hook-classifier-canary.sh +158 -0
  17. package/dist/lite/.claude/hooks/kiss-default-check.sh +129 -0
  18. package/dist/lite/.claude/hooks/multi-tenancy-check.sh +83 -0
  19. package/dist/lite/.claude/hooks/oo-ad-entry-point-check.sh +216 -0
  20. package/dist/lite/.claude/hooks/operator-private-path-check.sh +203 -0
  21. package/dist/lite/.claude/hooks/pattern-annotation-validate.sh +142 -0
  22. package/dist/lite/.claude/hooks/plain-english-steering.sh +15 -1
  23. package/dist/lite/.claude/hooks/post-write-trace.sh +66 -0
  24. package/dist/lite/.claude/hooks/pr-body-scrub-check.sh +446 -0
  25. package/dist/lite/.claude/hooks/pre-commit-identifier-leak-scrub.sh +137 -0
  26. package/dist/lite/.claude/hooks/pre-gh-pr-body-scrub.sh +192 -0
  27. package/dist/lite/.claude/hooks/pre-gh-pr-title-scrub.sh +172 -0
  28. package/dist/lite/.claude/hooks/role-entry-gate.sh +115 -0
  29. package/dist/lite/.claude/hooks/save-state.sh +268 -0
  30. package/dist/lite/.claude/hooks/session-reflection.d/08-settings-drift.sh +8 -1
  31. package/dist/lite/.claude/hooks/session-reflection.d/10-abrupt-stop-recovery.sh +52 -0
  32. package/dist/lite/.claude/hooks/session-reflection.d/55-orientation-gate.sh +40 -4
  33. package/dist/lite/.claude/hooks/session-reflection.d/80-hook-heartbeat-check.sh +12 -5
  34. package/dist/lite/.claude/hooks/session-reflection.d/81-hook-manifest-staleness.sh +18 -2
  35. package/dist/lite/.claude/hooks/session-reflection.d/91-npm-version-drift.sh +54 -0
  36. package/dist/lite/.claude/hooks/session-reflection.d/tests/10-abrupt-stop-recovery.test.sh +95 -0
  37. package/dist/lite/.claude/hooks/session-reflection.sh +62 -15
  38. package/dist/lite/.claude/hooks/tool-failure-diagnosis.sh +50 -0
  39. package/dist/lite/.claude/luminaries/andrej-karpathy.md +165 -0
  40. package/dist/lite/.claude/luminaries/dave-gray.md +155 -0
  41. package/dist/lite/.claude/luminaries/gary-klein.md +166 -0
  42. package/dist/lite/.claude/luminaries/kaoru-ishikawa.md +162 -0
  43. package/dist/lite/.claude/luminaries/lean-product-canvas.md +33 -0
  44. package/dist/lite/.claude/luminaries/luke-wroblewski.md +224 -0
  45. package/dist/lite/.claude/luminaries/ryan-singer.md +113 -0
  46. package/dist/lite/.claude/luminaries/steve-krug.md +168 -0
  47. package/dist/lite/.claude/luminaries/tony-ulwick.md +134 -0
  48. package/dist/lite/.claude/rules/arc-level-orientation-before-leaf.md +60 -0
  49. package/dist/lite/.claude/rules/architect-review-discipline.md +71 -0
  50. package/dist/lite/.claude/rules/auto-fix-criteria.md +126 -0
  51. package/dist/lite/.claude/rules/bassclef-hook-drift-blocker.md +144 -0
  52. package/dist/lite/.claude/rules/bassclef-models-discovery.md +107 -0
  53. package/dist/lite/.claude/rules/bassclef-workflow-parity.md +104 -0
  54. package/dist/lite/.claude/rules/cost-governance.md +154 -0
  55. package/dist/lite/.claude/rules/file-rename-discipline.md +95 -0
  56. package/dist/lite/.claude/rules/mechanism-fidelity.md +88 -0
  57. package/dist/lite/.claude/rules/prototype-production-coupling.md +125 -0
  58. package/dist/lite/.claude/rules/quick-fix-criteria.md +90 -0
  59. package/dist/lite/.claude/rules/session-artifacts.md +30 -0
  60. package/dist/lite/.claude/rules/sibling-smoke-after-substrate-change.md +107 -0
  61. package/dist/lite/.claude/rules/substrate-as-system.md +67 -0
  62. package/dist/lite/.claude/rules/usability.md +22 -0
  63. package/dist/lite/.claude/settings.json +20 -0
  64. package/dist/lite/.claude/skills/agent-research-spawn/SKILL.md +100 -0
  65. package/dist/lite/.claude/skills/architect-review/SKILL.md +201 -0
  66. package/dist/lite/.claude/skills/auto-fix/SKILL.md +297 -0
  67. package/dist/lite/.claude/skills/autonomous/SKILL.md +300 -0
  68. package/dist/lite/.claude/skills/bind-subdomain/SKILL.md +232 -0
  69. package/dist/lite/.claude/skills/canvas/SKILL.md +41 -0
  70. package/dist/lite/.claude/skills/deploy-prod/SKILL.md +106 -0
  71. package/dist/lite/.claude/skills/docs-sync/SKILL.md +188 -0
  72. package/dist/lite/.claude/skills/eisenhower/SKILL.md +273 -0
  73. package/dist/lite/.claude/skills/empathy-map/SKILL.md +168 -0
  74. package/dist/lite/.claude/skills/frontend-design/SKILL.md +53 -0
  75. package/dist/lite/.claude/skills/interview-me/SKILL.md +171 -0
  76. package/dist/lite/.claude/skills/journal-export/SKILL.md +293 -0
  77. package/dist/lite/.claude/skills/jtbd-tasks/SKILL.md +203 -0
  78. package/dist/lite/.claude/skills/objectory-decompose/SKILL.md +256 -0
  79. package/dist/lite/.claude/skills/pick-luminaries/SKILL.md +100 -0
  80. package/dist/lite/.claude/skills/pre-mortem/SKILL.md +180 -0
  81. package/dist/lite/.claude/skills/prototype-gallery/SKILL.md +264 -0
  82. package/dist/lite/.claude/skills/provision-deploy-host/SKILL.md +257 -0
  83. package/dist/lite/.claude/skills/quick-fix/SKILL.md +273 -0
  84. package/dist/lite/.claude/skills/release/SKILL.md +311 -0
  85. package/dist/lite/.claude/skills/release-notes/SKILL.md +202 -0
  86. package/dist/lite/.claude/skills/rfc/SKILL.md +222 -0
  87. package/dist/lite/.claude/skills/riff-prototypes/SKILL.md +637 -0
  88. package/dist/lite/.claude/skills/secrets-bootstrap/SKILL.md +209 -0
  89. package/dist/lite/.claude/skills/skill/SKILL.md +304 -0
  90. package/dist/lite/.claude/skills/smoke-test/SKILL.md +100 -0
  91. package/dist/lite/.claude/skills/state/SKILL.md +204 -0
  92. package/dist/lite/.claude/skills/substrate-check/SKILL.md +218 -0
  93. package/dist/lite/.claude/skills/synthetic-user/SKILL.md +381 -0
  94. package/dist/lite/.claude/skills/task-scenarios/SKILL.md +105 -0
  95. package/dist/lite/.claude/skills/tier-dependency-audit/SKILL.md +139 -0
  96. package/dist/lite/.claude/skills/ux-migration/SKILL.md +424 -0
  97. package/dist/lite/.claude/skills/value-prop-canvas/SKILL.md +297 -0
  98. package/dist/lite/README.md +5 -1
  99. package/dist/lite/gitignore +6 -0
  100. package/dist/lite/lib/bassclef-dir-resolver.sh +85 -0
  101. package/dist/lite/lib/clone-failure-classifier.sh +59 -0
  102. package/dist/lite/lib/fixture-builder.sh +190 -0
  103. package/dist/lite/lib/fresh-install-check.sh +49 -0
  104. package/dist/lite/lib/hook-heartbeat.sh +0 -1
  105. package/dist/lite/lib/mechanism-fidelity.sh +569 -0
  106. package/dist/lite/lib/npm-version-check.sh +112 -0
  107. package/dist/lite/lib/preview-state.sh +229 -0
  108. package/dist/lite/lib/session-rescue.sh +0 -1
  109. package/dist/lite/scripts/generate-lite-manifest.sh +145 -4
  110. package/dist/lite/scripts/lite-manifest-drift-check.sh +5 -1
  111. package/dist/lite/standards/architect-review-discipline.md +222 -0
  112. package/dist/lite/standards/bassclef-platform.md +249 -0
  113. package/dist/lite/standards/bassclef-test-repos.md +97 -0
  114. package/dist/lite/standards/bassclef-wiring-manifest.json +25 -1
  115. package/dist/lite/standards/cold-adopter-harness.md +205 -0
  116. package/dist/lite/standards/data-management.md +135 -0
  117. package/dist/lite/standards/frontend-stack/nextjs-prisma.md +124 -0
  118. package/dist/lite/standards/lite-manifest-schema-changes.md +27 -0
  119. package/dist/lite/standards/lite-manifest.json +1456 -14
  120. package/dist/lite/standards/mechanism-fidelity.md +205 -0
  121. package/dist/lite/standards/operator-private-discipline.md +200 -0
  122. package/dist/lite/standards/operator-to-public-flow.md +195 -0
  123. package/dist/lite/standards/prototype-gallery.md +251 -0
  124. package/dist/lite/standards/pseudonym-key-schema.md +109 -0
  125. package/dist/lite/standards/sibling-validation-checklist.md +181 -0
  126. package/dist/lite/standards/slack-notifications.md +161 -0
  127. package/dist/lite/standards/synthetic-user-testing.md +173 -0
  128. package/dist/lite/standards/vendor-bindings.md +165 -0
  129. package/dist/lite/standards/vendor-plugins/frontend-design.md +66 -0
  130. package/dist/lite/standards/vpc-fit-validation.md +167 -0
  131. package/dist/lite/templates/gallery-yml.md +113 -0
  132. package/dist/lite/templates/product-canvas.md +169 -0
  133. package/dist/lite/templates/value-prop-canvas.md +180 -0
  134. package/package.json +3 -3
  135. /package/dist/lite/{whereami.md → docs/whereami.md} +0 -0
@@ -0,0 +1,297 @@
1
+ ---
2
+ tier: lite
3
+ name: value-prop-canvas
4
+ description: "Produce a Strategyzer Value Proposition Canvas per persona \u2014 Customer Profile (Jobs/Pains/Gains) plus Value Map (Products/Pain-relievers/Gain-creators) plus fit-validation. The diagnostic lens over /personas."
5
+ problem: "Value propositions get stated without persona anchoring. Jobs and pains and gains float free."
6
+ value: "Strategyzer Value Proposition Canvas per persona. Customer profile plus value map."
7
+ inputs: [Persona name from personas file]
8
+ outputs: [Customer profile — Jobs plus Pains plus Gains, Value map, Fit gap]
9
+ user_invocable: true
10
+ disable_model_invocation: false
11
+ ---
12
+
13
+ # /value-prop-canvas — Strategyzer VPC
14
+
15
+ Produce a Value Proposition Canvas (Strategyzer) per persona. Reads
16
+ `/personas` output; emits one canvas per persona; validates fit — every
17
+ Pain Reliever addresses a named Pain, every Gain Creator addresses a
18
+ named Gain. Orphan entries (relievers/creators without a target)
19
+ surface as validation failures.
20
+
21
+ ## Distinction from `/value-prop`
22
+
23
+ Two adjacent but non-overlapping skills; both keep their slots.
24
+
25
+ | Skill | Output shape | Purpose | When to use |
26
+ |-------|-------------|---------|-------------|
27
+ | `/value-prop` | Positioning statement (Moore) + 3 RTBs (Dunford Proof) | Compressed sales-ready framing | Decks, landing pages, pitch prep |
28
+ | `/value-prop-canvas` | Two-sided canvas (Customer Profile + Value Map) per persona | Diagnostic mapping — do our relievers/creators actually address named pains/gains? | Before committing to positioning; during product shaping; validating fit |
29
+
30
+ If you're trying to *say* something, `/value-prop`. If you're trying to
31
+ *check* something, `/value-prop-canvas`. Most iterations benefit from
32
+ running VPC first (to find the fit) then `/value-prop` (to phrase it).
33
+
34
+ ## Sources read
35
+
36
+ - Alexander Osterwalder et al. — Strategyzer *Value Proposition Design* (2014). Bassclef VPC source. https://www.strategyzer.com/library/the-value-proposition-canvas
37
+ - IxDF — *Value Proposition Canvas* overview. https://ixdf.org/literature/topics/value-proposition-canvas
38
+ - IxDF + Medium — *JTBD + VPC relationship* (Customer Jobs connection). https://medium.com/@pminanutshell/npd-phase-1-5-introducing-value-proposition-canvas-jobs-to-be-done-f5036ea6ff9
39
+ - `.claude/skills/personas/SKILL.md` — upstream read contract (file-system convention `docs/personas/*.md`)
40
+ - `standards/persona-schema.md` — persona shape this skill reads
41
+ - `standards/vpc-fit-validation.md` — companion standard (this skill's Stack-2 artifact) codifying the fit rules
42
+ - `templates/value-prop-canvas.md` — bassclef template (this skill's Stack-2 artifact)
43
+ - `.claude/skills/value-prop/SKILL.md` — adjacent skill; cross-linked in output but not reshaped
44
+ - `.claude/skills/jtbd-tasks/SKILL.md` — JTBD feeds Customer Jobs (functional jobs especially)
45
+
46
+ ## What I'm NOT reading
47
+
48
+ - `/lean-canvas` or `/business-model-canvas` — those are broader strategic canvases at the organization level; VPC is product-market-fit specific. If a consumer wants lean canvas or BMC, those are separate skills for future promotion
49
+ - Cross-persona aggregation (one VPC for "all customers") — explicitly out of scope per ticket; VPC is 1:1 with persona
50
+
51
+ ## When to invoke
52
+
53
+ - After `/personas` has produced at least one persona file (operator-default counts but produces a thin canvas — warn surfaced)
54
+ - During Elaboration or early Construction when fit between product decisions and customer needs is still being settled
55
+ - Before `/value-prop` if positioning feels ungrounded — VPC produces the evidence `/value-prop` needs
56
+ - When a `/risk-test-synthetic` matrix (future promotion) needs per-persona fit signal
57
+
58
+ ## Usage
59
+
60
+ ```
61
+ /value-prop-canvas → produce VPC for every persona in the repo
62
+ /value-prop-canvas [slug] → VPC for one persona
63
+ /value-prop-canvas validate → re-check fit on existing canvases at docs/value-prop-canvas/
64
+ ```
65
+
66
+ ## Procedure
67
+
68
+ ### Step 1: Load personas
69
+
70
+ Read personas via the `/personas` contract:
71
+
72
+ 1. Check `docs/personas/*.md` (preferred)
73
+ 2. Check `docs/design/personas/*.md` (legacy)
74
+ 3. If neither has files → emit operator-default warning and halt with:
75
+ "No personas found. Run `/personas default` to see the fallback, or
76
+ create real persona files in `docs/personas/` before producing VPC."
77
+
78
+ For a specific slug (`/value-prop-canvas couple-founders`), load only
79
+ that file. For the default invocation, enumerate all.
80
+
81
+ ### Step 2: Extract Customer Profile signals
82
+
83
+ For each persona, derive the three Customer Profile quadrants from its
84
+ content:
85
+
86
+ | VPC field | Persona source |
87
+ |-----------|---------------|
88
+ | **Customer Jobs** | Persona's `goal`, `tasks`, JTBD statements (if present), workflow descriptions. Split into functional / social / emotional |
89
+ | **Pains** | Persona's "Pain points" section (with evidence traces). Each pain is a named Pain with severity signal if traceable |
90
+ | **Gains** | Persona's "Motivators" section + "What would make them switch" + implicit gains inferable from pain inversions |
91
+
92
+ **Do not invent.** If the persona doesn't have the data, the VPC
93
+ quadrant stays thin and surfaces as WARN in fit-validation. Inventing
94
+ entries produces false-positive fit signals downstream — the whole
95
+ point of VPC is that the fit must be defensible.
96
+
97
+ ### Step 3: Build Value Map
98
+
99
+ For the product / iteration / feature being reasoned about:
100
+
101
+ | VPC field | Source |
102
+ |-----------|--------|
103
+ | **Products / Services** | What we ship — features, capabilities, affordances |
104
+ | **Pain Relievers** | Specific product behaviors that address specific Pains |
105
+ | **Gain Creators** | Specific product behaviors that produce specific Gains |
106
+
107
+ Each Pain Reliever is annotated with the Pain it addresses (by Pain ID
108
+ from Step 2). Each Gain Creator is annotated with the Gain.
109
+
110
+ Example format:
111
+
112
+ ```markdown
113
+ ## Pain Relievers
114
+
115
+ ### PR1 — Shared context digest
116
+ **Addresses:** P1 (Duplicate context rebuilding), P3 ("What did AI say
117
+ about X?" side-channel)
118
+ Description: auto-digest of both partners' AI conversations into a
119
+ shared daily read.
120
+
121
+ ### PR2 — Per-member session continuity
122
+ **Addresses:** P2 (Account-sharing workaround) — each member has their
123
+ own memory, shared context is opt-in not default.
124
+ ```
125
+
126
+ ### Step 4: Fit validation
127
+
128
+ Walk every Pain Reliever and Gain Creator. Check:
129
+
130
+ - [ ] Each Pain Reliever names ≥1 Pain it addresses (by ID or exact label)
131
+ - [ ] Each Gain Creator names ≥1 Gain it produces (by ID or exact label)
132
+ - [ ] No Pain has zero Relievers (WARN — unaddressed Pain is a scope signal, not a fit failure per se)
133
+ - [ ] No Gain has zero Creators (WARN — same)
134
+
135
+ **Orphan entries fail validation.** A Pain Reliever without a named
136
+ Pain is either (a) a feature looking for a problem, or (b) addressing
137
+ a pain that should be named but isn't yet. Both are signals — write
138
+ them down in the canvas's "Orphans surfaced" section with operator-
139
+ facing next steps ("Add P6: [inferred pain], or drop PR3 from the
140
+ value map").
141
+
142
+ Unaddressed Pains/Gains (coverage gaps) are WARN, not FAIL — they
143
+ might be deliberately out of scope, and the canvas surfaces them for
144
+ operator decision rather than blocking.
145
+
146
+ ### Step 5: Emit canvas
147
+
148
+ Write to `docs/value-prop-canvas/{persona-slug}.md`. One file per
149
+ persona. Never merge multiple personas into one canvas.
150
+
151
+ Template: `templates/value-prop-canvas.md`. Structure:
152
+
153
+ ```markdown
154
+ # Value Proposition Canvas — [Persona Name]
155
+
156
+ **Persona:** [slug] ([path to persona file])
157
+ **Iteration / feature:** [goal path or feature name]
158
+ **Generated:** [YYYY-MM-DD]
159
+ **Fit validation:** PASS | WARN (coverage gaps) | FAIL (orphans)
160
+
161
+ ## Customer Profile
162
+
163
+ ### Customer Jobs
164
+ - [J1] Functional: [label] — [one line]
165
+ - [J2] Social: [label] — [one line]
166
+ - [J3] Emotional: [label] — [one line]
167
+
168
+ ### Pains
169
+ - [P1] [label] — [one line; source-trace if present in persona]
170
+ - [P2] ...
171
+
172
+ ### Gains
173
+ - [G1] [label] — [one line]
174
+ - [G2] ...
175
+
176
+ ## Value Map
177
+
178
+ ### Products / Services
179
+ - [Feature A]
180
+ - [Feature B]
181
+
182
+ ### Pain Relievers
183
+ - [PR1] [label] — addresses: [Pain IDs]. Description.
184
+ - [PR2] ...
185
+
186
+ ### Gain Creators
187
+ - [GC1] [label] — produces: [Gain IDs]. Description.
188
+ - [GC2] ...
189
+
190
+ ## Fit summary
191
+
192
+ | Element | Count | Addressed | Unaddressed |
193
+ |---------|-------|-----------|-------------|
194
+ | Pains | N | M | K |
195
+ | Gains | N | M | K |
196
+
197
+ ## Orphans surfaced
198
+
199
+ [Each orphan: the entry, why it has no target, operator decision needed]
200
+
201
+ ## Notes
202
+ [Optional: edge cases, deferred decisions, open questions]
203
+ ```
204
+
205
+ ### Step 6: Output summary
206
+
207
+ Print a compact summary to the conversation:
208
+
209
+ ```markdown
210
+ ## VPC produced: [N] canvases
211
+
212
+ | Persona | Status | Orphans | Coverage gaps |
213
+ |---------|--------|---------|---------------|
214
+ | couple-founders | PASS | 0 | 1 gain unaddressed |
215
+ | cofounder-pair | WARN | 0 | 2 pains unaddressed |
216
+ | operator-advisor | FAIL | 1 orphan PR | — |
217
+ ```
218
+
219
+ ## Worked example — inline fit-validation demo
220
+
221
+ To make the fit rule concrete, here's a deliberate orphan that
222
+ validation should catch:
223
+
224
+ **Persona P1 (hypothetical):** "cofounder-pair" — two technical
225
+ co-founders frustrated by ChatGPT Business gaps.
226
+
227
+ **Pains:**
228
+ - P1: Chat history siloed between accounts
229
+ - P2: Can't share project context with teammates
230
+ - P3: Monthly cost scales badly (2 seats = $50/mo)
231
+
232
+ **Pain Relievers drafted:**
233
+ - PR1: Shared workspace with cross-account memory → **addresses P1, P2**
234
+ - PR2: Per-project billing pool → **addresses P3**
235
+ - PR3: AI-powered meeting notes → **addresses — (no Pain named)**
236
+
237
+ Running fit-validation catches PR3: orphan. Either a P4 ("meeting
238
+ context lost between sessions") should be added, or PR3 should drop
239
+ from the Value Map. Operator decides. `/value-prop-canvas validate`
240
+ fails this canvas until the orphan resolves.
241
+
242
+ Without the explicit Pain-addressing rule, PR3 would sneak into the
243
+ value map as a feature-looking-for-a-problem. Classic failure mode.
244
+
245
+ ## Common pitfalls
246
+
247
+ - **Inventing customer jobs** — VPC Customer Profile MUST derive from the persona. If the persona doesn't have the job, the job isn't there yet. Fix by enriching the persona (via research), not by padding the VPC.
248
+ - **"General" VPC** — one canvas that covers "all customers" destroys the fit signal. If you have three personas, you have three canvases. Compressing them hides which fit is strong and which is weak.
249
+ - **Aspirational Pain Relievers** — "We'll solve X better than anyone" is not a reliever. Relievers are specific product behaviors tied to specific pains.
250
+ - **Pattern-matching Gains from Pains (lazy inversion)** — "Pain: context lost" → "Gain: context preserved" is a low-value inversion. Real gains are desired outcomes the customer would articulate independently — often motivational rather than problem-solving.
251
+ - **Skipping fit validation** — emitting a canvas without running the fit walk defeats the entire point. `/value-prop-canvas validate` MUST run before any canvas is considered complete.
252
+
253
+ ## Relationship to other skills
254
+
255
+ | Skill | Relationship |
256
+ |-------|-------------|
257
+ | `/personas` | Upstream read. This skill halts without personas. |
258
+ | `/value-prop` | Sibling. VPC is diagnostic (check fit); `/value-prop` is generative (compose positioning). Run VPC first, then `/value-prop`. |
259
+ | `/jtbd-tasks` | JTBD statements → Customer Jobs (especially functional jobs) |
260
+ | `/risk-test-synthetic` | Reads VPC per persona to build risk × persona × artifact matrix |
261
+ | `/user-stories` | Pain Relievers + Gain Creators inform the `<benefit>` clause in INVEST stories |
262
+ | `/spec` | VPC Value Map maps to spec "success criteria" |
263
+ | `/riff-prototypes` | VPC fit-validation per variant surfaces which variant addresses the most pains — selection input |
264
+
265
+ ## Chain position
266
+
267
+ ```
268
+ /personas (WHO)
269
+
270
+ /jtbd-tasks (WHY — what they're hiring for)
271
+
272
+ /value-prop-canvas (WHAT TO SAY / HOW TO HELP) ← this skill
273
+
274
+ /value-prop (COMPRESSED POSITIONING — uses VPC as evidence)
275
+
276
+ /user-stories (HOW WE BUILD IT — INVEST)
277
+
278
+ /ia-model + /interaction-design (HOW IT RENDERS)
279
+
280
+ /decompose + /spec (HOW IT IMPLEMENTS)
281
+ ```
282
+
283
+ ## Provenance & evolution
284
+
285
+ - Drafted in an operator project during user-centric chain shaping
286
+ - Promoted to bassclef via issue #201
287
+ - Stack-2 of iteration `docs/iteration-bets/2026-04-19e-persona-vpc-promotions.md` (Stack-1 shipped `/personas`)
288
+
289
+ Future promotions in the same family (separate goals):
290
+ - `/user-stories` — downstream consumer
291
+ - `/risk-test-synthetic` — downstream consumer
292
+ - `/psychographic-mine` — upstream persona generator
293
+ - `/auto-user-research` — persona generator pipeline
294
+
295
+ ## Output discipline
296
+
297
+ Dispatch `/kiss words --rewrite` on your skill output before you return it. See `standards/skill-output-discipline.md` for the contract.
@@ -11,7 +11,11 @@ description: A shared substrate for working with AI coding agents.
11
11
  >
12
12
  > Then read the rest of this README as background. About 10 minutes total.
13
13
 
14
- **A shared substrate for working with AI coding agents.** Install it once into your repo, and every Claude Code session starts loaded: 76 skills, 53 rules, 16 agents, 32 practitioner profiles, 27 hooks, 67 standards, and 27 ADRs that wire them together. The agent reads your rules, knows the catalog, handles failure cleanly, and ships with discipline. You stop re-explaining your conventions every session — the difference between an assistant you brief and a band that already knows the set.
14
+ **A shared substrate for working with AI coding agents.** Install it once into your repo, and every Claude Code session starts loaded: skills you invoke, rules the agent reads, specialist agents you dispatch, practitioner profiles it designs against, hooks that catch mistakes, plus the standards and decision records that wire them together.
15
+
16
+ Run `/skills` or `/luminary` in any session to see exactly what your install carries. The counts differ by tier, so this README does not print them.
17
+
18
+ The agent reads your rules, knows the catalog, handles failure cleanly, and ships with discipline. You stop re-explaining your conventions every session — the difference between an assistant you brief and a band that already knows the set.
15
19
 
16
20
  It is not a product. It is not a SaaS. It's a public framework, Apache 2.0: clone the repo, run the install script, own your stack.
17
21
 
@@ -56,3 +56,9 @@ substrate.secrets.md
56
56
 
57
57
  # Adopter-specific ignores below
58
58
  # <adopter-content-below>
59
+
60
+ # Bassclef synced substrate — vendored via `bassclef init` + `bassclef sync`.
61
+ # Ignore by default so `git add -A` does not sweep hundreds of files.
62
+ # Adopters who want to pin substrate: remove these lines OR add `!path/to/track`.
63
+ .claude/
64
+ .bassclef/
@@ -0,0 +1,85 @@
1
+ #!/bin/bash
2
+ # tier: lite
3
+ #
4
+ # bassclef-dir-resolver.sh — resolve BASSCLEF_DIR across install layouts.
5
+ # Cures sunj-labs/bassclef-cli#105 root cause where session-reflection.sh:43
6
+ # derived BASSCLEF_DIR by walking up two levels from the dispatcher's own
7
+ # path, resolving to $HOME under operator install (dispatcher is a real
8
+ # file at $HOME/.claude/hooks/, not a symlink to a checkout).
9
+ #
10
+ # The resolver probes four paths in order per Chain-of-Responsibility:
11
+ # 1. Peer-checkout — $CWD/../bassclef with sentinel file present
12
+ # 2. $HOME/bassclef — tarball adopter path with sentinel file present
13
+ # 3. Bundled path — walk up from $HOOK_REAL_PATH with sentinel present
14
+ # 4. Fallback — $CWD (adopter repo); safer than $HOME because the files
15
+ # fragments want ship into the repo via bassclef init
16
+ #
17
+ # The sentinel file is presence/install/bassclef-hook-connect.sh. Every
18
+ # probe requires it — an empty peer dir or empty $HOME/bassclef does NOT win.
19
+ #
20
+ # Silent contract: never crashes, never writes to stderr on the resolve path.
21
+ # Consumers (13 fragments plus session-reflection.sh coordinator) treat the
22
+ # result as authoritative.
23
+ #
24
+ # Anchor luminaries:
25
+ # @luminary john-ousterhout — deep module (narrow interface hides 4-path probe)
26
+ # @luminary linus-torvalds — adopter contract (fallback preserves the case
27
+ # where an adopter's checkout is not in a
28
+ # well-known place)
29
+ # @luminary tony-hoare — postcondition (returns an existing path OR $CWD;
30
+ # never returns $HOME under operator install)
31
+ # @luminary michael-nygard — stability pattern (silent-return; no crash path)
32
+ #
33
+ # Companion audible-fail helper: emit_missing_dep_notice — used by fragments
34
+ # whose dependencies still cannot resolve after the coordinator sets
35
+ # $BASSCLEF_DIR. Cures the two silent-fail fragments named in cli#105 body.
36
+
37
+ # @pattern patterns/code/gof/chain-of-responsibility.md
38
+ # Four probe paths in order; first hit wins; fallback covers the null case.
39
+ resolve_bassclef_dir() {
40
+ local hook_path="${HOOK_REAL_PATH:-}"
41
+ local cwd="${CWD:-.}"
42
+ local home_dir="${HOME_OVERRIDE:-${HOME:-/nonexistent}}"
43
+ local sentinel="presence/install/bassclef-hook-connect.sh"
44
+
45
+ # 1. Peer-checkout — sibling bassclef dir next to $CWD
46
+ if [ -d "$cwd/../bassclef" ] && [ -f "$cwd/../bassclef/$sentinel" ]; then
47
+ ( cd "$cwd/../bassclef" 2>/dev/null && pwd ) && return 0
48
+ fi
49
+
50
+ # 2. $HOME/bassclef — tarball adopter path
51
+ if [ -d "$home_dir/bassclef" ] && [ -f "$home_dir/bassclef/$sentinel" ]; then
52
+ printf '%s\n' "$home_dir/bassclef" && return 0
53
+ fi
54
+
55
+ # 3. Bundled path — walk up two levels from dispatcher
56
+ if [ -n "$hook_path" ]; then
57
+ local candidate
58
+ candidate="$( cd "$(dirname "$hook_path")/../.." 2>/dev/null && pwd )" || candidate=""
59
+ if [ -n "$candidate" ] && [ -f "$candidate/$sentinel" ]; then
60
+ printf '%s\n' "$candidate" && return 0
61
+ fi
62
+ fi
63
+
64
+ # 4. Fallback — $CWD (adopter repo). Safer than $HOME because the files
65
+ # fragments want (init manifest, presence/install/*) ship into the repo.
66
+ ( cd "$cwd" 2>/dev/null && pwd ) || printf '%s\n' "$cwd"
67
+ return 0
68
+ }
69
+
70
+ # emit_missing_dep_notice — companion audible-fail helper.
71
+ # Fragments call this when their dependency still cannot resolve after
72
+ # $BASSCLEF_DIR is set. Prints ONE plain line to stderr naming the
73
+ # fragment and the expected path. Silent-safe — never crashes the caller.
74
+ #
75
+ # Usage: emit_missing_dep_notice <fragment-name> <expected-path>
76
+ emit_missing_dep_notice() {
77
+ local fragment="${1:-unknown-fragment}"
78
+ local expected="${2:-<unknown-path>}"
79
+ printf '%s: skip — dependency not at %s. Sync bassclef or set BASSCLEF_DIR.\n' \
80
+ "$fragment" "$expected" >&2
81
+ }
82
+
83
+ # Export for consumers that source this lib.
84
+ export -f resolve_bassclef_dir 2>/dev/null || true
85
+ export -f emit_missing_dep_notice 2>/dev/null || true
@@ -0,0 +1,59 @@
1
+ #!/bin/bash
2
+ # tier: lite
3
+ #
4
+ # clone-failure-classifier.sh — classify a git clone failure by its stderr.
5
+ # Cures sunj-labs/bassclef-cli#106 where bassclef-sync.sh printed
6
+ # "set up GitHub auth" even when authentication was fine and the cause
7
+ # was repo visibility (private repo, adopter cannot see it).
8
+ #
9
+ # Contract: takes git stderr as $1. Prints a multi-line message to stdout
10
+ # naming the cause (auth / visibility / network / unknown) and a hint the
11
+ # adopter can act on. Includes the raw stderr in the message. Exit 0.
12
+ #
13
+ # Anchor luminaries:
14
+ # @luminary donald-norman — visibility of system status (adopter hears
15
+ # the real cause, not a wrong guess)
16
+ # @luminary michael-nygard — the case statement is a strategy per cause
17
+ # class; each cause gets its own hint
18
+ # @luminary michael-feathers — 3 canonical error shapes fixture-tested
19
+
20
+ # @pattern patterns/code/gof/strategy.md
21
+ # One strategy per error shape; unknown falls through to verbatim passthrough.
22
+ classify_clone_failure() {
23
+ local git_stderr="${1:-}"
24
+ local cause hint
25
+
26
+ case "$git_stderr" in
27
+ *"Authentication failed"*|*"could not read Username"*|*"Permission denied (publickey)"*)
28
+ cause="auth"
29
+ hint="Optional: set up GitHub auth to unlock full-tier sync — run: gh auth login"
30
+ ;;
31
+ *"Repository not found"*|*"repository "*"not found"*)
32
+ cause="visibility"
33
+ hint="Repository sunj-labs/bassclef may be private and your account cannot see it. Confirm access or continue on lite tier only."
34
+ ;;
35
+ *"Could not resolve host"*|*"Connection timed out"*|*"Failed to connect"*)
36
+ cause="network"
37
+ hint="Network unavailable. Lite tier works without it."
38
+ ;;
39
+ *)
40
+ cause="unknown"
41
+ hint="Unknown git failure. See the raw error above."
42
+ ;;
43
+ esac
44
+
45
+ cat <<MSG
46
+ ### Bassclef sync — full-tier not synced (${cause})
47
+
48
+ Git said:
49
+ ${git_stderr}
50
+
51
+ ${hint}
52
+
53
+ Lite tier works without it — your session is fine.
54
+ Skills / rules / agents beyond lite become available once sync succeeds.
55
+ MSG
56
+ return 0
57
+ }
58
+
59
+ export -f classify_clone_failure 2>/dev/null || true
@@ -0,0 +1,190 @@
1
+ #!/usr/bin/env bash
2
+ # tier: lite
3
+ # Deep module for adopter-environment fixtures used by bassclef Tier 0 tests.
4
+ # Per ADR-038 (adopter testing harness redesign) + R5 amendment to bet 30a
5
+ # (@luminary john-ousterhout deep modules — the 5 fixture builders are thin
6
+ # orchestrators on top of this library).
7
+ #
8
+ # Public API (functions tests source + call):
9
+ # fixture_init(name, tmproot) → echo path; returns 0
10
+ # fixture_cleanup(path) → safe rm; refuses paths without sentinel
11
+ # fixture_cleanup_all() → cleanup every fixture this process created
12
+ # fixture_setup_substrate_sibling(fixture_dir, substrate_name)
13
+ # fixture_inject_pre_rename_refs(adopter_dir, canonical_substrate_dir)
14
+ #
15
+ # Override: SKIP_FIXTURE_BUILDER=1 — every public function exits 0 silently
16
+ # (fixture_init echoes empty path).
17
+ # Logged via trace-helper per bassclef hook idiom.
18
+ #
19
+ # Per .claude/rules/defensive-bash.md — strict mode, quoted vars, local-safe,
20
+ # trap-safe (composes with caller's trap via fixture_cleanup_all).
21
+
22
+ set -u
23
+
24
+ # Sentinel filename written into every fixture root by fixture_init.
25
+ # fixture_cleanup refuses to remove a path that lacks this file — safe by default.
26
+ # Prefixed underscore is convention for "do not depend on this name from outside"
27
+ # but the symbol stays in scope so functions can reference it. The test for
28
+ # global-var pollution (T14) checks specifically for `FIXTURE_TMP_INTERNAL` which
29
+ # this lib never declares.
30
+ _FIXTURE_SENTINEL=".fixture-builder-marker"
31
+
32
+ # Track every fixture created in this shell so fixture_cleanup_all sweeps them.
33
+ # Bash 3.2 compatible — newline-separated list of paths in one string.
34
+ _FIXTURE_REGISTRY=""
35
+
36
+ # -----------------------------------------------------------------------------
37
+ # fixture_init <name> <tmproot>
38
+ # Create a fresh fixture dir under tmproot, write the sentinel, register the
39
+ # path, and echo it to stdout.
40
+ # Override SKIP_FIXTURE_BUILDER=1 — echo nothing, return 0.
41
+ # -----------------------------------------------------------------------------
42
+ fixture_init() {
43
+ if [ "${SKIP_FIXTURE_BUILDER:-0}" = "1" ]; then
44
+ return 0
45
+ fi
46
+ local name="${1:?fixture_init requires name}"
47
+ local tmproot="${2:?fixture_init requires tmproot}"
48
+ if [ ! -d "$tmproot" ]; then
49
+ echo "fixture_init: tmproot does not exist: $tmproot" >&2
50
+ return 1
51
+ fi
52
+ local d
53
+ d=$(mktemp -d "$tmproot/${name}.XXXXXX")
54
+ touch "$d/$_FIXTURE_SENTINEL"
55
+ _FIXTURE_REGISTRY="${_FIXTURE_REGISTRY}${d}
56
+ "
57
+ echo "$d"
58
+ }
59
+
60
+ # -----------------------------------------------------------------------------
61
+ # fixture_cleanup <path>
62
+ # Remove the fixture dir. Refuses unless the sentinel file is present at the
63
+ # path — prevents accidental rm of system dirs even when caller passes
64
+ # an unexpected argument.
65
+ # Idempotent — missing dirs return 0 silently.
66
+ # -----------------------------------------------------------------------------
67
+ fixture_cleanup() {
68
+ if [ "${SKIP_FIXTURE_BUILDER:-0}" = "1" ]; then
69
+ return 0
70
+ fi
71
+ local path="${1:?fixture_cleanup requires path}"
72
+ if [ ! -e "$path" ]; then
73
+ # Idempotent — nothing to do
74
+ return 0
75
+ fi
76
+ if [ ! -f "$path/$_FIXTURE_SENTINEL" ]; then
77
+ echo "fixture_cleanup: refusing to remove path without sentinel: $path" >&2
78
+ return 1
79
+ fi
80
+ rm -rf "$path"
81
+ return 0
82
+ }
83
+
84
+ # -----------------------------------------------------------------------------
85
+ # fixture_cleanup_all
86
+ # Sweep every fixture this shell created. Caller wires this into their trap:
87
+ # trap fixture_cleanup_all EXIT
88
+ # -----------------------------------------------------------------------------
89
+ fixture_cleanup_all() {
90
+ if [ "${SKIP_FIXTURE_BUILDER:-0}" = "1" ]; then
91
+ return 0
92
+ fi
93
+ local IFS=$'\n'
94
+ local path
95
+ for path in $_FIXTURE_REGISTRY; do
96
+ [ -n "$path" ] || continue
97
+ fixture_cleanup "$path" 2>/dev/null || true
98
+ done
99
+ _FIXTURE_REGISTRY=""
100
+ }
101
+
102
+ # -----------------------------------------------------------------------------
103
+ # fixture_setup_substrate_sibling <fixture_dir> <substrate_name>
104
+ # Create the .claude tree under <fixture_dir>/<substrate_name>/, stocked with
105
+ # stub hook files that adopter symlinks point into. Used by every fixture
106
+ # that needs a sibling-substrate layout.
107
+ # -----------------------------------------------------------------------------
108
+ fixture_setup_substrate_sibling() {
109
+ if [ "${SKIP_FIXTURE_BUILDER:-0}" = "1" ]; then
110
+ return 0
111
+ fi
112
+ local fixture_dir="${1:?fixture_setup_substrate_sibling requires fixture_dir}"
113
+ local substrate_name="${2:?fixture_setup_substrate_sibling requires substrate_name}"
114
+ local substrate="$fixture_dir/$substrate_name"
115
+ mkdir -p "$substrate/.claude/hooks"
116
+ mkdir -p "$substrate/.claude/skills"
117
+ mkdir -p "$substrate/.claude/rules"
118
+ mkdir -p "$substrate/.claude/agents"
119
+ mkdir -p "$substrate/scripts"
120
+ # Stock the substrate with the hook files the existing tests reference
121
+ local hook
122
+ for hook in pre-commit-gate.sh type-check.sh artifact-ingestion-gate.sh bassclef-sync.sh; do
123
+ cat > "$substrate/.claude/hooks/$hook" <<EOF
124
+ #!/bin/bash
125
+ # Stub hook for fixture testing — emits no-op exit 0
126
+ exit 0
127
+ EOF
128
+ chmod +x "$substrate/.claude/hooks/$hook"
129
+ done
130
+ # Stock a representative script the migrate workflow references
131
+ cat > "$substrate/scripts/migrate-adopter-references.sh" <<'EOF'
132
+ #!/bin/bash
133
+ # Stub for fixture testing — emits no-op exit 0
134
+ exit 0
135
+ EOF
136
+ chmod +x "$substrate/scripts/migrate-adopter-references.sh"
137
+ }
138
+
139
+ # -----------------------------------------------------------------------------
140
+ # fixture_inject_pre_rename_refs <adopter_dir> <canonical_substrate_dir>
141
+ # Drop canonical-* references into an adopter setup — symlinks under
142
+ # .claude/hooks/ pointing at the sibling canonical substrate, plus a
143
+ # settings.json that references canonical paths. Simulates an adopter who
144
+ # synced BEFORE the canonical → bassclef rename.
145
+ #
146
+ # No-op if adopter_dir does not exist (returns 0).
147
+ # -----------------------------------------------------------------------------
148
+ fixture_inject_pre_rename_refs() {
149
+ if [ "${SKIP_FIXTURE_BUILDER:-0}" = "1" ]; then
150
+ return 0
151
+ fi
152
+ local adopter_dir="${1:?fixture_inject_pre_rename_refs requires adopter_dir}"
153
+ local canonical_dir="${2:?fixture_inject_pre_rename_refs requires canonical_dir}"
154
+ if [ ! -d "$adopter_dir" ]; then
155
+ # Caller will see no side effects — adopter dir absent, nothing to do
156
+ return 0
157
+ fi
158
+ mkdir -p "$adopter_dir/.claude/hooks"
159
+ # Create canonical-targeted symlinks for each hook in the sibling
160
+ local hook
161
+ for hook in pre-commit-gate.sh type-check.sh artifact-ingestion-gate.sh bassclef-sync.sh; do
162
+ # Symlink relative path so the fixture is portable; target uses "canonical"
163
+ # literal name so the fixture exposes pre-rename state.
164
+ ln -sf "../../canonical/.claude/hooks/$hook" "$adopter_dir/.claude/hooks/$hook" 2>/dev/null || true
165
+ done
166
+ # Drop a settings.json that references canonical hook paths (matches how an
167
+ # adopter who synced pre-rename would have wired things).
168
+ cat > "$adopter_dir/.claude/settings.json" <<'EOF'
169
+ {
170
+ "hooks": {
171
+ "PreToolUse": [
172
+ {
173
+ "matcher": "Edit|Write|MultiEdit",
174
+ "hooks": [
175
+ { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/pre-commit-gate.sh" }
176
+ ]
177
+ }
178
+ ],
179
+ "SessionStart": [
180
+ {
181
+ "hooks": [
182
+ { "type": "command", "command": "bash ../canonical/.claude/hooks/bassclef-sync.sh" }
183
+ ]
184
+ }
185
+ ]
186
+ }
187
+ }
188
+ EOF
189
+ return 0
190
+ }