@thebassclef/lite 1.9.9 → 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 +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/hooks/pre-commit-gate.sh +31 -0
- package/dist/lite/.claude/hooks/pre-commit-identifier-leak-scrub.sh +58 -2
- 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/rules/install-written-paths-mediation.md +74 -0
- package/dist/lite/.claude/skills/autonomous/SKILL.md +53 -7
- package/dist/lite/.claude/skills/build/SKILL.md +34 -4
- 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 +18 -18
- package/dist/lite/.claude/skills/personas/SKILL.md +1 -1
- package/dist/lite/bassclef-version.json +4 -4
- package/dist/lite/lib/capability-probe.sh +39 -1
- package/dist/lite/lib/composer-preflight.sh +8 -4
- package/dist/lite/lib/install-written-paths.sh +369 -0
- package/dist/lite/lib/luminary-pick.sh +35 -13
- package/dist/lite/lib/state.sh +71 -11
- package/dist/lite/standards/lite-manifest-schema-changes.md +45 -0
- package/dist/lite/standards/lite-manifest.json +40 -17
- package/dist/lite/standards/state-spine.md +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -67,7 +67,7 @@ your browser.
|
|
|
67
67
|
|
|
68
68
|
## Current release
|
|
69
69
|
|
|
70
|
-
<!-- version-start -->1.9.
|
|
70
|
+
<!-- version-start -->1.9.10<!-- version-end -->
|
|
71
71
|
|
|
72
72
|
See [CHANGELOG.md](CHANGELOG.md) for the full changelog. Adopter-facing
|
|
73
73
|
release notes live at [docs.bassclef.dev/docs/whats-new/releases](https://docs.bassclef.dev/docs/whats-new/releases).
|
package/dist/index.cjs
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const version: "1.9.
|
|
1
|
+
export declare const version: "1.9.10";
|
|
2
2
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -201,6 +201,37 @@ if ! { declare -F skip_var_set >/dev/null && skip_var_set "SKIP_LEAD_LENS_SIGNOF
|
|
|
201
201
|
-e '^\.github/workflows/bassclef-.*\.yml$' \
|
|
202
202
|
-e '^scripts/[^/]+\.sh$' \
|
|
203
203
|
|| true)
|
|
204
|
+
# Install-written-paths filter per bassclef-upstream#2036 Finding #8 (Kunal).
|
|
205
|
+
# Rule: .claude/rules/install-written-paths-mediation.md
|
|
206
|
+
# Any staged substrate path registered as install-written AND unchanged since
|
|
207
|
+
# install is dropped from the author-edit set. Lead-lens gate fires only on
|
|
208
|
+
# author-edited substrate paths.
|
|
209
|
+
if [ -n "$STAGED_SUBSTRATE_LL" ]; then
|
|
210
|
+
IWP_LIB=""
|
|
211
|
+
if [ -f "lib/install-written-paths.sh" ]; then
|
|
212
|
+
IWP_LIB="lib/install-written-paths.sh"
|
|
213
|
+
elif [ -f "$BASSCLEF_DIR/lib/install-written-paths.sh" ]; then
|
|
214
|
+
IWP_LIB="$BASSCLEF_DIR/lib/install-written-paths.sh"
|
|
215
|
+
fi
|
|
216
|
+
if [ -n "$IWP_LIB" ]; then
|
|
217
|
+
# shellcheck source=/dev/null
|
|
218
|
+
. "$IWP_LIB" 2>/dev/null || true
|
|
219
|
+
if declare -F is_install_written_path >/dev/null 2>&1; then
|
|
220
|
+
FILTERED_LL=""
|
|
221
|
+
while IFS= read -r _iwp_f; do
|
|
222
|
+
[ -z "$_iwp_f" ] && continue
|
|
223
|
+
if is_install_written_path "$_iwp_f" 2>/dev/null; then
|
|
224
|
+
trace_log "pre-commit" "lead-lens skip install-written path=$_iwp_f"
|
|
225
|
+
continue
|
|
226
|
+
fi
|
|
227
|
+
FILTERED_LL="${FILTERED_LL}${FILTERED_LL:+$'\n'}$_iwp_f"
|
|
228
|
+
done <<EOF
|
|
229
|
+
$STAGED_SUBSTRATE_LL
|
|
230
|
+
EOF
|
|
231
|
+
STAGED_SUBSTRATE_LL="$FILTERED_LL"
|
|
232
|
+
fi
|
|
233
|
+
fi
|
|
234
|
+
fi
|
|
204
235
|
if [ -n "$STAGED_SUBSTRATE_LL" ]; then
|
|
205
236
|
LL_BRANCH_SLUG=$(git branch --show-current 2>/dev/null | tr '/' '-')
|
|
206
237
|
PREM_M="state/markers/pre-mortem/${LL_BRANCH_SLUG}.marker"
|
|
@@ -97,8 +97,36 @@ fi
|
|
|
97
97
|
# Filter to '+' lines only so a commit that REMOVES a pre-existing leak
|
|
98
98
|
# does not trip on the removed-content line. `+++` file headers stripped.
|
|
99
99
|
# Per sunj-labs/bassclef-upstream#1575.
|
|
100
|
+
#
|
|
101
|
+
# Self-exclude per sunj-labs/bassclef-cli#305: the hook, its test, the
|
|
102
|
+
# rule, and the pattern-source file all carry pattern-looking strings
|
|
103
|
+
# as documentation. Scanning them blocks the first commit after a fresh
|
|
104
|
+
# bassclef init and teaches adopters to skip the check on day one.
|
|
105
|
+
# Non-self paths with the same patterns STILL block (Test 19).
|
|
106
|
+
SELF_EXCLUDE_PATHS=(
|
|
107
|
+
".claude/hooks/pre-commit-identifier-leak-scrub.sh"
|
|
108
|
+
".claude/hooks/tests/pre-commit-identifier-leak-scrub.test.sh"
|
|
109
|
+
".claude/rules/identifier-leak-prevention.md"
|
|
110
|
+
"standards/identifier-leak-patterns.txt"
|
|
111
|
+
)
|
|
100
112
|
if [ -z "$BLOCK_REASON" ]; then
|
|
101
|
-
|
|
113
|
+
STAGED_FILES=$(git diff --cached --name-only 2>/dev/null || echo "")
|
|
114
|
+
STAGED_DIFF=""
|
|
115
|
+
while IFS= read -r file; do
|
|
116
|
+
[ -z "$file" ] && continue
|
|
117
|
+
skip=0
|
|
118
|
+
for sp in "${SELF_EXCLUDE_PATHS[@]}"; do
|
|
119
|
+
if [ "$file" = "$sp" ]; then
|
|
120
|
+
skip=1
|
|
121
|
+
break
|
|
122
|
+
fi
|
|
123
|
+
done
|
|
124
|
+
[ "$skip" = "1" ] && continue
|
|
125
|
+
file_diff=$(git diff --cached -- "$file" 2>/dev/null | grep '^+' | grep -v '^+++' || echo "")
|
|
126
|
+
if [ -n "$file_diff" ]; then
|
|
127
|
+
STAGED_DIFF+="$file_diff"$'\n'
|
|
128
|
+
fi
|
|
129
|
+
done <<< "$STAGED_FILES"
|
|
102
130
|
if [ -n "$STAGED_DIFF" ]; then
|
|
103
131
|
MATCH=$(echo "$STAGED_DIFF" | grep -oE "$IDENTIFIER_PATTERNS" | head -1)
|
|
104
132
|
if [ -n "$MATCH" ]; then
|
|
@@ -108,6 +136,29 @@ if [ -z "$BLOCK_REASON" ]; then
|
|
|
108
136
|
fi
|
|
109
137
|
fi
|
|
110
138
|
|
|
139
|
+
# Check 3 — git author identity (per sunj-labs/bassclef-cli#305)
|
|
140
|
+
# On a Mac without user.email set, git builds the author from username +
|
|
141
|
+
# hostname (e.g., `<user>@<host>.local`). The address ships in every commit.
|
|
142
|
+
# Scan GIT_AUTHOR_IDENT against the pattern set plus the `.local` suffix.
|
|
143
|
+
# Fail-soft when git is missing or the ident cannot be resolved.
|
|
144
|
+
if [ -z "$BLOCK_REASON" ] && command -v git >/dev/null 2>&1; then
|
|
145
|
+
AUTHOR_IDENT=$(git var GIT_AUTHOR_IDENT 2>/dev/null || true)
|
|
146
|
+
if [ -n "$AUTHOR_IDENT" ]; then
|
|
147
|
+
# Format: "Name <email> timestamp timezone"
|
|
148
|
+
AUTHOR_EMAIL=$(echo "$AUTHOR_IDENT" | grep -oE '<[^>]+>' | tr -d '<>')
|
|
149
|
+
if [ -n "$AUTHOR_EMAIL" ]; then
|
|
150
|
+
MATCH=$(echo "$AUTHOR_EMAIL" | grep -oE "$IDENTIFIER_PATTERNS" | head -1)
|
|
151
|
+
if [ -z "$MATCH" ] && echo "$AUTHOR_EMAIL" | grep -qE '\.local$'; then
|
|
152
|
+
MATCH="$AUTHOR_EMAIL"
|
|
153
|
+
fi
|
|
154
|
+
if [ -n "$MATCH" ]; then
|
|
155
|
+
BLOCK_REASON="commit author"
|
|
156
|
+
BLOCK_MATCH="$MATCH"
|
|
157
|
+
fi
|
|
158
|
+
fi
|
|
159
|
+
fi
|
|
160
|
+
fi
|
|
161
|
+
|
|
111
162
|
# BLOCK if any pattern matched
|
|
112
163
|
if [ -n "$BLOCK_REASON" ]; then
|
|
113
164
|
cat >&2 <<EOF
|
|
@@ -128,7 +179,12 @@ Resolution paths:
|
|
|
128
179
|
1. Rewrite the commit message or staged content to drop the identifier
|
|
129
180
|
- Replace machine names with placeholders like <machine> or the branch
|
|
130
181
|
- Replace absolute paths with relative paths or \$HOME references
|
|
131
|
-
2.
|
|
182
|
+
2. If the match is in your commit author identity:
|
|
183
|
+
- Set a stable identity: git config --global user.email \\
|
|
184
|
+
<username>@users.noreply.github.com
|
|
185
|
+
- And: git config --global user.name "<Your Name>"
|
|
186
|
+
- Then retry the commit; the author will no longer include the host.
|
|
187
|
+
3. Override (rare — for legitimate cases like DON'T-do-this documentation):
|
|
132
188
|
SKIP_IDENTIFIER_LEAK_SCRUB=1 git commit ...
|
|
133
189
|
|
|
134
190
|
See .claude/rules/identifier-leak-prevention.md for full discipline.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# tier: lite
|
|
3
|
+
# install-class: dual
|
|
4
|
+
#
|
|
5
|
+
# Session-start fragment: rebuild install-written-paths manifest when missing/stale.
|
|
6
|
+
# Per bassclef-upstream#2036 Finding #8 (Kunal Slot 1 cure).
|
|
7
|
+
#
|
|
8
|
+
# Walks lite-manifest.json. Registers each shipped file as install-written
|
|
9
|
+
# via the lib. Runs when state/install-written-paths.json is missing OR
|
|
10
|
+
# when any file in lite-manifest is newer than the manifest.
|
|
11
|
+
#
|
|
12
|
+
# Fail-soft per Nygard — logs advisory and continues on error.
|
|
13
|
+
# Override: SKIP_INSTALL_WRITTEN_PATHS_REBUILD=1
|
|
14
|
+
|
|
15
|
+
# Env-reach safe guard per bassclef-upstream#2036 Finding #4.
|
|
16
|
+
# Fragment is sourced by session-reflection.sh; use return (not exit) so parent survives.
|
|
17
|
+
# shellcheck disable=SC2317
|
|
18
|
+
if [ -n "${SKIP_INSTALL_WRITTEN_PATHS_REBUILD:-}" ]; then
|
|
19
|
+
return 0 2>/dev/null
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
_iwp_fragment_log() {
|
|
23
|
+
if command -v trace_log >/dev/null 2>&1; then
|
|
24
|
+
trace_log "install-written-paths-rebuild" "$*"
|
|
25
|
+
fi
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
_iwp_fragment_main() {
|
|
29
|
+
local project_root="${CLAUDE_PROJECT_DIR:-$(pwd)}"
|
|
30
|
+
local lite_manifest="$project_root/lite-manifest.json"
|
|
31
|
+
local write_manifest="$project_root/state/install-written-paths.json"
|
|
32
|
+
local lib="$project_root/lib/install-written-paths.sh"
|
|
33
|
+
|
|
34
|
+
# Fallback to BASSCLEF_DIR when CLAUDE_PROJECT_DIR doesn't carry bassclef
|
|
35
|
+
if [ ! -f "$lite_manifest" ] && [ -n "${BASSCLEF_DIR:-}" ]; then
|
|
36
|
+
lite_manifest="$BASSCLEF_DIR/lite-manifest.json"
|
|
37
|
+
lib="$BASSCLEF_DIR/lib/install-written-paths.sh"
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# Skip when inputs missing (fail-soft)
|
|
41
|
+
if [ ! -f "$lib" ]; then
|
|
42
|
+
_iwp_fragment_log "skip reason=no-lib"
|
|
43
|
+
return 0
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
if [ ! -f "$lite_manifest" ]; then
|
|
47
|
+
_iwp_fragment_log "skip reason=no-lite-manifest"
|
|
48
|
+
return 0
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
52
|
+
_iwp_fragment_log "skip reason=no-jq"
|
|
53
|
+
return 0
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
# Decide whether to rebuild: missing OR older than lite-manifest
|
|
57
|
+
local rebuild=0
|
|
58
|
+
if [ ! -f "$write_manifest" ]; then
|
|
59
|
+
rebuild=1
|
|
60
|
+
elif [ "$lite_manifest" -nt "$write_manifest" ]; then
|
|
61
|
+
rebuild=1
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
if [ "$rebuild" -eq 0 ]; then
|
|
65
|
+
_iwp_fragment_log "skip reason=manifest-fresh"
|
|
66
|
+
return 0
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
# Source lib — subshell so caller scope stays clean
|
|
70
|
+
(
|
|
71
|
+
# shellcheck source=/dev/null
|
|
72
|
+
. "$lib" 2>/dev/null || exit 0
|
|
73
|
+
|
|
74
|
+
if ! declare -F install_written_paths_register >/dev/null 2>&1; then
|
|
75
|
+
_iwp_fragment_log "skip reason=lib-missing-verb"
|
|
76
|
+
exit 0
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
# Reset manifest to empty, then walk lite-manifest entries
|
|
80
|
+
rm -f "$write_manifest" 2>/dev/null || true
|
|
81
|
+
install_written_paths_rebuild 2>/dev/null || true
|
|
82
|
+
|
|
83
|
+
local registered=0
|
|
84
|
+
local skipped=0
|
|
85
|
+
|
|
86
|
+
# Each lite-manifest entry has .path field — register when file exists on disk
|
|
87
|
+
while IFS= read -r path; do
|
|
88
|
+
[ -z "$path" ] && continue
|
|
89
|
+
local full
|
|
90
|
+
case "$path" in
|
|
91
|
+
/*) full="$path" ;;
|
|
92
|
+
*) full="$project_root/$path" ;;
|
|
93
|
+
esac
|
|
94
|
+
if [ -f "$full" ]; then
|
|
95
|
+
if install_written_paths_register "$path" "bassclef-sync-template" 2>/dev/null; then
|
|
96
|
+
registered=$((registered + 1))
|
|
97
|
+
else
|
|
98
|
+
skipped=$((skipped + 1))
|
|
99
|
+
fi
|
|
100
|
+
else
|
|
101
|
+
skipped=$((skipped + 1))
|
|
102
|
+
fi
|
|
103
|
+
done < <(jq -r '.entries[]?.path // empty' "$lite_manifest" 2>/dev/null)
|
|
104
|
+
|
|
105
|
+
_iwp_fragment_log "rebuild complete registered=$registered skipped=$skipped"
|
|
106
|
+
) || true
|
|
107
|
+
|
|
108
|
+
return 0
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
_iwp_fragment_main
|
|
@@ -61,6 +61,14 @@ SCHEMA_DIR="${PROJECT_DIR}/standards/state-spine/schemas"
|
|
|
61
61
|
|
|
62
62
|
# If schema dir doesn't exist, this repo doesn't have spine v0 yet — pass through
|
|
63
63
|
if [ ! -d "$SCHEMA_DIR" ]; then
|
|
64
|
+
# Per cli#316 — honest skip. Previously exited 0 silently; adopters +
|
|
65
|
+
# agents on lite couldn't tell "validated" from "not checked". /launch
|
|
66
|
+
# and /objectory-decompose SKILLs promise this hook will BLOCK bad
|
|
67
|
+
# frontmatter. On lite, where schemas don't ship, this message makes
|
|
68
|
+
# the skip visible so the promise doesn't lie.
|
|
69
|
+
if [ "${STATE_VALIDATE_QUIET:-0}" != "1" ]; then
|
|
70
|
+
echo "state-validate: schemas not available (standards/state-spine/schemas missing at $SCHEMA_DIR); validation skipped at this tier — set STATE_VALIDATE_QUIET=1 to silence" >&2
|
|
71
|
+
fi
|
|
64
72
|
exit 0
|
|
65
73
|
fi
|
|
66
74
|
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
tier: lite
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Install-Written-Paths — single accessor mediation
|
|
6
|
+
|
|
7
|
+
Discipline hooks that would fire on files written by install writers (`bassclef init`, `bassclef-sync.sh`, `bassclef-hook-connect`, `schedule-auto-save`, template scripts) MUST consult `lib/install-written-paths.sh` via the single accessor `is_install_written_path <path>` before firing on each staged file.
|
|
8
|
+
|
|
9
|
+
The lib + manifest ship per bassclef-upstream#2036 Finding #8 (Kunal cold-adopter report, 2026-10-02). Structural cure for Class A (install-leak surfaces).
|
|
10
|
+
|
|
11
|
+
## When this rule fires
|
|
12
|
+
|
|
13
|
+
Any discipline hook that currently fires on file content without discriminating install-written from author-edited. Candidate hooks:
|
|
14
|
+
|
|
15
|
+
- `.claude/hooks/pre-commit-gate.sh` — lead-lens 3-marker gate section (consumer wired per this cure's V1 PR)
|
|
16
|
+
- `.claude/hooks/pre-commit-identifier-leak-scrub.sh` — identifier-leak sister per Kunal #1 (future adopter per R2 risk ledger)
|
|
17
|
+
- Any new discipline hook authored under the loop discipline (`.claude/rules/loop-discipline.md`) that assumes author-edit
|
|
18
|
+
|
|
19
|
+
## What the rule requires
|
|
20
|
+
|
|
21
|
+
Before firing discipline on a staged path, each discipline hook:
|
|
22
|
+
|
|
23
|
+
1. Sources `lib/install-written-paths.sh`.
|
|
24
|
+
2. Calls `is_install_written_path "$staged_path"`.
|
|
25
|
+
3. When return is 0 (true — path is install-written AND content hash matches), SKIP discipline for that path. Emit a trace line via `trace_log` for audit.
|
|
26
|
+
4. When return is 1 (false — path not in manifest OR hash drifted), FIRE discipline as today.
|
|
27
|
+
|
|
28
|
+
When all staged paths return 0, the hook returns pass without discipline. When at least one returns 1, the hook fires discipline on the author-edited paths.
|
|
29
|
+
|
|
30
|
+
## Anti-patterns
|
|
31
|
+
|
|
32
|
+
### Reimplementing the discrimination
|
|
33
|
+
|
|
34
|
+
Hook authors who grep `.bassclef-source.json` or hard-code install path lists duplicate the lib. Future rename events or new install writers break them silently.
|
|
35
|
+
|
|
36
|
+
INSTEAD: source the lib. Compose with the shared discipline.
|
|
37
|
+
|
|
38
|
+
### Skipping the lib for sister hooks
|
|
39
|
+
|
|
40
|
+
Discipline hooks that fire on install-written content but don't consult the lib produce Kunal-pattern false fires on cold adopters.
|
|
41
|
+
|
|
42
|
+
INSTEAD: add the consultation at the first opportunity. Per @luminary michael-feathers legacy-code retrofit — sister hooks consult the lib when next touched for other work.
|
|
43
|
+
|
|
44
|
+
## Composes with
|
|
45
|
+
|
|
46
|
+
- `.claude/rules/bootstrap-pair-discipline.md` — this rule + lib + schema + hook consumption + session-start fragment ship paired
|
|
47
|
+
- `.claude/rules/state-schema-validation.md` — schema at `standards/state-spine/schemas/install-written-paths.schema.json` validates on write
|
|
48
|
+
- `.claude/rules/we-dont-break-adopters.md` — additive; existing SKIP_* paths preserved
|
|
49
|
+
- `.claude/rules/sibling-smoke-after-substrate-change.md` — post-merge sibling smoke confirms Kunal #8 cured end-to-end
|
|
50
|
+
- @luminary linus-torvalds — adopter contract (manifest IS the adopter-visible surface this cure protects)
|
|
51
|
+
- @luminary michael-feathers — characterization tests (lib tests pin actual install-vs-author discrimination)
|
|
52
|
+
- @luminary john-ousterhout — deep module (narrow 5-verb interface hides schema + hash + I/O complexity)
|
|
53
|
+
- @luminary michael-nygard — fail-soft (missing manifest, malformed JSON, missing hash tool → return "not install-written" + advisory to stderr)
|
|
54
|
+
|
|
55
|
+
## Override path
|
|
56
|
+
|
|
57
|
+
`SKIP_INSTALL_WRITTEN_PATHS=1` — the lib's `is_install_written_path` returns 1 (false) unconditionally when this env var is set. Hooks fire discipline normally. Logged via `trace_log`.
|
|
58
|
+
|
|
59
|
+
INSTEAD of overriding routinely: trust the lib. Overrides are for one-shot debugging where the manifest-based path has misclassified.
|
|
60
|
+
|
|
61
|
+
## V1 scope — this cure's PR
|
|
62
|
+
|
|
63
|
+
- `lib/install-written-paths.sh` + Tier 0 tests
|
|
64
|
+
- `standards/state-spine/schemas/install-written-paths.schema.json` + state-spine.md Shape C entry
|
|
65
|
+
- `.claude/hooks/pre-commit-gate.sh` — lead-lens 3-marker gate section amended to consult the lib
|
|
66
|
+
- `presence/install/bassclef-hook-connect.sh` — registers each path on write
|
|
67
|
+
- `presence/install/bassclef-sync.template.sh` — registers each path on sync
|
|
68
|
+
- `.claude/hooks/session-reflection.d/83-install-written-paths-rebuild.sh` — regenerates manifest when missing at session-start
|
|
69
|
+
|
|
70
|
+
## Deferred to follow-on
|
|
71
|
+
|
|
72
|
+
- `bassclef init` npm-side registration (lands in bassclef-cli; sources the lib via package symlink)
|
|
73
|
+
- `pre-commit-identifier-leak-scrub.sh` consultation (sister hook adoption per Feathers legacy-code retrofit)
|
|
74
|
+
- Any other hook that assumes author-edit — audit at next /architect-review
|
|
@@ -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
|
|
@@ -590,7 +590,26 @@ already open. Operator merges inline.
|
|
|
590
590
|
|
|
591
591
|
### Phase 7 — ApprovalGateLink (LIVE — STUBBED)
|
|
592
592
|
|
|
593
|
-
|
|
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:
|
|
594
613
|
|
|
595
614
|
```
|
|
596
615
|
TODO: live execution — when all steps merged + CI green, would dispatch
|
|
@@ -599,6 +618,17 @@ required-reviewer rail per manual-prod-approval.md. Operator approves
|
|
|
599
618
|
prod deploy via GitHub UI from phone. /build NEVER bypasses this rail.
|
|
600
619
|
```
|
|
601
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
|
+
|
|
602
632
|
<!-- FKGL-EXEMPT: Phase 7.5 references paths + skip criteria per architect-review SKILL; technical dispatch stub matches sibling STUB pattern -->
|
|
603
633
|
### Phase 7.5 — /architect-review auto-dispatch (LIVE — STUBBED, per #1437 Step 2 wiring)
|
|
604
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
|
|
@@ -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
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": "v1.6.6",
|
|
3
|
-
"marker_tag": "release-2026-10-
|
|
4
|
-
"release_date": "2026-10-
|
|
5
|
-
"release_sha": "
|
|
6
|
-
"release_tag": "release-2026-10-
|
|
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
|
}
|