@thebassclef/lite 1.9.8 → 1.9.10
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 +6 -2
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/lite/.claude/hooks/git-stash-u-guard.sh +4 -1
- package/dist/lite/.claude/hooks/post-skill-friction-check.sh +6 -1
- package/dist/lite/.claude/hooks/pre-commit-gate.sh +49 -6
- package/dist/lite/.claude/hooks/pre-commit-identifier-leak-scrub.sh +68 -8
- package/dist/lite/.claude/hooks/pre-commit-manifest-autoregen.sh +4 -2
- package/dist/lite/.claude/hooks/save-state.sh +24 -0
- package/dist/lite/.claude/hooks/session-reflection.d/83-install-written-paths-rebuild.sh +111 -0
- package/dist/lite/.claude/hooks/state-validate.sh +8 -0
- package/dist/lite/.claude/hooks/trace-helper.sh +29 -0
- package/dist/lite/.claude/rules/install-written-paths-mediation.md +74 -0
- package/dist/lite/.claude/rules/lite-manifest-schema-change-discipline.md +30 -0
- package/dist/lite/.claude/skills/autonomous/SKILL.md +53 -7
- package/dist/lite/.claude/skills/build/SKILL.md +53 -11
- package/dist/lite/.claude/skills/deploy-prod/SKILL.md +10 -0
- package/dist/lite/.claude/skills/launch/SKILL.md +26 -0
- package/dist/lite/.claude/skills/onboard-repo/SKILL.md +59 -18
- package/dist/lite/.claude/skills/personas/SKILL.md +1 -1
- package/dist/lite/.claude/skills/release-notes/SKILL.md +24 -0
- package/dist/lite/bassclef-version.json +5 -5
- package/dist/lite/gitignore +8 -0
- package/dist/lite/lib/capability-probe.sh +39 -1
- package/dist/lite/lib/composer-preflight.sh +8 -4
- package/dist/lite/lib/deferred-actions.sh +4 -4
- package/dist/lite/lib/fixture-builder.sh +9 -9
- package/dist/lite/lib/identifier-leak-check.sh +85 -0
- package/dist/lite/lib/install-written-paths.sh +369 -0
- package/dist/lite/lib/luminary-pick.sh +35 -13
- package/dist/lite/lib/preview-state.sh +20 -20
- package/dist/lite/lib/skip-env-inline-check.sh +61 -0
- package/dist/lite/lib/state.sh +102 -39
- package/dist/lite/lib/tier-check.sh +9 -9
- package/dist/lite/lib/tier-dependency-audit.sh +23 -23
- package/dist/lite/presence/install/schedule-auto-save.taskscheduler.md +1 -1
- package/dist/lite/standards/lite-manifest-schema-changes.md +83 -0
- package/dist/lite/standards/lite-manifest.json +70 -47
- package/dist/lite/standards/state-spine.md +1 -0
- package/dist/lite/templates/spec-template.md +10 -6
- package/package.json +1 -1
- package/dist/lite/.claude/hooks/longrun-prep-compounding-axis-check.sh +0 -492
- package/dist/lite/.claude/rules/compounding-axis-fresh-analysis.md +0 -173
|
@@ -15,15 +15,19 @@ requires:
|
|
|
15
15
|
|
|
16
16
|
# Autonomous Development
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
<!-- FKGL-EXEMPT: cli#331 cure — orientation block names skill scope + tier split. Short SVO loses the tier contract. -->
|
|
19
|
+
Entry point for autonomous SDLC sessions. Use in any repo inheriting bassclef.
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
**Lite adopters:** this file is self-contained. The `## Lite procedure` block below has the minimum steps to run `/autonomous start`. No `strategy/` file is needed at lite tier.
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
**Standard and ultra adopters:** deeper procedure lives in these standard-tier files:
|
|
24
|
+
|
|
25
|
+
- `strategy/autonomous-dry-run.md` — read-only boot preview
|
|
26
|
+
- `strategy/autonomous-boot-sequence.md` — full `/autonomous start` steps 0-9 + Construction automation A-E
|
|
27
|
+
- `strategy/agent-choreography.md` — multi-agent operational guide
|
|
28
|
+
|
|
29
|
+
Per cli#331 — closes the "lite skill points at files lite doesn't ship" gap.
|
|
30
|
+
<!-- /FKGL-EXEMPT -->
|
|
27
31
|
|
|
28
32
|
## Usage
|
|
29
33
|
|
|
@@ -263,6 +267,48 @@ silently proceed with defaults.
|
|
|
263
267
|
|
|
264
268
|
---
|
|
265
269
|
|
|
270
|
+
## Lite procedure — self-contained minimum (cli#331)
|
|
271
|
+
|
|
272
|
+
<!-- FKGL-EXEMPT: cli#331 cure — procedure block for lite adopters. Short SVO loses step contract. -->
|
|
273
|
+
Lite adopters run `/autonomous start` with this block only. No `strategy/` file needed.
|
|
274
|
+
|
|
275
|
+
**Step 0 — validate args.** Accept `operator-gated` or `orchestrator-gated` for gating. Accept `sequential` or `parallel` for mode. Reject anything else with a helpful error.
|
|
276
|
+
|
|
277
|
+
**Step 1 — ask the operator two choices.** Gating (default: operator-gated). Mode (default: sequential). Use AskUserQuestion.
|
|
278
|
+
|
|
279
|
+
**Step 2 — check readiness.** Run through this checklist. Scaffold missing items as you go:
|
|
280
|
+
- `substrate.config.md` present → if missing, dispatch `/onboard-repo` first
|
|
281
|
+
- `docs/whereami.md` present → if missing, dispatch `/onboard-repo` first
|
|
282
|
+
- Current iteration goal doc at `docs/iteration-bets/<slug>.md` → if missing, ask operator for the goal; create a minimal doc
|
|
283
|
+
- Session lock free → if active and >30 min old, clear with announcement
|
|
284
|
+
- Chronicle fresh (last 24h) → if stale, note "will write at session-end"
|
|
285
|
+
|
|
286
|
+
**Step 3 — risk register (optional on lite).** `docs/risk-register.md` is optional at lite tier. Create one only when operator asks or when mode is orchestrator-gated. Skip the check otherwise.
|
|
287
|
+
|
|
288
|
+
**Step 4 — budget ceiling (optional on lite).** Ask the operator "how many turns are you OK spending on this session?" Default to "proceed until operator says stop" when operator skips. Record whatever they say in session memory.
|
|
289
|
+
|
|
290
|
+
**Step 5 — confirm scope.** Echo the goal, the two choices, and the ceiling (or "no ceiling"). Ask: "Ready to start?" Wait for yes.
|
|
291
|
+
|
|
292
|
+
**Step 6 — execute the SDLC chain.** Fire the agents in order per gating choice:
|
|
293
|
+
- **operator-gated:** pause between each agent for operator approval. Agents: Shaper → PM → Architect → Designer → Builder → Reviewer → Deployer → Closer. Operator picks which fire.
|
|
294
|
+
- **orchestrator-gated:** chain the agents without pausing. Each writes a handoff doc. Builder commits code. Reviewer runs `/verify`. PRs open for operator merge (or admin-merge within scope).
|
|
295
|
+
|
|
296
|
+
**Step 7 — handle Construction.** For code work:
|
|
297
|
+
- Parse scope into GitHub issues (one issue per discrete change)
|
|
298
|
+
- Write stack manifest at `docs/stacks/<slug>.md` if more than one branch
|
|
299
|
+
- Create branches with issue numbers in name (not placeholder — per bassclef#295)
|
|
300
|
+
- Dispatch Builder per branch; fire `/temperance` + `/diagnose` + `/verify` per branch
|
|
301
|
+
- Open PR per branch; squash merge after Reviewer PASS
|
|
302
|
+
|
|
303
|
+
**Step 8 — close the session.** Dispatch `/session-end` which handles chronicle write, whereami bump, journal entry.
|
|
304
|
+
|
|
305
|
+
Lite adopters at any point can escalate to operator-gated mode mid-session. Say "pause for me to review" and the next agent handoff waits.
|
|
306
|
+
|
|
307
|
+
**Deep procedure for standard+ adopters.** Standard+ and ultra adopters have the strategy/ files above. Those cover Construction automation A-E, pre-build gates, branch stacking, context management, transition hierarchy, and the full choreography rules. Read them for the complete design.
|
|
308
|
+
<!-- /FKGL-EXEMPT -->
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
266
312
|
## Rules
|
|
267
313
|
|
|
268
314
|
- Never start work without operator confirmation
|
|
@@ -255,7 +255,7 @@ FLOOR_PATTERN='src/lib/auth/|src/middleware\.ts|prisma/schema\.prisma|prisma/mig
|
|
|
255
255
|
ACCEPTANCE_CONTENT=$(awk '
|
|
256
256
|
/^```/{in_code = !in_code; next}
|
|
257
257
|
in_code{next}
|
|
258
|
-
/^### WU-/{in_wu=1; next}
|
|
258
|
+
/^### (Step|WU)-/{in_wu=1; next}
|
|
259
259
|
/^## /{in_wu=0}
|
|
260
260
|
in_wu && /^- \[ \]/ {print}
|
|
261
261
|
' "docs/specs/${SPEC_PATH}.md" "docs/decompositions/${DECOMP_PATH}.md" 2>/dev/null)
|
|
@@ -273,8 +273,8 @@ fi
|
|
|
273
273
|
```
|
|
274
274
|
|
|
275
275
|
**Why this is precise (per bassclef#366):** the scan only looks at
|
|
276
|
-
step acceptance criteria (lines starting `- [ ]` under `###
|
|
277
|
-
headings, outside code blocks) plus file-path-shaped references in
|
|
276
|
+
step acceptance criteria (lines starting `- [ ]` under `### Step-N`
|
|
277
|
+
or `### WU-N` headings, outside code blocks) plus file-path-shaped references in
|
|
278
278
|
the goal's frontmatter. Prose paragraphs that DESCRIBE the floor (like
|
|
279
279
|
this section) don't trigger refusal. Code blocks that document the
|
|
280
280
|
floor don't trigger refusal. Only structured ACTIONS the agent would
|
|
@@ -330,14 +330,25 @@ Parse the validated goal's structure:
|
|
|
330
330
|
```bash
|
|
331
331
|
# Already have BET_JSON, SPEC_PATH, DECOMP_PATH, UX_MIG_PATH from Phase 0
|
|
332
332
|
# Read spec body for step enumeration. Per bassclef#367, spec MUST have
|
|
333
|
-
# the
|
|
334
|
-
#
|
|
335
|
-
#
|
|
333
|
+
# the heading `## Steps enumerated` (pinned in /spec SKILL.md rules +
|
|
334
|
+
# templates/spec-template.md). /launch's Phase 9 emits this heading by
|
|
335
|
+
# contract. Specs that lack the section → exit 4.
|
|
336
|
+
#
|
|
337
|
+
# Finding #2 + #3 cure (#2036): the previous awk range
|
|
338
|
+
# `/^## Steps enumerated/,/^## /` closed on its own start line because
|
|
339
|
+
# `^## ` matches `^## Steps enumerated`. Flag-based extraction fixes it.
|
|
340
|
+
# Grace window per ADR-040 D1 (through 2026-10-31): accept both the new
|
|
341
|
+
# "Steps enumerated" / "### Step-N" and the historical "Workunits
|
|
342
|
+
# enumerated" / "### WU-N" headings so legacy specs still build.
|
|
336
343
|
SPEC_FILE="docs/specs/${SPEC_PATH}.md"
|
|
337
|
-
WU_LIST=$(awk '
|
|
344
|
+
WU_LIST=$(awk '
|
|
345
|
+
/^## (Steps|Workunits) enumerated/ { in_section=1; next }
|
|
346
|
+
/^## / { in_section=0 }
|
|
347
|
+
in_section
|
|
348
|
+
' "$SPEC_FILE" | grep -E '^### (Step|WU)-')
|
|
338
349
|
|
|
339
|
-
# Each
|
|
340
|
-
WU_COUNT=$(echo "$WU_LIST" | grep -
|
|
350
|
+
# Each step should reference at least one story (US-NNN)
|
|
351
|
+
WU_COUNT=$(echo "$WU_LIST" | grep -cE '^### (Step|WU)-' || echo 0)
|
|
341
352
|
```
|
|
342
353
|
|
|
343
354
|
Build structured object: `{ bet, spec_path, decomp_path, ux_migration_path, wus[] }`.
|
|
@@ -348,7 +359,8 @@ Verify each step traces to at least one story. Refuse if any step lacks
|
|
|
348
359
|
story traceability.
|
|
349
360
|
|
|
350
361
|
```bash
|
|
351
|
-
|
|
362
|
+
# Keep only step headings; drop body lines before the US-NNN check.
|
|
363
|
+
ORPHAN_WUS=$(echo "$WU_LIST" | grep -E '^### (Step|WU)-' | grep -v 'US-' || true)
|
|
352
364
|
if [ -n "$ORPHAN_WUS" ]; then
|
|
353
365
|
echo "/build: step enumeration lacks story traceability (bassclef#358 violation)" >&2
|
|
354
366
|
echo "Orphan steps (no US-NNN ref):" >&2
|
|
@@ -578,7 +590,26 @@ already open. Operator merges inline.
|
|
|
578
590
|
|
|
579
591
|
### Phase 7 — ApprovalGateLink (LIVE — STUBBED)
|
|
580
592
|
|
|
581
|
-
|
|
593
|
+
<!-- FKGL-EXEMPT: cli#332 cure — Phase 7 branches on hosting_platform value. Three code-shape outputs. Technical stub-shape dispatch pattern. -->
|
|
594
|
+
|
|
595
|
+
Phase 7 branches on `hosting_platform` read from `substrate.config.md`:
|
|
596
|
+
|
|
597
|
+
**When `hosting_platform: none`** (lite adopters, operator-only tools, local-first apps) — emit:
|
|
598
|
+
|
|
599
|
+
```
|
|
600
|
+
TODO: live execution — built, not deployed. hosting_platform=none in
|
|
601
|
+
substrate.config.md. The code is reviewed and committed. Running it is
|
|
602
|
+
your choice.
|
|
603
|
+
|
|
604
|
+
To add hosting later:
|
|
605
|
+
- Edit substrate.config.md: set hosting_platform to one of
|
|
606
|
+
github-pages | netlify | cloudflare-pages | vercel | amplify
|
|
607
|
+
- Run /onboard-repo --with-deploy-host to wire the host
|
|
608
|
+
- Then /build Phase 7 will dispatch /deploy-prod via GitHub Environment
|
|
609
|
+
+ required-reviewer rail per manual-prod-approval.md.
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
**When `hosting_platform` is set to a known value** — emit:
|
|
582
613
|
|
|
583
614
|
```
|
|
584
615
|
TODO: live execution — when all steps merged + CI green, would dispatch
|
|
@@ -587,6 +618,17 @@ required-reviewer rail per manual-prod-approval.md. Operator approves
|
|
|
587
618
|
prod deploy via GitHub UI from phone. /build NEVER bypasses this rail.
|
|
588
619
|
```
|
|
589
620
|
|
|
621
|
+
**When `hosting_platform` is unset or unrecognized** — emit:
|
|
622
|
+
|
|
623
|
+
```
|
|
624
|
+
TODO: live execution — hosting_platform not set in substrate.config.md.
|
|
625
|
+
Can't deploy without a target. Set hosting_platform to one of none |
|
|
626
|
+
github-pages | netlify | cloudflare-pages | vercel | amplify, then re-run.
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
Per cli#332 — closes the "lite promises deployed app without a deploy path" honesty gap.
|
|
630
|
+
<!-- /FKGL-EXEMPT -->
|
|
631
|
+
|
|
590
632
|
<!-- FKGL-EXEMPT: Phase 7.5 references paths + skip criteria per architect-review SKILL; technical dispatch stub matches sibling STUB pattern -->
|
|
591
633
|
### Phase 7.5 — /architect-review auto-dispatch (LIVE — STUBBED, per #1437 Step 2 wiring)
|
|
592
634
|
|
|
@@ -17,8 +17,18 @@ requires:
|
|
|
17
17
|
|
|
18
18
|
# Deploy to Production
|
|
19
19
|
|
|
20
|
+
<!-- FKGL-EXEMPT: cli#332 cure — tier contract block names scope + override path. Short SVO loses host-override contract. -->
|
|
20
21
|
Standard deployment procedure. Run after code is reviewed and ready to ship.
|
|
21
22
|
|
|
23
|
+
**Tier contract (per cli#332):**
|
|
24
|
+
|
|
25
|
+
- This skill ships at `tier: lite` as a generic 5-step template: test → build → push → CI → verify.
|
|
26
|
+
- The template body is host-agnostic. Host-specific commands (AWS, Vercel, Netlify, Fly, Railway, GitHub Pages) are not shipped here.
|
|
27
|
+
- When `substrate.config.md` sets `hosting_platform` to a known value, standard-tier adopters add a host-specific wrapper that calls this skill AND runs the host commands. Lite adopters without `hosting_platform` run the template steps + stop.
|
|
28
|
+
- `/build` Phase 7 dispatches this skill only when `hosting_platform` is set to a known value — see /build Phase 7 branching logic per cli#332.
|
|
29
|
+
- `manual-prod-approval.md` applies in all tiers: GitHub Environment `prod` with required reviewer MUST be configured before any prod deploy fires.
|
|
30
|
+
<!-- /FKGL-EXEMPT -->
|
|
31
|
+
|
|
22
32
|
## Procedure
|
|
23
33
|
|
|
24
34
|
### Step 1: Pre-flight
|
|
@@ -309,9 +309,35 @@ Per `standards/voice-input-pattern.md` + Phase V Hey-Alexa MVD goal (`docs/itera
|
|
|
309
309
|
- Existing text-mode + brownfield-mode behavior unchanged when flag absent
|
|
310
310
|
- Composes with `--brownfield` (rare; voice-driven brownfield refactor is plausible but not the MVD path)
|
|
311
311
|
|
|
312
|
+
### Phase 0b — hosting_platform ask (per cli#332)
|
|
313
|
+
|
|
314
|
+
<!-- FKGL-EXEMPT: cli#332 cure — hosting_platform ask step. Short SVO loses the config-key contract. -->
|
|
315
|
+
Read `substrate.config.md` for the `hosting_platform` key. If unset or missing, ask the operator once:
|
|
316
|
+
|
|
317
|
+
```
|
|
318
|
+
Where should this run?
|
|
319
|
+
a. local only (default — develop + preview on your machine)
|
|
320
|
+
b. a static host (GitHub Pages / Netlify / Cloudflare Pages / Vercel)
|
|
321
|
+
c. a server host (Amplify / Fly.io / Railway)
|
|
322
|
+
d. I'll deploy myself — just build the plan
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Write the answer to `substrate.config.md` `hosting_platform`:
|
|
326
|
+
- `a` → `hosting_platform: none`
|
|
327
|
+
- `b` → prompt for which static host; write that value (`github-pages` / `netlify` / `cloudflare-pages` / `vercel`)
|
|
328
|
+
- `c` → prompt for which server host; write that value (`amplify` / `fly` / `railway`)
|
|
329
|
+
- `d` → `hosting_platform: operator-managed`
|
|
330
|
+
|
|
331
|
+
If already set, skip the question. The answer flows to /build Phase 7 which branches on this value per cli#332.
|
|
332
|
+
|
|
333
|
+
Per cli#332 — closes "Nothing asks where the app will run" at the earliest surface in the chain.
|
|
334
|
+
<!-- /FKGL-EXEMPT -->
|
|
335
|
+
|
|
312
336
|
### Phase 1 — `/interpret-input`
|
|
313
337
|
|
|
338
|
+
<!-- FKGL-EXEMPT: pre-existing text-mode + brownfield-mode description — technical dispatch contract per bassclef#459 sub-goal 1. -->
|
|
314
339
|
Dispatches `/interpret-input` with the type detected by Phase 0. Text mode preserves the existing text-mode behavior; brownfield mode invokes the Phase C extractor (LR2 WU-1, bassclef#459 sub-goal 1) which walks the repo and populates structural hints (entities, actors, routes, README excerpt).
|
|
340
|
+
<!-- /FKGL-EXEMPT -->
|
|
315
341
|
|
|
316
342
|
```bash
|
|
317
343
|
# Generate sprint slug + InputArtifact path
|
|
@@ -433,25 +433,25 @@ Idempotent API calls against the target repo via `gh`.
|
|
|
433
433
|
# Read from git remote — don't infer from cwd basename (cwd can be renamed)
|
|
434
434
|
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)
|
|
435
435
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
[
|
|
441
|
-
[bug]="E4443A:Defect"
|
|
442
|
-
[enhancement]="A2EEEF:New or improved functionality"
|
|
443
|
-
[security]="FF0000:Security-relevant"
|
|
444
|
-
[infra]="C9D1D9:Infrastructure / workflows / tooling"
|
|
445
|
-
[priority-high]="E4443A:High priority"
|
|
446
|
-
[priority-medium]="F5B94A:Medium priority"
|
|
447
|
-
[question]="D876E3:Needs operator input or design discussion"
|
|
448
|
-
)
|
|
449
|
-
|
|
450
|
-
for NAME in "${!LABELS[@]}"; do
|
|
451
|
-
COLOR="${LABELS[$NAME]%%:*}"
|
|
452
|
-
DESC="${LABELS[$NAME]#*:}"
|
|
436
|
+
# Per cli#306 — use while-read loop over pipe-delimited heredoc instead
|
|
437
|
+
# of `declare -A`. macOS ships bash 3.2 which has no associative arrays.
|
|
438
|
+
# Format per line: NAME|COLOR|DESCRIPTION
|
|
439
|
+
while IFS='|' read -r NAME COLOR DESC; do
|
|
440
|
+
[ -z "$NAME" ] && continue
|
|
453
441
|
gh label create "$NAME" --repo "$REPO" --color "$COLOR" --description "$DESC" --force >/dev/null
|
|
454
|
-
done
|
|
442
|
+
done <<'EOF'
|
|
443
|
+
bassclef-evolution|A6E0F2|Candidate for promotion to bassclef
|
|
444
|
+
agent-user-proposed|D4A5F5|Proposed by agent in an app repo
|
|
445
|
+
bassclef-sync|8FD4A4|Related to bassclef substrate syncing
|
|
446
|
+
review-required|F5B94A|Blocks — human review required
|
|
447
|
+
bug|E4443A|Defect
|
|
448
|
+
enhancement|A2EEEF|New or improved functionality
|
|
449
|
+
security|FF0000|Security-relevant
|
|
450
|
+
infra|C9D1D9|Infrastructure / workflows / tooling
|
|
451
|
+
priority-high|E4443A|High priority
|
|
452
|
+
priority-medium|F5B94A|Medium priority
|
|
453
|
+
question|D876E3|Needs operator input or design discussion
|
|
454
|
+
EOF
|
|
455
455
|
```
|
|
456
456
|
|
|
457
457
|
Uses `--force` so the call is idempotent (updates existing label or
|
|
@@ -462,9 +462,28 @@ immediately without waiting for a sync cycle.
|
|
|
462
462
|
|
|
463
463
|
##### 1.2 Protect main from force-push and deletion
|
|
464
464
|
|
|
465
|
+
**Heads up — GitHub free-tier adopters on PRIVATE repos:** the API call
|
|
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.
|
|
470
|
+
|
|
471
|
+
Three ways to clear this step:
|
|
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.
|
|
482
|
+
|
|
465
483
|
```bash
|
|
466
484
|
DEFAULT_BRANCH=$(gh repo view "$REPO" --json defaultBranchRef -q '.defaultBranchRef.name')
|
|
467
485
|
|
|
486
|
+
# Pro / public-repo path — run the API call.
|
|
468
487
|
gh api "repos/$REPO/branches/$DEFAULT_BRANCH/protection" \
|
|
469
488
|
--method PUT \
|
|
470
489
|
--input - <<EOF
|
|
@@ -484,6 +503,28 @@ required here — agent-created PRs (bassclef-sync) need to merge
|
|
|
484
503
|
without human intervention for the mobile-sync story. Add stricter
|
|
485
504
|
rules per-repo in `.github/branch-protection.yml` if the repo warrants.
|
|
486
505
|
|
|
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
|
+
The adopter can revisit this step after switching to public OR
|
|
526
|
+
upgrading the plan.
|
|
527
|
+
|
|
487
528
|
##### 1.3 Add the production approval gate (if this repo deploys to prod)
|
|
488
529
|
|
|
489
530
|
If the repo will deploy to production, per `manual-prod-approval.md`:
|
|
@@ -87,7 +87,7 @@ When no persona files exist in the repo, auto-populate a minimal persona file fo
|
|
|
87
87
|
|
|
88
88
|
- `CLAUDE.md` — read the "What this repo is" / "Active initiative" sections for goal context
|
|
89
89
|
- `substrate.config.md` — read `agents:` and `deploy_targets:` for role context
|
|
90
|
-
-
|
|
90
|
+
- Default slug: `operator`. Do not derive it from `user.email`. GitHub no-reply addresses carry the account ID and handle. The slug then leaks into committed docs (cli#320). Ask for a display name in-turn if the operator wants one.
|
|
91
91
|
|
|
92
92
|
Emit the operator default to the conversation (not to disk — operator decides whether to persist it):
|
|
93
93
|
|
|
@@ -108,6 +108,30 @@ Rules for external notes:
|
|
|
108
108
|
- No feature names that aren't visible to users
|
|
109
109
|
- Test: could someone who's never seen the codebase understand this?
|
|
110
110
|
|
|
111
|
+
### 3.5. Run `/ogilvy-writing-audit` on each body
|
|
112
|
+
|
|
113
|
+
Before saving the drafted bodies to disk, run `/ogilvy-writing-audit`
|
|
114
|
+
on each one. The skill scans against Ogilvy + Roman-Raphaelson's
|
|
115
|
+
rules (see `standards/ogilvy-writing-rules.md`) and returns
|
|
116
|
+
severity-tagged findings.
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
/ogilvy-writing-audit docs/release-notes/YYYY-MM-DD-internal.md
|
|
120
|
+
/ogilvy-writing-audit docs/release-notes/YYYY-MM-DD-external.md
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Fix every 🔴 and 🟡 finding before step 4. When a 🟡 ships without
|
|
124
|
+
a fix, cite the audit in the commit body and name why.
|
|
125
|
+
|
|
126
|
+
Why this step. Release notes land in reader surfaces that must read
|
|
127
|
+
clean — the GitHub Release artifact plus the Google Doc the team
|
|
128
|
+
reviews. Jargon and grade-13 prose creep in without a mechanical
|
|
129
|
+
check. PR #408 ran this discipline by hand across 8 entries, and
|
|
130
|
+
PR #412 formalizes it so every future entry inherits the floor.
|
|
131
|
+
|
|
132
|
+
Cross-ref: `.claude/rules/session-artifacts.md` §Release notes names
|
|
133
|
+
this step as the discipline anchor.
|
|
134
|
+
|
|
111
135
|
### 4. Save locally
|
|
112
136
|
|
|
113
137
|
```
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "v1.6.
|
|
3
|
-
"marker_tag": "release-2026-
|
|
4
|
-
"release_date": "2026-
|
|
5
|
-
"release_sha": "
|
|
6
|
-
"release_tag": "release-2026-
|
|
2
|
+
"version": "v1.6.6",
|
|
3
|
+
"marker_tag": "release-2026-10-05-484c6f3e",
|
|
4
|
+
"release_date": "2026-10-05T03:42:33Z",
|
|
5
|
+
"release_sha": "484c6f3e",
|
|
6
|
+
"release_tag": "release-2026-10-05-484c6f3e"
|
|
7
7
|
}
|
package/dist/lite/gitignore
CHANGED
|
@@ -31,6 +31,14 @@ state/luminary-implementations/
|
|
|
31
31
|
.claude/hooks/logs/
|
|
32
32
|
.claude/hooks/*.trace
|
|
33
33
|
|
|
34
|
+
# SDLC traces (operator-private; runtime artifacts carry operator paths)
|
|
35
|
+
# Per #2036 Finding #1 (adopter report 2026-10-02) — auto-save was
|
|
36
|
+
# committing /Users/<name>/ paths to adopter git every fire. Shipping this
|
|
37
|
+
# line stops future adopter installs from leaking. Existing installs run
|
|
38
|
+
# `git rm --cached -r docs/sdlc-traces/` one time to untrack files
|
|
39
|
+
# already in history.
|
|
40
|
+
docs/sdlc-traces/
|
|
41
|
+
|
|
34
42
|
# Build output
|
|
35
43
|
dist/
|
|
36
44
|
|
|
@@ -44,8 +44,46 @@ probe_gh_auth() {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
probe_mcp_playwright() {
|
|
47
|
-
#
|
|
47
|
+
# Fast path — explicit opt-in via env var. Adopters who want to force the
|
|
48
|
+
# probe TRUE set CLAUDE_MCP_PLAYWRIGHT=1 in their shell init. Documented at
|
|
49
|
+
# docs/use-cases/UC-lib-capability-probe-mcp-fallback.md.
|
|
48
50
|
[ -n "${CLAUDE_MCP_PLAYWRIGHT:-}" ] && return 0
|
|
51
|
+
|
|
52
|
+
# Fallback — look for a Playwright MCP server in known MCP config files.
|
|
53
|
+
# jq is required for parsing. When absent, the probe fails soft to 1.
|
|
54
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
55
|
+
echo "probe_mcp_playwright: jq not found; env-var fast path only" >&2
|
|
56
|
+
return 1
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
local project_dir="${CLAUDE_PROJECT_DIR:-.}"
|
|
60
|
+
local home_dir="${HOME:-}"
|
|
61
|
+
|
|
62
|
+
# Check paths in precedence order. First hit wins.
|
|
63
|
+
_probe_mcp_json_has_playwright "${project_dir}/.mcp.json" && return 0
|
|
64
|
+
_probe_mcp_json_has_playwright "${project_dir}/.claude/settings.json" && return 0
|
|
65
|
+
if [ -n "$home_dir" ]; then
|
|
66
|
+
_probe_mcp_json_has_playwright "${home_dir}/.claude/settings.json" && return 0
|
|
67
|
+
_probe_mcp_json_has_playwright "${home_dir}/.claude.json" && return 0
|
|
68
|
+
fi
|
|
69
|
+
return 1
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
# _probe_mcp_json_has_playwright <path>
|
|
73
|
+
# Returns 0 when the JSON file names a Playwright MCP server. Checks two
|
|
74
|
+
# shapes:
|
|
75
|
+
# 1. Top-level "playwright" key (used by `.mcp.json` on some adopters)
|
|
76
|
+
# 2. Nested "mcpServers.playwright" (used by `settings.json` + `~/.claude.json`)
|
|
77
|
+
# Fail-soft on missing file + malformed JSON — returns 1 silently.
|
|
78
|
+
# Per bassclef-upstream Finding #6 (#2036): `local path` is a zsh-magic variable
|
|
79
|
+
# name — ties to $PATH when sourced from zsh. Renamed to `local p`.
|
|
80
|
+
_probe_mcp_json_has_playwright() {
|
|
81
|
+
local p="$1"
|
|
82
|
+
[ -f "$p" ] || return 1
|
|
83
|
+
# Shape 1 — top-level playwright
|
|
84
|
+
jq -e '.playwright // empty' "$p" >/dev/null 2>&1 && return 0
|
|
85
|
+
# Shape 2 — nested mcpServers.playwright
|
|
86
|
+
jq -e '.mcpServers.playwright // empty' "$p" >/dev/null 2>&1 && return 0
|
|
49
87
|
return 1
|
|
50
88
|
}
|
|
51
89
|
|
|
@@ -178,10 +178,14 @@ composer_preflight_check() {
|
|
|
178
178
|
echo "check_5_recommendation="
|
|
179
179
|
pass=$((pass + 1))
|
|
180
180
|
elif [ -f "$repo_skill" ] || [ -L "$repo_skill" ]; then
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
181
|
+
# Per cli#321 — Claude Code's harness loads project .claude/skills/
|
|
182
|
+
# directly; user-level symlinks are not required. Repo-level IS a
|
|
183
|
+
# valid discovery path. Previously flagged as WARN, trained adopters
|
|
184
|
+
# to ignore warnings. Now PASS with informational message.
|
|
185
|
+
echo "check_5_status=pass"
|
|
186
|
+
echo "check_5_message=Skill resolves at repo-level: $repo_skill (harness loads project .claude/skills directly)"
|
|
187
|
+
echo "check_5_recommendation="
|
|
188
|
+
pass=$((pass + 1))
|
|
185
189
|
elif [ -n "${BASSCLEF_DIR:-}" ] && [ -f "$bassclef_skill" ]; then
|
|
186
190
|
echo "check_5_status=warn"
|
|
187
191
|
echo "check_5_message=Skill at bassclef only; consumer-side links missing — substrate sync incomplete"
|
|
@@ -72,9 +72,9 @@ _da_resolve_path() {
|
|
|
72
72
|
da_get_field() {
|
|
73
73
|
local id="$1"
|
|
74
74
|
local field="$2"
|
|
75
|
-
local
|
|
76
|
-
|
|
77
|
-
[[ -f "$
|
|
75
|
+
local p
|
|
76
|
+
p="$(_da_resolve_path "$id")"
|
|
77
|
+
[[ -f "$p" ]] || { echo "not-found: $p" >&2; return 1; }
|
|
78
78
|
# Read frontmatter only (between two `---` lines)
|
|
79
79
|
awk -v f="$field" '
|
|
80
80
|
BEGIN { in_fm = 0; seen_open = 0 }
|
|
@@ -89,7 +89,7 @@ da_get_field() {
|
|
|
89
89
|
print
|
|
90
90
|
exit
|
|
91
91
|
}
|
|
92
|
-
' "$
|
|
92
|
+
' "$p"
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
da_resolve() {
|
|
@@ -82,16 +82,16 @@ fixture_cleanup() {
|
|
|
82
82
|
if [ "${SKIP_FIXTURE_BUILDER:-0}" = "1" ]; then
|
|
83
83
|
return 0
|
|
84
84
|
fi
|
|
85
|
-
local
|
|
86
|
-
if [ ! -e "$
|
|
85
|
+
local p="${1:?fixture_cleanup requires path}"
|
|
86
|
+
if [ ! -e "$p" ]; then
|
|
87
87
|
# Idempotent — nothing to do
|
|
88
88
|
return 0
|
|
89
89
|
fi
|
|
90
|
-
if [ ! -f "$
|
|
91
|
-
echo "fixture_cleanup: refusing to remove path without sentinel: $
|
|
90
|
+
if [ ! -f "$p/$_FIXTURE_SENTINEL" ]; then
|
|
91
|
+
echo "fixture_cleanup: refusing to remove path without sentinel: $p" >&2
|
|
92
92
|
return 1
|
|
93
93
|
fi
|
|
94
|
-
rm -rf "$
|
|
94
|
+
rm -rf "$p"
|
|
95
95
|
return 0
|
|
96
96
|
}
|
|
97
97
|
|
|
@@ -105,10 +105,10 @@ fixture_cleanup_all() {
|
|
|
105
105
|
return 0
|
|
106
106
|
fi
|
|
107
107
|
local IFS=$'\n'
|
|
108
|
-
local
|
|
109
|
-
for
|
|
110
|
-
[ -n "$
|
|
111
|
-
fixture_cleanup "$
|
|
108
|
+
local p
|
|
109
|
+
for p in $_FIXTURE_REGISTRY; do
|
|
110
|
+
[ -n "$p" ] || continue
|
|
111
|
+
fixture_cleanup "$p" 2>/dev/null || true
|
|
112
112
|
done
|
|
113
113
|
_FIXTURE_REGISTRY=""
|
|
114
114
|
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# tier: lite
|
|
3
|
+
# Operator-identifier leak check for staged git content.
|
|
4
|
+
#
|
|
5
|
+
# Shared across:
|
|
6
|
+
# - .claude/hooks/save-state.sh (inline before `git commit`;
|
|
7
|
+
# bypasses pre-commit-gate.sh because save-state runs git
|
|
8
|
+
# directly, not through the agent's PreToolUse path)
|
|
9
|
+
# - future: .claude/hooks/pre-commit-gate.sh CCF-3 (unification
|
|
10
|
+
# deferred to a follow-on; shape intentionally matches CCF-3
|
|
11
|
+
# today so the two can merge without semantic drift)
|
|
12
|
+
#
|
|
13
|
+
# Rejects staged content carrying absolute operator paths matching
|
|
14
|
+
# /Users/<name>/ or /home/<name>/. Mirrors pre-commit-gate.sh:50-53
|
|
15
|
+
# exemptions so policy docs that quote the pattern don't trip.
|
|
16
|
+
#
|
|
17
|
+
# Per #2036 Finding #1 (adopter report 2026-10-02).
|
|
18
|
+
# Per @luminary nygard — stability pattern (circuit breaker on commit).
|
|
19
|
+
# Per @luminary hoare — precondition contract before `git commit`.
|
|
20
|
+
|
|
21
|
+
# check_staged_for_leaks — scan git-staged content for operator paths.
|
|
22
|
+
#
|
|
23
|
+
# Returns 0 when staged content is clean OR when every leaking file
|
|
24
|
+
# sits in an exempt path (policy docs, rules, luminaries).
|
|
25
|
+
# Returns 1 when staged content outside exempt paths carries a leak.
|
|
26
|
+
# On exit 1, every leaking file is named on stderr with line number
|
|
27
|
+
# and the matched pattern.
|
|
28
|
+
check_staged_for_leaks() {
|
|
29
|
+
# Staged non-exempt files. Match pre-commit-gate.sh:46-53 exemption shape
|
|
30
|
+
# so the two gates agree on which paths carry policy docs legitimately
|
|
31
|
+
# quoting operator paths.
|
|
32
|
+
local staged
|
|
33
|
+
staged=$(git diff --cached --name-only --diff-filter=AM 2>/dev/null | \
|
|
34
|
+
grep -vE '^\.claude/(rules|hooks|skills|luminaries|agents)/' | \
|
|
35
|
+
grep -vE '^standards/' | \
|
|
36
|
+
grep -vE '^architecture/' | \
|
|
37
|
+
grep -vE '^design/' | \
|
|
38
|
+
grep -vE '^docs/standards/' | \
|
|
39
|
+
grep -vE '^docs/rules/' | \
|
|
40
|
+
grep -vE '^chronicle/' | \
|
|
41
|
+
grep -vE '^strategy/' | \
|
|
42
|
+
grep -vE '^scripts/tests/' || true)
|
|
43
|
+
|
|
44
|
+
[ -z "$staged" ] && return 0
|
|
45
|
+
|
|
46
|
+
local leaked=""
|
|
47
|
+
while IFS= read -r f; do
|
|
48
|
+
[ -z "$f" ] && continue
|
|
49
|
+
[ ! -f "$f" ] && continue
|
|
50
|
+
local matches
|
|
51
|
+
matches=$(grep -nE '/Users/[A-Za-z0-9_.-]+|/home/[A-Za-z0-9_.-]+' "$f" 2>/dev/null || true)
|
|
52
|
+
if [ -n "$matches" ]; then
|
|
53
|
+
leaked="${leaked}
|
|
54
|
+
${f}:
|
|
55
|
+
${matches}
|
|
56
|
+
"
|
|
57
|
+
fi
|
|
58
|
+
done <<< "$staged"
|
|
59
|
+
|
|
60
|
+
if [ -n "$leaked" ]; then
|
|
61
|
+
{
|
|
62
|
+
echo ""
|
|
63
|
+
echo "============================================"
|
|
64
|
+
echo "BLOCKED: operator path in staged content (#2036 Finding #1)"
|
|
65
|
+
echo "============================================"
|
|
66
|
+
echo "$leaked"
|
|
67
|
+
echo ""
|
|
68
|
+
echo "Operator-specific paths (/Users/<name>, /home/<name>) must NOT"
|
|
69
|
+
echo "ship in adopter git. Common cause: docs/sdlc-traces/*.log"
|
|
70
|
+
echo "carrying absolute paths from PreToolUse hook callers."
|
|
71
|
+
echo ""
|
|
72
|
+
echo "Fixes:"
|
|
73
|
+
echo " 1. Delete the staged file if it's a trace log auto-generated"
|
|
74
|
+
echo " (gitignored going forward per #2036 Finding #1 cure)"
|
|
75
|
+
echo " 2. Rewrite the path as repo-relative"
|
|
76
|
+
echo " 3. Move policy docs under docs/standards/ or docs/rules/ (exempt)"
|
|
77
|
+
echo ""
|
|
78
|
+
echo "Policy: standards/two-layer-config.md (bassclef#740)"
|
|
79
|
+
echo "============================================"
|
|
80
|
+
} >&2
|
|
81
|
+
return 1
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
return 0
|
|
85
|
+
}
|