Lamprey Change Control
SkillDev toolsHow changes are classified, gated, approved, committed, and shipped in the Lamprey Harness repo. Load this BEFORE making any change — code, docs, config, or release — or when you see terms like P-SPR, STS, verify gate, era-lock, commit trailer, push policy, or when a commit/push is rejected by a hook.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Lamprey Change Control skill
What this skill tells your AI
The instructions your AI receives, as published by uss-parks/lamprey-harness in .claude/skills/lamprey-change-control/SKILL.md and read by ahel’s review.
When to use / when not
- Use before starting any work in this repo, when planning a phase, when a hook rejects your commit, when deciding whether something needs user approval, or when tempted to add a feature.
- Don't use for the mechanics of running tests (see
lamprey-validation-and-qa), release execution (seelamprey-ship-and-release), or writing DEVLOG/README entries (seelamprey-docs-and-writing).
TL;DR
- Classify the change: trivial one-off → just do it with the standard gates. Anything non-trivial → plan first, get explicit approval, then execute.
- Non-trivial work follows P-SPR → approval → STS: a saved plan file, an explicit user green light, then prompt-by-prompt execution with a verify gate and one commit per prompt.
- Every commit must pass the hook gates (lint, tsc ×2, AI-artifact scan, message rules including a mandatory trailer).
- Never push unless the user asked. When they ask, push on the first try.
- The project is era-locked: features beyond the Claude Code / Opus 4.5 era (2025-11-24 → 2026-01-24) require explicit user authorization, documented as such.
Change classification
| You want to… | Classification | Required gate |
|---|---|---|
| Fix a typo, single small edit, answer a question | Trivial one-off | Standard commit gates (hooks run tsc ×2 + lint + artifact scan) |
| Fix a bug touching 1–3 files | Small change | Same + targeted npx vitest run <affected tests>; npm run verify:proof -- --no-tests if electron/ipc/chat.ts is touched |
| Add a feature, refactor across files, new subsystem | Non-trivial | Full P-SPR → approval → STS cycle (below) |
| Add anything beyond the Opus 4.5-era feature set | Era-lock exception | Explicit user authorization first; document the exception (see Loop Phase precedent) |
| Release a version | Ship | lamprey-ship-and-release pipeline + README update (lamprey-docs-and-writing) |
| Delete a subsystem | Non-trivial + user direction | Deletion is a legitimate tool here (Unburdening precedent) but only on explicit user direction |
The P-SPR → approval → STS cycle
P-SPR = Plan – Sequential Prompt Roster. A single canonical plan file at PLANNING/LAMPREY_<PHASE>_PLAN.md (template: PLANNING/PSPR_TEMPLATE.md) defining one phase end to end: goal, scope, non-goals, ordered numbered prompts, files touched, verify gates, commit/DEVLOG discipline, completion criteria, and approval state.
- Drafted or pasted text is not a P-SPR until saved as that plan file.
- A plan's own "STS authorization" wording is not approval. Only the user's explicit go-ahead is.
STS = Stem to Stern. After explicit approval, execute the roster in order, first prompt through phase wrap. Per prompt:
- Do the work of that prompt only. No skipping, batching, or reopening plan decisions unless blocked by new facts.
- Pass the verify gate:
npx tsc --noEmit -p tsconfig.node.json— cleannpx tsc --noEmit -p tsconfig.web.json— cleannpx vitest run <affected test files>— passing- If
electron/ipc/chat.tswas touched:npm run verify:proof -- --no-tests→ exit 0
- Write the DEVLOG entry (format in
lamprey-docs-and-writing). - Commit — one commit per prompt, message per the hook rules below.
- Mark the prompt
[x]in the plan.
Phase wrap gate: full npx vitest run + npm run build + npm run verify:proof, version bump, README + CLAUDE.md current-state update, DEVLOG phase entry.
Hook-enforced commit rules (verified against scripts/hooks/ 2026-07-02)
Install once: npm run hooks:install (sets core.hooksPath to scripts/hooks).
pre-commit runs, in order: node scripts/check-ai-artifacts.cjs → npm run lint → npx tsc --noEmit -p tsconfig.node.json → npx tsc --noEmit -p tsconfig.web.json. First failure stops the commit.
commit-msg hard rules:
- Required owner footer, verbatim, on its own line:
Authored and reviewed by Basho Parks, copyright 2026 - Subject: non-empty, ≤ 72 chars, states the change (no filler openers: "This commit", "Updated", "Various", "Misc", "WIP", "Changes", "Some")
- Banned phrases anywhere in the message (case-insensitive):
Co-Authored-By: Claude,Generated with,🤖,As an AI,Certainly,Here's what,Here is what,Key changes:,Summary of changes,In this commit,This PR,delve,seamlessly,leverages - Body cap: subject + up to 12 body lines (trailer excluded). Long explanations go in
DEVLOG.md. - Bypass requires
--no-verify— a deliberate human decision, not a convenience.
pre-push runs npm run verify:proof (full gate).
check-ai-artifacts.cjs scans the staged diff (added lines) for machine residue: elision placeholders ("… existing code …"), placeholder tags/secrets (YOUR_API_KEY), assistant voice ("As an AI…"), narration comments in code ("Let's…", "TODO: implement"). Exempt paths include PLANNING/**, DEVLOG.md, README.md, *.md. Deliberate bypass: ALLOW_AI_ARTIFACTS=1 git commit … (rare).
Push policy
- The user is the reviewer and pusher. Do not volunteer pushes.
- When the user explicitly asks to push (any phrasing), execute on the first try — the request itself satisfies the review step.
- Never
--forcewithout an explicit force-push instruction. - Parallel sessions on this repo must run in separate git worktrees so commits don't conflate.
Era-lock as a change-control rule
Scope is locked to Claude Code / Opus 4.5-era parity (2025-11-24 → 2026-01-24). Features from later eras are out of scope by default. The one shipped exception is the Loop Phase (v0.15.0), and it is the template for how an exception happens:
- Explicit user authorization in their own words ("incorporate a Looping option").
- Documented as a deliberate exception in CLAUDE.md, the plan, and the DEVLOG.
- Shipped OFF by default (
loopsEnabled: false) so the era-faithful default experience is unchanged.
Corollary: the multi-agent pipeline, auto-router, runtime proof gate, and composer were deliberately deleted (Unburdening, v0.14.0, −7,400 lines). Do not rebuild them. If old docs reference them, those entries are historical record.
The non-negotiables and the incident behind each
| Rule | Rationale | Incident |
|---|---|---|
| Every prompt passes its verify gate before commit | A green gate that silently skips is how P0s ship | v0.9.2: the schema-init regression test was silently skipping under a native-binding ABI mismatch; an invalid DDL shipped and every chat send failed. See lamprey-failure-archaeology. |
| Tests must assert the right invariant, not just pass | A passing suite can codify a defect | v0.11.1: two unit tests asserted that the Coder's reply was excluded from the reviewer packet — locking the bug in and making it invisible at CI. |
| No debug/diagnostic code force-enabled in shipped builds | Plaintext logs can capture secrets | JM-1/SEC-3: v0.15.x shipped with forceDebugTraceOn() persisting tool arguments to a plaintext log. Removed in v0.16.0. |
Config-file writes must be atomic; corrupt files preserved, never healed to {} | A torn write must not destroy credentials | JM-13: pre-v0.16.0, a crash mid-write to keys.json could wipe every provider key permanently. Now temp+rename via electron/services/atomic-json.ts. |
| Prefer deletion over gating for out-of-scope machinery | Gated dead weight still costs prompt bytes, maintenance, and cogency | Unburdening (v0.14.0): user-directed excision of the multi-agent stack; the product got simpler and prompt bytes dropped. |
| Any settings default must change in BOTH canonical and renderer literals | Silent drift between main and renderer once shipped wrong behavior | SP-1: renderer said 'auto', main said 'single', main silently won. Now default-app-settings.test.ts locks them byte-for-byte. |
| Documented ≠ wired: verify call sites | Load-bearing claims were found scaffolded but dead | Wiring Closure (v0.9.1): seven documented features had no caller. LP-0: the loop scaffold never ran a turn. See lamprey-proof-and-analysis-toolkit recipe 2. |
Provenance and maintenance
Based on direct reads of scripts/hooks/commit-msg, scripts/hooks/pre-commit, scripts/hooks/pre-push, scripts/check-ai-artifacts.cjs, the active parity PSPR, and CLAUDE.md Execution Rules, at v0.20.0 (2026-07-18).
Re-verify when in doubt:
- Trailer text:
grep -n "TRAILER=" scripts/hooks/commit-msg - Gate composition:
cat scripts/hooks/pre-commit scripts/hooks/pre-push - Current version:
node -e "console.log(require('./package.json').version)" - Active plan: inspect
PLANNING/LAMPREY_CODEX_JULY_2026_PARITY_PSPR.mdand CLAUDE.md "Current State"
Authored and reviewed by Basho Parks, copyright 2026
Signals
- GitHub stars
- 62
- Forks
- 2
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
lamprey-change-control- Source
- github.com/uss-parks/lamprey-harness