@thebassclef/lite 1.0.4 → 1.1.1

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 +298 -55
  2. package/dist/cli.js +298 -55
  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 +12 -5
@@ -0,0 +1,1640 @@
1
+ ---
2
+ tier: lite
3
+ name: onboard-repo
4
+ description: "Bootstrap the bassclef framework in a new repo. Installs the sync hook. Scaffolds config, whereami, and CLAUDE.md. Modes: default, --with-deploy-host, --with-secrets, --full, --greenfield-from-intent (cold-adopter magic demo)."
5
+ problem: "Setting up bassclef in a new repo takes an hour of trial. Missing directories and wrong hook wiring."
6
+ value: "One command bootstraps everything \u2014 sync hook and config file and whereami scaffold."
7
+ inputs: [Optional flags — --with-deploy-host or --with-secrets or --full]
8
+ outputs: [Installed bassclef-sync hook, Config scaffold, Whereami stub]
9
+ user_invocable: true
10
+ disable_model_invocation: false
11
+ requires:
12
+ cli: [git, gh]
13
+ network: true
14
+ modes: [default, --with-deploy-host, --with-secrets, --full, --greenfield-from-intent]
15
+ ---
16
+
17
+ # /onboard-repo — bassclef substrate adoption for a new repo
18
+
19
+ Brings a repo from "zero bassclef wiring" to "inherits full substrate
20
+ on desktop + mobile" in a single operator-gated session. Distinct from:
21
+
22
+ - `scripts/boot-bassclef.sh` — **machine-level** one-time setup (gh
23
+ auth, service account, launchd). Run once per machine.
24
+ - `/autonomous start` — **session-level** scaffolding (iteration goal,
25
+ phase state, risk register) for a repo that's ALREADY wired into
26
+ bassclef.
27
+
28
+ This skill sits between them: it's **repo-level** substrate adoption.
29
+ Run once per new consumer repo.
30
+
31
+ ## When to invoke
32
+
33
+ - Adding a new repo that will use bassclef
34
+ - Re-onboarding a repo that pre-dates the bassclef substrate
35
+ - Refreshing substrate wiring in an existing consumer (idempotent)
36
+
37
+ ## Which preset fits your setup?
38
+
39
+ Pick the shape that matches how you plan to work. The picker is the first fork. The procedure below runs the phases that match your pick.
40
+
41
+ | Preset | For | Runs |
42
+ |---|---|---|
43
+ | **share via GitHub** | A repo you push to GitHub and share | Path A — standard onboarding (Phases 1-3) |
44
+ | **browse first** | Scanning what /onboard-repo does before you commit | Path A read-only walk (dry-run mode) |
45
+ | **just me on this Mac** | A local-only project. No GitHub push. | Path B — empty-repo starter (`--greenfield-from-intent`) |
46
+
47
+ **Recommended:** `share via GitHub` when you have a GitHub org and repo ready. Otherwise `just me on this Mac`.
48
+
49
+ If the operator did not name a preset, ask first: `Share via GitHub / Browse first / Just me on this Mac? (g/b/j/skip)`
50
+
51
+ Path A and Path B stay as internal names for the procedure sections below. Adopter reads the picker at the top. The Path A/B and Phase X labels sit inside the procedure body as reference names.
52
+
53
+ ## Prerequisites (fail fast if missing)
54
+
55
+ Different prereqs apply to Path A (standard onboarding) vs Path B
56
+ (`--greenfield-from-intent` cold-adopter magic demo). Check the path
57
+ the operator picked before validating.
58
+
59
+ ### Path A — standard onboarding
60
+
61
+ - `gh` authenticated (`gh auth status`)
62
+ - `claude` resolvable in PATH (`command -v claude`) — required for the
63
+ acceptance test at the end. If missing from a Zellij/tmux subpane,
64
+ move `eval "$(/opt/homebrew/bin/brew shellenv)"` from `~/.zprofile`
65
+ to `~/.zshenv` so non-login shells pick up homebrew's PATH.
66
+ - Target repo exists on GitHub under your org
67
+ - Target repo has a default branch (`main` preferred)
68
+ - Bassclef is cloned as a peer at `$BASSCLEF_DIR` (default `~/src/<your-org>/bassclef`, for
69
+ desktop `additionalDirectories` resolution)
70
+ - You are currently `cd`'d into the target repo's working directory
71
+ - Claude Code session was started with `--add-dir ~/src/sunj-labs/bassclef`
72
+ so this skill file is accessible
73
+
74
+ ### Path B — `--greenfield-from-intent` (cold-adopter magic demo)
75
+
76
+ - `claude` resolvable in PATH
77
+ - `git` available
78
+ - `python3` available (for the localhost gallery server)
79
+ - `jq` available (JSON parsing for bassclef-sync + LLM-pick adapter)
80
+ - `curl` available (bassclef-sync fallback + LLM-pick API calls)
81
+ - No separate API key needed. The skill uses whichever LLM your Claude Code session provides. Per the tier reframe (bassclef-web#190 + #193), tier is about catalog size, not credentials.
82
+ - You are currently `cd`'d into an **empty target directory** (or one
83
+ with only files Path B is allowed to overwrite — see "Working
84
+ directory convention" below)
85
+ - `gh` is NOT required (no GitHub repo gets created)
86
+ - A peer bassclef checkout at `~/src/sunj-labs/bassclef` is preferred
87
+ but not required (the thin-pointer dispatcher falls back to the
88
+ GitHub tarball when the sibling is absent — Path B's `Phase B.3`
89
+ installs it)
90
+
91
+ ### When prereqs are missing — operator menu
92
+
93
+ If a prereq fails, surface it to the operator and present this menu
94
+ verbatim before stopping:
95
+
96
+ ```
97
+ Prerequisite missing for standard onboarding: <name of failed check>.
98
+
99
+ Pick one:
100
+
101
+ 1. Empty-repo starter demo — runs /launch --local, no GitHub repo
102
+ created, no vendor accounts needed. Switches this dispatch to
103
+ --greenfield-from-intent (Path B below). No separate API key
104
+ needed — uses the LLM your Claude Code session provides.
105
+ 2. Fix the prereq and re-run standard onboarding (Path A).
106
+ 3. Cancel.
107
+ ```
108
+
109
+ Operator picks `1` → continue under Path B. Picks `2` → stop and wait
110
+ for the operator to fix + re-dispatch. Picks `3` → stop.
111
+
112
+ Silence is not deferral. Wait for an explicit choice.
113
+
114
+ ## Working directory convention
115
+
116
+ | Path | Working directory |
117
+ |---|---|
118
+ | Path A — Phases 1–3 | **target repo** (existing GitHub repo) |
119
+ | Path A — Phase 4 | retired (see Phase 4 note below) |
120
+ | Path B — all phases | **target directory** (typically empty; never leaves it) |
121
+
122
+ For Path A the `pwd` check at the start of each phase exists for a
123
+ reason — don't lose track. Path B runs entirely inside one directory
124
+ and never reaches out to GitHub.
125
+
126
+ ## Procedure
127
+
128
+ The Procedure branches at the top into **Path A** (standard
129
+ onboarding) or **Path B** (`--greenfield-from-intent` cold-adopter
130
+ magic demo). Decide first, then walk only the phases under the chosen
131
+ path. Do not mix.
132
+
133
+ ### Choosing the path
134
+
135
+ | Signal | Path |
136
+ |---|---|
137
+ | Operator dispatched `/onboard-repo --greenfield-from-intent ...` | B |
138
+ | Operator picked option `1` from the prereqs-missing menu | B |
139
+ | All Path A prereqs pass + no `--greenfield-from-intent` flag | A |
140
+ | Operator dispatched `/onboard-repo --with-deploy-host` / `--with-secrets` / `--full` | A (with Phase 3.5 chained) |
141
+
142
+ When in doubt, ask the operator which path; don't infer.
143
+
144
+ ---
145
+
146
+ ### Path B — `--greenfield-from-intent` (cold-adopter magic demo)
147
+
148
+ **Working directory: empty.** Never leaves it. No GitHub repo. No vendor accounts touched. The path runs in ≤5 steps using the LLM your Claude Code session provides.
149
+
150
+ The task list the agent generates for Path B MUST be exactly these
151
+ five tasks, in this order. Do not add Phase 1 GitHub work, Phase 1.3
152
+ prod environment, Phase 3.5 follow-on prompts, or Phase 4 matrix PRs.
153
+ Those belong to Path A.
154
+
155
+ #### Phase B.1 — Confirm intent
156
+
157
+ Operator pastes a paragraph or voice transcript describing what they
158
+ want to build (the recipe-test example: "a wiki app for sharing
159
+ recipes with family"). Agent echoes the intent back and asks for
160
+ operator confirmation before continuing. No edits hit disk yet.
161
+
162
+ #### Phase B.2 — Init local git
163
+
164
+ ```bash
165
+ git init
166
+ git commit --allow-empty -m "chore: init repo"
167
+ ```
168
+
169
+ First empty commit so subsequent file writes have a baseline.
170
+
171
+ #### Phase B.3 — Scaffold the bassclef wiring
172
+
173
+ Subset of Path A Phase 2 — only the files `/launch --local` actually
174
+ reads. Skip everything that needs a remote.
175
+
176
+ ```bash
177
+ mkdir -p .claude/hooks docs
178
+
179
+ # Install the thin-pointer dispatcher (same source as Path A Phase 2.1).
180
+ # Sibling-fast-path preferred; the curl fallback works for cold adopters.
181
+ cp ~/src/sunj-labs/bassclef/presence/install/bassclef-sync.dispatcher.template.sh \
182
+ .claude/hooks/bassclef-sync.sh 2>/dev/null \
183
+ || curl -sL https://raw.githubusercontent.com/sunj-labs/bassclef/main/presence/install/bassclef-sync.dispatcher.template.sh \
184
+ -o .claude/hooks/bassclef-sync.sh
185
+ chmod +x .claude/hooks/bassclef-sync.sh
186
+
187
+ # Minimal settings.json — only the SessionStart hook
188
+ cat > .claude/settings.json <<'JSON'
189
+ {
190
+ "permissions": {
191
+ "additionalDirectories": ["../bassclef"]
192
+ },
193
+ "hooks": {
194
+ "SessionStart": [
195
+ {
196
+ "matcher": "",
197
+ "hooks": [
198
+ { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/bassclef-sync.sh", "timeout": 30 }
199
+ ]
200
+ }
201
+ ]
202
+ }
203
+ }
204
+ JSON
205
+
206
+ # Minimal substrate.config.md
207
+ cat > substrate.config.md <<'MD'
208
+ # substrate.config.md
209
+
210
+ hosting_platform: none
211
+ deploy_targets:
212
+ prod: false
213
+ budget:
214
+ session_ceiling: $0
215
+ iteration_ceiling: $0
216
+ MD
217
+
218
+ # Minimal .claude/bassclef-configs.jsonc — adopter-default seed (bassclef#1135 WU-4)
219
+ cat > .claude/bassclef-configs.jsonc <<'JSONC'
220
+ // bassclef-configs.jsonc — unified adopter configuration discovery surface.
221
+ // JSON Schema: standards/state-spine/schemas/bassclef-configs.schema.json
222
+ {
223
+ "sync": { "enabled": false },
224
+ "model_tier": {
225
+ "Builder": "balanced",
226
+ "Closer": "cheap-fast",
227
+ "Deployer": "cheap-fast",
228
+ "DocsWriter": "cheap-fast",
229
+ "Explorer": "cheap-fast",
230
+ "Orchestrator": "cheap-fast",
231
+ "Reviewer": "cheap-fast",
232
+ "Shaper": "capable"
233
+ },
234
+ "plan_tier": "tier-1",
235
+ "prose_discipline": { "kiss_words_turn_prose": true },
236
+ "testing": { "global_floor": 1, "path_matchers": [] }
237
+ }
238
+ JSONC
239
+
240
+ # Minimal CLAUDE.md — operator owns this going forward
241
+ cat > CLAUDE.md <<'MD'
242
+ # <repo-name>
243
+
244
+ ## What this repo is
245
+
246
+ Empty-repo starter demo from a stated intent. Substrate inherited from
247
+ bassclef via `--add-dir ../bassclef` or thin-pointer fetch.
248
+
249
+ ## Stack
250
+
251
+ To be determined by `/launch --local` output.
252
+ MD
253
+ ```
254
+
255
+ Skip in Path B:
256
+
257
+ - `gh repo create` (no remote)
258
+ - Phase 1.1 standard labels (no remote to apply them to)
259
+ - Phase 1.2 branch protection (same)
260
+ - Phase 1.3 prod environment (same)
261
+ - `.bassclef-source.json` (only needed for cloud/mobile sessions
262
+ where the sibling sync isn't available; cold adopters running
263
+ locally don't need it for the magic demo)
264
+ - Phase 3.5 interactive follow-on prompts (no `/provision-deploy-host`,
265
+ no `/secrets-bootstrap` — Path B has no vendor surfaces to bind)
266
+
267
+ #### Phase B.4 — Dispatch `/launch --local --voice-input`
268
+
269
+ Hand the intent paragraph straight to `/launch`:
270
+
271
+ ```
272
+ /launch medium --local --voice-input "<intent paragraph from Phase B.1>"
273
+ ```
274
+
275
+ Path B's last action is this dispatch. Do not chain `/build` or
276
+ `/launch-preview` afterward — those belong to the extended path for
277
+ operators with vendor bindings.
278
+
279
+ #### Phase B.5 — `/launch --local` runs
280
+
281
+ `/launch` writes the full artifact chain to disk (input-artifact, spec,
282
+ prototypes gallery, user stories, decomposition, migration plan) and
283
+ serves the gallery on `localhost:8000+`. The localhost URL is the
284
+ deliverable. Operator inspects, picks a direction, and either keeps
285
+ iterating locally or moves to standard onboarding (Path A) when they're
286
+ ready to push to a GitHub repo.
287
+
288
+ When `/launch --local` returns, Path B is done. Skip everything below
289
+ this divider.
290
+
291
+ ---
292
+
293
+ ### Path A — standard onboarding
294
+
295
+ Run each phase in order. Operator confirms before destructive or
296
+ cross-repo actions. Each phase is independently re-runnable.
297
+
298
+ #### Phase 0 — Refuse to run from main
299
+
300
+ Substrate changes go through PRs, same as feature work. If `/onboard-repo`
301
+ runs from `main`, every scaffold (`.claude/`, `CLAUDE.md`,
302
+ `docs/whereami.md`, `substrate.config.md`, `.bassclef-source.json`,
303
+ `.gitignore`) lands as a direct-to-main commit by surprise. Path A
304
+ refuses that shape and prints the remediation:
305
+
306
+ ```bash
307
+ CURRENT_BRANCH=$(git branch --show-current 2>/dev/null || echo "")
308
+
309
+ case "$CURRENT_BRANCH" in
310
+ main|master)
311
+ cat >&2 <<'EOF'
312
+
313
+ 🛑 /onboard-repo refuses to run from main.
314
+
315
+ Why: substrate scaffolding (`.claude/`, `CLAUDE.md`, `docs/whereami.md`,
316
+ `substrate.config.md`, `.bassclef-source.json`, `.gitignore`) is a
317
+ substrate change — it goes through a PR, not a direct commit to main.
318
+
319
+ Remediation:
320
+
321
+ git checkout -b chore/bassclef-bootstrap
322
+ # re-run /onboard-repo
323
+
324
+ When you reach the end of Phase 3, /onboard-repo will guide you to
325
+ open the bootstrap PR; merging it lands the substrate on main with
326
+ audit history (this is flywheel turn 1 from the first-use sequence —
327
+ see docs/first-use-sequence.md).
328
+
329
+ V1 (bassclef#956 follow-up) will auto-create the branch + PR. V0.5
330
+ keeps the operator in the loop on the branching decision.
331
+
332
+ EOF
333
+ exit 1
334
+ ;;
335
+ "")
336
+ cat >&2 <<'EOF'
337
+
338
+ 🛑 /onboard-repo cannot detect the current git branch.
339
+
340
+ The cwd may not be a git repository, OR git is in a detached-HEAD state.
341
+
342
+ Remediation:
343
+
344
+ git init # if not a git repo
345
+ git checkout -b chore/bassclef-bootstrap # from a fresh branch
346
+ # re-run /onboard-repo
347
+
348
+ EOF
349
+ exit 1
350
+ ;;
351
+ *)
352
+ # Any other branch — proceed
353
+ ;;
354
+ esac
355
+ ```
356
+
357
+ The remediation message is the contract. If a cold adopter dispatches
358
+ `/onboard-repo` from `main`, they see exactly what to do — no operator
359
+ coaching, no second-guess. V0.5 ships in bassclef#956; V1
360
+ (auto-create branch + PR) is post-launch hardening per the goal's
361
+ operator-decision items.
362
+
363
+ #### Phase 1 — Set up the GitHub repo (labels, branch protection)
364
+
365
+ **Working directory: target repo** (`pwd` should match `gh repo view --json name -q .name`).
366
+
367
+ Idempotent API calls against the target repo via `gh`.
368
+
369
+ ##### 1.1 Create the 11 standard labels
370
+
371
+ ```bash
372
+ # Read from git remote — don't infer from cwd basename (cwd can be renamed)
373
+ REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)
374
+
375
+ declare -A LABELS=(
376
+ [bassclef-evolution]="A6E0F2:Candidate for promotion to bassclef"
377
+ [agent-user-proposed]="D4A5F5:Proposed by agent in an app repo"
378
+ [bassclef-sync]="8FD4A4:Related to bassclef substrate syncing"
379
+ [review-required]="F5B94A:Blocks — human review required"
380
+ [bug]="E4443A:Defect"
381
+ [enhancement]="A2EEEF:New or improved functionality"
382
+ [security]="FF0000:Security-relevant"
383
+ [infra]="C9D1D9:Infrastructure / workflows / tooling"
384
+ [priority-high]="E4443A:High priority"
385
+ [priority-medium]="F5B94A:Medium priority"
386
+ [question]="D876E3:Needs operator input or design discussion"
387
+ )
388
+
389
+ for NAME in "${!LABELS[@]}"; do
390
+ COLOR="${LABELS[$NAME]%%:*}"
391
+ DESC="${LABELS[$NAME]#*:}"
392
+ gh label create "$NAME" --repo "$REPO" --color "$COLOR" --description "$DESC" --force >/dev/null
393
+ done
394
+ ```
395
+
396
+ Uses `--force` so the call is idempotent (updates existing label or
397
+ creates new). This matches the bootstrap logic shipped in bassclef
398
+ #160 (sync hook does the same for `bassclef-evolution` + `agent-user-proposed`);
399
+ this phase adds the broader set up-front so the operator can label issues
400
+ immediately without waiting for a sync cycle.
401
+
402
+ ##### 1.2 Protect main from force-push and deletion
403
+
404
+ ```bash
405
+ DEFAULT_BRANCH=$(gh repo view "$REPO" --json defaultBranchRef -q '.defaultBranchRef.name')
406
+
407
+ gh api "repos/$REPO/branches/$DEFAULT_BRANCH/protection" \
408
+ --method PUT \
409
+ --input - <<EOF
410
+ {
411
+ "required_status_checks": null,
412
+ "enforce_admins": false,
413
+ "required_pull_request_reviews": null,
414
+ "restrictions": null,
415
+ "allow_force_pushes": false,
416
+ "allow_deletions": false
417
+ }
418
+ EOF
419
+ ```
420
+
421
+ Minimum defense: no force-push or deletion of main. PR reviews NOT
422
+ required here — agent-created PRs (bassclef-sync) need to merge
423
+ without human intervention for the mobile-sync story. Add stricter
424
+ rules per-repo in `.github/branch-protection.yml` if the repo warrants.
425
+
426
+ ##### 1.3 Add the production approval gate (if this repo deploys to prod)
427
+
428
+ If the repo will deploy to production, per `manual-prod-approval.md`:
429
+
430
+ ```bash
431
+ # Prompt operator: "Does this repo deploy to prod? [y/N]"
432
+ # If yes:
433
+ USER_ID=$(gh api user --jq '.id')
434
+ gh api "repos/$REPO/environments/prod" --method PUT \
435
+ -f "wait_timer=0" \
436
+ -f "deployment_branch_policy[protected_branches]=false" \
437
+ -f "deployment_branch_policy[custom_branch_policies]=true"
438
+
439
+ gh api "repos/$REPO/environments/prod" --method PUT \
440
+ -F "reviewers[][type]=User" \
441
+ -F "reviewers[][id]=$USER_ID"
442
+ ```
443
+
444
+ Skip if repo is docs-only (like bassclef itself) or doesn't have a
445
+ production deploy target.
446
+
447
+ #### Phase 2 — Install bassclef wiring (settings, sync script, config)
448
+
449
+ **Working directory: target repo.** All file writes happen here.
450
+
451
+ ##### 2.1 Install the auto-update script (off by default per bassclef#939)
452
+
453
+ ```bash
454
+ mkdir -p .claude/hooks
455
+
456
+ # Install thin-pointer dispatcher from bassclef's own template directory.
457
+ # This is the source-of-truth file consumers vendor.
458
+ cp ~/src/sunj-labs/bassclef/presence/install/bassclef-sync.dispatcher.template.sh \
459
+ .claude/hooks/bassclef-sync.sh
460
+
461
+ # OR — if bassclef isn't checked out alongside this repo, fetch from
462
+ # bassclef's main branch on GitHub (public tarball release works too
463
+ # once bassclef itself goes public):
464
+ # curl -sL https://raw.githubusercontent.com/sunj-labs/bassclef/main/presence/install/bassclef-sync.dispatcher.template.sh \
465
+ # -o .claude/hooks/bassclef-sync.sh
466
+
467
+ chmod +x .claude/hooks/bassclef-sync.sh
468
+
469
+ # Verify the version header reads `thin-pointer-2026-05-15` or later:
470
+ head -2 .claude/hooks/bassclef-sync.sh
471
+ ```
472
+
473
+ The thin-pointer dispatcher does NOT vendor bassclef's sync logic.
474
+ It reads `.bassclef-source.json` (Phase 2.4) for the upstream tarball
475
+ URL + auth, fetches it, and execs the included template — always-current.
476
+ Eliminates two prior patching layers: hook content drift (vendored
477
+ template diverging from bassclef's) and URL refresh ceremony.
478
+
479
+ When the dispatcher can't load the substrate (sibling missing AND curl
480
+ fallback unconfigured / unauthenticated), it prints a plain-language
481
+ explanation with three resolution paths (public adopter, local dev,
482
+ private fork). External adopters get actionable guidance instead of
483
+ internal-vocabulary errors. Closes the adoption-friendliness gap noted
484
+ in bassclef#715.
485
+
486
+ ##### 2.2 Configure Claude Code for this repo
487
+
488
+ Standard bassclef settings — SessionStart → `bassclef-sync.sh`, +
489
+ other hooks per-agent configuration. Copy from a reference consumer
490
+ (POA or ops) and scrub for repo-specific paths:
491
+
492
+ ```bash
493
+ cat > .claude/settings.json <<'JSON'
494
+ {
495
+ "permissions": {
496
+ "additionalDirectories": ["../bassclef"]
497
+ },
498
+ "hooks": {
499
+ "SessionStart": [
500
+ {
501
+ "matcher": "",
502
+ "hooks": [
503
+ { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/bassclef-sync.sh", "timeout": 30 }
504
+ ]
505
+ }
506
+ ]
507
+ }
508
+ }
509
+ JSON
510
+ ```
511
+
512
+ Operator confirms — may want to add app-specific hooks (pre-build-gate,
513
+ pre-commit-gate) if the repo has source code.
514
+
515
+ ##### 2.2.1 Wire all Phase 2.2 hooks (13 hooks in one pass)
516
+
517
+ Phase 2.2 wires 13 bassclef hooks that gate adopter writes, commits, sessions, and role transitions. Read the whole table first. Then apply the canonical jq recipe. Then run the 3 verify blocks.
518
+
519
+ **Lite adopter note** (bassclef#740 Task 1.2). 6 hooks ship at `tier: standard` and skip on lite. Resolve tier via `lib/tier-check.sh`. The table marks each standard-tier hook with `std`. The bassclef-lite tarball does not carry those 6.
520
+
521
+ **Symlink all hooks in one pass:**
522
+
523
+ ```bash
524
+ mkdir -p .claude/hooks
525
+ cd .claude/hooks
526
+ for h in turn-prose-kiss-check substrate-clarity-gate artifact-ingestion-gate \
527
+ pattern-annotation-validate pre-commit-gate state-validate \
528
+ destructive-command-guard multi-tenancy-check atomic-pr-check \
529
+ post-write-trace testing-tier-enforce role-entry-gate temperance-gate; do
530
+ ln -sf "../../../bassclef/.claude/hooks/${h}.sh" "${h}.sh"
531
+ done
532
+ # Two allowlist files paired with hooks that read them:
533
+ ln -sf "../../../bassclef/.claude/hooks/substrate-clarity-allowlist.txt" substrate-clarity-allowlist.txt
534
+ ln -sf "../../../bassclef/.claude/hooks/testing-tier-enforce-allowlist.txt" testing-tier-enforce-allowlist.txt
535
+ cd -
536
+ ```
537
+
538
+ **Hook table:**
539
+
540
+ | # | Hook | Event | Matcher | Tier | Notes |
541
+ |---|---|---|---|---|---|
542
+ | 1 | turn-prose-kiss-check | Stop | (empty) | lite | Reads `prose_discipline.kiss_words_turn_prose` toggle from bassclef-configs; short-circuits when false; timeout 10s |
543
+ | 2 | substrate-clarity-gate | PreToolUse | Edit\|Write | lite | Reads bassclef baseline allowlist + optional adopter-side `substrate-clarity-allowlist-adopter.txt` |
544
+ | 3 | artifact-ingestion-gate | PreToolUse | Write | lite | Reads `artifact_ingestion.paths` from bassclef-configs; 13 default paths seeded by Phase 2.3.5 |
545
+ | 4 | pattern-annotation-validate | PreToolUse | Edit\|Write\|MultiEdit | std | Reads `tech_stack.lang` for language scoping (Phase 2.3.6) |
546
+ | 5 | pre-commit-gate | PreToolUse | Edit\|Write\|MultiEdit | lite | Runs first; composes testing-tier-enforce internally as one of its check steps |
547
+ | 6 | state-validate | PreToolUse | Edit\|Write\|MultiEdit | lite | Runs after pre-commit-gate; heavier ajv-cli schema check |
548
+ | 7 | destructive-command-guard | PreToolUse | Bash | std | Catches destructive verbs + force flags + amplifiers (rm -rf, FLUSHALL, prisma migrate reset) |
549
+ | 8 | multi-tenancy-check | PreToolUse | Edit\|Write\|MultiEdit | std | Template — customize via `TENANT_MODELS` / `TENANT_CONTEXT_FN` / `TENANT_PARAMS_FN` env vars |
550
+ | 9 | atomic-pr-check | PreToolUse | Bash | std | Fires on `git push` patterns; BLOCKs multi-step branches lacking `bundle: true` in goal frontmatter |
551
+ | 10 | post-write-trace | PostToolUse | Write\|Edit | std | Append-only trace; no override (never blocks) |
552
+ | 11 | testing-tier-enforce | (composed) | (via pre-commit-gate) | lite | Fires inside pre-commit-gate; no separate matcher entry; 60-day allowlist grace |
553
+ | 12 | role-entry-gate | PreToolUse | Edit\|Write\|MultiEdit | std | MVP: source-code file extensions only; reads `state/markers/role/<role>/<session>.marker` |
554
+ | 13 | temperance-gate | PreToolUse | Edit\|Write\|MultiEdit | lite | Fires on high-impact edits (.claude/, standards/, lib/state.sh, SKILL.md) when temperance marker missing |
555
+
556
+ **Order matters within each matcher block.** Place `pre-commit-gate` before `state-validate` (cheap SDLC checks fire first; heavier schema check runs second). Place `role-entry-gate` and `temperance-gate` LAST — methodology gates fire after structural + format + state checks pass.
557
+
558
+ **Canonical jq recipe — write settings.json in one pass.** The recipe uses JSON literal syntax so the `"matcher": "..."` and `"command": "..."` keys land verbatim in `.claude/settings.json` for grep-verifiability:
559
+
560
+ ```bash
561
+ # Assumes .claude/settings.json exists from Phase 2.2 (bare SessionStart entry).
562
+ # Reads adopter tier and skips standard-tier hooks on lite.
563
+ TIER=$(bash ../bassclef/lib/tier-check.sh 2>/dev/null || echo lite)
564
+
565
+ # Lite tier — 7 hooks land in .claude/settings.json (rows 1,2,3,5,6,11,13).
566
+ # Standard/ultra tier — all 13 hooks land in .claude/settings.json.
567
+ jq --arg tier "$TIER" '
568
+ .hooks.Stop = ((.hooks.Stop // []) + [
569
+ { "matcher": "", "hooks": [
570
+ { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/turn-prose-kiss-check.sh", "timeout": 10 }
571
+ ]}
572
+ ]) |
573
+ .hooks.PreToolUse = ((.hooks.PreToolUse // []) + [
574
+ { "matcher": "Edit|Write|MultiEdit", "hooks": (
575
+ [
576
+ { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/substrate-clarity-gate.sh" },
577
+ { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/pre-commit-gate.sh" },
578
+ { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/state-validate.sh" },
579
+ { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/temperance-gate.sh" }
580
+ ] +
581
+ (if $tier != "lite" then [
582
+ { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/pattern-annotation-validate.sh" },
583
+ { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/multi-tenancy-check.sh" },
584
+ { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/role-entry-gate.sh" }
585
+ ] else [] end)
586
+ )},
587
+ { "matcher": "Write", "hooks": [
588
+ { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/artifact-ingestion-gate.sh" }
589
+ ]}
590
+ ] + (if $tier != "lite" then [
591
+ { "matcher": "Bash", "hooks": [
592
+ { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/destructive-command-guard.sh" },
593
+ { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/atomic-pr-check.sh" }
594
+ ]}
595
+ ] else [] end)) |
596
+ (if $tier != "lite" then
597
+ .hooks.PostToolUse = ((.hooks.PostToolUse // []) + [
598
+ { "matcher": "Write|Edit", "hooks": [
599
+ { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/post-write-trace.sh" }
600
+ ]}
601
+ ])
602
+ else . end)
603
+ ' .claude/settings.json > .claude/settings.json.tmp \
604
+ && mv .claude/settings.json.tmp .claude/settings.json
605
+ ```
606
+
607
+ **Alternate matcher notes.** The `"matcher": "Edit|Write"` shape (without MultiEdit) appears in older adopter settings.json — the widening to `"matcher": "Edit|Write|MultiEdit"` in this recipe covers MultiEdit for hooks that need it.
608
+
609
+ **On re-run against existing settings.json** — jq's `+=` appends. Duplicate matcher entries are safe (Claude Code processes all in order), but the cleaner shape merges hooks under one matcher. To dedupe a re-run, strip existing entries with `jq 'del(...)'` before appending.
610
+
611
+ **Verify block 1 — Stop event:**
612
+
613
+ ```bash
614
+ python3 -c "import json; d=json.load(open('.claude/settings.json')); \
615
+ hooks=[h.get('command','') for entry in d.get('hooks',{}).get('Stop',[]) for h in entry.get('hooks',[])]; \
616
+ print('turn-prose-kiss-check wired' if any('turn-prose-kiss-check' in c for c in hooks) else 'NOT wired')"
617
+ ```
618
+
619
+ **Verify block 2 — PreToolUse event (all matchers):**
620
+
621
+ ```bash
622
+ python3 -c "import json; d=json.load(open('.claude/settings.json')); \
623
+ cmds=[h.get('command','') for entry in d.get('hooks',{}).get('PreToolUse',[]) for h in entry.get('hooks',[])]; \
624
+ hooks=['substrate-clarity-gate','artifact-ingestion-gate','pre-commit-gate','state-validate','temperance-gate','pattern-annotation-validate','destructive-command-guard','multi-tenancy-check','atomic-pr-check','role-entry-gate']; \
625
+ [print(f'{h}: {\"wired\" if any(h in c for c in cmds) else \"NOT wired\"}') for h in hooks]"
626
+ ```
627
+
628
+ **Verify block 3 — PostToolUse event:**
629
+
630
+ ```bash
631
+ python3 -c "import json; d=json.load(open('.claude/settings.json')); \
632
+ cmds=[h.get('command','') for entry in d.get('hooks',{}).get('PostToolUse',[]) for h in entry.get('hooks',[])]; \
633
+ print('post-write-trace wired' if any('post-write-trace' in c for c in cmds) else 'NOT wired')"
634
+ ```
635
+
636
+ **Rule propagation** — 8 rules load into the adopter session on their own via the `additionalDirectories: ["../bassclef"]` entry Phase 2.2 wrote. No per-rule symlink needed. Rules: `sdlc-gates.md`, `state-schema-validation.md`, `testing-tier-config.md`, `test-list-discipline.md`, `test-sufficiency.md`, `destructive-operations.md`, `pattern-annotation.md`, `pr-strategy.md`. Verify with:
637
+
638
+ ```bash
639
+ for r in sdlc-gates state-schema-validation testing-tier-config test-list-discipline \
640
+ test-sufficiency destructive-operations pattern-annotation pr-strategy; do
641
+ test -f ../bassclef/.claude/rules/${r}.md && echo "${r} reachable" || echo "${r} NOT reachable"
642
+ done
643
+ ```
644
+
645
+ **Composed hook: testing-tier-enforce** — Row 11 fires inside `.claude/hooks/pre-commit-gate.sh` as one of its check steps (no separate matcher entry in `.claude/settings.json`). The symlink at `.claude/hooks/testing-tier-enforce.sh` + the allowlist at `.claude/hooks/testing-tier-enforce-allowlist.txt` are enough; the enforcer runs whenever pre-commit-gate fires (PreToolUse Edit|Write|MultiEdit). Grace window: 60 days on the allowlist baseline. When an adopter edits a Tier 0 source file without touching its matching test file, pre-commit-gate calls `.claude/hooks/testing-tier-enforce.sh` and the commit BLOCKs with a structured stderr message.
646
+
647
+ Sanity check that the hook is reachable and composed into pre-commit-gate:
648
+
649
+ ```bash
650
+ ls -l .claude/hooks/testing-tier-enforce.sh .claude/hooks/testing-tier-enforce-allowlist.txt
651
+ grep -q "testing-tier-enforce.sh" .claude/hooks/pre-commit-gate.sh \
652
+ && echo "tier-enforce composed in pre-commit-gate" \
653
+ || echo "NOT composed (pre-commit-gate may be stale; re-run bassclef-sync)"
654
+ ```
655
+
656
+ **Override paths** — each hook honors a `SKIP_*` env var (logged via trace-helper per bassclef override idiom). Use only for one-shot migrations or emergency rescue:
657
+
658
+ | Hook | Override |
659
+ |---|---|
660
+ | turn-prose-kiss-check | (toggle via `prose_discipline.kiss_words_turn_prose: false` in bassclef-configs) |
661
+ | substrate-clarity-gate | `SKIP_SUBSTRATE_CLARITY=1` |
662
+ | artifact-ingestion-gate | `SKIP_ARTIFACT_INGESTION=1` |
663
+ | pattern-annotation-validate | `SKIP_PATTERN_ANNOTATION=1` |
664
+ | pre-commit-gate | `SKIP_PRE_COMMIT_GATE=1` |
665
+ | state-validate | `SKIP_STATE_VALIDATE=1` |
666
+ | destructive-command-guard | `SKIP_DESTRUCTIVE_GUARD=1` |
667
+ | multi-tenancy-check | `SKIP_MULTI_TENANCY_CHECK=1` |
668
+ | atomic-pr-check | `SKIP_ATOMIC_PR_CHECK=1` |
669
+ | post-write-trace | (none — append-only trace never blocks) |
670
+ | testing-tier-enforce | `SKIP_TESTING_TIER_ENFORCE=1` |
671
+ | role-entry-gate | `SKIP_ROLE_ENTRY=1` |
672
+ | temperance-gate | `SKIP_TEMPERANCE_GATE=1` |
673
+
674
+ **Not yet wired in bassclef** — `role-entry-gate` and `temperance-gate` ship to adopters first. Bassclef's own settings.json adds them in a follow-on after the marker convention runs in the wild for a few sessions and the multi-role + trigger-taxonomy follow-ons land.
675
+
676
+ Source: bassclef#1136 T3 (pre-commit-gate + state-validate), bassclef#1137 T4 (substrate-clarity-gate), bassclef#1138 T5 (turn-prose-kiss-check), bassclef#1139 T6 (pattern-annotation-validate), bassclef#1140 T7 (artifact-ingestion-gate), bassclef#1141 T8 (destructive-command-guard + multi-tenancy-check), bassclef#1142 T9 (atomic-pr-check + post-write-trace), bassclef#1143 T10 (testing-tier-enforce), bassclef#1144 T11 (test-discipline rule propagation), bassclef#1145 T13 (role-entry-gate), bassclef#1147 T15 (temperance-gate). Follow-ons deferred: `operator-private-path-check`, `type-check`, `post-skill-friction-check`, `role-entry` skill, multi-role matcher matrix, `standards/temperance-discipline.md`.
677
+
678
+ ##### 2.3 Create the project config file
679
+
680
+ Copy from `presence/install/substrate-config.md`, then prompt operator
681
+ for:
682
+
683
+ - `journal_doc_id` (optional — create Google Doc now or later)
684
+ - `changelog_doc_id` (optional)
685
+ - `deploy_targets` (local/staging/prod booleans)
686
+ - `budget.session_ceiling` / `iteration_ceiling` (sequential mode → `$0`)
687
+ - `hosting_platform` (REQUIRED for any consumer that ships a UI). Default
688
+ to `amplify` per ADR-008 + app-consumer precedent. Set `none` for
689
+ docs-only / no-UI repos. Enum:
690
+ `amplify | ec2-tailscale | vercel | netlify | cloudflare-pages | none`.
691
+ `/bind-subdomain` + `/launch-preview` refuse on `none` unless
692
+ `BIND_SUBDOMAIN_OVERRIDE=1` is set. Closes bassclef#449.
693
+
694
+ If operator says "defer", scaffold with placeholders and `TODO:` markers
695
+ so next session surfaces them.
696
+
697
+ ##### 2.3.5 Write the bassclef-configs adopter-default seed
698
+
699
+ Write `.claude/bassclef-configs.jsonc` with the adopter-default seed.
700
+ Every downstream hook + skill reads from this file; without it, defaults
701
+ are invisible to the adopter. Phase 2.5 (security_scanning) appends to
702
+ this file later in the same Procedure run, so the foundation MUST land
703
+ first.
704
+
705
+ ```bash
706
+ cat > .claude/bassclef-configs.jsonc <<'JSONC'
707
+ // bassclef-configs.jsonc — unified adopter configuration discovery surface
708
+ //
709
+ // Edit the values below. Each block has a comment explaining what it does,
710
+ // what the default is, and which bassclef substrate component reads it.
711
+ //
712
+ // JSON Schema: standards/state-spine/schemas/bassclef-configs.schema.json
713
+ // Full reference: standards/bassclef-configs-schema.md
714
+ {
715
+ // Whether bassclef's substrate syncs from upstream at SessionStart.
716
+ // Adopter default: false (opt-in trust posture). Turn on when you want
717
+ // bassclef to keep itself current automatically.
718
+ // Pairs with: .claude/hooks/bassclef-sync.sh
719
+ "sync": { "enabled": false },
720
+
721
+ // Per-agent LLM model routing. Most agents stay cheap-fast; Builder
722
+ // gets balanced for code quality; Shaper gets capable for problem framing.
723
+ // Pairs with: .claude/agents/<role>.md frontmatter
724
+ "model_tier": {
725
+ "Builder": "balanced",
726
+ "Closer": "cheap-fast",
727
+ "Deployer": "cheap-fast",
728
+ "DocsWriter": "cheap-fast",
729
+ "Explorer": "cheap-fast",
730
+ "Orchestrator": "cheap-fast",
731
+ "Reviewer": "cheap-fast",
732
+ "Shaper": "capable"
733
+ },
734
+
735
+ // Adopter plan tier. Caps parallel agent dispatch per Anthropic plan limits.
736
+ // tier-1 = single-agent serial (safest); tier-2 = 2-3 parallel after upgrade;
737
+ // tier-4 = 5+ parallel for operator-scale workflows.
738
+ // Pairs with: .claude/skills/longrun/SKILL.md parallel-dispatch logic
739
+ "plan_tier": "tier-1",
740
+
741
+ // Plain-English discipline for agent reply prose to operator. When true,
742
+ // the Stop hook scans the agent's last message for bassclef-internal
743
+ // jargon and surfaces findings to stderr (advisory). 'strict' makes the
744
+ // hook block the stop until prose is clean. false disables the scan.
745
+ //
746
+ // Optional: kiss_words_strict_places escalates specific places to strict
747
+ // even when the global toggle stays advisory. V1 places (bassclef#1171):
748
+ // - closeout_blocks — matches a "## Closeout audit" heading
749
+ // - summary_tables — matches a "## Status" heading
750
+ // - next_pickup — matches a "## Next pickup" heading
751
+ // Adopter default: advisory everywhere; no strict places. Flip to strict
752
+ // or add places when you want the rule to actually catch you.
753
+ //
754
+ // Pairs with: .claude/rules/plain-english-discipline.md
755
+ // .claude/hooks/turn-prose-kiss-check.sh
756
+ "prose_discipline": {
757
+ "kiss_words_turn_prose": true
758
+ // "kiss_words_strict_places": ["closeout_blocks"] // uncomment when ready
759
+ },
760
+
761
+ // Per-path testing-tier enforcement (4 tiers: 0 strict TDD / 1 test-with /
762
+ // 2 smoke / 3 manual verify). global_floor applies when no path_matcher matches.
763
+ // Adopter default: floor=1 (WARN on missing test); empty matchers (add your own).
764
+ // Pairs with: .claude/rules/testing-tier-config.md
765
+ "testing": {
766
+ "global_floor": 1,
767
+ "path_matchers": []
768
+ }
769
+
770
+ // Phase 2.5 below appends "security_scanning" here.
771
+ // /onboard-repo Phase 2.x or future tickets append "tech_stack", "hook_chain",
772
+ // "discipline_layers" as those vocabularies stabilize. Per bassclef#1135.
773
+ }
774
+ JSONC
775
+ ```
776
+
777
+ Validate the written file against the schema:
778
+
779
+ ```bash
780
+ perl -pe 's,^\s*//.*$,,; s,/\*.*?\*/,,g' .claude/bassclef-configs.jsonc \
781
+ | ajv validate -s ~/src/sunj-labs/bassclef/standards/state-spine/schemas/bassclef-configs.schema.json \
782
+ -d - --spec=draft2020 -c ajv-formats
783
+ ```
784
+
785
+ Expect a single `valid` line. The file is now the single source of truth for adopter configuration; subsequent Phase 2.x steps APPEND to it (Phase 2.3.6 tech_stack, Phase 2.5 security_scanning, future T-tickets for hook_chain etc.) rather than rewriting from empty.
786
+
787
+ If the adopter has a pre-existing `.claude/bassclef-configs.jsonc` from a prior SENTINEL_bassclef_version, prompt before overwriting; offer a `--merge` flow (operator-driven; not automated in V1).
788
+
789
+ ##### 2.3.6 Discover and write the tech_stack block
790
+
791
+ Stack-bound rules + standards in bassclef (`api-conventions.md`, `sdlc-gates.md`, `schema-management.md`, `new-dependency-check.md`, `frontend-stack.md`, `deployment-topology.md`) read `tech_stack:` from `.claude/bassclef-configs.jsonc` to route per-stack discipline. Without the block, non-matching adopters see false-fires (Prisma rules at SQLAlchemy adopters, Next.js API conventions at FastAPI adopters, etc.). This step writes the block so the bleed stops at install time.
792
+
793
+ Schema reference: `standards/state-spine/schemas/tech-stack.schema.json`. Standard: `standards/tech-stack-config.md`.
794
+
795
+ **Auto-detection signals** (per `standards/tech-stack-config.md` § Auto-detection at `/onboard-repo`):
796
+
797
+ | Build file present | Suggests |
798
+ |---|---|
799
+ | `package.json` with `"next"` dep | `frontend: nextjs`, `lang: typescript` (if `tsconfig.json` also present) |
800
+ | `package.json` with `"react"` dep (no `next`) | `frontend: react-vite` (if `vite.config.*` present) |
801
+ | `package.json` with `"prisma"` dep | `orm: prisma` |
802
+ | `package.json` with `"drizzle-orm"` dep | `orm: drizzle` |
803
+ | `package.json` + `pnpm-lock.yaml` | `pkg_manager: pnpm` |
804
+ | `package.json` + `yarn.lock` | `pkg_manager: yarn` |
805
+ | `package.json` + `package-lock.json` | `pkg_manager: npm` |
806
+ | `pyproject.toml` or `requirements.txt` | `lang: python` |
807
+ | `pyproject.toml` with `sqlalchemy` | `orm: sqlalchemy` |
808
+ | `pyproject.toml` with `alembic` | `orm: alembic` |
809
+ | `pyproject.toml` with `fastapi` | `frontend: fastapi`, `backend: python` |
810
+ | `pyproject.toml` with `django` | `frontend: django`, `backend: python` |
811
+ | `Gemfile` | `lang: ruby`, `pkg_manager: gem` |
812
+ | `Gemfile` with `rails` | `frontend: rails`, `backend: ruby` |
813
+ | `go.mod` | `lang: go`, `pkg_manager: go-mod`, `backend: go` |
814
+ | `Cargo.toml` | `lang: rust`, `pkg_manager: cargo`, `backend: rust` |
815
+ | `vercel.json` or `.vercelrc` | `deploy: vercel` |
816
+ | `fly.toml` | `deploy: fly` |
817
+ | `netlify.toml` | `deploy: netlify` |
818
+ | `render.yaml` | `deploy: render` |
819
+
820
+ No signal → field stays `none` and waits for operator override.
821
+
822
+ **Operator prompt** (surface this exact text):
823
+
824
+ ```
825
+ Detected stack signals:
826
+
827
+ lang: <detected or "(no signal)">
828
+ frontend: <detected or "(no signal)">
829
+ backend: <detected or "(no signal)">
830
+ orm: <detected or "(no signal)">
831
+ pkg_manager: <detected or "(no signal)">
832
+ deploy: <detected or "(no signal)">
833
+
834
+ Stack-bound rules route per-adopter from this block. Without it,
835
+ non-matching adopters see false-fires from rules written for the
836
+ default stack (TypeScript + Next.js + Prisma + EC2-Tailscale).
837
+
838
+ Three paths:
839
+
840
+ [a] Accept detected values
841
+ [b] Override per field (5-7 short prompts)
842
+ [c] Skip — write declared_via: deferred and revisit later
843
+ (rules fall back to operator defaults; expect some false-fires
844
+ until you set the block)
845
+
846
+ Pick a/b/c:
847
+ ```
848
+
849
+ **On accept (a):** write the block with detected values + `declared_via: onboard-repo` + `declared_at: <ISO date>`.
850
+
851
+ **On per-field override (b):** prompt each field in order with detected value as the default. Field-level enums per `standards/tech-stack-config.md` § Fields.
852
+
853
+ **On skip (c):** write `tech_stack: { declared_via: "deferred", declared_at: <ISO date> }` only. The schema admits all fields as optional; rules fall back gracefully. Operator can revisit by re-running `/onboard-repo` or editing the block directly.
854
+
855
+ **Append to `.claude/bassclef-configs.jsonc`** using `jq` or in-place edit; the block goes immediately before the closing brace + after `testing`:
856
+
857
+ ```bash
858
+ # Pseudo-procedure; actual implementation reads the operator's path choice
859
+ # and constructs the block from detected + override values.
860
+ cat >> .claude/bassclef-configs.jsonc <<TECH_STACK
861
+ ,
862
+
863
+ // Tech stack vocabulary. Stack-bound rules read this to route per-
864
+ // stack discipline (schema-management.md ORM routing, api-conventions
865
+ // frontend routing, sdlc-gates lang routing, etc.).
866
+ // Auto-detected at /onboard-repo Phase 2.3.6; operator confirms or
867
+ // overrides per field.
868
+ // Pairs with: standards/tech-stack-config.md (schema + semantics),
869
+ // standards/state-spine/schemas/tech-stack.schema.json
870
+ // Schema reference: bassclef#1127 tech_stack discovery
871
+ "tech_stack": {
872
+ "lang": "<value>",
873
+ "frontend": "<value>",
874
+ "backend": "<value>",
875
+ "orm": "<value>",
876
+ "pkg_manager": "<value>",
877
+ "deploy": "<value>",
878
+ "declared_at": "<ISO date>",
879
+ "declared_via": "onboard-repo"
880
+ }
881
+ TECH_STACK
882
+ ```
883
+
884
+ (In practice the writer holds the file open as JSON-with-comments, mutates the parsed object, re-emits with comments preserved per the comment-aware JSONC editor pattern; the heredoc above is illustrative.)
885
+
886
+ **Validate after append:**
887
+
888
+ ```bash
889
+ perl -pe 's,^\s*//.*$,,; s,/\*.*?\*/,,g' .claude/bassclef-configs.jsonc \
890
+ | ajv validate -s ~/src/sunj-labs/bassclef/standards/state-spine/schemas/bassclef-configs.schema.json \
891
+ -d - --spec=draft2020 -c ajv-formats
892
+ ```
893
+
894
+ Expect `valid`. If the file fails to validate, revert the append, surface the schema error, and re-prompt.
895
+
896
+ **Acceptance:**
897
+
898
+ - After Phase 2.3.6 completes, `.claude/bassclef-configs.jsonc` contains a `tech_stack:` block.
899
+ - Block validates against `tech-stack.schema.json`.
900
+ - `declared_via` is one of `onboard-repo` (path a or b) or `deferred` (path c); `migrated` and `demo-prompt` reserved for other callers.
901
+ - Operator can re-run `/onboard-repo` and the existing block is detected; prompt asks whether to keep, re-detect, or edit per-field.
902
+
903
+ **Composes with downstream Phase 2.x steps:**
904
+
905
+ - Phase 2.3.7 (testing-tier path_matchers seed) reads `tech_stack.lang` to pick the per-stack default tier matchers.
906
+ - Phase 2.5 (security scanning) reads `tech_stack.lang` to seed the scanner adapter.
907
+ - Future Phase 2.x for `hook_chain` reads stack signals to pick per-stack hook defaults.
908
+
909
+ ##### 2.3.7 Seed testing.path_matchers per declared tech_stack
910
+
911
+ Phase 2.3.5 wrote the `testing` block with `global_floor: 1` + empty `path_matchers`. Phase 2.3.6 just discovered + wrote `tech_stack`. This step reads `tech_stack.lang` and seeds `testing.path_matchers` with sensible per-stack defaults so the Tier 0 / Tier 1 enforcer (Phase 2.2.8) fires on the right paths from day one.
912
+
913
+ **Per-stack default seeds** (operator-eyes design choices):
914
+
915
+ For `tech_stack.lang: typescript` + `tech_stack.frontend: nextjs` (bassclef default):
916
+
917
+ ```jsonc
918
+ "testing": {
919
+ "global_floor": 1,
920
+ "path_matchers": [
921
+ { "match": "lib/domain/**/*.ts", "tier": 0 },
922
+ { "match": "lib/infra/**/*.ts", "tier": 0 },
923
+ { "match": "app/api/**/*.ts", "tier": 1 },
924
+ { "match": "app/actions/**/*.ts", "tier": 1 },
925
+ { "match": "app/_components/**/*.tsx", "tier": 2 },
926
+ { "match": "app/**/*.tsx", "tier": 2 },
927
+ { "match": "docs/**/*.md", "tier": 3 }
928
+ ]
929
+ }
930
+ ```
931
+
932
+ For `tech_stack.lang: python` + `tech_stack.frontend: fastapi`:
933
+
934
+ ```jsonc
935
+ "testing": {
936
+ "global_floor": 1,
937
+ "path_matchers": [
938
+ { "match": "domain/**/*.py", "tier": 0 },
939
+ { "match": "infrastructure/**/*.py", "tier": 0 },
940
+ { "match": "api/**/*.py", "tier": 1 },
941
+ { "match": "templates/**/*", "tier": 2 },
942
+ { "match": "docs/**/*.md", "tier": 3 }
943
+ ]
944
+ }
945
+ ```
946
+
947
+ Other stacks (ruby-rails, go-gin, java-spring) ship default seeds as per-stack siblings under `standards/testing-tier-seeds/<stack>.md` — deferred to a follow-on ticket when an adopter on that stack files for them. The pattern is the same: Tier 0 on the essential pure-domain layer; Tier 1 on the API + actions layer; Tier 2 on UI + template surfaces; Tier 3 on docs.
948
+
949
+ **On `tech_stack.lang: none` or `deferred`** — skip the seed; leave `path_matchers: []` empty. The `global_floor: 1` keeps the WARN posture; adopter can hand-edit later.
950
+
951
+ **Operator prompt** (surface this exact text after Phase 2.3.6 completes):
952
+
953
+ ```
954
+ Tech stack: <detected lang + frontend>
955
+
956
+ Seed testing.path_matchers with the per-stack default for <stack>?
957
+
958
+ [a] Yes, accept default seed (recommended)
959
+ [b] Show me the seed first
960
+ [c] Skip — keep path_matchers empty (manual seed later)
961
+
962
+ Pick a/b/c:
963
+ ```
964
+
965
+ **On accept (a)** — write the matching per-stack seed into `testing.path_matchers` in `bassclef-configs.jsonc`. Use the comment-aware JSONC editor pattern so the existing comments + `global_floor` survive.
966
+
967
+ **On show first (b)** — print the seed inline; ask for accept/edit/skip.
968
+
969
+ **On skip (c)** — leave empty; print "Adopter chose to skip — `testing.path_matchers` stays empty. Set with `/onboard-repo` re-run or hand-edit later."
970
+
971
+ **Validate after write:**
972
+
973
+ ```bash
974
+ perl -pe 's,^\s*//.*$,,; s,/\*.*?\*/,,g' .claude/bassclef-configs.jsonc \
975
+ | ajv validate -s ~/src/sunj-labs/bassclef/standards/state-spine/schemas/bassclef-configs.schema.json \
976
+ -d - --spec=draft2020 -c ajv-formats
977
+ ```
978
+
979
+ Expect a single `valid` line. The `testing.path_matchers` items must validate against the bassclef-configs schema.
980
+
981
+ **Stack siblings deferred** — only typescript-nextjs + python-fastapi ship in this step. Adopters on ruby-rails / go-gin / java-spring / rust-axum etc. get `global_floor: 1` + empty matchers (the safe default WARN posture) and can hand-seed per their layout. A follow-on ticket adds per-stack seed siblings under `standards/testing-tier-seeds/<stack>.md` as adopters request them.
982
+
983
+ Source: bassclef#1143 (this seed step — T10, iteration-2 BLOCKER). Sister rule: `.claude/rules/testing-tier-config.md`. Pairs with Phase 2.2.8 (the enforcer that reads this seed).
984
+
985
+ ##### 2.3.8 Surface the wiki_sync toggle
986
+
987
+ The `wiki_sync` block in `.claude/bassclef-configs.jsonc` controls whether the adopter's repo gets the bassclef-docs-sync workflow vendored from `presence/install/bassclef-docs-sync.template.yml`. This step surfaces the toggle so adopters see the option exists.
988
+
989
+ **Phase 1 (this step — bet 2026-06-20b) — minimal stub:**
990
+
991
+ Read the adopter's `wiki_sync.enabled` value from the bassclef-configs file just written. Print one of the following:
992
+
993
+ - **`enabled: false`** (default — universal): print
994
+ > Wiki-sync is OFF. The wiki-as-we-go discipline rule still loads at session-start, but no workflow fires. To enable later: edit `.claude/bassclef-configs.jsonc` `wiki_sync.enabled` to `true` and re-run `/onboard-repo` for the vendoring step (full vendoring lands in Phase 2 of bet 2026-06-20b — see `docs/iteration-bets/2026-06-20b-cold-adopter-mechanism-inheritance.md`).
995
+ - **`enabled: true`**: print
996
+ > Wiki-sync is ON. Full vendoring of `presence/install/bassclef-docs-sync.template.yml` → `.github/workflows/bassclef-docs-sync.yml` + `presence/install/docs-sync-allowlist.template.md` → `standards/docs-sync-allowlist.md` is **deferred to Phase 2 of bet 2026-06-20b**. For now, copy both templates manually if you need the wiki to update from main pushes today.
997
+
998
+ **Phase 2 (next session) — full vendoring (deferred):**
999
+
1000
+ - Auto-copy both templates into the adopter's repo
1001
+ - Open a follow-up PR for GHA secrets if `target_wiki_repo` requires non-default auth
1002
+ - Walk the adopter through the three workflow-edit surfaces (the `on.push.paths` glob, the Filter step's case-glob, the Sync step's source-path → wiki-page mapping)
1003
+ - Smoke-test by pushing a docs change and verifying the wiki updates
1004
+
1005
+ The Phase 1 stub keeps this step minimal so the goal stays bounded. Adopters who want wiki-sync today can copy the templates by hand from bassclef's `presence/install/` (workflows + cold-adopter assets).
1006
+
1007
+ **Composes with:**
1008
+
1009
+ - `.claude/skills/docs-sync/SKILL.md` § Adopter mode (read at runtime; surfaces BLOCK if templates not vendored)
1010
+ - `.claude/rules/session-artifacts.md` § Wiki-as-we-go discipline (methodology rule that triggers the closeout question)
1011
+
1012
+ Source: bassclef#1265 (this surfacing step — wiki-sync mechanism adopter inheritance). Sister bet: `docs/iteration-bets/2026-06-20b-cold-adopter-mechanism-inheritance.md` WU-2.
1013
+
1014
+ ##### 2.3.9 Write the onboard-repo state marker
1015
+
1016
+ Write `.claude/state/onboard-repo.state.json` after Phase 2.3 has
1017
+ populated the config file(s). The marker captures which mode was used,
1018
+ the ISO timestamp, and which files were written. The configs UI reads
1019
+ this marker to render the first-run overlay (per canvas 2026-07-08
1020
+ Appendix C). Future audits trace how a repo got wired.
1021
+
1022
+ Re-runs append a history entry — the marker keeps prior runs, not
1023
+ clobber them.
1024
+
1025
+ Invoke the helper script that ships alongside this SKILL:
1026
+
1027
+ ```bash
1028
+ # ONBOARD_MODE is set earlier in Procedure —
1029
+ # default / --with-deploy-host / --with-secrets / --full / --greenfield-from-intent
1030
+ bash .claude/skills/onboard-repo/write-state-marker.sh "${ONBOARD_MODE:-default}"
1031
+ ```
1032
+
1033
+ The script writes / updates `.claude/state/onboard-repo.state.json`
1034
+ with shape `{mode, timestamp_iso, paths_written[], history[], skill_version}`.
1035
+ Tier 0 tests at `.claude/skills/onboard-repo/tests/write-state-marker.test.sh`
1036
+ pin all behavior including re-run history append.
1037
+
1038
+ **Composes with:**
1039
+
1040
+ - Configs UI first-run overlay (`bassclef/configs/`, bet 2026-07-08a WU-7)
1041
+ - Future audits reading `.claude/state/onboard-repo.state.json`
1042
+
1043
+ Source: bassclef-upstream#664 (state marker for onboard-repo). Part of goal
1044
+ `docs/iteration-bets/2026-07-08a-configs-ui-iteration-1.md` WU-4.
1045
+
1046
+ ##### 2.3.10 Wire the cron installer for auto-save
1047
+
1048
+ Goal 27b (PR #937) shipped `presence/install/schedule-auto-save.cron.sh` at
1049
+ `tier: lite`. The installer writes a cron entry that fires
1050
+ `save-state.sh --auto --quiet` on idle. Sam's magic demo per canvas
1051
+ `docs/canvases/2026-07-19-bassclef-lite.md` L67-71 promises session-state
1052
+ continuity as part of onboarding. This step wires the installer in.
1053
+
1054
+ Behavior per OS:
1055
+
1056
+ - **macOS + Linux + WSL** — run the installer directly. It appends one
1057
+ crontab entry and is idempotent (re-running is safe per PR #937 Test 4).
1058
+ - **Native Windows (no WSL)** — cron is not available. Point the adopter at
1059
+ `presence/install/schedule-auto-save.taskscheduler.md` for the manual
1060
+ Task Scheduler setup.
1061
+
1062
+ ```bash
1063
+ OS_KIND="$(uname -s)"
1064
+ case "$OS_KIND" in
1065
+ Darwin|Linux)
1066
+ if [ -x "$BASSCLEF_DIR/presence/install/schedule-auto-save.cron.sh" ]; then
1067
+ bash "$BASSCLEF_DIR/presence/install/schedule-auto-save.cron.sh" \
1068
+ || echo "WARNING: cron installer failed; run manually to enable auto-save" >&2
1069
+ else
1070
+ echo "WARNING: schedule-auto-save.cron.sh not found; skip auto-save wire" >&2
1071
+ fi
1072
+ ;;
1073
+ MINGW*|CYGWIN*|MSYS*)
1074
+ echo "Native Windows detected. Cron is not available."
1075
+ echo "See presence/install/schedule-auto-save.taskscheduler.md for the"
1076
+ echo "manual Task Scheduler setup that wires auto-save on Windows."
1077
+ ;;
1078
+ *)
1079
+ echo "Unknown OS '$OS_KIND'; skip auto-save wire"
1080
+ ;;
1081
+ esac
1082
+ ```
1083
+
1084
+ The installer prints its own progress. Failures do not stop onboarding —
1085
+ auto-save is a nice-to-have on first install, and adopters can re-run
1086
+ the installer any time via `bash $BASSCLEF_DIR/presence/install/schedule-auto-save.cron.sh`.
1087
+
1088
+ **Composes with:**
1089
+
1090
+ - `presence/install/schedule-auto-save.cron.sh` (PR #937 — the cron installer)
1091
+ - `presence/install/schedule-auto-save.taskscheduler.md` (PR #937 — Windows guide)
1092
+ - ADR-046 cross-OS scheduling (accepted; Option C picked)
1093
+
1094
+ Source: bassclef-upstream#941 (wire cron into onboard for Sam's magic demo).
1095
+
1096
+ ##### 2.4 Point at bassclef's source (URL + auth)
1097
+
1098
+ The thin-pointer dispatcher installed in 2.1 reads `.bassclef-source.json`
1099
+ for the upstream tarball URL + auth metadata when the curl fallback
1100
+ fires (Cloud Env / mobile / fresh sandboxes / CI). Schema codified at
1101
+ `standards/bassclef-source-config.md`; validation hook at
1102
+ `.claude/hooks/bassclef-source-config-validate.sh`.
1103
+
1104
+ Before writing the file, prompt the adopter explicitly:
1105
+
1106
+ ```
1107
+ Bassclef can auto-pull the latest skills, rules, and agents into this
1108
+ repo at every Claude Code session start. Keeps you current with bassclef's
1109
+ evolution; you never manually update.
1110
+
1111
+ Off by default. Turn on now? [y/N]
1112
+ ```
1113
+
1114
+ Persist the adopter's answer to the `auto_sync` field. Default is `false` when in doubt.
1115
+
1116
+ ```bash
1117
+ cat > .bassclef-source.json <<JSON
1118
+ {
1119
+ "source_url": "https://api.github.com/repos/sunj-labs/bassclef/tarball/main",
1120
+ "auth_method": "Bearer",
1121
+ "token_env": "BASSCLEF_TOKEN",
1122
+ "auto_sync": false,
1123
+ "comment": "Provider: GitHub repo tarball API. Auth: fine-grained PAT 'bassclef-substrate-read' (Contents:read on sunj-labs/bassclef), stored as BASSCLEF_TOKEN in the consumer's Cloud Code environment. Schema: standards/bassclef-source-config.md. auto_sync controls whether SessionStart fetches bassclef's latest substrate; off by default per bassclef#939."
1124
+ }
1125
+ JSON
1126
+ ```
1127
+
1128
+ **Operator action — out of band, one-time per consumer:**
1129
+
1130
+ 1. Create fine-grained GitHub PAT scoped to `sunj-labs/bassclef`
1131
+ - Permission: Contents: read
1132
+ - Expiry: 90 days
1133
+ - Name: `bassclef-read-{REPO_SHORT}-{YYYYMMDD}`
1134
+ 2. Paste into the consumer's Cloud Code environment as `BASSCLEF_TOKEN`.
1135
+ 3. Track the PAT lifecycle in operator's `substrate.secrets.md` per
1136
+ `standards/secrets-lifecycle.md`.
1137
+
1138
+ Provider alternatives (see `standards/bassclef-source-config.md` for
1139
+ GitHub public, GitHub private release, ADO Repos, GitLab examples).
1140
+
1141
+ After writing the file, run the hook once locally to validate via
1142
+ sibling fast-path (no PAT needed for desktop):
1143
+
1144
+ ```bash
1145
+ echo "{\"cwd\":\"$PWD\"}" | bash .claude/hooks/bassclef-sync.sh
1146
+ ```
1147
+
1148
+ Expect: `### BASSCLEF SUBSTRATE — SYNCED` banner; skills/rules/hooks/
1149
+ luminaries symlinked into `.claude/`; no errors surfaced.
1150
+
1151
+ ##### 2.5 Configure security scanning (per bassclef goal 2026-06-17a Phase Y)
1152
+
1153
+ Auto-detect the adopter's stack from build files, confirm with the operator, and write the `security_scanning` block to `.claude/bassclef-configs.jsonc`. Adopter copies the matching reference workflow next.
1154
+
1155
+ Auto-detection signals (per `standards/security-scanner-adapter.md` § Stack auto-detection):
1156
+
1157
+ ```bash
1158
+ # Detect stack by build-file signal.
1159
+ STACK_GUESS="custom"
1160
+ if [ -f "package.json" ]; then
1161
+ if grep -q '"typescript"\|"@types/' package.json; then
1162
+ STACK_GUESS="node-typescript"
1163
+ else
1164
+ STACK_GUESS="node-typescript" # TS opt-out can happen later
1165
+ fi
1166
+ elif [ -f "requirements.txt" ] || [ -f "pyproject.toml" ] || [ -f "setup.py" ]; then
1167
+ STACK_GUESS="python"
1168
+ elif [ -f "Gemfile" ] || ls *.gemspec >/dev/null 2>&1; then
1169
+ STACK_GUESS="ruby"
1170
+ elif [ -f "pom.xml" ] || [ -f "build.gradle" ] || ls **/*.java >/dev/null 2>&1; then
1171
+ STACK_GUESS="java"
1172
+ elif [ -f "go.mod" ] || ls **/*.go >/dev/null 2>&1; then
1173
+ STACK_GUESS="go"
1174
+ fi
1175
+ ```
1176
+
1177
+ Prompt the operator (sample):
1178
+
1179
+ ```
1180
+ Bassclef security scanner adapter detected stack: <STACK_GUESS>
1181
+
1182
+ Default scanners for this stack (per standards/security-scanner-adapter.md):
1183
+ - node-typescript: eslint-plugin-security + audit-ci + gitleaks
1184
+ - python: bandit + safety + gitleaks
1185
+ - ruby: brakeman + bundler-audit + gitleaks
1186
+ - java: spotbugs-security + dependency-check + gitleaks
1187
+ - go: gosec + govulncheck + gitleaks
1188
+ - custom: adopter-supplied list
1189
+
1190
+ Activate scanners with stack=<STACK_GUESS>? [Y/n/custom/skip]
1191
+ ```
1192
+
1193
+ Persist the answer to the bassclef-configs block. Phase 2.3.5 (bassclef#1135 WU-4) wrote the seed file; this step adds the `security_scanning` block to it via a Python merge to keep the JSONC valid.
1194
+
1195
+ ```bash
1196
+ # Add security_scanning block to .claude/bassclef-configs.jsonc (bassclef#1135).
1197
+ # Phase 2.3.5 already wrote the seed; we add a block via JSONC-aware Python merge.
1198
+ python3 - "$STACK_GUESS" <<'PY'
1199
+ import json, re, sys, pathlib
1200
+ path = pathlib.Path('.claude/bassclef-configs.jsonc')
1201
+ raw = path.read_text()
1202
+ # Strip line + block comments before parsing
1203
+ stripped = re.sub(r'/\*.*?\*/', '', re.sub(r'//.*$', '', raw, flags=re.M), flags=re.S)
1204
+ data = json.loads(stripped)
1205
+ stack = sys.argv[1]
1206
+ data['security_scanning'] = {
1207
+ 'stack': None if stack in ('null', 'skip', '') else stack,
1208
+ 'additional_scanners': [],
1209
+ 'block_on_high_severity': True,
1210
+ }
1211
+ path.write_text(json.dumps(data, indent=2) + '\n')
1212
+ PY
1213
+ ```
1214
+
1215
+ Note: the Python merge re-serializes the file without comments. Operators
1216
+ keep the schema-doc reference (`standards/bassclef-configs-schema.md`)
1217
+ as the bassclef comment-bearing source; the on-disk file is the values.
1218
+ A follow-on may add a comment-preserving JSONC writer.
1219
+
1220
+ INSTEAD of asking the operator to know the scanner names: the standard supplies the per-stack defaults; the operator confirms the stack choice only.
1221
+
1222
+ If the operator answers `skip`, write `"stack": null` — scanners stay off until the next session re-runs the question.
1223
+
1224
+ **Operator follow-up — copy the reference workflow:**
1225
+
1226
+ After the bassclef-configs block is written, point the operator at the matching reference workflow:
1227
+
1228
+ ```
1229
+ Next step: copy the per-stack reference workflow into your repo's CI.
1230
+
1231
+ cp ~/src/sunj-labs/bassclef/config/security-scanners/<STACK_GUESS>.yml \
1232
+ .github/workflows/security-scan.yml
1233
+
1234
+ The workflow auto-skips when the bassclef-configs stack value is null,
1235
+ so copying is harmless if you're not ready to activate yet.
1236
+ ```
1237
+
1238
+ For stacks beyond node-typescript + python (which ship reference workflows), the operator authors their own workflow guided by `standards/security-scanner-adapter.md` § Stack reference matrix.
1239
+
1240
+ ##### 2.6 Set up .gitignore for bassclef's runtime files
1241
+
1242
+ If `.gitignore` doesn't exist, create with bassclef runtime markers:
1243
+
1244
+ ```bash
1245
+ [ -f .gitignore ] || cat > .gitignore <<'EOF'
1246
+ # Bassclef runtime artifacts (per-machine, not content)
1247
+ .claude/LAST_SAVE
1248
+ .claude/SESSION_LOCK
1249
+ .claude/CHECKPOINT.md
1250
+ .claude/settings.local.json
1251
+ state/markers/verify/
1252
+ EOF
1253
+ ```
1254
+
1255
+ The sync hook will add its managed symlink block on next run; this
1256
+ seeds the file with everything else.
1257
+
1258
+ #### Phase 3 — Create starter docs (CLAUDE.md, whereami)
1259
+
1260
+ **Working directory: target repo.**
1261
+
1262
+ ##### 3.1 Create the starter CLAUDE.md
1263
+
1264
+ Minimal starter. Operator owns this file going forward.
1265
+
1266
+ The first non-title line reads `@.claude/bassclef-orientation.md` (per
1267
+ ADR-032 + Anthropic's `@filename` convention). This import loads bassclef's
1268
+ orientation into every session. The orientation names the gates, the
1269
+ luminaries, the tier ladder, and the rules the agent should not break.
1270
+
1271
+ The orientation file lands in the adopter repo as a symlink into bassclef.
1272
+ The sync template Section 3d-bis writes the symlink.
1273
+ Without this symlink, the import resolves only through `additionalDirectories`.
1274
+ If that path breaks — rename, delete, corporate laptop with no sibling — the
1275
+ import silently no-ops. The symlink closes that gap.
1276
+
1277
+ Bassclef updates the file via release. The adopter's CLAUDE.md stays
1278
+ adopter-owned outside the import line.
1279
+
1280
+ ```markdown
1281
+ # [repo-name]
1282
+
1283
+ @.claude/bassclef-orientation.md
1284
+
1285
+ ## What this repo is
1286
+
1287
+ [One-paragraph description]
1288
+
1289
+ ## Substrate
1290
+
1291
+ Inherits bassclef substrate via `--add-dir ../bassclef` (desktop) and
1292
+ S3 tarball sync (mobile). The `@.claude/bassclef-orientation.md` import
1293
+ above auto-loads the substrate discipline (gates, luminaries, tier ladder,
1294
+ what-NOT-to-do). For the upstream role declaration, see
1295
+ `~/src/sunj-labs/bassclef/CLAUDE.md`.
1296
+
1297
+ ## Stack
1298
+
1299
+ [Framework, language, key dependencies — or "documentation only"]
1300
+
1301
+ ## Current state
1302
+
1303
+ [Phase, active iteration, any context a fresh session needs]
1304
+ ```
1305
+
1306
+ ##### 3.2 Create the starter docs/whereami.md
1307
+
1308
+ ```bash
1309
+ mkdir -p docs
1310
+ cp ~/src/sunj-labs/bassclef/templates/whereami-template.md \
1311
+ docs/whereami.md
1312
+ ```
1313
+
1314
+ Operator fills in phase + iteration section. If repo is fresh,
1315
+ `phase: Inception` with `iteration_bet: none — new repo` is fine.
1316
+
1317
+ #### Phase 3.5 — Optional: provision the deploy host + bootstrap secrets
1318
+
1319
+ **Working directory: target repo.**
1320
+
1321
+ After Phase 3 (docs stubs) lands the substrate config files, three opt-in
1322
+ flags chain follow-on skills inline so every new sunj-labs repo bootstraps
1323
+ in one dispatch instead of four manual steps. Without these flags, the
1324
+ operator runs the follow-on skills separately afterward (older pattern,
1325
+ still supported).
1326
+
1327
+ ##### Flag reference
1328
+
1329
+ | Invocation | Behavior |
1330
+ |---|---|
1331
+ | `/onboard-repo` (no flag) | Phases 1–3 only. Interactive prompt at end: "Run /provision-deploy-host now? [Y/n/skip]" + same for /secrets-bootstrap. Skip-state persists per below. |
1332
+ | `/onboard-repo --with-deploy-host` | Phases 1–3, then dispatches `/provision-deploy-host` inline (operator-confirms before AWS calls). Skips the interactive prompt for deploy-host. |
1333
+ | `/onboard-repo --with-secrets` | Phases 1–3, then dispatches `/secrets-bootstrap` inline (audits + bootstraps env per substrate.secrets.md). Skips the interactive prompt for secrets. |
1334
+ | `/onboard-repo --full` | All of the above — substrate scaffolded + Amplify host provisioned + secrets audited in one dispatch. Recommended for new sunj-labs repos. |
1335
+ | `/onboard-repo --greenfield-from-intent "<intent>"` | Cold-adopter demo path. Skips Path A entirely and runs Path B — empty directory in, full artifact chain on disk plus localhost gallery URL out. No GitHub repo gets created. No vendor accounts needed. Uses the LLM your Claude Code session provides. For the extended path (deploy mocks to a configured subdomain plus chain to `/build` plus `/launch-preview`), finish Path A first to wire vendor bindings, then dispatch `/launch --voice-input` without `--local`. See `docs/iteration-bets/2026-05-12-phase-v-hey-alexa-mvd.md` and bassclef#923 / PR #924 for the local-mode building block. |
1336
+
1337
+ ##### Tier gate
1338
+
1339
+ Three of the flags above dispatch skills that ship at `tier: standard`.
1340
+ Lite adopters running the bassclef-lite tarball do not carry
1341
+ `/provision-deploy-host` or `/secrets-bootstrap`. Before dispatching
1342
+ `--with-deploy-host`, `--with-secrets`, or `--full`, resolve the
1343
+ adopter tier through `lib/tier-check.sh`:
1344
+
1345
+ ```bash
1346
+ source lib/tier-check.sh
1347
+ tier=$(resolve_adopter_tier)
1348
+ ```
1349
+
1350
+ The check reads `.claude/bassclef-configs.jsonc` `adopter.tier` field
1351
+ first. Falls back to skill probe — presence of `/provision-deploy-host`
1352
+ skill returns `standard`. Safe default is `standard`.
1353
+
1354
+ Behavior per tier:
1355
+
1356
+ | Invocation | tier=lite | tier=standard or pro |
1357
+ |---|---|---|
1358
+ | `/onboard-repo` (no flag) | Phases 1–3 run. Skip interactive prompts for /provision-deploy-host and /secrets-bootstrap. | Phases 1–3 + interactive prompts. |
1359
+ | `/onboard-repo --with-deploy-host` (lite adopter) | Print graceful upgrade message: "--with-deploy-host requires bassclef standard. Reason: /provision-deploy-host is a standard-tier skill. Upgrade path: install bassclef standard, or run Phases 1–3 without the flag and provision the deploy host manually later." Continue Phases 1–3 as if no flag was passed. | Phases 1–3 + `/provision-deploy-host` dispatched inline. |
1360
+ | `/onboard-repo --with-secrets` (lite adopter) | Print graceful upgrade message: "--with-secrets requires bassclef standard. Reason: /secrets-bootstrap is a standard-tier skill. Upgrade path: install bassclef standard, or run Phases 1–3 without the flag and manage secrets manually via substrate.secrets.md." Continue Phases 1–3. | Phases 1–3 + `/secrets-bootstrap` dispatched inline. |
1361
+ | `/onboard-repo --full` (lite adopter) | Print graceful upgrade message: "--full requires bassclef standard. Reason: /provision-deploy-host and /secrets-bootstrap are both standard-tier skills. Upgrade path: install bassclef standard." Continue Phases 1–3. | Phases 1–3 + both skills dispatched inline. |
1362
+ | `/onboard-repo --greenfield-from-intent` | Runs Path B via `/launch --local`. Lite-safe by design. | Same. |
1363
+
1364
+ Per canvas 2026-07-19-bassclef-lite Q6 Option E — one SKILL.md file,
1365
+ same name in both tiers, body carries runtime tier awareness with
1366
+ graceful degrade.
1367
+
1368
+ ##### Interactive prompt (when no flag)
1369
+
1370
+ After Phase 3 completes, agent surfaces follow-on prompts. Prompts are
1371
+ gated on artifact existence and the deploy-host prompt
1372
+ uses honest platform framing:
1373
+
1374
+ ```bash
1375
+ # Check for substrate.secrets.md (bassclef#961) — silently skip the
1376
+ # secrets prompt if the manifest doesn't exist. No point prompting an
1377
+ # adopter to bootstrap secrets when they haven't declared any.
1378
+ HAS_SECRETS_MANIFEST=0
1379
+ if [ -f substrate.secrets.md ]; then
1380
+ HAS_SECRETS_MANIFEST=1
1381
+ fi
1382
+ ```
1383
+
1384
+ Then surface (deploy-host always; secrets only when manifest present):
1385
+
1386
+ ```
1387
+ Substrate scaffolded. One or two follow-on steps remain before /launch
1388
+ runs cleanly end-to-end:
1389
+
1390
+ 1. /provision-deploy-host — provisions a preview deploy host. Tested
1391
+ today with AWS Amplify; other platforms (Vercel, Netlify, Cloudflare
1392
+ Pages, GCP, Azure) ship via adapter PRs. If you want a platform that
1393
+ doesn't ship yet, file a ticket — or build the adapter (it's a single
1394
+ shell script following `scripts/adapters/deploy/amplify.sh` as the
1395
+ reference). The provision takes ~1-2h, mostly waiting. Required
1396
+ before /launch can bind a subdomain on the chosen host. Skip if this
1397
+ repo opts out of preview deployment (hosting_platform: none) or if
1398
+ you want to provision later.
1399
+
1400
+ 2. /secrets-bootstrap — audits + bootstraps env credentials per
1401
+ substrate.secrets.md. Required before /launch, /deploy-prod, or
1402
+ /journal push. Skip if creds are already known-good.
1403
+
1404
+ Run /provision-deploy-host now? [Y/n/skip]
1405
+ Run /secrets-bootstrap now? [Y/n/skip]
1406
+ ```
1407
+
1408
+ When `HAS_SECRETS_MANIFEST=0` (no substrate.secrets.md on disk), the
1409
+ agent OMITS step 2 entirely + the second prompt — no "(likely no-op)"
1410
+ hedge, no prompt asking the adopter to bootstrap secrets they haven't
1411
+ declared. The numbered list collapses to "One follow-on step remains".
1412
+
1413
+ Each `Y` triggers the inline dispatch (operator-confirms any destructive
1414
+ substep — AWS calls, env writes). Each `n` defers to a later session.
1415
+ Each `skip` persists in `substrate.config.md` so re-running /onboard-repo
1416
+ on this repo doesn't re-prompt for that step.
1417
+
1418
+ The deploy-host prompt wording matters: cold adopters reading it should
1419
+ understand bassclef's posture on multi-platform support without
1420
+ operator coaching. "Tested with AWS Amplify; other platforms via
1421
+ adapter PRs" reads as honest (we have one tested path + a clear
1422
+ contribution route) instead of overpromising. Filing a ticket for an
1423
+ unsupported platform is invited, not gated.
1424
+
1425
+ ##### Skip-state persistence
1426
+
1427
+ When operator chooses `skip` (not `n`) for a follow-on step, the agent
1428
+ writes one of these fields to `substrate.config.md`:
1429
+
1430
+ ```yaml
1431
+ # === Onboarding follow-on skip state (bassclef#522) ===
1432
+ #
1433
+ # Set by /onboard-repo when the operator explicitly skips a follow-on
1434
+ # step. Re-runs of /onboard-repo do NOT re-prompt for skipped steps;
1435
+ # operator can dispatch the underlying skill directly when ready, or
1436
+ # unset the field to re-enable the prompt.
1437
+ onboarding_deploy_host_skipped: true # set when operator answers 'skip'
1438
+ onboarding_secrets_skipped: true # set when operator answers 'skip'
1439
+ ```
1440
+
1441
+ `n` (decline-this-time) does NOT persist — re-runs re-prompt because the
1442
+ operator didn't say skip-permanently.
1443
+
1444
+ `Y` sets the per-platform provisioning indicator (e.g., `amplify_app_id`) on success. Chain pre-flight Check 6 reads that indicator when /launch dispatches. Without it, /launch BLOCKs with three-path remediation. The two flags pair well. `--with-deploy-host` pre-empts the BLOCK. The default flow lets the BLOCK surface the missing setup.
1445
+
1446
+ ##### Composes with
1447
+
1448
+ | Skill | Role |
1449
+ |---|---|
1450
+ | `/provision-deploy-host` | Inline dispatch when `--with-deploy-host` or interactive `Y`. Populates `amplify_app_id` (or platform-equivalent indicator). |
1451
+ | `/secrets-bootstrap` | Inline dispatch when `--with-secrets` or interactive `Y`. Audits creds against `substrate.secrets.md`. |
1452
+ | `/bind-subdomain <subdomain>` | Separate dispatch — not chained from /onboard-repo (subdomain choice is repo-specific; no good default). Run after deploy host provisioned. |
1453
+ | `/launch` | First substantive dispatch after onboarding completes. Chain pre-flight Check 6 verifies the provisioning indicator before variant generation runs. |
1454
+
1455
+ #### Phase 3.6 — Closing handoff
1456
+
1457
+ After Phase 3 (and Phase 3.5 if any flag fired), Path A surfaces a
1458
+ closing handoff. Two templates — adopter-mode and operator-mode —
1459
+ mirror the same split documented at `.claude/skills/launch/SKILL.md`
1460
+ Phase 14b.
1461
+
1462
+ ##### Adopter-mode auto-chain (default when context signals cold-adopter)
1463
+
1464
+ Cold-adopter signals: `/onboard-repo` was invoked from a fresh
1465
+ directory (no prior chronicle / no whereami / no iteration-goal), OR
1466
+ the `--greenfield-from-intent "<paragraph>"` flag was used. In either
1467
+ shape, the agent has a paragraph in hand (either from the flag or
1468
+ asked at Phase 1 as part of the "what is this repo for?" prompt).
1469
+
1470
+ The adopter-mode handoff template re-uses that paragraph and offers
1471
+ the build:
1472
+
1473
+ ```
1474
+ Your repo is wired. Two things you can do next — pick one:
1475
+
1476
+ 1. Build something now. I'll take the paragraph you gave me earlier
1477
+ ("<INTENT_PARAGRAPH>") and run /launch --local. About 4 minutes
1478
+ later you'll have four clickable mock directions to pick from on
1479
+ your phone or laptop. After you pick a direction, I'll write the
1480
+ formal artifacts + the app code for that direction only (~15 min
1481
+ total). You'll have a working local version to play with.
1482
+
1483
+ 2. Stop here and come back later. I'll save your spot. When you come
1484
+ back, just open Claude Code in this repo and say "/launch --local"
1485
+ to pick up where we left off.
1486
+
1487
+ Build now? [Y/n]
1488
+ ```
1489
+
1490
+ `Y` triggers `/launch --local "<INTENT_PARAGRAPH>"` inline in the
1491
+ same session — no context switch, no second dispatch. `n` writes
1492
+ the paragraph to `docs/whereami.md` under "Pending intent" so the
1493
+ next session's `/sprint` surfaces it.
1494
+
1495
+ Substitute `<INTENT_PARAGRAPH>` with the actual paragraph (from
1496
+ `--greenfield-from-intent` flag value OR from the Phase 1 "what is
1497
+ this repo for?" prompt — operator confirms it's still accurate before
1498
+ the auto-chain fires).
1499
+
1500
+ The adopter-mode handoff **skips entirely**:
1501
+ - "Run /sprint to orient" — adopter has no work in flight to orient
1502
+ to
1503
+ - "Run /whereami" — same
1504
+ - Bare command names (`/launch`) without the plain-English explanation
1505
+ of what /launch produces
1506
+
1507
+ ##### Operator-mode handoff (non-cold-adopter context)
1508
+
1509
+ This mode fires when cold-adopter signals are absent. Signals absent means: the repo has prior chronicles, whereami is populated, OR the operator passed `--no-auto-chain`. The agent uses this wording:
1510
+
1511
+ ```
1512
+ Your bassclef is ready.
1513
+
1514
+ What landed this session:
1515
+ - Skills, rules, and hooks synced from bassclef
1516
+ - GitHub labels + branch protection set up
1517
+ - Session-start wiring wired
1518
+
1519
+ Best single next move — try /sprint in a fresh session. It reads
1520
+ your current state and proposes the next work.
1521
+
1522
+ Other useful next moves:
1523
+ - /whereami — current state in one glance
1524
+ - /launch <tier> "<paragraph>" — start a new feature; see /launch
1525
+ SKILL.md for sizes + flags
1526
+ - /launch --local "<paragraph>" — same as above but writes artifacts
1527
+ to disk + serves the gallery on localhost (no vendor accounts
1528
+ needed)
1529
+
1530
+ Run any of those in a fresh session.
1531
+ ```
1532
+
1533
+ Operator-mode keeps a hard break between onboard and build. Operators often onboard a repo as one task. They pick up build work later in a fresh session.
1534
+
1535
+ ##### Composes with
1536
+
1537
+ | Skill | How it composes |
1538
+ |---|---|
1539
+ | `/launch --local` | Adopter-mode auto-chain dispatch. Inline in same session. |
1540
+ | `/sprint` | Operator-mode orientation skill. Surfaces "Pending intent" if `n` was chosen for the build-now prompt. |
1541
+ | `/whereami` | Same. |
1542
+
1543
+ #### Phase 4 — Bassclef-side matrix PRs
1544
+
1545
+ **Phase 4 retired under bassclef goal 2026-05-03-consumer-bassclef-sync-rollout WU-7.**
1546
+
1547
+ Under thin-pointer architecture (Phase 2.1 + 2.4 above), the `bassclef-template-sync.yml` workflow is deleted (no more auto-PRs). The `bassclef-s3-publish.yml` URL-refresh matrix is unused by thin-pointer (no `.bassclef-url`); a follow-on issue tracks its retirement separately.
1548
+
1549
+ **No matrix-PR step is needed for new consumers.** The thin-pointer dispatcher reads from `.bassclef-source.json` directly; bassclef's matrix list is no longer the source of truth for which consumers receive substrate updates — every consumer fetches HEAD on every session-start.
1550
+
1551
+ Skip this phase entirely. Phase 5 (Verify) below validates that the consumer is correctly wired without any bassclef-side matrix change.
1552
+
1553
+ #### Historical note
1554
+
1555
+ Pre-2026-05-03, this phase added the new consumer to BOTH `bassclef-s3-publish.yml` and `bassclef-template-sync.yml` matrices. The 2026-04-18 lesson (#166 caught a one-of-two miss after #158) drove the bassclef-workflow-parity rule. With both workflows retired/unused under thin-pointer, the parity rule no longer applies to this surface.
1556
+
1557
+ ## Verify (acceptance)
1558
+
1559
+ Acceptance differs per path.
1560
+
1561
+ ### Path A — verify everything's wired correctly (after Phases 1–3 + 3.5 if flagged)
1562
+
1563
+ - [ ] `gh label list --repo "$REPO"` shows all 11 standard labels
1564
+ - [ ] `gh api repos/$REPO/branches/$DEFAULT_BRANCH/protection` returns 200
1565
+ - [ ] (If applicable) `gh api repos/$REPO/environments/prod` shows required_reviewers
1566
+ - [ ] `.claude/hooks/bassclef-sync.sh` is executable
1567
+ - [ ] `.claude/settings.json` validates as JSON
1568
+ - [ ] `substrate.config.md` has no `TODO:` markers (or operator approved deferring them)
1569
+ - [ ] `.bassclef-source.json` exists, validates against bassclef schema (`standards/bassclef-source/schemas/bassclef-source.schema.json`), references a valid `BASSCLEF_TOKEN` env var, and has an explicit `auto_sync` value (true OR false) set by the adopter at Phase 2.4 — silence is not deferral here
1570
+ - [ ] Running the sync hook produces no errors; banner shows `### BASSCLEF SUBSTRATE — SYNCED`; symlinks resolve
1571
+ - [ ] `CLAUDE.md` exists with at least a one-paragraph description
1572
+ - [ ] `docs/whereami.md` exists with phase + iteration filled in
1573
+ - [ ] **(Retired)** ~~Bassclef PR opened with both workflow matrices updated~~ — Phase 4 retired under bassclef goal 2026-05-03 WU-7
1574
+ - [ ] Test session in target repo: `claude` → SessionStart hook fires → no BLOCKED items from missing substrate
1575
+
1576
+ ### Path B acceptance — after Phases B.1–B.5
1577
+
1578
+ - [ ] Generated task list had at most 5 tasks (Phase B.1–B.5); no Path A phases queued
1579
+ - [ ] No `gh` calls fired during the dispatch
1580
+ - [ ] No `gh repo create`, no `gh api .../environments/prod`, no branch-protection writes
1581
+ - [ ] `.git/` exists with at least one commit
1582
+ - [ ] `.claude/hooks/bassclef-sync.sh` is executable
1583
+ - [ ] `.claude/settings.json` validates as JSON
1584
+ - [ ] `substrate.config.md` exists with `hosting_platform: none`
1585
+ - [ ] `CLAUDE.md` exists
1586
+ - [ ] `/launch --local --voice-input` was the final dispatch (not extended `/launch` and not `/build` and not `/launch-preview`)
1587
+ - [ ] `/launch` emitted a `localhost:80xx` URL pointing at the generated gallery
1588
+ - [ ] Operator opened the URL and saw the variants gallery
1589
+
1590
+ ## What NOT to do
1591
+
1592
+ - **Do not** restore Phase 4 — the bassclef-template-sync.yml workflow is retired. Adding new consumers to a deleted matrix produces nothing.
1593
+ - **Do not** vendor `bassclef-sync.template.sh` directly — that was the pre-2026-05-03 pattern. The thin-pointer dispatcher reads `.bassclef-source.json` and fetches bassclef's CURRENT logic at fire-time. Vendoring reproduces the drift problem WU-7 retires.
1594
+ - **Do not** auto-merge the bassclef-side PR. Bassclef is the trust
1595
+ root; every matrix change needs operator review.
1596
+ - **Do not** hardcode the presigned URL anywhere — read from
1597
+ `.bassclef-url` at runtime.
1598
+ - **Do not** copy `.claude/settings.local.json` from another repo — it's
1599
+ machine-local per-operator permission grants.
1600
+ - **Do not** commit secrets. The sync URL expires in ~7 days; don't
1601
+ treat it as a secret, but don't commit long-lived tokens either.
1602
+ - **Do not** mix Path A and Path B in one dispatch. If the operator picked
1603
+ Path B at the prereqs-missing menu, skip every Path A phase — don't
1604
+ generate a task list that walks Phase 1.1 / 1.2 / 1.3 / 2.4 / 3.5 /
1605
+ Phase 4. The whole point of Path B is the ≤5-step task list ending
1606
+ in `/launch --local --voice-input`. Any Path A task that leaks into a
1607
+ Path B run is the bassclef#934 regression.
1608
+ - **Do not** chain `/build` or `/launch-preview` after Path B's final
1609
+ dispatch. Path B's deliverable is the localhost URL `/launch --local`
1610
+ emits; the extended chain belongs to operators with vendor bindings.
1611
+
1612
+ ## Relationship to other skills
1613
+
1614
+ - **`/autonomous start`** — runs AFTER `/onboard-repo` to set up iteration
1615
+ scaffolding. `/onboard-repo` does the one-time wiring; `/autonomous
1616
+ start` does the per-iteration setup.
1617
+ - **`/substrate-check`** — validates substrate wiring AFTER onboarding.
1618
+ Run it as a post-flight check.
1619
+ - **`/promote`** — once onboarded, the new repo can file
1620
+ `bassclef-evolution` issues. The labels bootstrapped in Phase 1.1
1621
+ make them scannable.
1622
+
1623
+ ## Source
1624
+
1625
+ Ritual observed 4x on 2026-04-17: four consumer repos (refresh). Each took ~15 minutes by hand.
1626
+ Codified here so the fifth, sixth, and nth take ~3 minutes.
1627
+
1628
+ Closes bassclef #164.
1629
+
1630
+ Path B added 2026-06-13. Cold-adopter smoke test on `new-recipe-test`
1631
+ 2026-06-13 01:30am showed PR #931's edit to the flag-row description
1632
+ was cosmetic — `--greenfield-from-intent` still queued 12 standard
1633
+ onboarding tasks because the Procedure was monolithic. Refactor splits
1634
+ Procedure into Path A (standard, unchanged) and Path B (≤5 steps, no
1635
+ GitHub-remote operations, ends in `/launch --local --voice-input`).
1636
+ Closes bassclef#934.
1637
+
1638
+ ## Output discipline
1639
+
1640
+ Dispatch `/kiss words --rewrite` on your skill output before you return it. See `standards/skill-output-discipline.md` for the contract.