@thebassclef/lite 1.9.16 → 1.9.19
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/README.md +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/lite/.claude/agents/builder.md +7 -4
- package/dist/lite/.claude/bassclef-orientation.md +22 -0
- package/dist/lite/.claude/hooks/artifact-ingestion-gate.sh +11 -3
- package/dist/lite/.claude/hooks/assert-verify-steering.sh +1 -19
- package/dist/lite/.claude/hooks/plain-english-steering.sh +86 -41
- package/dist/lite/.claude/hooks/pre-commit-gate.sh +10 -2
- package/dist/lite/.claude/hooks/pre-push-shellcheck.sh +196 -0
- package/dist/lite/.claude/hooks/reviewer-dispatch-check.sh +153 -0
- package/dist/lite/.claude/hooks/session-reflection.d/83-install-written-paths-rebuild.sh +15 -32
- package/dist/lite/.claude/hooks/turn-prose-density-measure.sh +109 -0
- package/dist/lite/.claude/hooks/turn-prose-kiss-check.sh +28 -0
- package/dist/lite/.claude/rules/branching.md +2 -0
- package/dist/lite/.claude/rules/identifier-leak-prevention.md +2 -1
- package/dist/lite/.claude/rules/install-written-paths-mediation.md +7 -0
- package/dist/lite/.claude/rules/lite-manifest-schema-change-discipline.md +23 -0
- package/dist/lite/.claude/rules/reviewer-dispatch.md +95 -0
- package/dist/lite/.claude/settings.json +10 -0
- package/dist/lite/.claude/skills/build/SKILL.md +81 -6
- package/dist/lite/.claude/skills/eisenhower/SKILL.md +26 -0
- package/dist/lite/.claude/skills/launch/SKILL.md +45 -2
- package/dist/lite/.claude/skills/onboard-repo/SKILL.md +208 -40
- package/dist/lite/.claude/skills/onboard-repo/claude-oauth-probe.sh +60 -0
- package/dist/lite/.claude/skills/onboard-repo/concise-prompt.sh +73 -0
- package/dist/lite/.claude/skills/onboard-repo/write-state-marker.sh +81 -0
- package/dist/lite/.claude/skills/pre-mortem/SKILL.md +56 -0
- package/dist/lite/.claude/skills/sprint/SKILL.md +24 -3
- package/dist/lite/.claude/skills/temperance/SKILL.md +15 -4
- package/dist/lite/README.md +2 -0
- package/dist/lite/bassclef-version.json +5 -5
- package/dist/lite/lib/install-written-paths.sh +250 -3
- package/dist/lite/lib/prose-marker.sh +203 -0
- package/dist/lite/lib/tier-dependency-audit.sh +52 -25
- package/dist/lite/presence/install/bassclef-sync.template.sh +86 -8
- package/dist/lite/presence/install/schedule-auto-save.cron.sh +30 -2
- package/dist/lite/scripts/generate-lite-manifest.sh +15 -0
- package/dist/lite/scripts/launch/local-serve.sh +149 -8
- package/dist/lite/standards/bassclef-wiring-manifest.json +12 -0
- package/dist/lite/standards/lite-manifest-schema-changes.md +84 -0
- package/dist/lite/standards/lite-manifest.json +100 -29
- package/dist/lite/standards/prose-marker-format.md +105 -0
- package/package.json +1 -1
|
@@ -214,13 +214,28 @@ if echo "$@" | grep -q -- '--explain'; then
|
|
|
214
214
|
EXPLAIN_MODE=true
|
|
215
215
|
fi
|
|
216
216
|
|
|
217
|
-
# Resolve goal via accessor
|
|
217
|
+
# Resolve goal via accessor. #2132 — capture stderr so parse errors surface
|
|
218
|
+
# instead of masquerading as "not found". Map accessor return codes:
|
|
219
|
+
# 1 → goal file not found; 3 → goal file could not be parsed.
|
|
218
220
|
source lib/state.sh
|
|
219
221
|
BET_SLUG="$1"
|
|
220
|
-
BET_JSON=$(state_iteration_bet_get "$BET_SLUG" 2
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
222
|
+
BET_JSON=$(state_iteration_bet_get "$BET_SLUG" 2>&1)
|
|
223
|
+
BET_RC=$?
|
|
224
|
+
if [ "$BET_RC" -ne 0 ]; then
|
|
225
|
+
case "$BET_RC" in
|
|
226
|
+
1)
|
|
227
|
+
echo "/build: goal file not found: $BET_SLUG" >&2
|
|
228
|
+
;;
|
|
229
|
+
3)
|
|
230
|
+
echo "/build: goal file could not be parsed: $BET_SLUG" >&2
|
|
231
|
+
;;
|
|
232
|
+
*)
|
|
233
|
+
echo "/build: goal '$BET_SLUG' lookup failed (rc=$BET_RC)" >&2
|
|
234
|
+
;;
|
|
235
|
+
esac
|
|
236
|
+
echo "$BET_JSON" >&2
|
|
237
|
+
exit "$BET_RC"
|
|
238
|
+
fi
|
|
224
239
|
|
|
225
240
|
# Check status active
|
|
226
241
|
STATUS=$(echo "$BET_JSON" | jq -r '.status // empty')
|
|
@@ -234,6 +249,15 @@ SPEC_PATH=$(echo "$BET_JSON" | jq -r '.references[]? | select(.type == "spec") |
|
|
|
234
249
|
DECOMP_PATH=$(echo "$BET_JSON" | jq -r '.references[]? | select(.type == "decomposition") | .id // empty')
|
|
235
250
|
UX_MIG_PATH=$(echo "$BET_JSON" | jq -r '.references[]? | select(.type == "ux-migration") | .id // empty')
|
|
236
251
|
|
|
252
|
+
# #2132 — goal MUST declare a spec reference. Empty SPEC_PATH means Phase 1
|
|
253
|
+
# would awk against docs/specs/.md and silently find nothing; cure refuses
|
|
254
|
+
# at Phase 0 instead with a clear error.
|
|
255
|
+
if [ -z "$SPEC_PATH" ]; then
|
|
256
|
+
echo "/build: goal '$BET_SLUG' has no spec reference — refusing" >&2
|
|
257
|
+
echo "Add a {type: spec, id: <spec-slug>} entry to goal frontmatter references[]." >&2
|
|
258
|
+
exit 4
|
|
259
|
+
fi
|
|
260
|
+
|
|
237
261
|
# Validate references exist
|
|
238
262
|
for ref_type in spec decomposition; do
|
|
239
263
|
ref_id=$(echo "$BET_JSON" | jq -r --arg t "$ref_type" '.references[]? | select(.type == $t) | .id // empty')
|
|
@@ -349,6 +373,16 @@ WU_LIST=$(awk '
|
|
|
349
373
|
|
|
350
374
|
# Each step should reference at least one story (US-NNN)
|
|
351
375
|
WU_COUNT=$(echo "$WU_LIST" | grep -cE '^### (Step|WU)-' || echo 0)
|
|
376
|
+
|
|
377
|
+
# #2132 — refuse zero-step specs. The Phase 2 orphan check does not fire
|
|
378
|
+
# on empty WU_LIST (no steps → no orphans → silent pass). Phase 1 refuses
|
|
379
|
+
# so adopters see the real problem.
|
|
380
|
+
if [ "$WU_COUNT" = "0" ]; then
|
|
381
|
+
echo "/build: spec has zero steps — refusing" >&2
|
|
382
|
+
echo "Spec file: $SPEC_FILE" >&2
|
|
383
|
+
echo "Need a Steps enumerated section with Step-N or WU-N entries." >&2
|
|
384
|
+
exit 4
|
|
385
|
+
fi
|
|
352
386
|
```
|
|
353
387
|
|
|
354
388
|
Build structured object: `{ bet, spec_path, decomp_path, ux_migration_path, wus[] }`.
|
|
@@ -483,6 +517,23 @@ Operator can force adopter-mode via `--adopter-mode` flag (V2). Operator can for
|
|
|
483
517
|
|
|
484
518
|
### Phase 3 — DryRunPlanner
|
|
485
519
|
|
|
520
|
+
**Read the pre-mortem marker first (per bassclef-upstream#2175 Batch B — F5).** Before enumerating steps, read `state/markers/pre-mortem/<branch-slug>.marker` if present. The marker names the risk ledger file plus top-5 risks. Surface the ledger path + top-5 risks in the dry-run output. Builder dispatches in future LIVE mode read the ledger before writing code.
|
|
521
|
+
|
|
522
|
+
<!-- FKGL-EXEMPT: bash command block; shell commands are not graded prose. -->
|
|
523
|
+
|
|
524
|
+
```bash
|
|
525
|
+
BRANCH_SLUG=$(git branch --show-current | tr '/' '-')
|
|
526
|
+
MARKER="state/markers/pre-mortem/${BRANCH_SLUG}.marker"
|
|
527
|
+
if [ -f "$MARKER" ]; then
|
|
528
|
+
echo "Pre-mortem ledger — reading top-5 risks:"
|
|
529
|
+
cat "$MARKER"
|
|
530
|
+
fi
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
<!-- /FKGL-EXEMPT -->
|
|
534
|
+
|
|
535
|
+
When the marker is absent, `/build` emits a one-line note that no pre-mortem fired for this branch and proceeds. `/pre-mortem` is mandatory on always-fire domains per its SKILL body; Phase 3 does not re-enforce that gate.
|
|
536
|
+
|
|
486
537
|
Walk step enumeration; for each, plan what would happen in live mode:
|
|
487
538
|
|
|
488
539
|
```
|
|
@@ -534,6 +585,8 @@ TODO: live execution — operator-supervised first run only.
|
|
|
534
585
|
- Operator-tap moments: 1 (prod deploy approval via GitHub Environment)
|
|
535
586
|
```
|
|
536
587
|
|
|
588
|
+
<!-- FKGL-EXEMPT: Phase 4 stub — technical dispatch TODO; OOAD artifact names + branch slug template resist short SVO rewrites. Per bassclef-upstream#2175 Batch A — slug canon matches Phase 3. -->
|
|
589
|
+
|
|
537
590
|
### Phase 4 — BuilderDispatcher (LIVE — STUBBED)
|
|
538
591
|
|
|
539
592
|
**Amendment per #1171 — Builder inputs name OOAD artifacts.**
|
|
@@ -545,7 +598,7 @@ TODO: live execution — operator-supervised first run only. Would:
|
|
|
545
598
|
dispatch Builder against step <slug> with context from spec section
|
|
546
599
|
<X> + decomp matrix entry <Y> + paired OOAD artifacts (decomposition
|
|
547
600
|
+ interaction-design + use-case per goal doc references). Branch:
|
|
548
|
-
feature/<goal-slug>-stack-<N>.
|
|
601
|
+
feature/<goal-slug>-stack-<N>-<wu-slug>.
|
|
549
602
|
```
|
|
550
603
|
|
|
551
604
|
The string `TODO: live execution` is grep-able for audit. Live mode
|
|
@@ -556,6 +609,10 @@ in the goal doc `references` array — decomposition (grep for
|
|
|
556
609
|
`type: interaction-design`), use-case (grep for `type: use-case`).
|
|
557
610
|
Per #1171 — every OOAD artifact consulted for any engineering change.
|
|
558
611
|
|
|
612
|
+
<!-- /FKGL-EXEMPT -->
|
|
613
|
+
|
|
614
|
+
<!-- FKGL-EXEMPT: Phase 5 stub + Phase 5a Reviewer dispatch — technical TODO blocks for live-mode scaffolding. F10 cure per bassclef-upstream#2175 Batch D. -->
|
|
615
|
+
|
|
559
616
|
### Phase 5 — VerifyOrchestrator (LIVE — STUBBED)
|
|
560
617
|
|
|
561
618
|
Tonight emits literal:
|
|
@@ -566,6 +623,24 @@ Match change type (UI smoke / unit / integration) and BLOCK on
|
|
|
566
623
|
failure with line-numbered output.
|
|
567
624
|
```
|
|
568
625
|
|
|
626
|
+
### Phase 5a — Reviewer dispatch (per bassclef-upstream#2175 Batch D — F10)
|
|
627
|
+
|
|
628
|
+
After `/verify` passes, Phase 5 adds a Reviewer dispatch step. Running `/verify` alone catches test failures. The Reviewer agent (`.claude/agents/reviewer.md`) catches spec-acceptance drift, missing-test patterns, ADR deviations, and friction the Builder did not surface. One review step per PR before merge.
|
|
629
|
+
|
|
630
|
+
Tonight emits literal:
|
|
631
|
+
|
|
632
|
+
```
|
|
633
|
+
TODO: live execution — would dispatch Reviewer agent against branch <name>.
|
|
634
|
+
Reviewer reads: spec acceptance criteria, decomposition matrix entry, PR
|
|
635
|
+
body friction report. Reviewer writes: state/markers/reviewer/<branch>.md
|
|
636
|
+
with PASS / FAIL / NOTE findings. BLOCK merge on FAIL; NOTE findings file
|
|
637
|
+
as follow-on tickets.
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
The Reviewer dispatch is MANDATORY per `.claude/rules/reviewer-dispatch.md` for any session shipping source code. Phase 5a is the Phase-level wiring. Live mode consumes the Reviewer marker before Phase 6 opens the PR.
|
|
641
|
+
|
|
642
|
+
<!-- /FKGL-EXEMPT -->
|
|
643
|
+
|
|
569
644
|
### Phase 5.5 — Amendment B2: /pattern-review trigger reads decomposition (per #1150 + #1167)
|
|
570
645
|
|
|
571
646
|
When the goal references a decomposition doc AND that doc contains `@pattern` references, dispatch `/pattern-review` with the decomposition path as input. Skip when the decomposition names no `@pattern`. Contract per `.claude/rules/pattern-annotation.md` L57-62.
|
|
@@ -151,6 +151,32 @@ Individual items: ...
|
|
|
151
151
|
- #127 — title — no path to advance the goal — CLOSE
|
|
152
152
|
```
|
|
153
153
|
|
|
154
|
+
### Step 4b — Emit the hard stack rank
|
|
155
|
+
|
|
156
|
+
After the per-quadrant tables, emit one final table. Columns fixed:
|
|
157
|
+
|
|
158
|
+
1. **Rank** — 1 to N, cross-repo, top-down
|
|
159
|
+
2. **Ticket** — `<repo>#<number>` form
|
|
160
|
+
3. **Repo** — the owning repo. Bold the repo name when work ships somewhere other than the filed repo.
|
|
161
|
+
4. **Why this rank** — one plain-English sentence. Grade-8 target. Cite the Depen. tie or class fit.
|
|
162
|
+
|
|
163
|
+
Row order:
|
|
164
|
+
|
|
165
|
+
- Q1 first, then Q2, then Q3, then Q4
|
|
166
|
+
- Within quadrant, sort by Depen. first (independents at top), then class, then ticket number
|
|
167
|
+
- Flag cross-repo work in the Repo column
|
|
168
|
+
|
|
169
|
+
Example row shape:
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
| Rank | Ticket | Repo | Why this rank |
|
|
173
|
+
|------|--------|-------------------|--------------------------------------|
|
|
174
|
+
| 1 | #2008 | **bassclef-web** | Q1 lead. Live Sam bounce. |
|
|
175
|
+
| 2 | #2011 | **bassclef-web** | Q1 rider. Same PR as #2008. |
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Per bassclef-upstream#2096 amendment 3.
|
|
179
|
+
|
|
154
180
|
### Step 5 — Optional follow-on
|
|
155
181
|
|
|
156
182
|
If Q3 surfaces 5+ items in the same shape, the skill offers to draft one `/promote` ticket. That ticket proposes automating the class. You accept, edit, or skip.
|
|
@@ -264,6 +264,8 @@ fi
|
|
|
264
264
|
|
|
265
265
|
**Local mode (`--local`) — bassclef#923 A2:**
|
|
266
266
|
|
|
267
|
+
**Issue-per-branch exemption (per bassclef-upstream#2175 Batch A — F2).** `/launch --local` creates adopter prototype branches that are exempt from the `.claude/rules/branching.md` "every branch ties to a GitHub Issue" rule. Local prototype mode exists for adopters who do not yet have a GitHub repo. No issue is required for `--local` branches. All other `/launch` modes (full, scratch, operator-mode) still require an issue.
|
|
268
|
+
|
|
267
269
|
`/launch --local` prints a banner first. The banner shows which picker is active:
|
|
268
270
|
|
|
269
271
|
```
|
|
@@ -546,6 +548,43 @@ The gallery is THE cameo-review surface. Luminary perspectives
|
|
|
546
548
|
agent runtime per roadmap Stage 3) consume the gallery + spec + decomp
|
|
547
549
|
to produce reviews per perspective. Reviews surface in PR body.
|
|
548
550
|
|
|
551
|
+
### Phase 10a — Stack-choice ask (per bassclef-upstream#2175 Batch D — F13)
|
|
552
|
+
|
|
553
|
+
<!-- FKGL-EXEMPT: Phase 10a — technical ask step with config-key contract. Short SVO loses the stack-key list. Fires before Phase 11 /ux-migration so the migration plan picks the right adapter. -->
|
|
554
|
+
|
|
555
|
+
Before Phase 11 runs, ask the operator which frontend stack the migration targets. Today `/launch` silently assumes Next.js — nine SKILL bodies lean on Next.js examples. Non-React adopters hit the silent pick at Phase 11 and must rework. The ask fires once per `/launch` dispatch; the answer writes to `substrate.config.md` key `frontend_stack` for Phase 11 to read.
|
|
556
|
+
|
|
557
|
+
Read `substrate.config.md` for `frontend_stack`. If set, skip the ask. If unset, ask:
|
|
558
|
+
|
|
559
|
+
```
|
|
560
|
+
Which stack is this app?
|
|
561
|
+
|
|
562
|
+
a. Next.js — React + App Router (bassclef default; nine SKILL bodies lean on Next.js examples)
|
|
563
|
+
b. Vite + React — React + Vite dev server
|
|
564
|
+
c. Remix — React + Remix
|
|
565
|
+
d. SvelteKit — Svelte + Kit
|
|
566
|
+
e. SolidStart — Solid + Start
|
|
567
|
+
f. none — static HTML + CSS, no framework
|
|
568
|
+
g. other — operator names it
|
|
569
|
+
|
|
570
|
+
[a-g]
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
Write the answer to `substrate.config.md` `frontend_stack`:
|
|
574
|
+
- `a` → `frontend_stack: nextjs`
|
|
575
|
+
- `b` → `frontend_stack: vite-react`
|
|
576
|
+
- `c` → `frontend_stack: remix`
|
|
577
|
+
- `d` → `frontend_stack: sveltekit`
|
|
578
|
+
- `e` → `frontend_stack: solidstart`
|
|
579
|
+
- `f` → `frontend_stack: none`
|
|
580
|
+
- `g` → `frontend_stack: <operator-named>`
|
|
581
|
+
|
|
582
|
+
Default on Enter → `a` (Next.js) to preserve the historical silent pick. Operator can edit `substrate.config.md` directly at any time.
|
|
583
|
+
|
|
584
|
+
Phase 11 reads `frontend_stack` and picks the matching migration adapter. When unset at Phase 11 fire, Phase 11 BLOCKs with a one-line note citing this ask.
|
|
585
|
+
|
|
586
|
+
<!-- /FKGL-EXEMPT -->
|
|
587
|
+
|
|
549
588
|
### Phase 11 — `/ux-migration` (chosen variant → production migration plan)
|
|
550
589
|
|
|
551
590
|
```bash
|
|
@@ -699,8 +738,8 @@ Two templates — adopter-mode and operator-mode. Default is adopter when `--loc
|
|
|
699
738
|
After Phase 12-alt (`local-serve.sh` running) + Phase 13 (preview-state.yml on disk), emit this template directly to the adopter — no YAML edits, no frontmatter flip, no command-soup:
|
|
700
739
|
|
|
701
740
|
```
|
|
702
|
-
I made you N directions for your family recipe wiki. Walk through them
|
|
703
|
-
|
|
741
|
+
I made you N directions for your family recipe wiki. Walk through them
|
|
742
|
+
on this computer at <LOCAL_URL> and tell me which one feels right.
|
|
704
743
|
|
|
705
744
|
When you've picked, just tell me — "I like variant 2" or "#3 looks
|
|
706
745
|
great".
|
|
@@ -740,8 +779,12 @@ None of them feel right? Tell me what's off and I'll generate new
|
|
|
740
779
|
directions for you. (See /launch --refine, bassclef#942.)
|
|
741
780
|
```
|
|
742
781
|
|
|
782
|
+
<!-- FKGL-EXEMPT: substitution instructions name three distinct placeholders; short SVO loses the mapping precision -->
|
|
743
783
|
Substitute `<LOCAL_URL>` with the URL returned by Phase 12-alt. Substitute the actual variant count (`I made you N directions...`). Substitute the actual app description (`your family recipe wiki` etc.) from the InputArtifact's `intent` field.
|
|
744
784
|
|
|
785
|
+
**Phone or iPad reach — opt-in with `--lan`.** The default URL binds `127.0.0.1`. Only this computer can open it. The adopter may want the gallery on a phone or iPad on the same Wi-Fi. Re-run Phase 12-alt with `--lan`: `bash scripts/launch/local-serve.sh --lan <gallery-dir>`. The script binds `0.0.0.0` and prints a one-line warning. Any device on the Wi-Fi can then reach the URL. Swap the handoff line to "on your phone, laptop, or iPad at <LOCAL_URL>" when `--lan` fires.
|
|
786
|
+
<!-- /FKGL-EXEMPT -->
|
|
787
|
+
|
|
745
788
|
The adopter-mode template **surfaces** (per bassclef#969):
|
|
746
789
|
- The formal artifacts the chain will produce post-pick, in plain English (use case, user stories, IA, interaction design, responsibility map, build spec, migration plan)
|
|
747
790
|
- The chain-ordering rationale (variants are cheap shared data; formal artifacts are expensive per-direction; cheap first → commit → expensive once)
|
|
@@ -356,7 +356,82 @@ this divider.
|
|
|
356
356
|
Run each phase in order. Operator confirms before destructive or
|
|
357
357
|
cross-repo actions. Each phase is independently re-runnable.
|
|
358
358
|
|
|
359
|
-
#### Phase 0 —
|
|
359
|
+
#### Phase 0 — Preflight checks (OAuth, git identity, branch)
|
|
360
|
+
|
|
361
|
+
Phase 0 bundles three cheap preflight checks before any Phase 1 work runs. The checks fire together so adopter sees all gaps at once, not one at a time. Per bassclef-upstream#2242 preflight-first SKILL design + folds C1 + C4 from the 2026-10-14 pre-mortem.
|
|
362
|
+
|
|
363
|
+
##### 0.1 Claude OAuth probe (per bassclef-upstream#2233)
|
|
364
|
+
|
|
365
|
+
Cold adopters have hit `/onboard-repo` with expired OAuth tokens. The skill wastes an orientation turn, then returns `Login expired · Please run /login`. The adopter re-fires the skill after login. Preflight the probe so the login prompt lands before any phase work.
|
|
366
|
+
|
|
367
|
+
Run the cheap-hello pattern (per memory `feedback_oauth_verify_via_cheap_hello`):
|
|
368
|
+
|
|
369
|
+
```bash
|
|
370
|
+
if ! command -v claude >/dev/null 2>&1; then
|
|
371
|
+
cat >&2 <<'EOF'
|
|
372
|
+
|
|
373
|
+
🛑 /onboard-repo preflight — Claude CLI not found on PATH.
|
|
374
|
+
|
|
375
|
+
Install Claude Code first. Then re-fire /onboard-repo.
|
|
376
|
+
|
|
377
|
+
EOF
|
|
378
|
+
exit 1
|
|
379
|
+
fi
|
|
380
|
+
|
|
381
|
+
<!-- FKGL-EXEMPT: shell command with long path reads as a single dense "sentence" to the grader; backtick-safe here per bassclef-upstream#2255 -->
|
|
382
|
+
if ! bash "$CLAUDE_PROJECT_DIR/.claude/skills/onboard-repo/claude-oauth-probe.sh" 10; then
|
|
383
|
+
cat >&2 <<'EOF'
|
|
384
|
+
|
|
385
|
+
🛑 /onboard-repo preflight — Claude OAuth check failed.
|
|
386
|
+
|
|
387
|
+
Run `/login` first. Then re-fire `/onboard-repo`.
|
|
388
|
+
|
|
389
|
+
EOF
|
|
390
|
+
exit 1
|
|
391
|
+
fi
|
|
392
|
+
<!-- /FKGL-EXEMPT -->
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
Two checks: binary on PATH, then OAuth probe. Cost: ~2s on green path. The probe is portable. Closes bassclef-upstream#2255.
|
|
396
|
+
|
|
397
|
+
##### 0.2 Git identity preflight (per bassclef-upstream#2232)
|
|
398
|
+
|
|
399
|
+
`/onboard-repo` runs commit paths in Phase 2. Git fails with `Author identity unknown` when `user.name` or `user.email` is unset. The adopter sees the gap mid-flow and has to answer a 3-option prompt. Preflight the check so the question lands here, not later.
|
|
400
|
+
|
|
401
|
+
```bash
|
|
402
|
+
GIT_NAME=$(git config --get user.name 2>/dev/null || echo "")
|
|
403
|
+
GIT_EMAIL=$(git config --get user.email 2>/dev/null || echo "")
|
|
404
|
+
|
|
405
|
+
if [ -z "$GIT_NAME" ] || [ -z "$GIT_EMAIL" ]; then
|
|
406
|
+
cat >&2 <<'EOF'
|
|
407
|
+
|
|
408
|
+
🛑 /onboard-repo preflight — git identity not set.
|
|
409
|
+
|
|
410
|
+
Pick one option (then re-fire /onboard-repo):
|
|
411
|
+
|
|
412
|
+
1. GitHub no-reply address (private, derived from `gh api user`):
|
|
413
|
+
(requires `gh auth login` first — see Prerequisites)
|
|
414
|
+
GH_USER=$(gh api user --jq .login)
|
|
415
|
+
GH_ID=$(gh api user --jq .id)
|
|
416
|
+
git config --global user.name "$GH_USER"
|
|
417
|
+
git config --global user.email "${GH_ID}+${GH_USER}@users.noreply.github.com"
|
|
418
|
+
|
|
419
|
+
2. Your own name + email:
|
|
420
|
+
git config --global user.name "Your Name"
|
|
421
|
+
git config --global user.email "you@example.com"
|
|
422
|
+
|
|
423
|
+
3. Fixture smoke (keep repo-local identity for test runs):
|
|
424
|
+
git config user.name "fixture"
|
|
425
|
+
git config user.email "fixture@localhost"
|
|
426
|
+
|
|
427
|
+
EOF
|
|
428
|
+
exit 1
|
|
429
|
+
fi
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
Three options cover the common paths. GitHub no-reply is private and matches the pattern bassclef uses for its own commits.
|
|
433
|
+
|
|
434
|
+
##### 0.3 Refuse to run from main
|
|
360
435
|
|
|
361
436
|
Substrate changes go through PRs, same as feature work. If `/onboard-repo`
|
|
362
437
|
runs from `main`, every scaffold (`.claude/`, `CLAUDE.md`,
|
|
@@ -427,6 +502,59 @@ operator-decision items.
|
|
|
427
502
|
|
|
428
503
|
Idempotent API calls against the target repo via `gh`.
|
|
429
504
|
|
|
505
|
+
##### 1.0a Repo-name collision helper (per bassclef-upstream#2236)
|
|
506
|
+
|
|
507
|
+
When an agent or adopter runs `gh repo create` on behalf of `/onboard-repo` and the name is taken, iterate the suffix one-by-one is slow. A cold adopter on 2026-10-13 hit three round-trips before landing on `-4`. Enumerate the taken set in ONE call. Propose the lowest free name up front.
|
|
508
|
+
|
|
509
|
+
Use this helper whenever the flow creates a new repo:
|
|
510
|
+
|
|
511
|
+
```bash
|
|
512
|
+
basename="bassclef-smoke-test" # or whatever the adopter picked
|
|
513
|
+
owner=$(gh api user --jq .login)
|
|
514
|
+
|
|
515
|
+
# Pull every repo under $owner starting with $basename in ONE call
|
|
516
|
+
taken=$(gh repo list "$owner" --json name --jq "[.[].name | select(startswith(\"$basename\"))] | sort" 2>/dev/null)
|
|
517
|
+
|
|
518
|
+
# Find lowest free suffix
|
|
519
|
+
suffix=""
|
|
520
|
+
for i in '' $(seq 2 100); do
|
|
521
|
+
candidate="${basename}$([ -n "$i" ] && echo "-$i")"
|
|
522
|
+
if ! jq -e --arg c "$candidate" '.[] | select(. == $c)' <<<"$taken" >/dev/null 2>&1; then
|
|
523
|
+
suffix="$i"
|
|
524
|
+
break
|
|
525
|
+
fi
|
|
526
|
+
done
|
|
527
|
+
|
|
528
|
+
proposed="${basename}$([ -n "$suffix" ] && echo "-$suffix")"
|
|
529
|
+
echo "Taken under $owner matching ${basename}*: $taken"
|
|
530
|
+
echo "Proposed free name: $proposed"
|
|
531
|
+
echo "Accept '$proposed'? Or type your own:"
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
One `gh repo list` call enumerates every conflict. One prompt proposes the next free name. Adopter accepts or renames in one turn.
|
|
535
|
+
|
|
536
|
+
##### 1.0 Write the temperance marker up-front (per bassclef-upstream#2237)
|
|
537
|
+
|
|
538
|
+
`/onboard-repo` is the scope decision. Running it means the operator picked this plan. The `pre-build-gate.sh` BLOCK on first Edit is a false positive. The scope landed at skill dispatch, not mid-skill.
|
|
539
|
+
|
|
540
|
+
Write the marker now, before any Edit tool call fires:
|
|
541
|
+
|
|
542
|
+
```bash
|
|
543
|
+
mkdir -p state/markers/temperance
|
|
544
|
+
BRANCH=$(git branch --show-current)
|
|
545
|
+
cat > "state/markers/temperance/${BRANCH}.marker" <<EOF
|
|
546
|
+
# Temperance marker — /onboard-repo
|
|
547
|
+
- date: $(date -u +%Y-%m-%d)
|
|
548
|
+
- branch: ${BRANCH}
|
|
549
|
+
- scope-decision: scaffold bassclef setup via /onboard-repo
|
|
550
|
+
- right-thing: adopter needs .claude/ + .gitignore + .bassclef/ wiring
|
|
551
|
+
- right-way: idempotent API calls + file writes contained to adopter repo
|
|
552
|
+
- drift-trigger: operator asks for scope outside the standard bootstrap set
|
|
553
|
+
EOF
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
The marker satisfies `pre-build-gate.sh` at the right scope boundary. Phase 2's first Edit (settings.json, bassclef-configs.jsonc, .gitignore) proceeds clean. No mid-flow BLOCK banner.
|
|
557
|
+
|
|
430
558
|
##### 1.1 Create the 11 standard labels
|
|
431
559
|
|
|
432
560
|
```bash
|
|
@@ -462,31 +590,33 @@ immediately without waiting for a sync cycle.
|
|
|
462
590
|
|
|
463
591
|
##### 1.2 Protect main from force-push and deletion
|
|
464
592
|
|
|
465
|
-
|
|
466
|
-
below returns HTTP 403 ("Upgrade to GitHub Pro or make this repository
|
|
467
|
-
public") on free-tier accounts, because branch protection is a paid
|
|
468
|
-
feature for private repos. Public repos get branch protection on every
|
|
469
|
-
plan, free included. Pick a path below BEFORE running the call.
|
|
593
|
+
Branch protection on private repos is a paid GitHub feature. Free plan + private repo returns HTTP 403 on the API call. Public repos get branch protection on every plan.
|
|
470
594
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
1. **Make the repo public** — simplest; free plan includes branch
|
|
474
|
-
protection on public repos. Good fit when the code is open source
|
|
475
|
-
or ships to adopters anyway.
|
|
476
|
-
2. **Upgrade the GitHub plan** — Pro / Team / Enterprise includes
|
|
477
|
-
branch protection on private repos.
|
|
478
|
-
3. **Skip the API call** — rely on local safety (no `git push --force`
|
|
479
|
-
habits, PR review, pre-commit hooks). Mark the repo config so later
|
|
480
|
-
phases know branch protection is operator-managed, not substrate-
|
|
481
|
-
managed. See the fallback block below.
|
|
595
|
+
Preflight the plan + visibility pair. Skip the API call cleanly when free + private (per bassclef-upstream#2235). No adopter prompt, no 403 noise:
|
|
482
596
|
|
|
483
597
|
```bash
|
|
484
598
|
DEFAULT_BRANCH=$(gh repo view "$REPO" --json defaultBranchRef -q '.defaultBranchRef.name')
|
|
599
|
+
PLAN=$(gh api /user --jq .plan.name 2>/dev/null || echo "unknown")
|
|
600
|
+
VISIBILITY=$(gh repo view "$REPO" --json visibility --jq .visibility 2>/dev/null || echo "UNKNOWN")
|
|
485
601
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
602
|
+
if [ "$PLAN" = "free" ] && [ "$VISIBILITY" = "PRIVATE" ]; then
|
|
603
|
+
echo "Preflight: free plan + private repo. GitHub free does not offer branch protection on private repos. Skipping API call."
|
|
604
|
+
mkdir -p docs
|
|
605
|
+
cat >> docs/onboard-notes.md <<'NOTE'
|
|
606
|
+
## Branch protection — operator-managed
|
|
607
|
+
|
|
608
|
+
GitHub free plan does not offer branch protection on private repos.
|
|
609
|
+
This repo relies on:
|
|
610
|
+
- Local discipline: no `git push --force` to main.
|
|
611
|
+
- PR review before merge.
|
|
612
|
+
- Pre-commit hooks shipped by bassclef.
|
|
613
|
+
|
|
614
|
+
Revisit if the repo moves to public, or the plan upgrades to Pro+.
|
|
615
|
+
NOTE
|
|
616
|
+
else
|
|
617
|
+
gh api "repos/$REPO/branches/$DEFAULT_BRANCH/protection" \
|
|
618
|
+
--method PUT \
|
|
619
|
+
--input - <<EOF
|
|
490
620
|
{
|
|
491
621
|
"required_status_checks": null,
|
|
492
622
|
"enforce_admins": false,
|
|
@@ -496,6 +626,7 @@ gh api "repos/$REPO/branches/$DEFAULT_BRANCH/protection" \
|
|
|
496
626
|
"allow_deletions": false
|
|
497
627
|
}
|
|
498
628
|
EOF
|
|
629
|
+
fi
|
|
499
630
|
```
|
|
500
631
|
|
|
501
632
|
Minimum defense: no force-push or deletion of main. PR reviews NOT
|
|
@@ -503,25 +634,6 @@ required here — agent-created PRs (bassclef-sync) need to merge
|
|
|
503
634
|
without human intervention for the mobile-sync story. Add stricter
|
|
504
635
|
rules per-repo in `.github/branch-protection.yml` if the repo warrants.
|
|
505
636
|
|
|
506
|
-
**Free-tier private-repo fallback (path 3 above).** If the API
|
|
507
|
-
returned 403 and the operator picked "skip and manage locally":
|
|
508
|
-
|
|
509
|
-
```bash
|
|
510
|
-
# Record the choice so later audits know main is not API-protected.
|
|
511
|
-
mkdir -p .claude
|
|
512
|
-
cat >> .claude/onboard-notes.md <<'NOTE'
|
|
513
|
-
## Branch protection — operator-managed
|
|
514
|
-
|
|
515
|
-
GitHub free-tier does not include branch protection on private repos.
|
|
516
|
-
This repo relies on:
|
|
517
|
-
- Local discipline: no `git push --force` to main.
|
|
518
|
-
- PR review before merge.
|
|
519
|
-
- Pre-commit hooks shipped by bassclef.
|
|
520
|
-
|
|
521
|
-
Revisit if the repo moves to public, or the plan upgrades to Pro+.
|
|
522
|
-
NOTE
|
|
523
|
-
```
|
|
524
|
-
|
|
525
637
|
The adopter can revisit this step after switching to public OR
|
|
526
638
|
upgrading the plan.
|
|
527
639
|
|
|
@@ -550,6 +662,25 @@ production deploy target.
|
|
|
550
662
|
|
|
551
663
|
**Working directory: target repo.** All file writes happen here.
|
|
552
664
|
|
|
665
|
+
##### 2.0 Opt-in prompt pattern — lead with VALUE (per bassclef-upstream#2234)
|
|
666
|
+
|
|
667
|
+
Phase 2 fires four opt-in prompts: auto-update sync (2.1), auto-save cron (2.3.10), Concise output style (2.7), and deploy-host (3.5). The cold-adopter on 2026-10-13 wrote: "need to understand value of auto-save in the text". Current prompts render as 4-option tables with recommended labels but no VALUE row.
|
|
668
|
+
|
|
669
|
+
Every opt-in prompt the agent dispatches via `AskUserQuestion` MUST prepend one plain-English sentence on what the adopter gets. Keep the multi-option schema. Add value to the option body text.
|
|
670
|
+
|
|
671
|
+
**Pattern.** Each option description starts with the value sentence, then the mechanism:
|
|
672
|
+
|
|
673
|
+
- `description: "What this is for: <one-sentence benefit>. <one-sentence mechanism>."`
|
|
674
|
+
|
|
675
|
+
**Worked examples.** Agent composes these from the SKILL body text + the ticket semantics:
|
|
676
|
+
|
|
677
|
+
- **auto_sync** → "What this is for: your repo pulls bassclef skills + rules every session so you stay current. Mechanism: SessionStart hook fetches the latest tarball."
|
|
678
|
+
- **auto-save cron** → "What this is for: your work saves every 20 minutes so a crash or power loss costs minutes, not hours. Mechanism: launchd job (macOS) or Task Scheduler (Windows) commits uncommitted changes."
|
|
679
|
+
- **Concise output style** → "What this is for: Claude Code leads replies with the result, skips step-by-step narration, and skips the closing recap. Mechanism: adds `outputStyle: Concise` to your `~/.claude/settings.json`."
|
|
680
|
+
- **deploy-host** → "What this is for: your repo deploys to a live URL when main merges. Mechanism: AWS Amplify app + DNS + certificate via `/provision-deploy-host`."
|
|
681
|
+
|
|
682
|
+
The agent uses these as templates. One sentence of value. One sentence of mechanism. Then the standard options list.
|
|
683
|
+
|
|
553
684
|
##### 2.1 Install the auto-update script (off by default per bassclef#939)
|
|
554
685
|
|
|
555
686
|
```bash
|
|
@@ -1357,6 +1488,43 @@ EOF
|
|
|
1357
1488
|
The sync hook will add its managed symlink block on next run; this
|
|
1358
1489
|
seeds the file with everything else.
|
|
1359
1490
|
|
|
1491
|
+
##### 2.7 Prompt to enable Concise output style (ADR-049 opt-in)
|
|
1492
|
+
|
|
1493
|
+
**Working directory: operator home.** Writes land in `~/.claude/`, not the target repo.
|
|
1494
|
+
|
|
1495
|
+
Anthropic ships four output styles. Concise leads with the result. It skips step-by-step narration. It skips closing recap. Three bassclef steering dimensions line up with Concise. Five bassclef dimensions stay in play at the project layer. They are grade target, jargon wordlist, appositive discipline, metric feedback, writing-craft discipline. Concise at operator scope cuts per-turn reminders. It covers three bassclef dimensions on its own.
|
|
1496
|
+
|
|
1497
|
+
Fire this phase only when `concise_prompt_should_fire` returns 0. That means no declined sentinel. It also means no outputStyle set to Concise yet.
|
|
1498
|
+
|
|
1499
|
+
```bash
|
|
1500
|
+
HELPER="$CLAUDE_PROJECT_DIR/.claude/skills/onboard-repo/concise-prompt.sh"
|
|
1501
|
+
source "$HELPER"
|
|
1502
|
+
concise_prompt_should_fire || { echo "Concise prompt skipped (declined or already set)."; return 0 2>/dev/null || true; }
|
|
1503
|
+
```
|
|
1504
|
+
|
|
1505
|
+
Prompt the adopter with a 2-line preamble first (per bassclef-upstream#2256):
|
|
1506
|
+
|
|
1507
|
+
> **Concise is Anthropic's shorter output style.** Agents lead with the result and skip step-by-step narration. Turn off anytime via `/output-style default` or edit `~/.claude/settings.json`. Docs: https://code.claude.com/docs/en/output-styles
|
|
1508
|
+
>
|
|
1509
|
+
> Enable Concise output style? (Y/n/skip)
|
|
1510
|
+
> - **Y** — write `"outputStyle": "Concise"` to `~/.claude/settings.json`. jq read-modify-write. Every pre-existing field survives.
|
|
1511
|
+
> - **n** — keep Default style. Do not prompt again.
|
|
1512
|
+
> - **skip** — do not change settings. Re-prompt on next `/onboard-repo` run.
|
|
1513
|
+
|
|
1514
|
+
Default is **n** per ADR-049 opt-in default off.
|
|
1515
|
+
|
|
1516
|
+
Apply the pick via the helper:
|
|
1517
|
+
|
|
1518
|
+
```bash
|
|
1519
|
+
concise_prompt_apply "$CHOICE" # Y | n | skip
|
|
1520
|
+
```
|
|
1521
|
+
|
|
1522
|
+
The helper writes atomically. On **Y** it uses `jq '. + {"outputStyle": "Concise"}'` plus `mktemp` plus `mv`. No partial write ever lands. On **n** it writes `~/.claude/state/concise-prompt-declined`. On **skip** it writes `~/.claude/state/concise-prompt-skipped` so the operator sees the prompt again next run.
|
|
1523
|
+
|
|
1524
|
+
Characterization test at `.claude/skills/onboard-repo/tests/concise-prompt.test.sh` pins all three paths plus field preservation (T1-T11; 11 tests).
|
|
1525
|
+
|
|
1526
|
+
Per ADR-049 opt-in default off. The prompt defaults to **n**. The adopter must type Y to opt in. The helper NEVER writes without an explicit choice.
|
|
1527
|
+
|
|
1360
1528
|
#### Phase 3 — Create starter docs (CLAUDE.md, whereami)
|
|
1361
1529
|
|
|
1362
1530
|
**Working directory: target repo.**
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# tier: lite
|
|
3
|
+
# install-class: dual
|
|
4
|
+
# claude-oauth-probe.sh — portable "is Claude signed in" probe.
|
|
5
|
+
#
|
|
6
|
+
# Replaces inline `timeout 10 claude -p "say hello"` in /onboard-repo
|
|
7
|
+
# Phase 0.1. macOS BSD userland does not include GNU `timeout(1)`; the
|
|
8
|
+
# inline call returned 127 and the `!` test inverted it, firing a false
|
|
9
|
+
# OAUTH-FAIL banner on every macOS cold adopter. Closes bassclef-upstream#2255.
|
|
10
|
+
#
|
|
11
|
+
# Usage:
|
|
12
|
+
# bash claude-oauth-probe.sh [seconds-limit]
|
|
13
|
+
#
|
|
14
|
+
# Default seconds-limit: 10.
|
|
15
|
+
#
|
|
16
|
+
# Detection order:
|
|
17
|
+
# 1. `timeout` (GNU coreutils; Linux + CI runners)
|
|
18
|
+
# 2. `gtimeout` (brew coreutils on macOS)
|
|
19
|
+
# 3. Bash background + kill shim (portable; needs nothing external)
|
|
20
|
+
#
|
|
21
|
+
# Exit codes:
|
|
22
|
+
# 0 — claude -p "say hello" succeeded within the limit
|
|
23
|
+
# 1+ — claude failed OR hung past the limit (killed)
|
|
24
|
+
#
|
|
25
|
+
# Per @luminary michael-nygard — fail-soft on `kill` errors; killer PID handled.
|
|
26
|
+
# Per @luminary alan-cooper — adopter does not need to know timeout(1) is split.
|
|
27
|
+
|
|
28
|
+
set +e # never crash the caller
|
|
29
|
+
|
|
30
|
+
SECONDS_LIMIT="${1:-10}"
|
|
31
|
+
|
|
32
|
+
# Branch 1 — GNU timeout
|
|
33
|
+
if command -v timeout >/dev/null 2>&1; then
|
|
34
|
+
timeout "$SECONDS_LIMIT" claude -p "say hello" >/dev/null 2>&1
|
|
35
|
+
exit $?
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
# Branch 2 — brew gtimeout
|
|
39
|
+
if command -v gtimeout >/dev/null 2>&1; then
|
|
40
|
+
gtimeout "$SECONDS_LIMIT" claude -p "say hello" >/dev/null 2>&1
|
|
41
|
+
exit $?
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
# Branch 3 — bash background + kill shim (portable; no external bin)
|
|
45
|
+
claude -p "say hello" >/dev/null 2>&1 &
|
|
46
|
+
pid=$!
|
|
47
|
+
|
|
48
|
+
# Killer process — sleep then kill the probe
|
|
49
|
+
( sleep "$SECONDS_LIMIT" && kill -9 "$pid" 2>/dev/null ) &
|
|
50
|
+
killer=$!
|
|
51
|
+
|
|
52
|
+
# Wait for probe to finish (either on its own OR killed)
|
|
53
|
+
wait "$pid" 2>/dev/null
|
|
54
|
+
rc=$?
|
|
55
|
+
|
|
56
|
+
# Clean up killer regardless of outcome
|
|
57
|
+
kill -9 "$killer" 2>/dev/null
|
|
58
|
+
wait "$killer" 2>/dev/null
|
|
59
|
+
|
|
60
|
+
exit "$rc"
|