@thebassclef/lite 0.1.0 → 0.1.2
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.
- package/dist/cli.cjs +2 -0
- package/dist/cli.js +2 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/substrate/.bassclef/lite-manifest.json +999 -92
- package/substrate/.claude/hooks/longrun-prep-compounding-axis-check.sh +492 -0
- package/substrate/.claude/hooks/longrun-prep-compounding-sequence-check.sh +492 -0
- package/substrate/.claude/hooks/pre-commit-gate.sh +1 -2
- package/substrate/.claude/hooks/turn-prose-kiss-check.sh +30 -1
- package/substrate/.claude/luminaries/glenford-myers.md +230 -0
- package/substrate/.claude/luminaries/hunt-thomas.md +115 -0
- package/substrate/.claude/luminaries/hyrum-wright.md +94 -0
- package/substrate/.claude/luminaries/michael-feathers.md +2 -2
- package/substrate/.claude/luminaries/tony-hoare.md +170 -0
- package/substrate/.claude/luminaries/vaughn-vernon.md +50 -0
- package/substrate/.claude/luminaries/w-edwards-deming.md +158 -0
- package/substrate/.claude/rules/accessor-library-discipline.md +138 -0
- package/substrate/.claude/rules/adr-discipline.md +120 -0
- package/substrate/.claude/rules/api-conventions.md +125 -0
- package/substrate/.claude/rules/bootstrap-pair-discipline.md +141 -0
- package/substrate/.claude/rules/cold-adopter-harness-discipline.md +129 -0
- package/substrate/.claude/rules/compounding-axis-fresh-analysis.md +188 -0
- package/substrate/.claude/rules/compounding-sequence-fresh-analysis.md +188 -0
- package/substrate/.claude/rules/defensive-bash.md +68 -0
- package/substrate/.claude/rules/deferred-actions.md +233 -0
- package/substrate/.claude/rules/github-issue-flash-tweet.md +156 -0
- package/substrate/.claude/rules/hook-wire-on-author.md +103 -0
- package/substrate/.claude/rules/iteration-bet-brief-completeness.md +54 -0
- package/substrate/.claude/rules/lite-manifest-schema-change-discipline.md +3 -3
- package/substrate/.claude/rules/longrun-prep-plan-doc-compression.md +89 -0
- package/substrate/.claude/rules/loop-discipline.md +81 -0
- package/substrate/.claude/rules/manual-prod-approval.md +100 -0
- package/substrate/.claude/rules/marker-enrichment-discipline.md +99 -0
- package/substrate/.claude/rules/mobile-ephemeral-session.md +109 -0
- package/substrate/.claude/rules/new-dependency-check.md +51 -0
- package/substrate/.claude/rules/option-label-discipline.md +108 -0
- package/substrate/.claude/rules/pattern-annotation.md +100 -0
- package/substrate/.claude/rules/plain-english-discipline.md +11 -9
- package/substrate/.claude/rules/plan-enumeration-needs-value-props.md +211 -0
- package/substrate/.claude/rules/pr-title-shape.md +161 -0
- package/substrate/.claude/rules/prototype-workflow.md +65 -0
- package/substrate/.claude/rules/reserved-skill-names.md +123 -0
- package/substrate/.claude/rules/schema-management.md +49 -0
- package/substrate/.claude/rules/security.md +37 -0
- package/substrate/.claude/rules/skill-composition-declarations.md +124 -0
- package/substrate/.claude/rules/skill-description-clarity.md +247 -0
- package/substrate/.claude/rules/skill-procedure-step-list.md +137 -0
- package/substrate/.claude/rules/stuck-signal-diagnostic.md +140 -0
- package/substrate/.claude/rules/substrate-config-schema.md +98 -0
- package/substrate/.claude/rules/test-list-discipline.md +175 -0
- package/substrate/.claude/rules/test-sufficiency.md +210 -0
- package/substrate/.claude/rules/testing-tier-config.md +145 -0
- package/substrate/.claude/rules/testing.md +38 -0
- package/substrate/.claude/rules/turn-estimate-grounding.md +134 -0
- package/substrate/.claude/rules/visual-hierarchy.md +437 -0
- package/substrate/.claude/rules/we-dont-break-adopters.md +126 -0
- package/substrate/.claude/rules/wu-sequencing-compounds.md +145 -0
- package/substrate/.claude/skills/build/SKILL.md +1 -1
- package/substrate/.claude/skills/chronicle/SKILL.md +55 -0
- package/substrate/.claude/skills/clean-artifacts/SKILL.md +249 -0
- package/substrate/.claude/skills/decompose/SKILL.md +1 -1
- package/substrate/.claude/skills/diagnose/SKILL.md +1 -1
- package/substrate/.claude/skills/feynman/SKILL.md +90 -0
- package/substrate/.claude/skills/howdoi/SKILL.md +1 -1
- package/substrate/.claude/skills/ia-model/SKILL.md +1 -1
- package/substrate/.claude/skills/interaction-design/SKILL.md +1 -1
- package/substrate/.claude/skills/interpret-input/SKILL.md +8 -8
- package/substrate/.claude/skills/journal/SKILL.md +209 -0
- package/substrate/.claude/skills/kiss/SKILL.md +1 -1
- package/substrate/.claude/skills/launch/SKILL.md +14 -23
- package/substrate/.claude/skills/lean-canvas/SKILL.md +1 -1
- package/substrate/.claude/skills/longrun/SKILL.md +45 -8
- package/substrate/.claude/skills/luminary/SKILL.md +1 -1
- package/substrate/.claude/skills/ogilvy-writing-audit/SKILL.md +1 -1
- package/substrate/.claude/skills/onboard-repo/SKILL.md +143 -709
- package/substrate/.claude/skills/pattern-review/SKILL.md +1 -1
- package/substrate/.claude/skills/personas/SKILL.md +5 -5
- package/substrate/.claude/skills/promote/SKILL.md +1 -1
- package/substrate/.claude/skills/requirement/SKILL.md +1 -1
- package/substrate/.claude/skills/retro/SKILL.md +1 -1
- package/substrate/.claude/skills/riff/SKILL.md +1 -1
- package/substrate/.claude/skills/roadmap-reconcile/SKILL.md +1 -1
- package/substrate/.claude/skills/session-end/SKILL.md +1 -1
- package/substrate/.claude/skills/session-log/SKILL.md +3 -3
- package/substrate/.claude/skills/skills/SKILL.md +1 -1
- package/substrate/.claude/skills/spec/SKILL.md +1 -1
- package/substrate/.claude/skills/sprint/SKILL.md +1 -1
- package/substrate/.claude/skills/stage/SKILL.md +1 -1
- package/substrate/.claude/skills/state-a-problem/SKILL.md +1 -1
- package/substrate/.claude/skills/temperance/SKILL.md +1 -1
- package/substrate/.claude/skills/use-case/SKILL.md +1 -1
- package/substrate/.claude/skills/user-stories/SKILL.md +1 -1
- package/substrate/.claude/skills/value-prop/SKILL.md +1 -1
- package/substrate/.claude/skills/verify/SKILL.md +1 -1
- package/substrate/.claude/skills/visual-review/SKILL.md +503 -0
- package/substrate/.claude/skills/whats-the-plan/SKILL.md +202 -0
- package/substrate/.claude/skills/whereami/SKILL.md +2 -2
- package/substrate/CONTRIBUTING.md +1 -1
- package/substrate/README.md +5 -5
- package/substrate/lib/prose-scan-boundary.sh +171 -0
- package/substrate/lib/tier-check.sh +50 -1
- package/substrate/lib/tier-dependency-audit.sh +159 -4
- package/substrate/presence/install/bassclef-sync.template.sh +1 -1
- package/substrate/scripts/generate-lite-manifest.sh +21 -5
- package/substrate/standards/adr-template.md +86 -0
- package/substrate/standards/api-conventions/nextjs.md +84 -0
- package/substrate/standards/artifact-composition.md +209 -0
- package/substrate/standards/bash-hook-safety.md +246 -0
- package/substrate/standards/branch-stacking.md +408 -0
- package/substrate/standards/code-safety-principles.md +176 -0
- package/substrate/standards/composer-prerequisites.md +155 -0
- package/substrate/standards/dependency-discipline/cargo.md +39 -0
- package/substrate/standards/dependency-discipline/gem.md +43 -0
- package/substrate/standards/dependency-discipline/go-mod.md +41 -0
- package/substrate/standards/dependency-discipline/npm.md +42 -0
- package/substrate/standards/dependency-discipline/pip.md +42 -0
- package/substrate/standards/deployment-topology/ec2-tailscale.md +225 -0
- package/substrate/standards/deployment-topology.md +69 -0
- package/substrate/standards/docs-sync-allowlist.md +4 -4
- package/substrate/standards/domain-and-dns.md +145 -0
- package/substrate/standards/frontend-stack.md +67 -0
- package/substrate/standards/frontmatter-schema.md +154 -0
- package/substrate/standards/hook-injection-discipline.md +202 -0
- package/substrate/standards/hook-install-class.md +215 -0
- package/substrate/standards/input-handler-interface.md +152 -0
- package/substrate/standards/lite-manifest-schema-changes.md +60 -0
- package/substrate/standards/luminary-matching.md +105 -0
- package/substrate/standards/migration-discipline/active-record.md +50 -0
- package/substrate/standards/migration-discipline/alembic.md +43 -0
- package/substrate/standards/migration-discipline/gorm.md +50 -0
- package/substrate/standards/migration-discipline/prisma.md +53 -0
- package/substrate/standards/migration-discipline/sqlalchemy.md +51 -0
- package/substrate/standards/mobile-ephemeral-session.md +167 -0
- package/substrate/standards/model-routing-discipline.md +160 -0
- package/substrate/standards/persona-schema.md +229 -0
- package/substrate/standards/pluggable-luminaries.md +323 -0
- package/substrate/standards/pr-body-discipline.md +115 -0
- package/substrate/standards/preview-state-schema.md +189 -0
- package/substrate/standards/reserved-skill-names.md +120 -0
- package/substrate/standards/scannable-multi-option-output.md +261 -0
- package/substrate/standards/sdlc-gates/typescript.md +57 -0
- package/substrate/standards/session-board.md +256 -0
- package/substrate/standards/state-spine-contract.md +255 -0
- package/substrate/standards/steering-hints/kiss-words.md +11 -0
- package/substrate/standards/substrate-config-schema.md +267 -0
- package/substrate/standards/tier-dependency-analysis.md +1 -1
- package/substrate/standards/tier-tag-schema.md +1 -1
- package/substrate/standards/two-layer-config.md +99 -0
- package/substrate/standards/use-case-format.md +292 -0
- package/substrate/standards/user-story-invest.md +268 -0
- package/substrate/standards/velocity-and-appetite.md +229 -0
- package/substrate/standards/voice-input-pattern.md +119 -0
- package/substrate/standards/worktree-management.md +211 -0
- package/substrate/templates/chronicle-template.md +75 -0
- package/substrate/templates/memory-proposal-template.md +77 -0
- package/substrate/templates/persona-template.md +200 -0
- package/substrate/templates/pr-faq.md +45 -0
- package/substrate/templates/secret-rotation-template.md +162 -0
- package/substrate/templates/spec-template.md +131 -0
- package/substrate/templates/use-case-template.md +194 -0
- package/substrate/templates/user-story-template.md +107 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
tier: lite
|
|
3
3
|
name: onboard-repo
|
|
4
|
-
description: "Bootstrap bassclef framework in a new repo. Installs sync hook
|
|
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
5
|
problem: "Setting up bassclef in a new repo takes an hour of trial. Missing directories and wrong hook wiring."
|
|
6
6
|
value: "One command bootstraps everything \u2014 sync hook and config file and whereami scaffold."
|
|
7
7
|
inputs: [Optional flags — --with-deploy-host or --with-secrets or --full]
|
|
@@ -279,7 +279,7 @@ this divider.
|
|
|
279
279
|
Run each phase in order. Operator confirms before destructive or
|
|
280
280
|
cross-repo actions. Each phase is independently re-runnable.
|
|
281
281
|
|
|
282
|
-
#### Phase 0 — Refuse to run from main
|
|
282
|
+
#### Phase 0 — Refuse to run from main
|
|
283
283
|
|
|
284
284
|
Substrate changes go through PRs, same as feature work. If `/onboard-repo`
|
|
285
285
|
runs from `main`, every scaffold (`.claude/`, `CLAUDE.md`,
|
|
@@ -496,734 +496,168 @@ JSON
|
|
|
496
496
|
Operator confirms — may want to add app-specific hooks (pre-build-gate,
|
|
497
497
|
pre-commit-gate) if the repo has source code.
|
|
498
498
|
|
|
499
|
-
##### 2.2.1 Wire
|
|
499
|
+
##### 2.2.1 Wire all Phase 2.2 hooks (13 hooks in one pass)
|
|
500
500
|
|
|
501
|
-
|
|
502
|
-
message for bassclef-internal jargon (the `/kiss words` BLOCK list
|
|
503
|
-
from `standards/bassclef-internal-jargon.md`). When
|
|
504
|
-
`prose_discipline.kiss_words_turn_prose` is `true` in
|
|
505
|
-
`.claude/bassclef-configs.jsonc` (the adopter-default Phase 2.3.5
|
|
506
|
-
writes), the hook fires after every assistant turn and surfaces
|
|
507
|
-
findings; when `false`, the hook short-circuits silently.
|
|
501
|
+
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.
|
|
508
502
|
|
|
509
|
-
|
|
510
|
-
`additionalDirectories` convention):
|
|
503
|
+
**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.
|
|
511
504
|
|
|
512
|
-
|
|
513
|
-
mkdir -p .claude/hooks
|
|
514
|
-
ln -sf "../../../bassclef/.claude/hooks/turn-prose-kiss-check.sh" \
|
|
515
|
-
".claude/hooks/turn-prose-kiss-check.sh"
|
|
516
|
-
```
|
|
517
|
-
|
|
518
|
-
Add the Stop hook block to `.claude/settings.json`. If the file already
|
|
519
|
-
has a Stop block (for example, `session-end.sh`), append this hook
|
|
520
|
-
alongside — both run, turn-prose-kiss-check first, session-end second:
|
|
521
|
-
|
|
522
|
-
```jsonc
|
|
523
|
-
{
|
|
524
|
-
"hooks": {
|
|
525
|
-
"Stop": [
|
|
526
|
-
{
|
|
527
|
-
"matcher": "",
|
|
528
|
-
"hooks": [
|
|
529
|
-
{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/turn-prose-kiss-check.sh", "timeout": 10 }
|
|
530
|
-
]
|
|
531
|
-
}
|
|
532
|
-
]
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
```
|
|
536
|
-
|
|
537
|
-
**Composition rule** — when an existing Stop hook is present, leave it
|
|
538
|
-
in place and append this one. The turn-prose-kiss-check hook exits 0
|
|
539
|
-
even when findings surface (default toggle: advisory), so a downstream
|
|
540
|
-
session-end hook still runs. When the adopter opts in to strict mode
|
|
541
|
-
(`prose_discipline.kiss_words_turn_prose: "strict"` in
|
|
542
|
-
bassclef-configs.jsonc), the hook exits 2 and blocks the stop — that's
|
|
543
|
-
the conscious-strict trade-off.
|
|
544
|
-
|
|
545
|
-
**Conditional fire** — the hook reads
|
|
546
|
-
`.claude/bassclef-configs.jsonc` `prose_discipline.kiss_words_turn_prose`
|
|
547
|
-
at runtime and short-circuits when `false`. Adopters who never want the
|
|
548
|
-
check can flip the toggle without unwiring the hook.
|
|
549
|
-
|
|
550
|
-
**Verify the wiring:**
|
|
551
|
-
|
|
552
|
-
```bash
|
|
553
|
-
# Sanity: hook is executable + reachable
|
|
554
|
-
ls -l .claude/hooks/turn-prose-kiss-check.sh
|
|
555
|
-
|
|
556
|
-
# Sanity: settings.json parses
|
|
557
|
-
python3 -c "import json; json.load(open('.claude/settings.json'))"
|
|
558
|
-
```
|
|
559
|
-
|
|
560
|
-
**Composes with downstream Phase 2.x steps:**
|
|
561
|
-
|
|
562
|
-
- Phase 2.3.5 writes `prose_discipline.kiss_words_turn_prose: true` to
|
|
563
|
-
`.claude/bassclef-configs.jsonc` as the adopter default — this hook
|
|
564
|
-
fires when that toggle is true.
|
|
565
|
-
- Phase 2.5 (security scanning) is a separate hook wiring path; both
|
|
566
|
-
hooks can co-exist in the Stop block.
|
|
567
|
-
|
|
568
|
-
Source: bassclef#1051 (hook origin), bassclef#1138 (this wiring step).
|
|
569
|
-
|
|
570
|
-
##### 2.2.2 Wire substrate-clarity-gate PreToolUse hook (bassclef#1137 T4)
|
|
571
|
-
|
|
572
|
-
Symlink the bassclef PreToolUse hook that BLOCKs writes to
|
|
573
|
-
`.claude/skills/`, `.claude/rules/`, and `.claude/luminaries/` when
|
|
574
|
-
they violate the clarity discipline bassclef applies to its own
|
|
575
|
-
substrate — skill descriptions over 280 chars, rule + luminary
|
|
576
|
-
"NEVER" without paired "INSTEAD:" block, jargon usage where plain
|
|
577
|
-
language exists. Adopter writes to substrate paths trigger the same
|
|
578
|
-
gate bassclef does.
|
|
579
|
-
|
|
580
|
-
Symlink the hook + the bassclef baseline allowlist (the file that
|
|
581
|
-
grandfathers pre-existing violators during a grace window):
|
|
505
|
+
**Symlink all hooks in one pass:**
|
|
582
506
|
|
|
583
507
|
```bash
|
|
584
508
|
mkdir -p .claude/hooks
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
509
|
+
cd .claude/hooks
|
|
510
|
+
for h in turn-prose-kiss-check substrate-clarity-gate artifact-ingestion-gate \
|
|
511
|
+
pattern-annotation-validate pre-commit-gate state-validate \
|
|
512
|
+
destructive-command-guard multi-tenancy-check atomic-pr-check \
|
|
513
|
+
post-write-trace testing-tier-enforce role-entry-gate temperance-gate; do
|
|
514
|
+
ln -sf "../../../bassclef/.claude/hooks/${h}.sh" "${h}.sh"
|
|
515
|
+
done
|
|
516
|
+
# Two allowlist files paired with hooks that read them:
|
|
517
|
+
ln -sf "../../../bassclef/.claude/hooks/substrate-clarity-allowlist.txt" substrate-clarity-allowlist.txt
|
|
518
|
+
ln -sf "../../../bassclef/.claude/hooks/testing-tier-enforce-allowlist.txt" testing-tier-enforce-allowlist.txt
|
|
519
|
+
cd -
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
**Hook table:**
|
|
523
|
+
|
|
524
|
+
| # | Hook | Event | Matcher | Tier | Notes |
|
|
525
|
+
|---|---|---|---|---|---|
|
|
526
|
+
| 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 |
|
|
527
|
+
| 2 | substrate-clarity-gate | PreToolUse | Edit\|Write | lite | Reads bassclef baseline allowlist + optional adopter-side `substrate-clarity-allowlist-adopter.txt` |
|
|
528
|
+
| 3 | artifact-ingestion-gate | PreToolUse | Write | lite | Reads `artifact_ingestion.paths` from bassclef-configs; 13 default paths seeded by Phase 2.3.5 |
|
|
529
|
+
| 4 | pattern-annotation-validate | PreToolUse | Edit\|Write\|MultiEdit | std | Reads `tech_stack.lang` for language scoping (Phase 2.3.6) |
|
|
530
|
+
| 5 | pre-commit-gate | PreToolUse | Edit\|Write\|MultiEdit | lite | Runs first; composes testing-tier-enforce internally as one of its check steps |
|
|
531
|
+
| 6 | state-validate | PreToolUse | Edit\|Write\|MultiEdit | lite | Runs after pre-commit-gate; heavier ajv-cli schema check |
|
|
532
|
+
| 7 | destructive-command-guard | PreToolUse | Bash | std | Catches destructive verbs + force flags + amplifiers (rm -rf, FLUSHALL, prisma migrate reset) |
|
|
533
|
+
| 8 | multi-tenancy-check | PreToolUse | Edit\|Write\|MultiEdit | std | Template — customize via `TENANT_MODELS` / `TENANT_CONTEXT_FN` / `TENANT_PARAMS_FN` env vars |
|
|
534
|
+
| 9 | atomic-pr-check | PreToolUse | Bash | std | Fires on `git push` patterns; BLOCKs multi-step branches lacking `bundle: true` in goal frontmatter |
|
|
535
|
+
| 10 | post-write-trace | PostToolUse | Write\|Edit | std | Append-only trace; no override (never blocks) |
|
|
536
|
+
| 11 | testing-tier-enforce | (composed) | (via pre-commit-gate) | lite | Fires inside pre-commit-gate; no separate matcher entry; 60-day allowlist grace |
|
|
537
|
+
| 12 | role-entry-gate | PreToolUse | Edit\|Write\|MultiEdit | std | MVP: source-code file extensions only; reads `state/markers/role/<role>/<session>.marker` |
|
|
538
|
+
| 13 | temperance-gate | PreToolUse | Edit\|Write\|MultiEdit | lite | Fires on high-impact edits (.claude/, standards/, lib/state.sh, SKILL.md) when temperance marker missing |
|
|
539
|
+
|
|
540
|
+
**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.
|
|
541
|
+
|
|
542
|
+
**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:
|
|
616
543
|
|
|
617
544
|
```bash
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
545
|
+
# Assumes .claude/settings.json exists from Phase 2.2 (bare SessionStart entry).
|
|
546
|
+
# Reads adopter tier and skips standard-tier hooks on lite.
|
|
547
|
+
TIER=$(bash ../bassclef/lib/tier-check.sh 2>/dev/null || echo lite)
|
|
548
|
+
|
|
549
|
+
# Lite tier — 7 hooks land in .claude/settings.json (rows 1,2,3,5,6,11,13).
|
|
550
|
+
# Standard/ultra tier — all 13 hooks land in .claude/settings.json.
|
|
551
|
+
jq --arg tier "$TIER" '
|
|
552
|
+
.hooks.Stop = ((.hooks.Stop // []) + [
|
|
553
|
+
{ "matcher": "", "hooks": [
|
|
554
|
+
{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/turn-prose-kiss-check.sh", "timeout": 10 }
|
|
555
|
+
]}
|
|
556
|
+
]) |
|
|
557
|
+
.hooks.PreToolUse = ((.hooks.PreToolUse // []) + [
|
|
558
|
+
{ "matcher": "Edit|Write|MultiEdit", "hooks": (
|
|
559
|
+
[
|
|
560
|
+
{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/substrate-clarity-gate.sh" },
|
|
561
|
+
{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/pre-commit-gate.sh" },
|
|
562
|
+
{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/state-validate.sh" },
|
|
563
|
+
{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/temperance-gate.sh" }
|
|
564
|
+
] +
|
|
565
|
+
(if $tier != "lite" then [
|
|
566
|
+
{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/pattern-annotation-validate.sh" },
|
|
567
|
+
{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/multi-tenancy-check.sh" },
|
|
568
|
+
{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/role-entry-gate.sh" }
|
|
569
|
+
] else [] end)
|
|
570
|
+
)},
|
|
571
|
+
{ "matcher": "Write", "hooks": [
|
|
572
|
+
{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/artifact-ingestion-gate.sh" }
|
|
573
|
+
]}
|
|
574
|
+
] + (if $tier != "lite" then [
|
|
575
|
+
{ "matcher": "Bash", "hooks": [
|
|
576
|
+
{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/destructive-command-guard.sh" },
|
|
577
|
+
{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/atomic-pr-check.sh" }
|
|
578
|
+
]}
|
|
579
|
+
] else [] end)) |
|
|
580
|
+
(if $tier != "lite" then
|
|
581
|
+
.hooks.PostToolUse = ((.hooks.PostToolUse // []) + [
|
|
582
|
+
{ "matcher": "Write|Edit", "hooks": [
|
|
583
|
+
{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/post-write-trace.sh" }
|
|
584
|
+
]}
|
|
585
|
+
])
|
|
586
|
+
else . end)
|
|
587
|
+
' .claude/settings.json > .claude/settings.json.tmp \
|
|
588
|
+
&& mv .claude/settings.json.tmp .claude/settings.json
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
**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.
|
|
592
|
+
|
|
593
|
+
**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.
|
|
594
|
+
|
|
595
|
+
**Verify block 1 — Stop event:**
|
|
642
596
|
|
|
643
597
|
```bash
|
|
644
|
-
# Sanity: hook executable + reachable
|
|
645
|
-
ls -l .claude/hooks/substrate-clarity-gate.sh
|
|
646
|
-
ls -l .claude/hooks/substrate-clarity-allowlist.txt
|
|
647
|
-
|
|
648
|
-
# Sanity: settings.json parses + has the matcher
|
|
649
598
|
python3 -c "import json; d=json.load(open('.claude/settings.json')); \
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
for entry in d.get('hooks',{}).get('PreToolUse',[]) \
|
|
653
|
-
for h in entry.get('hooks',[])) else 'NOT wired')"
|
|
599
|
+
hooks=[h.get('command','') for entry in d.get('hooks',{}).get('Stop',[]) for h in entry.get('hooks',[])]; \
|
|
600
|
+
print('turn-prose-kiss-check wired' if any('turn-prose-kiss-check' in c for c in hooks) else 'NOT wired')"
|
|
654
601
|
```
|
|
655
602
|
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
##### 2.2.3 Wire artifact-ingestion-gate PreToolUse hook (bassclef#1140 T7)
|
|
659
|
-
|
|
660
|
-
Symlink the bassclef PreToolUse hook that BLOCKs writes to adopter
|
|
661
|
-
substantive artifacts (specs, decompositions, prototypes, ADRs,
|
|
662
|
-
proposals, iteration goals) when the artifact body lacks a
|
|
663
|
-
`## Sources read` section. The discipline catches the
|
|
664
|
-
"pattern-matched on generic X" failure mode that
|
|
665
|
-
`.claude/rules/artifact-ingestion.md` was built to close — applied at
|
|
666
|
-
adopter writes, not just at bassclef's own writes.
|
|
667
|
-
|
|
668
|
-
Symlink the hook:
|
|
603
|
+
**Verify block 2 — PreToolUse event (all matchers):**
|
|
669
604
|
|
|
670
605
|
```bash
|
|
671
|
-
mkdir -p .claude/hooks
|
|
672
|
-
ln -sf "../../../bassclef/.claude/hooks/artifact-ingestion-gate.sh" \
|
|
673
|
-
".claude/hooks/artifact-ingestion-gate.sh"
|
|
674
|
-
```
|
|
675
|
-
|
|
676
|
-
Add the PreToolUse Write block to `.claude/settings.json`. The hook
|
|
677
|
-
matches on `Write` (not `Edit`) — edits to existing artifacts pass
|
|
678
|
-
through; only new artifact writes trigger the gate. If a Write
|
|
679
|
-
matcher already exists from a prior phase, append this hook to its
|
|
680
|
-
`hooks` array:
|
|
681
|
-
|
|
682
|
-
```jsonc
|
|
683
|
-
{
|
|
684
|
-
"hooks": {
|
|
685
|
-
"PreToolUse": [
|
|
686
|
-
{
|
|
687
|
-
"matcher": "Write",
|
|
688
|
-
"hooks": [
|
|
689
|
-
{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/artifact-ingestion-gate.sh" }
|
|
690
|
-
]
|
|
691
|
-
}
|
|
692
|
-
]
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
```
|
|
696
|
-
|
|
697
|
-
**Adopter-default path matchers** — the hook reads
|
|
698
|
-
`.claude/bassclef-configs.jsonc` `artifact_ingestion.paths` to
|
|
699
|
-
decide which paths fire the gate. Phase 2.3.5 (bassclef-configs
|
|
700
|
-
adopter-default seed) appends this block with the bassclef default
|
|
701
|
-
list. Adopters edit the list per repo — adding paths their substrate
|
|
702
|
-
considers substantive, or removing paths that do not apply:
|
|
703
|
-
|
|
704
|
-
```jsonc
|
|
705
|
-
"artifact_ingestion": {
|
|
706
|
-
"paths": [
|
|
707
|
-
"docs/specs/**/*.md",
|
|
708
|
-
"docs/decompositions/**/*.md",
|
|
709
|
-
"docs/prototypes/**/*.html",
|
|
710
|
-
"docs/proposals/**/*.md",
|
|
711
|
-
"docs/adrs/**/*.md",
|
|
712
|
-
"docs/use-cases/**/*.md",
|
|
713
|
-
"docs/user-stories/**/*.md",
|
|
714
|
-
"docs/ia-models/**/*.md",
|
|
715
|
-
"docs/interaction-design/**/*",
|
|
716
|
-
"docs/personas/**/*.md",
|
|
717
|
-
"docs/jtbd-tasks/**/*.md",
|
|
718
|
-
"docs/value-props/**/*.md",
|
|
719
|
-
"docs/iteration-bets/**/*.md"
|
|
720
|
-
]
|
|
721
|
-
}
|
|
722
|
-
```
|
|
723
|
-
|
|
724
|
-
When the `artifact_ingestion.paths` field is absent (older adopters
|
|
725
|
-
predating this Phase), the hook falls back to its built-in default
|
|
726
|
-
matcher list — the wiring stays safe and quiet.
|
|
727
|
-
|
|
728
|
-
**Composition rule** — when an existing PreToolUse Write matcher is
|
|
729
|
-
present (for example, from a sibling hook in another Phase 2.x step),
|
|
730
|
-
append this hook's command entry to the same matcher's `hooks` array.
|
|
731
|
-
The matcher entry must not be duplicated.
|
|
732
|
-
|
|
733
|
-
**Override path** — adopter can bypass per-call with
|
|
734
|
-
`SKIP_ARTIFACT_INGESTION=1 <command>` (logged via trace-helper). Use
|
|
735
|
-
for migration scripts and emergency rescue.
|
|
736
|
-
|
|
737
|
-
**Verify the wiring:**
|
|
738
|
-
|
|
739
|
-
```bash
|
|
740
|
-
# Sanity: hook executable + reachable
|
|
741
|
-
ls -l .claude/hooks/artifact-ingestion-gate.sh
|
|
742
|
-
|
|
743
|
-
# Sanity: settings.json has the matcher
|
|
744
606
|
python3 -c "import json; d=json.load(open('.claude/settings.json')); \
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
for h in entry.get('hooks',[])) else 'NOT wired')"
|
|
607
|
+
cmds=[h.get('command','') for entry in d.get('hooks',{}).get('PreToolUse',[]) for h in entry.get('hooks',[])]; \
|
|
608
|
+
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']; \
|
|
609
|
+
[print(f'{h}: {\"wired\" if any(h in c for c in cmds) else \"NOT wired\"}') for h in hooks]"
|
|
749
610
|
```
|
|
750
611
|
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
##### 2.2.4 Wire pattern-annotation-validate PreToolUse hook (bassclef#1139 T6)
|
|
754
|
-
|
|
755
|
-
**Lite adopter note (bassclef#740 Task 1.2).** This hook ships at `tier: standard`. If your adopter tier is lite (resolved via `lib/tier-check.sh`), skip this Phase step and continue with 2.2.5. The bassclef-lite tarball does not carry this hook.
|
|
756
|
-
|
|
757
|
-
Symlink the bassclef PreToolUse hook that validates `@pattern <catalog-path>` annotations in adopter source code. Layer 3 of bassclef#478 traceability — code that instantiates a named pattern from bassclef's catalog (`patterns/<shelf>/<source>/<slug>.md`) must mark itself with the annotation so forward (which code uses this pattern) and reverse (which patterns is this code using) lookups work across the adopter portfolio.
|
|
758
|
-
|
|
759
|
-
Symlink the hook:
|
|
612
|
+
**Verify block 3 — PostToolUse event:**
|
|
760
613
|
|
|
761
614
|
```bash
|
|
762
|
-
mkdir -p .claude/hooks
|
|
763
|
-
ln -sf "../../../bassclef/.claude/hooks/pattern-annotation-validate.sh" \
|
|
764
|
-
".claude/hooks/pattern-annotation-validate.sh"
|
|
765
|
-
```
|
|
766
|
-
|
|
767
|
-
Add the PreToolUse Edit|Write|MultiEdit block to `.claude/settings.json`. If an `Edit|Write` matcher already exists from a prior phase, append this hook to its `hooks` array (the bassclef settings.json convention is to widen matchers when adding new hooks that share a tool set):
|
|
768
|
-
|
|
769
|
-
```jsonc
|
|
770
|
-
{
|
|
771
|
-
"hooks": {
|
|
772
|
-
"PreToolUse": [
|
|
773
|
-
{
|
|
774
|
-
"matcher": "Edit|Write|MultiEdit",
|
|
775
|
-
"hooks": [
|
|
776
|
-
{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/pattern-annotation-validate.sh" }
|
|
777
|
-
]
|
|
778
|
-
}
|
|
779
|
-
]
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
```
|
|
783
|
-
|
|
784
|
-
**Rule propagation** — the `pattern-annotation` rule lives at bassclef's `.claude/rules/pattern-annotation.md` and loads into adopter agent context via the `additionalDirectories: ["../bassclef"]` entry Phase 2.2 wrote. No copy needed; bassclef's rule body is the source of truth.
|
|
785
|
-
|
|
786
|
-
**Tech-stack-aware scoping** — the hook reads adopter's `.claude/bassclef-configs.jsonc` `tech_stack.lang` (Phase 2.3.6 writes) and fires only on source files matching the declared language: `.ts/.tsx` for `typescript`, `.py` for `python`, `.rb` for `ruby`, `.go` for `go`, `.rs` for `rust`. Non-source files silent. When `tech_stack.lang` is absent (older adopters or skip path), the hook fires on the union of language matchers (safe default).
|
|
787
|
-
|
|
788
|
-
**Composition rule** — when an existing PreToolUse Edit|Write matcher block is present (substrate-clarity-gate from 2.2.2 uses `Edit|Write`), the matcher set widens to `Edit|Write|MultiEdit` to cover both hooks. Adopters can keep the matchers separate if they prefer narrower scoping per hook.
|
|
789
|
-
|
|
790
|
-
**Override path** — `SKIP_PATTERN_ANNOTATION=1 <command>` (logged via trace-helper). Use for migration scripts when annotating retroactively is in flight.
|
|
791
|
-
|
|
792
|
-
**Verify the wiring:**
|
|
793
|
-
|
|
794
|
-
```bash
|
|
795
|
-
# Sanity: hook executable + reachable
|
|
796
|
-
ls -l .claude/hooks/pattern-annotation-validate.sh
|
|
797
|
-
|
|
798
|
-
# Sanity: rule loads via additionalDirectories
|
|
799
|
-
test -f ../bassclef/.claude/rules/pattern-annotation.md && echo "rule reachable" || echo "rule NOT reachable"
|
|
800
|
-
|
|
801
|
-
# Sanity: settings.json has the matcher
|
|
802
615
|
python3 -c "import json; d=json.load(open('.claude/settings.json')); \
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
for entry in d.get('hooks',{}).get('PreToolUse',[]) \
|
|
806
|
-
for h in entry.get('hooks',[])) else 'NOT wired')"
|
|
616
|
+
cmds=[h.get('command','') for entry in d.get('hooks',{}).get('PostToolUse',[]) for h in entry.get('hooks',[])]; \
|
|
617
|
+
print('post-write-trace wired' if any('post-write-trace' in c for c in cmds) else 'NOT wired')"
|
|
807
618
|
```
|
|
808
619
|
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
##### 2.2.5 Wire pre-commit-gate + state-validate PreToolUse hooks (bassclef#1136 T3)
|
|
812
|
-
|
|
813
|
-
Symlink the two bassclef PreToolUse hooks that gate adopter writes.
|
|
814
|
-
|
|
815
|
-
`pre-commit-gate.sh` runs the SDLC pre-build checks per `.claude/rules/sdlc-gates.md`. Those checks are temperance + diagnosis + scope drift.
|
|
816
|
-
|
|
817
|
-
`state-validate.sh` validates state-spine entity writes against JSON Schema per `.claude/rules/state-schema-validation.md`.
|
|
818
|
-
|
|
819
|
-
Together the hooks catch two failure classes before any source edit lands: skipped gates (silent SDLC bypass) and malformed state writes (silent schema drift).
|
|
820
|
-
|
|
821
|
-
Symlink both hooks:
|
|
620
|
+
**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:
|
|
822
621
|
|
|
823
622
|
```bash
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
".claude/hooks/state-validate.sh"
|
|
829
|
-
```
|
|
830
|
-
|
|
831
|
-
Add the PreToolUse Edit|Write|MultiEdit block to `.claude/settings.json`. If an `Edit|Write` or `Edit|Write|MultiEdit` matcher already exists from a prior phase (substrate-clarity-gate from 2.2.2, pattern-annotation-validate from 2.2.4), append both hooks to its `hooks` array — the matcher set widens to `Edit|Write|MultiEdit` when MultiEdit is not already covered:
|
|
832
|
-
|
|
833
|
-
```jsonc
|
|
834
|
-
{
|
|
835
|
-
"hooks": {
|
|
836
|
-
"PreToolUse": [
|
|
837
|
-
{
|
|
838
|
-
"matcher": "Edit|Write|MultiEdit",
|
|
839
|
-
"hooks": [
|
|
840
|
-
{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/pre-commit-gate.sh" },
|
|
841
|
-
{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/state-validate.sh" }
|
|
842
|
-
]
|
|
843
|
-
}
|
|
844
|
-
]
|
|
845
|
-
}
|
|
846
|
-
}
|
|
847
|
-
```
|
|
848
|
-
|
|
849
|
-
**Order matters** — `pre-commit-gate.sh` runs first (cheap SDLC checks), `state-validate.sh` runs second (heavier ajv-cli schema validation). The matcher block lists them in that order; a BLOCK from the first stops the chain before the second fires.
|
|
850
|
-
|
|
851
|
-
**Rule propagation** — both rules (`sdlc-gates.md` + `state-schema-validation.md`) live at bassclef's `.claude/rules/` and load into adopter agent context via the `additionalDirectories: ["../bassclef"]` entry Phase 2.2 wrote. No copy needed; bassclef's rule body is the source of truth.
|
|
852
|
-
|
|
853
|
-
**Composition rule** — when an existing PreToolUse Edit|Write matcher block is present from earlier Phase 2.x steps, append these two hooks to its `hooks` array (do not duplicate the matcher entry). Hook order within the array determines execution order; place `pre-commit-gate.sh` before `state-validate.sh` per the order rule above.
|
|
854
|
-
|
|
855
|
-
**Override paths** — `SKIP_PRE_COMMIT_GATE=1 <command>` and `SKIP_STATE_VALIDATE=1 <command>` (both logged via trace-helper). Use only for one-shot migration scripts (state bootstrapping) or emergency rescue when the hook itself is broken.
|
|
856
|
-
|
|
857
|
-
**Verify the wiring:**
|
|
858
|
-
|
|
859
|
-
```bash
|
|
860
|
-
# Sanity: both hooks executable + reachable
|
|
861
|
-
ls -l .claude/hooks/pre-commit-gate.sh .claude/hooks/state-validate.sh
|
|
862
|
-
|
|
863
|
-
# Sanity: both rules reachable via additionalDirectories
|
|
864
|
-
test -f ../bassclef/.claude/rules/sdlc-gates.md && echo "sdlc-gates reachable" || echo "sdlc-gates NOT reachable"
|
|
865
|
-
test -f ../bassclef/.claude/rules/state-schema-validation.md && echo "state-schema-validation reachable" || echo "state-schema-validation NOT reachable"
|
|
866
|
-
|
|
867
|
-
# Sanity: settings.json has both hooks wired in matcher block
|
|
868
|
-
python3 -c "import json; d=json.load(open('.claude/settings.json')); \
|
|
869
|
-
hooks=[h.get('command','') for entry in d.get('hooks',{}).get('PreToolUse',[]) for h in entry.get('hooks',[])]; \
|
|
870
|
-
print('pre-commit-gate wired' if any('pre-commit-gate' in c for c in hooks) else 'NOT wired'); \
|
|
871
|
-
print('state-validate wired' if any('state-validate' in c for c in hooks) else 'NOT wired')"
|
|
872
|
-
```
|
|
873
|
-
|
|
874
|
-
Source: bassclef#1136 (this wiring step — T3, iteration-2 BLOCKER). Sister rules: `.claude/rules/sdlc-gates.md` + `.claude/rules/state-schema-validation.md`.
|
|
875
|
-
|
|
876
|
-
##### 2.2.6 Wire destructive-command-guard + multi-tenancy-check PreToolUse hooks (bassclef#1141 T8 — partial)
|
|
877
|
-
|
|
878
|
-
**Lite adopter note (bassclef#740 Task 1.2).** Both hooks ship at `tier: standard`. Skip this step if your tier is lite. Resolve tier via `lib/tier-check.sh`. Continue with 2.2.7.
|
|
879
|
-
|
|
880
|
-
Symlink two bassclef PreToolUse hooks that catch runtime-safety problems before they reach the operator's filesystem or database. `destructive-command-guard.sh` fires on Bash and detects destructive verbs + force flags + amplifiers (catches "prisma migrate reset", "rm -rf", "FLUSHALL" patterns). `multi-tenancy-check.sh` fires on Edit/Write of source files and warns when tenant-scoped patterns are missing (queries without tenant context).
|
|
881
|
-
|
|
882
|
-
Bet 2026-06-18b scopes T8 to these two hooks; the ticket's other two (`operator-private-path-check.sh` + `type-check.sh`) are deferred to a follow-on per goal narrowing.
|
|
883
|
-
|
|
884
|
-
Symlink both hooks:
|
|
885
|
-
|
|
886
|
-
```bash
|
|
887
|
-
mkdir -p .claude/hooks
|
|
888
|
-
ln -sf "../../../bassclef/.claude/hooks/destructive-command-guard.sh" \
|
|
889
|
-
".claude/hooks/destructive-command-guard.sh"
|
|
890
|
-
ln -sf "../../../bassclef/.claude/hooks/multi-tenancy-check.sh" \
|
|
891
|
-
".claude/hooks/multi-tenancy-check.sh"
|
|
892
|
-
```
|
|
893
|
-
|
|
894
|
-
Add both PreToolUse blocks to `.claude/settings.json`. The matchers differ — `destructive-command-guard` watches Bash; `multi-tenancy-check` watches Edit|Write|MultiEdit. The Edit|Write|MultiEdit block likely already exists from Phase 2.2.2 / 2.2.3 / 2.2.4 / 2.2.5 — append `multi-tenancy-check` to its `hooks` array (do not duplicate the matcher entry). The Bash block is new for most adopters; create it if absent.
|
|
895
|
-
|
|
896
|
-
```jsonc
|
|
897
|
-
{
|
|
898
|
-
"hooks": {
|
|
899
|
-
"PreToolUse": [
|
|
900
|
-
{
|
|
901
|
-
"matcher": "Bash",
|
|
902
|
-
"hooks": [
|
|
903
|
-
{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/destructive-command-guard.sh" }
|
|
904
|
-
]
|
|
905
|
-
},
|
|
906
|
-
{
|
|
907
|
-
"matcher": "Edit|Write|MultiEdit",
|
|
908
|
-
"hooks": [
|
|
909
|
-
{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/multi-tenancy-check.sh" }
|
|
910
|
-
]
|
|
911
|
-
}
|
|
912
|
-
]
|
|
913
|
-
}
|
|
914
|
-
}
|
|
915
|
-
```
|
|
916
|
-
|
|
917
|
-
**Customization** — `multi-tenancy-check.sh` is a template. Adopters with multi-tenant codebases override `TENANT_MODELS` + `TENANT_CONTEXT_FN` + `TENANT_PARAMS_FN` via env vars OR drop a custom `multi-tenancy-check.sh` in `.claude/hooks/` (which wins over the symlink). Single-tenant adopters can disable per-call with `SKIP_MULTI_TENANCY_CHECK=1`.
|
|
918
|
-
|
|
919
|
-
**Rule propagation** — `.claude/rules/destructive-operations.md` loads into adopter agent context via the `additionalDirectories: ["../bassclef"]` entry Phase 2.2 wrote. No copy needed.
|
|
920
|
-
|
|
921
|
-
**Composition rule** — Bash and Edit|Write|MultiEdit matchers stay separate; never collapse them. When other Phase 2.x steps add Bash hooks (Phase 2.2.7 ships atomic-pr-check on Bash; type-check on Bash if T8 follow-on ships), append to the Bash matcher's `hooks` array — do not duplicate the matcher entry.
|
|
922
|
-
|
|
923
|
-
**Override paths** — `SKIP_DESTRUCTIVE_GUARD=1 <command>` (logged) and `SKIP_MULTI_TENANCY_CHECK=1 <command>` (logged). Both bypass logged via trace-helper. Use only for genuine cases (one-shot migrations, single-tenant repos where the check is noise).
|
|
924
|
-
|
|
925
|
-
**Verify the wiring:**
|
|
926
|
-
|
|
927
|
-
```bash
|
|
928
|
-
# Sanity: both hooks executable + reachable
|
|
929
|
-
ls -l .claude/hooks/destructive-command-guard.sh .claude/hooks/multi-tenancy-check.sh
|
|
930
|
-
|
|
931
|
-
# Sanity: destructive-operations rule reachable via additionalDirectories
|
|
932
|
-
test -f ../bassclef/.claude/rules/destructive-operations.md && echo "destructive-operations reachable" || echo "NOT reachable"
|
|
933
|
-
|
|
934
|
-
# Sanity: settings.json has both hooks wired with correct matchers
|
|
935
|
-
python3 -c "import json; d=json.load(open('.claude/settings.json')); \
|
|
936
|
-
bash_hooks=[h.get('command','') for entry in d.get('hooks',{}).get('PreToolUse',[]) if entry.get('matcher')=='Bash' for h in entry.get('hooks',[])]; \
|
|
937
|
-
edit_hooks=[h.get('command','') for entry in d.get('hooks',{}).get('PreToolUse',[]) if 'Edit' in entry.get('matcher','') for h in entry.get('hooks',[])]; \
|
|
938
|
-
print('destructive-command-guard wired (Bash)' if any('destructive-command-guard' in c for c in bash_hooks) else 'NOT wired (Bash)'); \
|
|
939
|
-
print('multi-tenancy-check wired (Edit|Write|MultiEdit)' if any('multi-tenancy-check' in c for c in edit_hooks) else 'NOT wired (Edit|Write|MultiEdit)')"
|
|
940
|
-
```
|
|
941
|
-
|
|
942
|
-
Source: bassclef#1141 (this wiring step — T8, runtime-safety chain). Sister rule: `.claude/rules/destructive-operations.md`. Follow-on: `operator-private-path-check.sh` + `type-check.sh` wires deferred from T8 goal scope.
|
|
943
|
-
|
|
944
|
-
##### 2.2.7 Wire atomic-pr-check + post-write-trace workflow hooks (bassclef#1142 T9)
|
|
945
|
-
|
|
946
|
-
**Lite adopter note (bassclef#740 Task 1.2).** Both hooks ship at `tier: standard`. Skip this step if your tier is lite. Resolve tier via `lib/tier-check.sh`. Continue with the next step.
|
|
947
|
-
|
|
948
|
-
Symlink two bassclef workflow hooks. `atomic-pr-check.sh` fires on Bash calls matching `git push` patterns and BLOCKs multi-step branches that lack `bundle: true` in the iteration goal's frontmatter — closes the silent atomic-PR-discipline gap that `.claude/rules/pr-strategy.md` describes. `post-write-trace.sh` fires on PostToolUse Write/Edit and records traceability rows so the agent can audit what wrote what.
|
|
949
|
-
|
|
950
|
-
Symlink both hooks:
|
|
951
|
-
|
|
952
|
-
```bash
|
|
953
|
-
mkdir -p .claude/hooks
|
|
954
|
-
ln -sf "../../../bassclef/.claude/hooks/atomic-pr-check.sh" \
|
|
955
|
-
".claude/hooks/atomic-pr-check.sh"
|
|
956
|
-
ln -sf "../../../bassclef/.claude/hooks/post-write-trace.sh" \
|
|
957
|
-
".claude/hooks/post-write-trace.sh"
|
|
958
|
-
```
|
|
959
|
-
|
|
960
|
-
Add a PreToolUse Bash block + a PostToolUse Write|Edit block to `.claude/settings.json`. The Bash matcher likely already exists from Phase 2.2.6 (destructive-command-guard) — append `atomic-pr-check` to its `hooks` array. The PostToolUse block is new for most adopters.
|
|
961
|
-
|
|
962
|
-
```jsonc
|
|
963
|
-
{
|
|
964
|
-
"hooks": {
|
|
965
|
-
"PreToolUse": [
|
|
966
|
-
{
|
|
967
|
-
"matcher": "Bash",
|
|
968
|
-
"hooks": [
|
|
969
|
-
{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/atomic-pr-check.sh" }
|
|
970
|
-
]
|
|
971
|
-
}
|
|
972
|
-
],
|
|
973
|
-
"PostToolUse": [
|
|
974
|
-
{
|
|
975
|
-
"matcher": "Write|Edit",
|
|
976
|
-
"hooks": [
|
|
977
|
-
{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/post-write-trace.sh" }
|
|
978
|
-
]
|
|
979
|
-
}
|
|
980
|
-
]
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
```
|
|
984
|
-
|
|
985
|
-
**Bet narrowing** — ticket #1142 (T9) also lists `post-skill-friction-check.sh`. The goal scopes this step to two hooks; the third deferred to a follow-on per goal shape.
|
|
986
|
-
|
|
987
|
-
**Composition rule** — when the Bash matcher already exists (Phase 2.2.6 wires destructive-command-guard on the same matcher), append `atomic-pr-check` to its `hooks` array; do not duplicate the matcher entry. Hook order within the Bash array does not matter for these two — destructive-command-guard and atomic-pr-check check different signals (destructive verbs vs git-push patterns) and never conflict on the same command.
|
|
988
|
-
|
|
989
|
-
**Rule propagation** — `.claude/rules/pr-strategy.md` (the methodology atomic-pr-check enforces) loads via `additionalDirectories`. No copy needed.
|
|
990
|
-
|
|
991
|
-
**Override paths** — `SKIP_ATOMIC_PR_CHECK=1 <command>` (logged via trace-helper) bypasses the atomic-PR gate for genuine bundle cases that the goal's `bundle: true` flag did not capture. `post-write-trace.sh` has no override — the trace is append-only and never blocks.
|
|
992
|
-
|
|
993
|
-
**Verify the wiring:**
|
|
994
|
-
|
|
995
|
-
```bash
|
|
996
|
-
# Sanity: both hooks executable + reachable
|
|
997
|
-
ls -l .claude/hooks/atomic-pr-check.sh .claude/hooks/post-write-trace.sh
|
|
998
|
-
|
|
999
|
-
# Sanity: pr-strategy rule reachable via additionalDirectories
|
|
1000
|
-
test -f ../bassclef/.claude/rules/pr-strategy.md && echo "pr-strategy reachable" || echo "NOT reachable"
|
|
1001
|
-
|
|
1002
|
-
# Sanity: settings.json has both hooks wired with correct matchers
|
|
1003
|
-
python3 -c "import json; d=json.load(open('.claude/settings.json')); \
|
|
1004
|
-
bash_hooks=[h.get('command','') for entry in d.get('hooks',{}).get('PreToolUse',[]) if entry.get('matcher')=='Bash' for h in entry.get('hooks',[])]; \
|
|
1005
|
-
post_hooks=[h.get('command','') for entry in d.get('hooks',{}).get('PostToolUse',[]) if 'Write' in entry.get('matcher','') or 'Edit' in entry.get('matcher','') for h in entry.get('hooks',[])]; \
|
|
1006
|
-
print('atomic-pr-check wired (PreToolUse Bash)' if any('atomic-pr-check' in c for c in bash_hooks) else 'NOT wired'); \
|
|
1007
|
-
print('post-write-trace wired (PostToolUse Write|Edit)' if any('post-write-trace' in c for c in post_hooks) else 'NOT wired')"
|
|
1008
|
-
```
|
|
1009
|
-
|
|
1010
|
-
Source: bassclef#1142 (this wiring step — T9, workflow chain). Sister rule: `.claude/rules/pr-strategy.md`. Follow-on: `post-skill-friction-check.sh` wire deferred from T9 goal scope.
|
|
1011
|
-
|
|
1012
|
-
##### 2.2.8 Wire testing-tier-enforce + allowlist (bassclef#1143 T10)
|
|
1013
|
-
|
|
1014
|
-
Symlink the bassclef testing-tier enforcer into adopter's `.claude/hooks/`. The hook covers Tier 0 through Tier 3. It does not register as its own PreToolUse entry. Instead it runs inside `pre-commit-gate.sh` from Phase 2.2.5. When an adopter edits a Tier 0 source file without touching its matching test file, `pre-commit-gate.sh` calls `testing-tier-enforce.sh`. The commit BLOCKs with a structured stderr message.
|
|
1015
|
-
|
|
1016
|
-
Symlink both the hook and the allowlist baseline:
|
|
1017
|
-
|
|
1018
|
-
```bash
|
|
1019
|
-
mkdir -p .claude/hooks
|
|
1020
|
-
ln -sf "../../../bassclef/.claude/hooks/testing-tier-enforce.sh" \
|
|
1021
|
-
".claude/hooks/testing-tier-enforce.sh"
|
|
1022
|
-
ln -sf "../../../bassclef/.claude/hooks/testing-tier-enforce-allowlist.txt" \
|
|
1023
|
-
".claude/hooks/testing-tier-enforce-allowlist.txt"
|
|
623
|
+
for r in sdlc-gates state-schema-validation testing-tier-config test-list-discipline \
|
|
624
|
+
test-sufficiency destructive-operations pattern-annotation pr-strategy; do
|
|
625
|
+
test -f ../bassclef/.claude/rules/${r}.md && echo "${r} reachable" || echo "${r} NOT reachable"
|
|
626
|
+
done
|
|
1024
627
|
```
|
|
1025
628
|
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
**Composition chain** — `pre-commit-gate.sh` (Phase 2.2.5) calls `testing-tier-enforce.sh` as one of its check steps. No new PreToolUse settings.json entry is needed; the hook fires whenever pre-commit-gate fires (PreToolUse Edit|Write|MultiEdit). This is the chained-composition pattern: Phase 2.2.5 wired the parent gate; Phase 2.2.8 plugs the tier-enforce check into the existing chain.
|
|
1029
|
-
|
|
1030
|
-
**Goal-vs-implementation note** — the goal 2026-06-18b WU-4 acceptance describes `testing-tier-enforce.sh` as "PreToolUse Edit|Write" wiring. The actual wiring is via pre-commit-gate composition (no separate matcher entry). Documented per the actual implementation.
|
|
1031
|
-
|
|
1032
|
-
**Rule propagation** — `.claude/rules/testing-tier-config.md` + `.claude/rules/test-list-discipline.md` + `.claude/rules/test-sufficiency.md` load via `additionalDirectories`. No copy needed.
|
|
629
|
+
**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.
|
|
1033
630
|
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
**Verify the wiring:**
|
|
631
|
+
Sanity check that the hook is reachable and composed into pre-commit-gate:
|
|
1037
632
|
|
|
1038
633
|
```bash
|
|
1039
|
-
# Sanity: hook + allowlist reachable
|
|
1040
634
|
ls -l .claude/hooks/testing-tier-enforce.sh .claude/hooks/testing-tier-enforce-allowlist.txt
|
|
1041
|
-
|
|
1042
|
-
# Sanity: pre-commit-gate composes testing-tier-enforce
|
|
1043
635
|
grep -q "testing-tier-enforce.sh" .claude/hooks/pre-commit-gate.sh \
|
|
1044
636
|
&& echo "tier-enforce composed in pre-commit-gate" \
|
|
1045
|
-
|| echo "NOT composed (pre-commit-gate may be stale;
|
|
1046
|
-
|
|
1047
|
-
# Sanity: testing-tier-config rule reachable
|
|
1048
|
-
test -f ../bassclef/.claude/rules/testing-tier-config.md && echo "tier-config rule reachable" || echo "NOT reachable"
|
|
1049
|
-
```
|
|
1050
|
-
|
|
1051
|
-
The `testing.path_matchers` seed (per-tech-stack defaults) lands in Phase 2.3.7 below — that is the step the goal flagged for operator-eyes design choices.
|
|
1052
|
-
|
|
1053
|
-
Source: bassclef#1143 (this wiring step — T10, iteration-2 BLOCKER). Sister rules: `.claude/rules/testing-tier-config.md` + `.claude/rules/test-list-discipline.md` + `.claude/rules/test-sufficiency.md`. Pairs with Phase 2.2.5 (pre-commit-gate parent chain).
|
|
1054
|
-
|
|
1055
|
-
##### 2.2.9 Verify test-discipline rules propagate to the adopter session (bassclef#1144 T11)
|
|
1056
|
-
|
|
1057
|
-
The two test-discipline rules propagate to the adopter session on their own. Those rules are `.claude/rules/test-list-discipline.md` (Beck's test list as planning artifact) and `.claude/rules/test-sufficiency.md` (10-criterion rubric per Myers + Hoare).
|
|
1058
|
-
|
|
1059
|
-
The `additionalDirectories: ["../bassclef"]` entry that Phase 2.2 wrote does the work. It tells Claude Code to load every file under bassclef's `.claude/rules/` into the adopter's session context at session-start.
|
|
1060
|
-
|
|
1061
|
-
No copy needed. No per-rule symlink needed.
|
|
1062
|
-
|
|
1063
|
-
This step is the explicit verification — without it, the install is silent and the adopter does not know the rules are live.
|
|
1064
|
-
|
|
1065
|
-
Verify the rules are reachable + loaded:
|
|
1066
|
-
|
|
1067
|
-
```bash
|
|
1068
|
-
# Sanity: both rule files reachable via additionalDirectories
|
|
1069
|
-
test -f ../bassclef/.claude/rules/test-list-discipline.md \
|
|
1070
|
-
&& echo "test-list-discipline reachable" \
|
|
1071
|
-
|| echo "test-list-discipline NOT reachable"
|
|
1072
|
-
test -f ../bassclef/.claude/rules/test-sufficiency.md \
|
|
1073
|
-
&& echo "test-sufficiency reachable" \
|
|
1074
|
-
|| echo "test-sufficiency NOT reachable"
|
|
1075
|
-
|
|
1076
|
-
# Sanity: settings.json carries the additionalDirectories entry
|
|
1077
|
-
python3 -c "import json; d=json.load(open('.claude/settings.json')); \
|
|
1078
|
-
dirs=d.get('permissions',{}).get('additionalDirectories',[]); \
|
|
1079
|
-
print('bassclef loaded via additionalDirectories' if '../bassclef' in dirs else 'NOT loaded — check Phase 2.2 wiring')"
|
|
637
|
+
|| echo "NOT composed (pre-commit-gate may be stale; re-run bassclef-sync)"
|
|
1080
638
|
```
|
|
1081
639
|
|
|
1082
|
-
**
|
|
640
|
+
**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:
|
|
1083
641
|
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
".claude/hooks/role-entry-gate.sh"
|
|
1104
|
-
```
|
|
1105
|
-
|
|
1106
|
-
Add to the PreToolUse Edit|Write|MultiEdit matcher block in `.claude/settings.json`. The matcher likely exists from earlier Phase 2.x steps (substrate-clarity-gate from 2.2.2, pattern-annotation-validate from 2.2.4, the parent gate chain from 2.2.5) — append `role-entry-gate` to its `hooks` array; do not duplicate the matcher entry.
|
|
1107
|
-
|
|
1108
|
-
```jsonc
|
|
1109
|
-
{
|
|
1110
|
-
"hooks": {
|
|
1111
|
-
"PreToolUse": [
|
|
1112
|
-
{
|
|
1113
|
-
"matcher": "Edit|Write|MultiEdit",
|
|
1114
|
-
"hooks": [
|
|
1115
|
-
{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/role-entry-gate.sh" }
|
|
1116
|
-
]
|
|
1117
|
-
}
|
|
1118
|
-
]
|
|
1119
|
-
}
|
|
1120
|
-
}
|
|
1121
|
-
```
|
|
1122
|
-
|
|
1123
|
-
**MVP scope** — the hook fires on source-code file extensions only (`.ts`, `.tsx`, `.js`, `.jsx`, `.py`, `.rb`, `.go`, `.rs`, `.java`, `.kt`, `.swift`, `.cs`, `.cpp`, `.c`, `.h`). Non-source paths pass through. Tightening per `tech_stack.lang` reading (so a Python adopter only fires on `.py`) is a follow-on; the safe default union catches the common cases.
|
|
1124
|
-
|
|
1125
|
-
**Marker writing** — the agent writes the marker once it enters the role. Marker shape:
|
|
1126
|
-
|
|
1127
|
-
```json
|
|
1128
|
-
{
|
|
1129
|
-
"role": "builder",
|
|
1130
|
-
"session_id": "<uuid from harness>",
|
|
1131
|
-
"entered_at": "<ISO 8601 UTC>"
|
|
1132
|
-
}
|
|
1133
|
-
```
|
|
1134
|
-
|
|
1135
|
-
A future `/role-entry` skill automates the marker write + persona load; until then, the agent writes the marker by hand after reading the persona file. The BLOCK message documents the exact one-liner.
|
|
1136
|
-
|
|
1137
|
-
**Composition rule** — when the Edit|Write|MultiEdit matcher block already exists, append `role-entry-gate` to its `hooks` array. Order within the array: place `role-entry-gate` AFTER substrate-clarity-gate + artifact-ingestion-gate + pattern-annotation-validate + pre-commit-gate + state-validate + multi-tenancy-check, so structural / format / state validation fires first; role-discipline check fires last. Role-entry is the methodology gate, not the structural gate — it should not run before the cheap structural checks pass.
|
|
1138
|
-
|
|
1139
|
-
**Override path** — `SKIP_ROLE_ENTRY=1 <command>` (logged via trace-helper). Use for one-shot scripts the operator runs without entering an agent role, OR when the adopter is on a workflow that does not map to bassclef's role taxonomy.
|
|
1140
|
-
|
|
1141
|
-
**Verify the wiring:**
|
|
1142
|
-
|
|
1143
|
-
```bash
|
|
1144
|
-
# Sanity: hook executable + reachable
|
|
1145
|
-
ls -l .claude/hooks/role-entry-gate.sh
|
|
1146
|
-
|
|
1147
|
-
# Sanity: agent personas reachable via additionalDirectories (the BLOCK message refers to them)
|
|
1148
|
-
test -f ~/.claude/agents/builder.md && echo "builder persona reachable" || echo "builder persona NOT reachable (user-level agents missing)"
|
|
1149
|
-
|
|
1150
|
-
# Sanity: settings.json has the hook wired under the Edit matcher
|
|
1151
|
-
python3 -c "import json; d=json.load(open('.claude/settings.json')); \
|
|
1152
|
-
hooks=[h.get('command','') for entry in d.get('hooks',{}).get('PreToolUse',[]) if 'Edit' in entry.get('matcher','') for h in entry.get('hooks',[])]; \
|
|
1153
|
-
print('role-entry-gate wired' if any('role-entry-gate' in c for c in hooks) else 'NOT wired')"
|
|
1154
|
-
```
|
|
1155
|
-
|
|
1156
|
-
**Not yet wired in bassclef** — this hook ships to the adopter via `/onboard-repo` first. Bassclef's own settings.json adds the hook in a follow-on once the marker convention has run in the wild for a few sessions and the multi-role matching follow-on lands.
|
|
1157
|
-
|
|
1158
|
-
Source: bassclef#1145 (this hook step — T13). Sister agent personas: `~/.claude/agents/builder.md` (MVP target) + `~/.claude/agents/architect.md` + `~/.claude/agents/reviewer.md` + `~/.claude/agents/designer.md` (follow-on coverage). Follow-on tickets: multi-role matching matrix + `/role-entry` skill + `state/markers/role/` schema authoring under `standards/state-spine.md`.
|
|
1159
|
-
|
|
1160
|
-
##### 2.2.11 Wire temperance-gate PreToolUse hook (bassclef#1147 T15)
|
|
1161
|
-
|
|
1162
|
-
Symlink the bassclef hook that fires the /temperance question at decision boundaries. MVP scope: one active trigger — "high-impact path edit". It catches edits to `.claude/`, `standards/`, `lib/state.sh`, and SKILL.md files when the session has no fresh temperance marker. Other triggers stay as stubs. Follow-on tickets will design them.
|
|
1163
|
-
|
|
1164
|
-
<!-- FKGL-EXEMPT: source ticket enumeration -->
|
|
1165
|
-
Sources: `2026-06-18b` WU-7 goal (explain-mode entry, chain-anchor entry, non-stacked-branch first edit, post-compaction recovery); ticket #1147 (N consecutive edits, substrate proposal without catalog browse, diagnose-repro marker absence).
|
|
1166
|
-
<!-- /FKGL-EXEMPT -->
|
|
1167
|
-
|
|
1168
|
-
The hook pairs with `pre-commit-gate.sh` from Phase 2.2.5. That hook handles the first edit on a branch that stands alone. This hook adds one more check. It catches edits to high-impact paths that the other hook misses.
|
|
1169
|
-
|
|
1170
|
-
Symlink the hook:
|
|
1171
|
-
|
|
1172
|
-
```bash
|
|
1173
|
-
mkdir -p .claude/hooks
|
|
1174
|
-
ln -sf "../../../bassclef/.claude/hooks/temperance-gate.sh" \
|
|
1175
|
-
".claude/hooks/temperance-gate.sh"
|
|
1176
|
-
```
|
|
1177
|
-
|
|
1178
|
-
Add to the PreToolUse Edit|Write|MultiEdit matcher block in `.claude/settings.json`. The matcher likely already exists; append `temperance-gate` to its `hooks` array. Order: place `temperance-gate` AFTER structural checks (substrate-clarity-gate, artifact-ingestion-gate, pattern-annotation-validate, pre-commit-gate, state-validate, multi-tenancy-check) and AFTER role-entry-gate. Methodology gate fires last; structural + role checks fire first.
|
|
1179
|
-
|
|
1180
|
-
```jsonc
|
|
1181
|
-
{
|
|
1182
|
-
"hooks": {
|
|
1183
|
-
"PreToolUse": [
|
|
1184
|
-
{
|
|
1185
|
-
"matcher": "Edit|Write|MultiEdit",
|
|
1186
|
-
"hooks": [
|
|
1187
|
-
{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/temperance-gate.sh" }
|
|
1188
|
-
]
|
|
1189
|
-
}
|
|
1190
|
-
]
|
|
1191
|
-
}
|
|
1192
|
-
}
|
|
1193
|
-
```
|
|
1194
|
-
|
|
1195
|
-
**Marker convention** — the hook reads `$CWD/state/markers/temperance/<session_id>.marker` (session-scoped) AND falls back to any existing marker under `state/markers/temperance/` (loose branch-scoped check; tighter matching-branch check is a follow-on). The temperance marker is written by the agent (or by `/temperance` skill invocation) once the right-thing / right-way questions have been answered.
|
|
1196
|
-
|
|
1197
|
-
**Marker shape:**
|
|
1198
|
-
|
|
1199
|
-
```json
|
|
1200
|
-
{
|
|
1201
|
-
"session_id": "<uuid from harness>",
|
|
1202
|
-
"entered_at": "<ISO 8601 UTC>",
|
|
1203
|
-
"question_answered": "yes"
|
|
1204
|
-
}
|
|
1205
|
-
```
|
|
1206
|
-
|
|
1207
|
-
**Override path** — `SKIP_TEMPERANCE_GATE=1 <command>` (logged via trace-helper). Use sparingly; the trigger is the point of the discipline.
|
|
1208
|
-
|
|
1209
|
-
**Verify the wiring:**
|
|
1210
|
-
|
|
1211
|
-
```bash
|
|
1212
|
-
# Sanity: hook executable + reachable
|
|
1213
|
-
ls -l .claude/hooks/temperance-gate.sh
|
|
1214
|
-
|
|
1215
|
-
# Sanity: temperance skill reachable via additionalDirectories
|
|
1216
|
-
test -f ../bassclef/.claude/skills/temperance/SKILL.md && echo "temperance skill reachable" || echo "NOT reachable"
|
|
1217
|
-
|
|
1218
|
-
# Sanity: settings.json has the hook wired under the Edit matcher
|
|
1219
|
-
python3 -c "import json; d=json.load(open('.claude/settings.json')); \
|
|
1220
|
-
hooks=[h.get('command','') for entry in d.get('hooks',{}).get('PreToolUse',[]) if 'Edit' in entry.get('matcher','') for h in entry.get('hooks',[])]; \
|
|
1221
|
-
print('temperance-gate wired' if any('temperance-gate' in c for c in hooks) else 'NOT wired')"
|
|
1222
|
-
```
|
|
1223
|
-
|
|
1224
|
-
**Not yet wired in bassclef** — adopters first; bassclef's own settings.json adds the hook in a follow-on once the MVP trigger has run in the wild for a few sessions and the trigger-taxonomy follow-on lands.
|
|
1225
|
-
|
|
1226
|
-
Source: bassclef#1147 (this hook step — T15). Sister skill: `.claude/skills/temperance/SKILL.md` (the methodology this gate enforces mechanically). Follow-on tickets: explain-mode + chain-anchor + post-compaction + non-stacked first edit + N consecutive edits + substrate proposal + diagnose-repro triggers + `standards/temperance-discipline.md` documenting the full trigger taxonomy.
|
|
642
|
+
| Hook | Override |
|
|
643
|
+
|---|---|
|
|
644
|
+
| turn-prose-kiss-check | (toggle via `prose_discipline.kiss_words_turn_prose: false` in bassclef-configs) |
|
|
645
|
+
| substrate-clarity-gate | `SKIP_SUBSTRATE_CLARITY=1` |
|
|
646
|
+
| artifact-ingestion-gate | `SKIP_ARTIFACT_INGESTION=1` |
|
|
647
|
+
| pattern-annotation-validate | `SKIP_PATTERN_ANNOTATION=1` |
|
|
648
|
+
| pre-commit-gate | `SKIP_PRE_COMMIT_GATE=1` |
|
|
649
|
+
| state-validate | `SKIP_STATE_VALIDATE=1` |
|
|
650
|
+
| destructive-command-guard | `SKIP_DESTRUCTIVE_GUARD=1` |
|
|
651
|
+
| multi-tenancy-check | `SKIP_MULTI_TENANCY_CHECK=1` |
|
|
652
|
+
| atomic-pr-check | `SKIP_ATOMIC_PR_CHECK=1` |
|
|
653
|
+
| post-write-trace | (none — append-only trace never blocks) |
|
|
654
|
+
| testing-tier-enforce | `SKIP_TESTING_TIER_ENFORCE=1` |
|
|
655
|
+
| role-entry-gate | `SKIP_ROLE_ENTRY=1` |
|
|
656
|
+
| temperance-gate | `SKIP_TEMPERANCE_GATE=1` |
|
|
657
|
+
|
|
658
|
+
**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.
|
|
659
|
+
|
|
660
|
+
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`.
|
|
1227
661
|
|
|
1228
662
|
##### 2.3 Create the project config file
|
|
1229
663
|
|
|
@@ -1244,7 +678,7 @@ for:
|
|
|
1244
678
|
If operator says "defer", scaffold with placeholders and `TODO:` markers
|
|
1245
679
|
so next session surfaces them.
|
|
1246
680
|
|
|
1247
|
-
##### 2.3.5 Write the bassclef-configs adopter-default seed
|
|
681
|
+
##### 2.3.5 Write the bassclef-configs adopter-default seed
|
|
1248
682
|
|
|
1249
683
|
Write `.claude/bassclef-configs.jsonc` with the adopter-default seed.
|
|
1250
684
|
Every downstream hook + skill reads from this file; without it, defaults
|
|
@@ -1336,7 +770,7 @@ Expect a single `valid` line. The file is now the single source of truth for ado
|
|
|
1336
770
|
|
|
1337
771
|
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).
|
|
1338
772
|
|
|
1339
|
-
##### 2.3.6 Discover and write the tech_stack block
|
|
773
|
+
##### 2.3.6 Discover and write the tech_stack block
|
|
1340
774
|
|
|
1341
775
|
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.
|
|
1342
776
|
|
|
@@ -1456,7 +890,7 @@ Expect `valid`. If the file fails to validate, revert the append, surface the sc
|
|
|
1456
890
|
- Phase 2.5 (security scanning) reads `tech_stack.lang` to seed the scanner adapter.
|
|
1457
891
|
- Future Phase 2.x for `hook_chain` reads stack signals to pick per-stack hook defaults.
|
|
1458
892
|
|
|
1459
|
-
##### 2.3.7 Seed testing.path_matchers per declared tech_stack
|
|
893
|
+
##### 2.3.7 Seed testing.path_matchers per declared tech_stack
|
|
1460
894
|
|
|
1461
895
|
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.
|
|
1462
896
|
|
|
@@ -1532,7 +966,7 @@ Expect a single `valid` line. The `testing.path_matchers` items must validate ag
|
|
|
1532
966
|
|
|
1533
967
|
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).
|
|
1534
968
|
|
|
1535
|
-
##### 2.3.8 Surface the wiki_sync toggle
|
|
969
|
+
##### 2.3.8 Surface the wiki_sync toggle
|
|
1536
970
|
|
|
1537
971
|
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.
|
|
1538
972
|
|
|
@@ -1561,7 +995,7 @@ The Phase 1 stub keeps this step minimal so the goal stays bounded. Adopters who
|
|
|
1561
995
|
|
|
1562
996
|
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.
|
|
1563
997
|
|
|
1564
|
-
##### 2.3.9 Write the onboard-repo state marker
|
|
998
|
+
##### 2.3.9 Write the onboard-repo state marker
|
|
1565
999
|
|
|
1566
1000
|
Write `.claude/state/onboard-repo.state.json` after Phase 2.3 has
|
|
1567
1001
|
populated the config file(s). The marker captures which mode was used,
|
|
@@ -1593,7 +1027,7 @@ pin all behavior including re-run history append.
|
|
|
1593
1027
|
Source: bassclef-upstream#664 (state marker for onboard-repo). Part of goal
|
|
1594
1028
|
`docs/iteration-bets/2026-07-08a-configs-ui-iteration-1.md` WU-4.
|
|
1595
1029
|
|
|
1596
|
-
##### 2.3.10 Wire the cron installer for auto-save
|
|
1030
|
+
##### 2.3.10 Wire the cron installer for auto-save
|
|
1597
1031
|
|
|
1598
1032
|
Goal 27b (PR #937) shipped `presence/install/schedule-auto-save.cron.sh` at
|
|
1599
1033
|
`tier: lite`. The installer writes a cron entry that fires
|
|
@@ -1651,7 +1085,7 @@ fires (Cloud Env / mobile / fresh sandboxes / CI). Schema codified at
|
|
|
1651
1085
|
`standards/bassclef-source-config.md`; validation hook at
|
|
1652
1086
|
`.claude/hooks/bassclef-source-config-validate.sh`.
|
|
1653
1087
|
|
|
1654
|
-
Before writing the file, prompt the adopter explicitly
|
|
1088
|
+
Before writing the file, prompt the adopter explicitly:
|
|
1655
1089
|
|
|
1656
1090
|
```
|
|
1657
1091
|
Bassclef can auto-pull the latest skills, rules, and agents into this
|
|
@@ -1765,7 +1199,7 @@ PY
|
|
|
1765
1199
|
Note: the Python merge re-serializes the file without comments. Operators
|
|
1766
1200
|
keep the schema-doc reference (`standards/bassclef-configs-schema.md`)
|
|
1767
1201
|
as the bassclef comment-bearing source; the on-disk file is the values.
|
|
1768
|
-
A follow-on
|
|
1202
|
+
A follow-on may add a comment-preserving JSONC writer.
|
|
1769
1203
|
|
|
1770
1204
|
INSTEAD of asking the operator to know the scanner names: the standard supplies the per-stack defaults; the operator confirms the stack choice only.
|
|
1771
1205
|
|
|
@@ -1819,7 +1253,7 @@ orientation into every session. The orientation names the gates, the
|
|
|
1819
1253
|
luminaries, the tier ladder, and the rules the agent should not break.
|
|
1820
1254
|
|
|
1821
1255
|
The orientation file lands in the adopter repo as a symlink into bassclef.
|
|
1822
|
-
The sync template Section 3d-bis writes the symlink
|
|
1256
|
+
The sync template Section 3d-bis writes the symlink.
|
|
1823
1257
|
Without this symlink, the import resolves only through `additionalDirectories`.
|
|
1824
1258
|
If that path breaks — rename, delete, corporate laptop with no sibling — the
|
|
1825
1259
|
import silently no-ops. The symlink closes that gap.
|
|
@@ -1864,7 +1298,7 @@ cp ~/src/sunj-labs/bassclef/templates/whereami-template.md \
|
|
|
1864
1298
|
Operator fills in phase + iteration section. If repo is fresh,
|
|
1865
1299
|
`phase: Inception` with `iteration_bet: none — new repo` is fine.
|
|
1866
1300
|
|
|
1867
|
-
#### Phase 3.5 — Optional: provision the deploy host + bootstrap secrets
|
|
1301
|
+
#### Phase 3.5 — Optional: provision the deploy host + bootstrap secrets
|
|
1868
1302
|
|
|
1869
1303
|
**Working directory: target repo.**
|
|
1870
1304
|
|
|
@@ -1884,7 +1318,7 @@ still supported).
|
|
|
1884
1318
|
| `/onboard-repo --full` | All of the above — substrate scaffolded + Amplify host provisioned + secrets audited in one dispatch. Recommended for new sunj-labs repos. |
|
|
1885
1319
|
| `/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. |
|
|
1886
1320
|
|
|
1887
|
-
##### Tier gate
|
|
1321
|
+
##### Tier gate
|
|
1888
1322
|
|
|
1889
1323
|
Three of the flags above dispatch skills that ship at `tier: standard`.
|
|
1890
1324
|
Lite adopters running the bassclef-lite tarball do not carry
|
|
@@ -1918,8 +1352,8 @@ graceful degrade.
|
|
|
1918
1352
|
##### Interactive prompt (when no flag)
|
|
1919
1353
|
|
|
1920
1354
|
After Phase 3 completes, agent surfaces follow-on prompts. Prompts are
|
|
1921
|
-
gated on artifact existence
|
|
1922
|
-
uses honest platform framing
|
|
1355
|
+
gated on artifact existence and the deploy-host prompt
|
|
1356
|
+
uses honest platform framing:
|
|
1923
1357
|
|
|
1924
1358
|
```bash
|
|
1925
1359
|
# Check for substrate.secrets.md (bassclef#961) — silently skip the
|
|
@@ -1991,7 +1425,7 @@ onboarding_secrets_skipped: true # set when operator answers 'skip'
|
|
|
1991
1425
|
`n` (decline-this-time) does NOT persist — re-runs re-prompt because the
|
|
1992
1426
|
operator didn't say skip-permanently.
|
|
1993
1427
|
|
|
1994
|
-
`Y` sets the per-platform provisioning indicator (e.g., `amplify_app_id`) on success. Chain pre-flight Check 6
|
|
1428
|
+
`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.
|
|
1995
1429
|
|
|
1996
1430
|
##### Composes with
|
|
1997
1431
|
|
|
@@ -2002,7 +1436,7 @@ operator didn't say skip-permanently.
|
|
|
2002
1436
|
| `/bind-subdomain <subdomain>` | Separate dispatch — not chained from /onboard-repo (subdomain choice is repo-specific; no good default). Run after deploy host provisioned. |
|
|
2003
1437
|
| `/launch` | First substantive dispatch after onboarding completes. Chain pre-flight Check 6 verifies the provisioning indicator before variant generation runs. |
|
|
2004
1438
|
|
|
2005
|
-
#### Phase 3.6 — Closing handoff
|
|
1439
|
+
#### Phase 3.6 — Closing handoff
|
|
2006
1440
|
|
|
2007
1441
|
After Phase 3 (and Phase 3.5 if any flag fired), Path A surfaces a
|
|
2008
1442
|
closing handoff. Two templates — adopter-mode and operator-mode —
|