@friedbotstudio/create-baseline 0.2.0 → 0.3.0

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.
Files changed (88) hide show
  1. package/README.md +7 -3
  2. package/obj/template/.claude/commands/grant-push.md +19 -0
  3. package/obj/template/.claude/commands/init-project.md +26 -4
  4. package/obj/template/.claude/hooks/consent_gate_grant.mjs +107 -0
  5. package/obj/template/.claude/hooks/git_commit_guard.mjs +224 -0
  6. package/obj/template/.claude/hooks/harness_continuation.sh +101 -34
  7. package/obj/template/.claude/hooks/lib/common.mjs +283 -0
  8. package/obj/template/.claude/hooks/lib/common.sh +1 -1
  9. package/obj/template/.claude/hooks/memory_session_start.sh +20 -6
  10. package/obj/template/.claude/hooks/memory_stop.sh +161 -2
  11. package/obj/template/.claude/hooks/spec_approval_guard.sh +1 -1
  12. package/obj/template/.claude/hooks/swarm_approval_guard.sh +1 -1
  13. package/obj/template/.claude/hooks/tests/fixtures/ac008_byte_equal_reference.txt +7 -7
  14. package/obj/template/.claude/hooks/tests/fixtures/memory_stop_landmark_baseline.txt +21 -0
  15. package/obj/template/.claude/hooks/tests/fixtures/regenerate-ac008.sh +47 -0
  16. package/obj/template/.claude/hooks/tests/memory_session_start_test.sh +7 -3
  17. package/obj/template/.claude/hooks/tests/memory_stop_intent_test.sh +329 -0
  18. package/obj/template/.claude/hooks/tests/regenerate_ac008_test.sh +99 -0
  19. package/obj/template/.claude/memory/README.md +8 -3
  20. package/obj/template/.claude/memory/backlog.md +12 -0
  21. package/obj/template/.claude/project.json +6 -1
  22. package/obj/template/.claude/settings.json +3 -4
  23. package/obj/template/.claude/skills/audit-baseline/audit.sh +39 -21
  24. package/obj/template/.claude/skills/audit-baseline/tests/fixtures/_pending_opener_only.md +3 -0
  25. package/obj/template/.claude/skills/audit-baseline/tests/fixtures/preamble_full_empty_body.md +4 -0
  26. package/obj/template/.claude/skills/audit-baseline/tests/fixtures/preamble_full_with_entries.md +9 -0
  27. package/obj/template/.claude/skills/audit-baseline/tests/fixtures/preamble_no_opener.md +3 -0
  28. package/obj/template/.claude/skills/audit-baseline/tests/fixtures/preamble_opener_only.md +3 -0
  29. package/obj/template/.claude/skills/audit-baseline/tests/preamble_check_test.sh +147 -0
  30. package/obj/template/.claude/skills/chore/SKILL.md +5 -3
  31. package/obj/template/.claude/skills/commit/SKILL.md +5 -4
  32. package/obj/template/.claude/skills/copywriting/LICENSE +21 -0
  33. package/obj/template/.claude/skills/copywriting/NOTICE +23 -0
  34. package/obj/template/.claude/skills/copywriting/SKILL.md +1 -1
  35. package/obj/template/.claude/skills/design-ui/SKILL.md +23 -5
  36. package/obj/template/.claude/skills/design-ui/references/design-vs-development.md +26 -5
  37. package/obj/template/.claude/skills/design-ui/references/orchestration.md +1 -0
  38. package/obj/template/.claude/skills/design-ui/references/state-machine.md +5 -3
  39. package/obj/template/.claude/skills/documentation/LICENSE +202 -0
  40. package/obj/template/.claude/skills/documentation/NOTICE +22 -0
  41. package/obj/template/.claude/skills/google-analytics/SKILL.md +129 -0
  42. package/obj/template/.claude/skills/google-analytics/references/audiences.md +389 -0
  43. package/obj/template/.claude/skills/google-analytics/references/bigquery.md +470 -0
  44. package/obj/template/.claude/skills/google-analytics/references/custom-dimensions.md +355 -0
  45. package/obj/template/.claude/skills/google-analytics/references/custom-events.md +383 -0
  46. package/obj/template/.claude/skills/google-analytics/references/data-management.md +416 -0
  47. package/obj/template/.claude/skills/google-analytics/references/debugview.md +364 -0
  48. package/obj/template/.claude/skills/google-analytics/references/events-fundamentals.md +398 -0
  49. package/obj/template/.claude/skills/google-analytics/references/gtag.md +502 -0
  50. package/obj/template/.claude/skills/google-analytics/references/gtm-integration.md +483 -0
  51. package/obj/template/.claude/skills/google-analytics/references/measurement-protocol.md +519 -0
  52. package/obj/template/.claude/skills/google-analytics/references/privacy.md +441 -0
  53. package/obj/template/.claude/skills/google-analytics/references/recommended-events.md +464 -0
  54. package/obj/template/.claude/skills/google-analytics/references/reporting.md +397 -0
  55. package/obj/template/.claude/skills/google-analytics/references/setup.md +344 -0
  56. package/obj/template/.claude/skills/google-analytics/references/user-tracking.md +417 -0
  57. package/obj/template/.claude/skills/harness/SKILL.md +3 -1
  58. package/obj/template/.claude/skills/humanizer/LICENSE +21 -0
  59. package/obj/template/.claude/skills/humanizer/NOTICE +21 -0
  60. package/obj/template/.claude/skills/impeccable/LICENSE +202 -0
  61. package/obj/template/.claude/skills/impeccable/NOTICE +24 -0
  62. package/obj/template/.claude/skills/memory-flush/SKILL.md +20 -4
  63. package/obj/template/.claude/skills/memory-flush/sweep.py +74 -6
  64. package/obj/template/.claude/skills/memory-flush/tests/run.sh +300 -1
  65. package/obj/template/.claude/skills/optimize-seo/SKILL.md +313 -0
  66. package/obj/template/.claude/skills/optimize-seo/scripts/pagespeed.mjs +197 -0
  67. package/obj/template/.claude/skills/pagespeed-insights/LICENSE.md +37 -0
  68. package/obj/template/.claude/skills/pagespeed-insights/SKILL.md +446 -0
  69. package/obj/template/.claude/skills/pagespeed-insights/reference.md +50 -0
  70. package/obj/template/.claude/skills/tdd/SKILL.md +2 -1
  71. package/obj/template/.claude/skills/tdd/drift_check.py +180 -0
  72. package/obj/template/.claude/skills/tdd/tests/drift_check_test.sh +190 -0
  73. package/obj/template/.claude/skills/tdd/tests/run.sh +21 -0
  74. package/obj/template/.claude/skills/technical-tutorials/LICENSE +21 -0
  75. package/obj/template/.claude/skills/technical-tutorials/NOTICE +23 -0
  76. package/obj/template/.claude/skills/technical-tutorials/SKILL.md +1 -1
  77. package/obj/template/.claude/skills/triage/SKILL.md +8 -3
  78. package/obj/template/CLAUDE.md +37 -26
  79. package/obj/template/docs/init/seed.md +38 -23
  80. package/obj/template/manifest.json +80 -33
  81. package/package.json +1 -1
  82. package/src/CLAUDE.template.md +37 -26
  83. package/src/memory/backlog.template.md +12 -0
  84. package/src/project.template.json +6 -1
  85. package/src/seed.template.md +38 -23
  86. package/src/settings.template.json +3 -4
  87. package/obj/template/.claude/hooks/consent_gate_grant.sh +0 -89
  88. package/obj/template/.claude/hooks/git_commit_guard.sh +0 -93
@@ -44,7 +44,7 @@ On every new session, before any work, you SHALL:
44
44
  You SHALL then proceed with whatever the user asks. Project-agnostic mode is **allowed** — the user is not required to run `/init-project` to use the baseline. The `setup_guard` hook surfaces a one-shot reminder on Write/Edit/MultiEdit (rate-limited to 10 minutes); it does **not** block writes. Other guards (commit, env, spec-approval, verify-pass, track, swarm-boundary) remain hard regardless of `configured` state.
45
45
  3. **If `configured: true`** — read `docs/init/seed.md` §16 if present so you know what was added. Tell the user:
46
46
  > "Configured for `<stack>`. Run `/triage \"<request>\"` to start a workflow, or `/harness` for the full pipeline."
47
- 4. **Memory check.** The `memory_session_start` hook injects a memory index into your additional context. If it reports `K candidates pending in _pending.md` with `K > 0`, you SHALL invoke `/memory-flush` before any workflow phase work keeps canonical memory fresh for downstream skills.
47
+ 4. **Memory check.** The `memory_session_start` hook injects a memory index into your additional context. The hook emits a **debt-mode nag** only when `_pending.md` has unflushed candidates AND no active workflow on disk (i.e., `.claude/state/workflow.json` is absent) those candidates are debt from a prior workflow that didn't end-flush. During an active workflow, **Phase 10.6** (memory-flush, between archive and grant-commit) handles flushing automatically; the session-start nag stays silent. You SHALL run `/memory-flush` when the debt-mode nag fires, before starting new work.
48
48
  5. **Git-repo check.** Run `git rev-parse --is-inside-work-tree 2>/dev/null` at the project root. If non-zero (not a git repo), surface this once per session and tell the user that gate C and the `commit` phase will be auto-excepted; the workflow ends after `/archive`. This is a sanctioned operating mode — Article IV phase 11 and Article VII are git-conditional.
49
49
  6. Once per session is sufficient. You SHALL NOT repeat the greeting on every prompt.
50
50
 
@@ -68,6 +68,7 @@ The 11-phase workflow is the only sanctioned path from request to commit. Phase
68
68
  | 9 | Integrate | `/integrate` | binding verify verdict |
69
69
  | 10 | Document | `/document` | docs |
70
70
  | 10.5 | Archive | `/archive` | bundle at `docs/archive/<date>/<slug>/` |
71
+ | 10.6 | Memory flush | `/memory-flush` | curated canonical memory + reset `_pending.md` |
71
72
  | 11 | **Grant commit** (gate C) + commit | user runs **`/grant-commit`**, then `/commit` (skill) | commit |
72
73
 
73
74
  **Mandatory rules:**
@@ -77,7 +78,7 @@ The 11-phase workflow is the only sanctioned path from request to commit. Phase
77
78
  - The only mechanism to bypass a phase is the `exceptions` array in `.claude/state/workflow.json`, written by `/triage`.
78
79
  - **Phase 6c and Phase 11 are git-conditional.** On a project where `git rev-parse --is-inside-work-tree` exits non-zero (no `.git/`, not inside a work tree), `/triage` SHALL auto-add `swarm-plan`, `approve-swarm`, `swarm-dispatch`, `grant-commit`, and `commit` to `exceptions`. Phase 6 routes to solo `/tdd` unconditionally; the workflow ends after `/archive`. Worktree isolation (the swarm contract's physical safety mechanism) requires git; `swarm.isolation: "shared"` is a sanctioned configuration knob for git projects that opt out of worktrees but does NOT restore the cross-task write isolation the swarm-worker assumes — it is unsafe as a non-git fallback, especially when `swarm.exempt_path_prefixes` covers baseline-internal paths (e.g. `.claude/`). Persistence outside git is the user's responsibility. See Article VII for the matching rule on git operations.
79
80
  - The three consent gates (A, B, C) are **commands**, not skills. They are structurally un-invokable by Claude. You SHALL NOT self-approve.
80
- - **How the gates are structurally enforced.** Each consent command (`/approve-spec`, `/approve-swarm`, `/grant-commit`) is a slash command typed by the user. The `consent_gate_grant` UserPromptSubmit hook (Art. VIII) parses the user's prompt **before Claude is invoked** and writes a short-lived consent marker at `.claude/state/.<gate>_grant`. The corresponding PreToolUse approval guard (`spec_approval_guard`, `swarm_approval_guard`, `git_commit_guard`) then allows Claude's slash-command-body write of the approval token only when the marker is present, fresh (≤ `consent.gate_marker_ttl_seconds`, default 120), and slug-matched; the marker is single-use and deleted on the allowed write. Slug derivation is centralized in `lib/common.sh → canonical_slug` (strip directory prefix + trailing `.md`) so the marker and the expected slug always agree, whether the user typed a bare slug, a filename, or a full path. The same guards block Claude from writing the marker file itself via Write/Edit/MultiEdit. Claude cannot reach the UserPromptSubmit code path, so it cannot forge consent.
81
+ - **How the gates are structurally enforced.** Each consent command (`/approve-spec`, `/approve-swarm`, `/grant-commit`, `/grant-push`) is a slash command typed by the user. The `consent_gate_grant` UserPromptSubmit hook (Art. VIII) parses the user's prompt **before Claude is invoked** and writes a short-lived consent marker at `.claude/state/.<gate>_grant`. The corresponding PreToolUse approval guard (`spec_approval_guard`, `swarm_approval_guard`, `git_commit_guard`) then allows Claude's slash-command-body write of the approval token only when the marker is present, fresh (≤ `consent.gate_marker_ttl_seconds`, default 120), and slug-matched; the marker is single-use and deleted on the allowed write. `/grant-push` is **not** a workflow-phase gate — it is a Bash-time consent for push to a protected branch (see Article VII). Slug derivation is centralized in `lib/common.sh → canonical_slug` (strip directory prefix + trailing `.md`) so the marker and the expected slug always agree, whether the user typed a bare slug, a filename, or a full path. The same guards block Claude from writing the marker file itself via Write/Edit/MultiEdit. Claude cannot reach the UserPromptSubmit code path, so it cannot forge consent.
81
82
  - **Out-of-band**: `/rca` produces an incident postmortem at `docs/rca/<slug>.md`. It is not a workflow phase and often precedes a bugfix intake.
82
83
 
83
84
  **Entry points** (`/triage` writes `workflow.json` with `entry_phase` and `exceptions`):
@@ -105,7 +106,7 @@ When `/harness` is invoked, you SHALL:
105
106
 
106
107
  **The safety net.** The `harness_continuation` Stop hook (Article VIII) re-fires `Skill(harness)` only when the loop exited mid-flow — i.e., on-disk state is `{state: "continue"}` with the marker present, and `stop_hook_active` is absent on the Stop payload. In normal operation (loop runs to gate/failure/done), the hook sees `state != continue` or marker absent and stays silent. The hook is a defense-in-depth signal, not the primary driver: a healthy `Skill(harness)` invocation never depends on it. The hook is also bounded to one block per turn by Claude Code's `stop_hook_active` semantics, so it cannot itself drive multi-phase chaining.
107
108
 
108
- **Resume after yield.** The user runs the consent command (which writes the gate marker via `consent_gate_grant`), then `/harness` again. The next invocation re-enters preflight, finds the gate token on disk, marks the gate task `completed`, and re-enters the loop.
109
+ **Resume after yield (auto).** After yielding at a consent gate, the harness skill writes `state: yielded` and removes `.harness_active`. The user runs the consent slash command in their next prompt; `consent_gate_grant` writes the gate marker (outside Claude's tool boundary), the command body writes the consent token, and the `harness_continuation` Stop hook detects fresh consent (rung 4: `workflow.json` present + `state=yielded` + a consent-token mtime newer than `harness_state`). The hook emits `{decision:"block"}`, and `Skill(harness)` is re-invoked in the same turn. The next invocation re-enters preflight, finds the gate token on disk, marks the gate task `completed`, and re-enters the loop. The user does not type `/harness` to resume.
109
110
 
110
111
  **Task discipline (autonomous progression).** `/triage` seeds a `TaskCreate`-backed checklist covering every non-excepted phase plus consent-gate placeholders (the placeholders carry `metadata.needs_user: true`). Inside the loop you SHALL: (a) call `TaskList` first; if empty, re-seed from `workflow.json → completed + exceptions + entry_phase` using the canonical templates in `triage`'s SKILL.md; (b) `TaskUpdate` the next pending non-blocked task to `in_progress` before invoking its phase skill; (c) `TaskUpdate` to `completed` only after the phase skill returns success; (d) when the next pending task carries `needs_user: true`, EXIT LOOP with YIELD — never invoke a skill for that task. The TaskList is session-bound; `workflow.json → completed` is the durable truth, and re-seeding always reconciles to it.
111
112
 
@@ -157,21 +158,25 @@ The following bind every code change.
157
158
 
158
159
  **Applicability.** Article VII applies only when the project is a git repository (`git rev-parse --is-inside-work-tree` exits 0 at the project root). On a non-git project, this Article is vacuously satisfied: you SHALL NOT attempt any git operation, gate C and the `commit` phase are auto-excepted at triage time (Art. IV), and the workflow ends after `/archive`. The rules below bind only inside the git-repository case.
159
160
 
160
- You SHALL run `git add <named paths>` and `git commit` only when **both** hold:
161
+ **Branch-aware consent policy.** Consent enforcement for `git commit` and `git push` is driven by two `project.json` knobs:
161
162
 
162
- 1. The user has explicitly asked for a commit in their current request; **and**
163
- 2. A fresh `commit_consent` token exists at `.claude/state/commit_consent` (5-minute TTL, written by `/grant-commit`).
163
+ - `git.protected_branches` glob list. `null` (default) means every branch is protected. Set e.g. `["main", "release/*"]` to limit consent enforcement to those branches.
164
+ - `git.branch_pattern` regex. `null` (default) means no naming check. Set e.g. `"^(feat|fix|chore|docs)/[a-z0-9-]+$"` to require conformant branch names on commit.
164
165
 
165
- `git_commit_guard` (Art. VIII) enforces both conditions.
166
+ On a **protected branch**, commits require a fresh `commit_consent` token (written by `/grant-commit`, 5-min TTL) and pushes require a fresh `push_consent` token (written by `/grant-push`, 5-min TTL) — both gated by the user having explicitly asked for the operation in their current request. On a non-protected branch, commits and pushes proceed without consent. `git_commit_guard` (Art. VIII) is the enforcer.
166
167
 
167
- You SHALL NEVER, unless the user names the exact operation in their current request:
168
+ **Detached HEAD.** When the current branch resolves to the literal string `HEAD` (detached state), the guard denies both commit and push with an explicit message. Check out a named branch before attempting either — branch-aware policy needs a named branch to evaluate `git.protected_branches` and `git.branch_pattern`.
168
169
 
169
- - `git push`, `git push --force`, `--force-with-lease`
170
- - `git commit --amend` — always create a new commit
171
- - `--no-verify`, `--no-gpg-sign`, or any flag that skips hooks/signing
172
- - `git reset --hard`, `git clean -f`, `git checkout --`, `git branch -D`
173
- - `git config`, `git rebase -i`, `git add -i`
174
- - `git add -A`, `git add .` — name the paths
170
+ **Hard-blocks regardless of consent, branch, or user request.** These operations rewrite history, skip safety, or sweep paths; `git_commit_guard`'s `FORBIDDEN_RE` blocks them flat-out:
171
+
172
+ - `git commit --amend` always create a new commit.
173
+ - `--no-verify`, `--no-gpg-sign`, or any flag that skips hooks/signing.
174
+ - `git reset --hard`, `git clean -f`, `git checkout --`, `git branch -D`.
175
+ - `git config` changes.
176
+ - `git rebase -i`, `git add -i` (interactive).
177
+ - `git add -A`, `git add .` — name the paths.
178
+
179
+ `git push` is no longer in this set — it is governed by the branch-aware policy above. `git push --force` and `--force-with-lease` are still forbidden unless the user names the exact operation in their current request, AND additionally subject to the branch-aware policy (force-push to a protected branch requires fresh `push_consent` plus the user-named carve-out).
175
180
 
176
181
  ## Article VIII — Hooks (the enforcement layer)
177
182
 
@@ -181,7 +186,7 @@ The 22 hooks in `.claude/hooks/` are the structural enforcement of this constitu
181
186
  |---|---|---|---|
182
187
  | `setup_guard` | PreToolUse / Edit\|Write\|MultiEdit | Art. III | Advisory reminder when `configured: false` (rate-limited 10 min). Does **not** block. |
183
188
  | `destructive_cmd_guard` | PreToolUse / Bash | Art. VII | Hard-block catastrophic commands; ask risky |
184
- | `git_commit_guard` | PreToolUse / Bash + Edit\|Write\|MultiEdit | Art. IV gate C, Art. VII | Bash: require fresh consent for `git commit`; hard-block forbidden flags. Write: gate writes to `.claude/state/commit_consent` and the `.commit_consent_grant` marker |
189
+ | `git_commit_guard` | PreToolUse / Bash + Edit\|Write\|MultiEdit | Art. IV gate C, Art. VII | Bash: enforce branch-aware policy `git commit` on a protected branch requires fresh `commit_consent`; `git push` on a protected branch requires fresh `push_consent`; both proceed without consent on non-protected branches; off-`branch_pattern` branches deny commits; detached HEAD denies both. Hard-block remaining forbidden flags (--amend, --no-verify, reset --hard, etc.). Write: gate writes to `.claude/state/{commit,push}_consent` and the matching `.{commit,push}_consent_grant` markers. |
185
190
  | `env_guard` | PreToolUse / Edit\|Write\|MultiEdit\|NotebookEdit | Art. VII | Block writes to `.env*` (allows `.env.example`) |
186
191
  | `spec_approval_guard` | PreToolUse / Edit\|Write\|MultiEdit | Art. IV gate A | Validate fresh `.spec_approval_grant` marker before allowing approval-token writes; block self-approval inside spec markdown; block direct writes to the marker |
187
192
  | `swarm_approval_guard` | PreToolUse / Edit\|Write\|MultiEdit | Art. IV gate B | Validate fresh `.swarm_approval_grant` marker before allowing swarm-approval writes; block direct writes to the marker |
@@ -200,13 +205,13 @@ The 22 hooks in `.claude/hooks/` are the structural enforcement of this constitu
200
205
  | `memory_stop` | Stop | Art. IX | Auto-extract memory candidates each turn-end |
201
206
  | `harness_continuation` | Stop | Art. V | Three-rung gate: (1) `stop_hook_active` absent on payload; (2) `.claude/state/.harness_active` exists (session-scoped marker created by the harness skill on `continue`, deleted on `yielded`/`done`, cleaned by `memory_session_start.sh` on session boundary); (3) `harness_state.state == "continue"`. When all three pass, emits `{"decision":"block","reason":"…invoke Skill(harness)…"}`. Sanity rail: marker-slug-vs-`workflow.json`-slug mismatch logs WARN to `harness_continuation.log` without changing the decision. Silent on any rung fail. Never writes consent markers. |
202
207
  | `memory_pre_compact` | PreCompact | Art. IX | Capture resume snapshot before context compaction |
203
- | `consent_gate_grant` | UserPromptSubmit | Art. IV gates A/B/C | Detect `/approve-spec`/`/approve-swarm`/`/grant-commit` in user input and write the gate-specific consent marker — runs OUTSIDE Claude's tool boundary so Claude cannot forge it |
208
+ | `consent_gate_grant` | UserPromptSubmit | Art. IV gates A/B/C, Art. VII | Detect `/approve-spec`/`/approve-swarm`/`/grant-commit`/`/grant-push` in user input and write the gate-specific consent marker — runs OUTSIDE Claude's tool boundary so Claude cannot forge it |
204
209
 
205
210
  ## Article IX — Project memory
206
211
 
207
212
  The memory system at `.claude/memory/` accumulates project facts across sessions. You SHALL:
208
213
 
209
- 1. Treat the six canonical files (`landmarks.md`, `libraries.md`, `decisions.md`, `landmines.md`, `conventions.md`, `pending-questions.md`) as long-term project memory. Each entry has a stable key per the schema in `.claude/memory/README.md`.
214
+ 1. Treat the seven canonical files (`landmarks.md`, `libraries.md`, `decisions.md`, `landmines.md`, `conventions.md`, `pending-questions.md`, `backlog.md`) as long-term project memory. Each entry has a stable key per the schema in `.claude/memory/README.md`.
210
215
  2. **Re-verify before citing.** Every skill that cites a memory entry SHALL re-verify it (file exists, symbol still at named line, library version still pinned). Failed verification → you SHALL correct or delete the entry in the same run before proceeding.
211
216
  3. Treat `_pending.md` as the auto-extraction inbox (written by `memory_stop`). Promote candidates to canonical files only via `/memory-flush`. You SHALL NOT write directly into canonical memory files outside the natural byproduct of phase skills.
212
217
  4. Treat `_resume.md` as the cross-session continuity snapshot (refreshed every turn-end and before compaction). It is **session memory**, not project memory.
@@ -257,7 +262,7 @@ Every UI design task that originates inside a workflow phase SHALL route through
257
262
  | A spec whose `write_set` intersects `project.json → tdd.ui_globs` SHALL declare a populated `## Design calls` section, one row per design surface. | `spec_design_calls_guard` (Art. VIII) at the Write boundary; `/spec-lint` at preflight. |
258
263
  | `/tdd` Step 6 SHALL invoke `Skill(design-ui, task_brief)` once per `## Design calls` row before Step 7 (verify). | `tdd` skill SOP. |
259
264
  | `design-ui` SHALL NOT write product code. Its only writes are the state file at `.claude/state/design/<slug>.json`, snapshots under `docs/design/<slug>.*.md`, and memory candidates. The product-code writes happen inside `impeccable` invocations. | `design-ui` SKILL.md. |
260
- | `design-ui` SHALL classify incoming intents at Stage 0 (design / development / copy). A misrouted intent returns `final_state: "not_a_design_task"` with a pointer to the correct lane and writes no code. | `design-ui` Stage 0 + `references/design-vs-development.md`. |
265
+ | `design-ui` SHALL classify incoming intents at Stage 0 (design / development / copy). A misrouted intent returns one of two terminal states: `final_state: "not_a_design_task"` (single-lane misroute) with `correct_lane`, OR `final_state: "mixed_brief"` (multi-lane misroute) with a structured `lane_split` array. Neither writes code. | `design-ui` Stage 0 + `references/design-vs-development.md`. |
261
266
  | Iteration cap: `audit → polish` loops SHALL terminate after 3 iterations with `final_state: "needs_human"` if P0 ≥ 1 or P1 > 0 persist. P0 issues block (do not loop). | `design-ui` SKILL.md + `references/orchestration.md`. |
262
267
  | Multi-step impeccable recipes SHALL ask the user before proceeding. Single-step recipes SHALL auto-execute. | `references/intent-table.md` `mode` column. |
263
268
 
@@ -267,15 +272,15 @@ The vendored `impeccable` skill stays untouched (Article IX). `design-ui` is the
267
272
 
268
273
  ## Article XI — Skill provenance and the baseline manifest
269
274
 
270
- Every skill at `.claude/skills/<slug>/SKILL.md` SHALL declare ownership in its YAML frontmatter as `owner: baseline` or `owner: user`. The build script `scripts/build-manifest.mjs` reads each `owner:` value and emits the canonical baseline-skill set into `obj/template/manifest.json` under `owners.skills` (a JSON object mapping slug → `"baseline"`). The CLI mirrors this manifest verbatim to `<target>/.claude/.baseline-manifest.json` on install. The audit at `.claude/skills/audit-baseline/audit.sh` consumes `manifest.owners.skills` as the canonical baseline-skill enumeration — the previous hard-coded `EXPECTED_SKILLS` set is removed.
275
+ A skill at `.claude/skills/<slug>/SKILL.md` is **baseline-owned** iff its YAML frontmatter declares `owner: baseline`. Every other skill on disk — those without an `owner:` field, or those declaring `owner: user` — is user/third-party and out-of-scope of baseline audit checks. Absence-of-`owner` is the deliberate default so a project with pre-existing skills can install the baseline without annotating any of its own files. The build script `scripts/build-manifest.mjs` reads each `owner:` value and emits the canonical baseline-skill set into `obj/template/manifest.json` under `owners.skills` (a JSON object mapping slug → `"baseline"`). The CLI mirrors this manifest verbatim to `<target>/.claude/.baseline-manifest.json` on install. The audit at `.claude/skills/audit-baseline/audit.sh` consumes `manifest.owners.skills` as the canonical baseline-skill enumeration — the previous hard-coded `EXPECTED_SKILLS` set is removed.
271
276
 
272
277
  You SHALL:
273
278
 
274
- 1. **Declare ownership.** Every new SKILL.md you author starts with `owner: baseline` (if it ships in the baseline) or `owner: user` (if it is project-local). The field appears in frontmatter directly after `name:`. Missing or invalid values fail the audit with `missing owner frontmatter` or `invalid owner=<value>`.
279
+ 1. **Declare baseline ownership only.** A SKILL.md that ships in the baseline SHALL declare `owner: baseline` in its frontmatter directly after `name:`. Authoring a user/third-party skill does NOT require any `owner:` annotation absence is the default. Explicit `owner: user` is permitted but never required. The only frontmatter-related FAIL the audit emits is `invalid owner=<value>` (a present-but-malformed `owner:` field, e.g. typo). Missing-`owner:` is silently skipped.
275
280
  2. **Trust the manifest.** The shipped `obj/template/manifest.json` (mirrored to `<target>/.claude/.baseline-manifest.json` on install) is the canonical record of baseline-owned skills and their content hashes. You SHALL NOT maintain a separate hard-coded list of baseline-skill slugs anywhere in the codebase.
276
281
  3. **Re-derive on drift.** The audit re-derives sha256 hashes from `manifest.files` for every path under `.claude/skills/<slug>/` whose slug appears in `owners.skills`, and compares against on-disk content. Mismatches surface as `hash mismatch at <path>`. A baseline-listed slug missing from disk surfaces as `baseline skill missing`. These are hard FAIL — drift detection has no opt-out.
277
282
  4. **Preserve constitutional citation.** This Article XI SHALL remain in CLAUDE.md AND in `src/CLAUDE.template.md` (byte-equal mirror). The genesis §17 in `docs/init/seed.md` SHALL remain present, with `src/seed.template.md` mirroring it. The audit verifies both citations and reports `CLAUDE.md missing Article XI citation` or `seed.md missing §17 citation` on absence.
278
- 5. **Exempt user skills from baseline checks.** User-owned skills (`owner: user`) are excluded from the baseline count, the names-match check, and the hash-drift check. Adding a local skill does not break the audit; it is the user's responsibility to maintain.
283
+ 5. **Out-of-scope skills don't break the audit.** Any skill on disk that doesn't declare `owner: baseline` is out-of-scope: excluded from the baseline count, the names-match check, and the hash-drift check. Installing the baseline into a project that already has its own skills is zero-friction — no per-file annotation required. Maintenance of those skills is the user's responsibility.
279
284
 
280
285
  Cryptographic supply-chain attestation, signed lock files, and per-skill aggregate merkle hashes are non-goals. The per-file `manifest.files` map already covers every file in every skill directory. A future `npx @friedbotstudio/create-baseline upgrade` subcommand will consume `manifest.owners.skills` + `manifest.files` to re-overlay baseline-owned files safely while leaving user-added or locally-customized files untouched — that subcommand is out of scope of this Article.
281
286
 
@@ -288,11 +293,11 @@ Cryptographic supply-chain attestation, signed lock files, and per-skill aggrega
288
293
  | `.claude/hooks/` | 22 hook scripts (17 write/run-boundary + 4 lifecycle + 1 input-boundary). Bash + python3, no jq. |
289
294
  | `.claude/agents/` | 1 baseline subagent: `swarm-worker` (rendered from `src/agents/swarm-worker.template.md`) |
290
295
  | `.claude/skills/` | 36 skills: artifact (4) + phases (10) + workers (5) + spec helpers (4) + orchestration (3) + memory (1) + shared globals (7) + audit (1) + alt tracks (1) |
291
- | `.claude/commands/` | 4 consent/bootstrap gates: `approve-spec`, `approve-swarm`, `grant-commit`, `init-project` |
292
- | `.claude/memory/` | 6 canonical knowledge files + `_pending.md` (staging) + `_resume.md` (continuity snapshot) + `README.md` |
296
+ | `.claude/commands/` | 5 consent/bootstrap gates: `approve-spec`, `approve-swarm`, `grant-commit`, `grant-push`, `init-project` |
297
+ | `.claude/memory/` | 7 canonical knowledge files + `_pending.md` (staging) + `_resume.md` (continuity snapshot) + `README.md` |
293
298
  | `.claude/project.json` | per-project config (test/lint cmd, TDD globs, destructive patterns, swarm config, additions). Populated by `/init-project`. |
294
299
  | `.claude/settings.json` | hook wiring + permissions |
295
- | `.claude/state/` | runtime: `workflow.json`, `commit_consent`, `spec_approvals/`, `swarm_approvals/`, `swarm/`, `harness/<slug>.log`, `last_test_result` |
300
+ | `.claude/state/` | runtime: `workflow.json`, `commit_consent`, `push_consent`, `spec_approvals/`, `swarm_approvals/`, `swarm/`, `harness/<slug>.log`, `last_test_result` |
296
301
  | `.mcp.json` | three baseline MCP servers: `context7`, `plantuml`, `playwright` |
297
302
  | `src/` | pristine ship-time templates for every file `/init-project` modifies (overlay source for `npx @friedbotstudio/create-baseline`) |
298
303
  | `docs/init/seed.md` | genesis prompt — governing specification of the baseline |
@@ -317,8 +322,14 @@ Cryptographic supply-chain attestation, signed lock files, and per-skill aggrega
317
322
  **Memory (1)**:
318
323
  - `memory-flush`
319
324
 
320
- **Shared globals (7)** — vendored / globally available:
321
- - `claude-automation-recommender` (Apache 2.0, vendored), `code-structure` (mandatory on all code), `humanizer`, `documentation`, `technical-tutorials`, `copywriting`, `impeccable`
325
+ **Shared globals (7)** — one written for this baseline, six vendored from external sources with their upstream licenses preserved in `LICENSE` + `NOTICE` alongside each skill:
326
+ - `claude-automation-recommender` vendored from Anthropic's `claude-code-setup` plugin, Apache 2.0.
327
+ - `code-structure` — written for this baseline (Friedbot Studio). Mandatory on every code-generation step.
328
+ - `humanizer` — vendored from [`blader/humanizer`](https://github.com/blader/humanizer), MIT.
329
+ - `documentation` — vendored from Anthropic's `claude-code-setup` plugin, Apache 2.0.
330
+ - `technical-tutorials` — vendored from [`jonathimer/devmarketing-skills`](https://github.com/jonathimer/devmarketing-skills), MIT.
331
+ - `copywriting` — vendored from [`coreyhaines31/marketingskills`](https://github.com/coreyhaines31/marketingskills), MIT.
332
+ - `impeccable` — vendored from [`pbakaus/impeccable`](https://github.com/pbakaus/impeccable), Apache 2.0.
322
333
 
323
334
  **Audit (1)**:
324
335
  - `audit-baseline` — drift check between this constitution + seed.md and the implementation
@@ -0,0 +1,12 @@
1
+ ---
2
+ owners: [/memory-flush]
3
+ category: future-work intent
4
+ size-cap: 500
5
+ key: <slug>-<4char-hash>
6
+ verifies-against: none
7
+ stale-exempt: true
8
+ ---
9
+
10
+ # Backlog
11
+
12
+ (populated by /memory-flush from auto-extracted candidates)
@@ -185,7 +185,12 @@
185
185
  },
186
186
  "consent": {
187
187
  "commit_ttl_seconds": 300,
188
- "gate_marker_ttl_seconds": 120
188
+ "gate_marker_ttl_seconds": 120,
189
+ "push_ttl_seconds": 300
190
+ },
191
+ "git": {
192
+ "protected_branches": null,
193
+ "branch_pattern": null
189
194
  },
190
195
  "swarm": {
191
196
  "max_parallel": 4,
@@ -11,7 +11,7 @@
11
11
 
12
12
  **Mandatory binding language.** Each numbered section (§) below specifies a binding requirement for the baseline. Implementations SHALL conform; `CLAUDE.md` Articles SHALL reference the corresponding §; project amendments (per `CLAUDE.md` Art. X) SHALL NOT contradict any § here.
13
13
 
14
- The baseline turns soft engineering rules (no unauthorized commits, no stubs, no mocks of internal code, no self-approved specs) into structural guarantees enforced by write-boundary hooks. Eleven workflow phases plus one stripped-down chore track (skips TDD; runs verify + archive mandatorily, simplify/integrate/document conditionally), seventeen write/run-boundary guards plus four lifecycle hooks plus one input-boundary hook (twenty-two `.sh` scripts total), thirty-six skills, one subagent, and three consent gates. Decisions live in main context; the lone subagent (`swarm-worker`) executes pre-decided recipes in parallel worktrees during `/swarm-dispatch`. Every artifact is archived; every third-party API is looked up against live docs. Project memory accumulates across sessions in `.claude/memory/` — auto-extracted by a Stop hook, curated in main context via `/memory-flush`, self-healing via re-verification.
14
+ The baseline turns soft engineering rules (no unauthorized commits, no stubs, no mocks of internal code, no self-approved specs) into structural guarantees enforced by write-boundary hooks. Eleven workflow phases plus one stripped-down chore track (skips TDD; runs verify + archive mandatorily, simplify/integrate/document conditionally), seventeen write/run-boundary guards plus four lifecycle hooks plus one input-boundary hook (twenty-two hook scripts total — twenty `.sh` + two `.mjs` after the JS-port pilot), thirty-six skills, one subagent, and four consent gates. Decisions live in main context; the lone subagent (`swarm-worker`) executes pre-decided recipes in parallel worktrees during `/swarm-dispatch`. Every artifact is archived; every third-party API is looked up against live docs. Project memory accumulates across sessions in `.claude/memory/` — auto-extracted by a Stop hook, curated in main context via `/memory-flush`, self-healing via re-verification.
15
15
 
16
16
  ---
17
17
 
@@ -109,9 +109,9 @@ Applies to every language. Mappings for TSX, Node, Python, Go, Rust ship inside
109
109
  │ ├── hooks/ # 22 hook scripts: 17 write/run-boundary guards + 4 lifecycle hooks + 1 input-boundary hook (bash + python3, no jq)
110
110
  │ │ └── lib/common.sh # shared helpers
111
111
  │ ├── agents/ # 1 subagent: swarm-worker (rendered from src/agents/swarm-worker.template.md)
112
- │ ├── commands/ # 4 consent/bootstrap gates (user-only — structurally)
112
+ │ ├── commands/ # 5 consent/bootstrap gates (user-only — structurally)
113
113
  │ ├── skills/ # 36 skills: artifact (4) + phases (10) + workers (5) + spec helpers (4) + orchestration (3) + memory (1) + shared globals (7) + audit (1) + alt tracks (1)
114
- │ ├── memory/ # project memory: 6 canonical files + _pending.md (gitignored body) + README.md
114
+ │ ├── memory/ # project memory: 7 canonical files + _pending.md (gitignored body) + README.md
115
115
  │ └── state/ # runtime: workflow.json, approvals, swarm plans, verdicts, logs
116
116
  ├── src/ # pristine ship-time templates (overlay source for `npx @friedbotstudio/create-baseline`)
117
117
  │ ├── CLAUDE.template.md
@@ -120,7 +120,7 @@ Applies to every language. Mappings for TSX, Node, Python, Go, Rust ship inside
120
120
  │ ├── .mcp.template.json
121
121
  │ ├── settings.template.json
122
122
  │ ├── agents/swarm-worker.template.md
123
- │ └── memory/<6 canonical>.template.md
123
+ │ └── memory/<7 canonical>.template.md
124
124
  └── docs/
125
125
  ├── init/seed.md # this file
126
126
  ├── intake/ brd/ scout/ research/ specs/ rca/ security/ site/
@@ -140,13 +140,13 @@ Applies to every language. Mappings for TSX, Node, Python, Go, Rust ship inside
140
140
 
141
141
  Each is an independent bash script that reads a JSON payload on stdin and emits a structured decision. Ordering within a `matcher` block matters only when one hook's decision should take precedence. The four lifecycle hooks (`memory_session_start`, `memory_stop`, `memory_pre_compact`, `harness_continuation`) are best-effort and never block; they maintain project memory, the cross-session resume snapshot, and the harness auto-continuation signal (`harness_continuation` reads `.claude/state/harness_state` on every Stop event and emits a `decision:block` directive when the harness has left `state: "continue"` AND the session-scoped marker `.claude/state/.harness_active` exists, so the next phase fires on the same turn; `memory_session_start` deletes that marker at every session boundary so yesterday's `continue` never ghost-resumes today).
142
142
 
143
- The single input-boundary hook (`consent_gate_grant`, on `UserPromptSubmit`) runs **before** Claude is invoked on every user turn. When the user types one of the three consent-gate slash commands (`/approve-spec <slug|path>`, `/approve-swarm <slug>`, `/grant-commit [note]`), this hook parses the prompt and writes a short-lived consent marker to `.claude/state/.<gate>_grant`. The PreToolUse approval guards (`spec_approval_guard`, `swarm_approval_guard`, `git_commit_guard`) read these markers as the structural source of consent: a Claude write to an approval token is allowed only when a fresh, slug-matched marker is on disk; the marker is single-use (deleted on the allowed write) and expires after `consent.gate_marker_ttl_seconds` (default 120). Slug derivation is centralized in `lib/common.sh → canonical_slug` (strip directory prefix + trailing `.md`) so the marker and the expected slug always agree — `docs/specs/foo.md`, `foo.md`, and `foo` all reduce to the bare slug `foo`. This is what makes Article IV's gates structurally un-invokable by Claude — Claude cannot reach the UserPromptSubmit code path, and the PreToolUse guards block Claude from writing the markers themselves.
143
+ The single input-boundary hook (`consent_gate_grant`, on `UserPromptSubmit`) runs **before** Claude is invoked on every user turn. When the user types one of the four consent-gate slash commands (`/approve-spec <slug|path>`, `/approve-swarm <slug>`, `/grant-commit [note]`, `/grant-push [note]`), this hook parses the prompt and writes a short-lived consent marker to `.claude/state/.<gate>_grant`. The PreToolUse approval guards (`spec_approval_guard`, `swarm_approval_guard`, `git_commit_guard`) read these markers as the structural source of consent: a Claude write to an approval token is allowed only when a fresh, slug-matched marker is on disk; the marker is single-use (deleted on the allowed write) and expires after `consent.gate_marker_ttl_seconds` (default 120). Slug derivation is centralized in `lib/common.sh → canonical_slug` (strip directory prefix + trailing `.md`) so the marker and the expected slug always agree — `docs/specs/foo.md`, `foo.md`, and `foo` all reduce to the bare slug `foo`. This is what makes Article IV's gates structurally un-invokable by Claude — Claude cannot reach the UserPromptSubmit code path, and the PreToolUse guards block Claude from writing the markers themselves.
144
144
 
145
145
  | Hook | Event / matcher | Enforces |
146
146
  |---|---|---|
147
147
  | `setup_guard` | PreToolUse / Write\|Edit\|MultiEdit\|NotebookEdit | Advisory. When `configured: false`, emits a one-shot reminder (rate-limited to 10 minutes) that the baseline is in project-agnostic mode and `/init-project` hasn't run. Does not block writes — bypass is intentional. The user gets baseline-only behaviour (test/lint runners in guide mode, no stack-specific tailoring) until `/init-project` runs. |
148
148
  | `destructive_cmd_guard` | PreToolUse / Bash | Hard-blocks catastrophic commands (`rm -rf /`, fork bombs, `dd of=/dev/sd*`, `mkfs`, `shutdown`). Asks on risky ones (`rm -rf <path>`, `git reset --hard`, `drop table`). Patterns sourced from `project.json → destructive`. |
149
- | `git_commit_guard` | PreToolUse / Bash + Write\|Edit\|MultiEdit | Bash matcher: requires fresh consent (`/grant-commit`, 5-minute TTL) for `git commit`. Hard-blocks `git push`, `git commit --amend`, `--no-verify`, `--no-gpg-sign`, `git reset --hard`, `git clean -f`, `git checkout --`, `git branch -D`, `git config`, `git rebase -i`, `git add -A`, `git add .`. Write matcher: blocks Claude from writing `.claude/state/.commit_consent_grant` (the marker — only `consent_gate_grant` may write it) and gates writes to `.claude/state/commit_consent` on a fresh marker. |
149
+ | `git_commit_guard` | PreToolUse / Bash + Write\|Edit\|MultiEdit | Bash matcher: enforces branch-aware policy. `git commit` on a protected branch (per `project.json → git.protected_branches` glob list; `null` = all branches protected) requires fresh `commit_consent` (`/grant-commit`, 5-min TTL); `git push` on a protected branch requires fresh `push_consent` (`/grant-push`, 5-min TTL); both proceed without consent on non-protected branches. `git.branch_pattern` regex (optional) gates commits on naming. Detached HEAD denies both. Hard-blocks remaining forbidden flags: `git commit --amend`, `--no-verify`, `--no-gpg-sign`, `git reset --hard`, `git clean -f`, `git checkout --`, `git branch -D`, `git config`, `git rebase -i`, `git add -A`, `git add .`. Write matcher: blocks Claude from writing `.claude/state/.commit_consent_grant` / `.push_consent_grant` (markers — only `consent_gate_grant` writes those) and gates writes to `.claude/state/commit_consent` / `push_consent` on a fresh marker. Implemented in `.claude/hooks/git_commit_guard.mjs` (Node ESM; JS-port pilot). |
150
150
  | `env_guard` | PreToolUse / Write\|Edit\|MultiEdit\|NotebookEdit | Blocks writes to `.env*`. Allows obvious templates (`.env.example`, `.env.sample`). |
151
151
  | `spec_approval_guard` | PreToolUse / Write\|Edit\|MultiEdit | Validates a fresh `.claude/state/.spec_approval_grant` marker (slug-matched, ≤ `consent.gate_marker_ttl_seconds`) before allowing Claude to write under `.claude/state/spec_approvals/`. Blocks Claude from writing the marker file itself. Blocks `Status: Approved` / `Approved: true` lines in spec markdown. |
152
152
  | `swarm_approval_guard` | PreToolUse / Write\|Edit\|MultiEdit | Symmetric to `spec_approval_guard` for gate B: validates `.claude/state/.swarm_approval_grant` before allowing writes under `.claude/state/swarm_approvals/`. Blocks Claude from writing the marker. |
@@ -165,7 +165,7 @@ The single input-boundary hook (`consent_gate_grant`, on `UserPromptSubmit`) run
165
165
  | `memory_stop` | Stop | At end of every assistant turn, reads the transcript, extracts memory candidates (touched source paths → landmarks; context7 queries → libraries), appends to `.claude/memory/_pending.md`, and refreshes `.claude/memory/_resume.md` for next session. Passive collector — never writes to canonical memory files. |
166
166
  | `memory_pre_compact` | PreCompact (manual\|auto) | Fires before context compaction. Walks the still-intact transcript and writes `.claude/memory/_resume.md` so the next `SessionStart` (source: `compact`) can re-inject the snapshot. Best-effort; never blocks compaction. |
167
167
  | `harness_continuation` | Stop | Auto-continues multi-phase workflows across non-gated boundaries. Reads `.claude/state/harness_state` (written by the harness skill on every tick) and `.claude/state/.harness_active` (session-scoped marker; created by the harness skill on `state: "continue"`, deleted on `yielded`/`done`, cleaned unconditionally by `memory_session_start.sh` on session boundary). Three-rung gate — all must pass to emit a decision: (1) `stop_hook_active` flag absent on payload; (2) `.harness_active` marker exists; (3) `harness_state.state` equals `"continue"`. When all pass, emits `{"decision":"block","reason":"…invoke Skill(harness)…"}` so the model resumes the harness on the same turn. Sanity rail: if the marker's slug content disagrees with `workflow.json → slug`, log one `WARN` line to `harness_continuation.log`; mismatch does not change the decision. Silent on any rung fail (`yielded`/`done`/missing marker/missing state/malformed). Treats every internal error as silence. Never writes consent markers; never bypasses Article IV gates. |
168
- | `consent_gate_grant` | UserPromptSubmit | Runs **before** Claude is invoked on every user turn. Detects the three consent-gate slash commands (`/approve-spec <slug\|path>`, `/approve-swarm <slug>`, `/grant-commit [note]`) at the start of the user's prompt and writes a short-lived consent marker (`.claude/state/.spec_approval_grant`, `.swarm_approval_grant`, or `.commit_consent_grant`). Slugs are canonicalized through `canonical_slug` (strip directory + trailing `.md`) so the marker matches whatever shape the approval guards derive from the approval filename. The marker is single-use and expires after `consent.gate_marker_ttl_seconds` (default 120). Because this hook fires outside Claude's tool boundary, Claude cannot reach this code path — the marker is structurally unforgeable by the model. |
168
+ | `consent_gate_grant` | UserPromptSubmit | Runs **before** Claude is invoked on every user turn. Detects the four consent-gate slash commands (`/approve-spec <slug\|path>`, `/approve-swarm <slug>`, `/grant-commit [note]`, `/grant-push [note]`) at the start of the user's prompt and writes a short-lived consent marker (`.claude/state/.spec_approval_grant`, `.swarm_approval_grant`, `.commit_consent_grant`, or `.push_consent_grant`). Slugs are canonicalized through `canonicalSlug` (strip directory + trailing `.md`) so the marker matches whatever shape the approval guards derive from the approval filename. The marker is single-use and expires after `consent.gate_marker_ttl_seconds` (default 120). Because this hook fires outside Claude's tool boundary, Claude cannot reach this code path — the marker is structurally unforgeable by the model. Implemented in `.claude/hooks/consent_gate_grant.mjs` (Node ESM; JS-port pilot). |
169
169
 
170
170
  All hooks source `.claude/hooks/lib/common.sh` for payload parsing, project-config reads, and decision emitters (`emit_allow`, `emit_block`, `emit_ask`, `emit_info`).
171
171
 
@@ -203,6 +203,7 @@ Each at `.claude/skills/<name>/SKILL.md`, frontmatter `name` + `description`, pl
203
203
  - `integrate` — Phase 9. Full suite + `verify` re-adjudication.
204
204
  - `document` — Phase 10. Orchestrator. Delegates technical reference to `documentation`, tutorials to `technical-tutorials`, and **all prose** to the `prose` skill (which applies `humanizer` mandatorily).
205
205
  - `archive` — Phase 10.5. Moves `<slug>`-matched artifacts to `docs/archive/<YYYY-MM-DD>/<slug>/`. `workflow.json` is held back and archived by `/commit`.
206
+ - `memory-flush` — Phase 10.6. Curates `_pending.md` candidates with full workflow context (or fast-paths on empty pending while still running canonical Step 0 sweeps). Canonical memory writes ship in the same commit as the work that motivated them.
206
207
  - `commit` — Phase 11. First step archives `workflow.json`; then stages named paths and commits.
207
208
 
208
209
  **Phase workers (5)** — execute pre-decided recipes; each mandatorily invokes a sub-skill. Caller (a phase skill) provides explicit inputs; the worker executes without picking architecture, register, or scope:
@@ -228,13 +229,15 @@ Each at `.claude/skills/<name>/SKILL.md`, frontmatter `name` + `description`, pl
228
229
 
229
230
  **Shared globals (7)** — skills the baseline *uses* heavily; vendored into `.claude/skills/` so they travel with the repo and have no external runtime dependency:
230
231
 
231
- - `claude-automation-recommender` Apache-2.0 vendored from upstream `claude-code-setup` plugin (Anthropic). Mandatory first step (§0); analyzes a target project and surfaces stack-specific tweaks for `/init-project`. License + attribution: `.claude/skills/claude-automation-recommender/{LICENSE,NOTICE}`.
232
- - `code-structure` — MANDATORY on every code-generation step. Language-agnostic three-layer model (Orchestration / Domain / Foundation). See §2.6.
233
- - `humanizer` — strips AI-writing tells (em-dash overuse, rule of three, inflated symbolism, AI vocabulary, superficial -ing, filler, hedging). Invoked by `prose` on every draft.
234
- - `documentation` — technical reference writing (API docs, architecture, runbooks). Delegate target from `/document`.
235
- - `technical-tutorials` — step-by-step / quickstart / walkthrough. Delegate target from `/document`. Audience-context shape lives in this skill's `references/audience-context.md` (consolidated from the upstream `developer-audience-context` skill on 2026-04-28).
236
- - `copywriting` — persuasive user-facing copy (landing, pricing, feature, hero, CTA). Invoked by `prose` when register is persuasive.
237
- - `impeccable` — production-grade frontend interface design. Loads `PRODUCT.md` / `DESIGN.md`, picks register (brand vs. product), applies shared design laws (OKLCH color, typography rhythm, layout cadence, motion tied to physics, copy with specificity). Vendored (Apache 2.0); stays untouched per Article IX. Inside workflow phases, `design-ui` orchestrates `impeccable` (per Article X.2) every UI design move is an `impeccable` subcommand invocation chosen and run from main context.
232
+ Each vendored shared global ships with its own `LICENSE` + `NOTICE` alongside the skill, recording the upstream URL and any local changes:
233
+
234
+ - `claude-automation-recommender` — Apache 2.0, vendored from Anthropic's `claude-code-setup` plugin. Mandatory first step (§0); analyzes a target project and surfaces stack-specific tweaks for `/init-project`.
235
+ - `code-structure` — MANDATORY on every code-generation step. Written for this baseline (Friedbot Studio); the repo license applies. Language-agnostic three-layer model (Orchestration / Domain / Foundation). See §2.6.
236
+ - `humanizer` — MIT, vendored from [`blader/humanizer`](https://github.com/blader/humanizer). Strips AI-writing tells (em-dash overuse, rule of three, inflated symbolism, AI vocabulary, superficial -ing, filler, hedging). Invoked by `prose` on every draft.
237
+ - `documentation` — Apache 2.0, vendored from Anthropic's `claude-code-setup` plugin. Technical reference writing (API docs, architecture, runbooks). Delegate target from `/document`.
238
+ - `technical-tutorials` — MIT, vendored from [`jonathimer/devmarketing-skills`](https://github.com/jonathimer/devmarketing-skills). Step-by-step / quickstart / walkthrough. Delegate target from `/document`. Audience-context shape lives in this skill's `references/audience-context.md` (consolidated from the upstream `developer-audience-context` skill on 2026-04-28).
239
+ - `copywriting` — MIT, vendored from [`coreyhaines31/marketingskills`](https://github.com/coreyhaines31/marketingskills). Persuasive user-facing copy (landing, pricing, feature, hero, CTA). Invoked by `prose` when register is persuasive.
240
+ - `impeccable` — Apache 2.0, vendored from [`pbakaus/impeccable`](https://github.com/pbakaus/impeccable). Production-grade frontend interface design. Loads `PRODUCT.md` / `DESIGN.md`, picks register (brand vs. product), applies shared design laws (OKLCH color, typography rhythm, layout cadence, motion tied to physics, copy with specificity). Stays untouched per Article IX. Inside workflow phases, `design-ui` orchestrates `impeccable` (per Article X.2) — every UI design move is an `impeccable` subcommand invocation chosen and run from main context.
238
241
 
239
242
  **Drift defender (1)**:
240
243
 
@@ -252,10 +255,11 @@ Files at `.claude/commands/<name>.md`. Commands differ from skills in exactly on
252
255
  |---|---|
253
256
  | `approve-spec` | Human approval of a spec draft. Accepts a bare slug, a filename, or a full path; canonicalizes via `lib/common.sh → canonical_slug` and writes `.claude/state/spec_approvals/<slug>.approval`. Only sanctioned path — `spec_approval_guard` blocks all other routes. |
254
257
  | `approve-swarm` | Human approval of a swarm plan. Writes `.claude/state/swarm_approvals/<slug>.approval`. Required before `swarm-dispatch` runs. |
255
- | `grant-commit` | Opens a 5-minute consent window for `git commit`. Writes `.claude/state/commit_consent`. Enforced by `git_commit_guard`. |
258
+ | `grant-commit` | Opens a 5-minute consent window for `git commit` on a protected branch. Writes `.claude/state/commit_consent`. Enforced by `git_commit_guard`. |
259
+ | `grant-push` | Opens a 5-minute consent window for `git push` on a protected branch. Writes `.claude/state/push_consent`. Enforced by `git_commit_guard`. Not a workflow-phase gate — a runtime consent for the branch-aware policy (§11). |
256
260
  | `init-project` | One-time bootstrap. Detects stack, proposes `.claude/project.json` (test cmd, lint cmd, TDD globs, destructive patterns, artifact required sections, swarm config). Flips `configured: true`. |
257
261
 
258
- **Adding a fifth command requires answering yes to both:** "does a human need to press this?" and "is 'user-only via frontmatter flag' too weak a guarantee?" Otherwise make it a skill.
262
+ **Adding a sixth command requires answering yes to both:** "does a human need to press this?" and "is 'user-only via frontmatter flag' too weak a guarantee?" Otherwise make it a skill.
259
263
 
260
264
  ### §4.5 MCP servers (3)
261
265
 
@@ -273,6 +277,7 @@ Runtime-only; gitignore or keep out of commits per project policy.
273
277
  |---|---|---|
274
278
  | `workflow.json` | `/triage` | `track_guard`, every phase skill, `/harness` |
275
279
  | `commit_consent` | `/grant-commit` | `git_commit_guard` |
280
+ | `push_consent` | `/grant-push` | `git_commit_guard` |
276
281
  | `spec_approvals/<slug>.approval` | `/approve-spec` | `tdd`, `swarm-plan`, `/harness` |
277
282
  | `swarm_approvals/<slug>.approval` | `/approve-swarm` | `swarm-dispatch`, `/harness` |
278
283
  | `swarm/<slug>.json` | `swarm-plan` | `swarm-dispatch`, `swarm_merge.sh` |
@@ -315,6 +320,7 @@ Phases are fixed ordering; `/triage` picks the entry and may mark phases as exce
315
320
  9 integrate
316
321
  10 document
317
322
  10.5 archive
323
+ 10.6 memory-flush
318
324
  11 /grant-commit — human consent gate C
319
325
  11b commit
320
326
  ```
@@ -332,14 +338,15 @@ Phases are fixed ordering; `/triage` picks the entry and may mark phases as exce
332
338
 
333
339
  ## §6 — Consent model
334
340
 
335
- **Three consent gates + one bootstrap gate.** All are slash commands, not skills. Commands live in `.claude/commands/`; Claude cannot invoke them via the Skill tool. The guarantee is structural (file location), not flag-based.
341
+ **Four consent gates + one bootstrap gate.** All are slash commands, not skills. Commands live in `.claude/commands/`; Claude cannot invoke them via the Skill tool. The guarantee is structural (file location), not flag-based. Three of the four gates are workflow-phase gates (A: `/approve-spec`, B: `/approve-swarm`, C: `/grant-commit`); the fourth (`/grant-push`) is a Bash-time consent for the branch-aware push policy in §11.
336
342
 
337
343
  | Gate | When it fires | Unlocks |
338
344
  |---|---|---|
339
345
  | `/init-project` | Once per repo, before any work | Flips `configured: true`; silences the `setup_guard` advisory and lets `test_runner` / `lint_runner` move out of guide mode |
340
346
  | `/approve-spec <path>` | After `/spec` produces a draft | Writes approval token; downstream phases proceed |
341
347
  | `/approve-swarm <slug>` | After `/swarm-plan` produces a plan | Writes approval token; `swarm-dispatch` may run |
342
- | `/grant-commit` | Before `/commit` | Writes 5-min consent token; `git_commit_guard` allows next commit |
348
+ | `/grant-commit` | Before `/commit` | Writes 5-min consent token; `git_commit_guard` allows next commit on a protected branch |
349
+ | `/grant-push` | Before `git push` on a protected branch | Writes 5-min consent token; `git_commit_guard` allows next push on a protected branch (non-protected branches need no consent) |
343
350
 
344
351
  Harness yields at each gate. User re-invokes `/harness` to resume.
345
352
 
@@ -461,7 +468,7 @@ Claude may run `git add <named paths>` and `git commit` only when the user has a
461
468
 
462
469
  The following are forbidden unless the user names the exact operation in their current request:
463
470
 
464
- - `git push` (any remote, any branch), `git push --force`, `--force-with-lease`.
471
+ - `git push --force`, `--force-with-lease` (the bare `git push` is governed by the branch-aware policy below, not by this list).
465
472
  - `git commit --amend` — always create a new commit.
466
473
  - `--no-verify`, `--no-gpg-sign`, or any flag that skips hooks/signing.
467
474
  - `git reset --hard`, `git clean -f`, `git checkout --`, `git branch -D`.
@@ -469,6 +476,13 @@ The following are forbidden unless the user names the exact operation in their c
469
476
  - `git rebase -i`, `git add -i` (interactive).
470
477
  - `git add -A`, `git add .` — name the paths to avoid sweeping in secrets or unrelated dirty files.
471
478
 
479
+ **Branch-aware consent policy.** `git_commit_guard` reads the current branch via `git rev-parse --abbrev-ref HEAD` on every `git commit` / `git push` invocation and routes per:
480
+
481
+ - `project.json → git.protected_branches` — glob list. `null` (default) means every branch is protected. Set e.g. `["main", "release/*"]` to limit consent enforcement.
482
+ - `project.json → git.branch_pattern` — regex, optional. When set, commits on off-pattern branches are denied with the pattern surfaced in the error.
483
+
484
+ On a **protected branch**, commit requires fresh `commit_consent` (`/grant-commit`), push requires fresh `push_consent` (`/grant-push`). On a non-protected branch, both proceed without consent. **Detached HEAD** (`git rev-parse` returns the literal `HEAD`) denies both — branch-aware policy needs a named branch.
485
+
472
486
  `git_commit_guard` enforces these; bypassing requires editing the hook, which is itself a visible change.
473
487
 
474
488
  ---
@@ -525,8 +539,9 @@ Seed-level requirement: no stale workflow artifacts in the working tree after co
525
539
  1. `/triage "<test request>"` → writes `workflow.json`.
526
540
  2. Write a spec at `docs/specs/test.md` with all 6 diagrams → `spec_diagram_presence_guard` + `plantuml_syntax_guard` allow.
527
541
  3. Write a spec missing a diagram → guard denies with named missing kinds.
528
- 4. Attempt `git commit` without `/grant-commit` → `git_commit_guard` denies.
529
- 5. Attempt `git push` → hard-blocked regardless of consent.
542
+ 4. Attempt `git commit` on a protected branch without `/grant-commit` → `git_commit_guard` denies.
543
+ 5. Attempt `git push` on a protected branch without `/grant-push` denied. Same `git push` on a non-protected branch (when `git.protected_branches` is set to e.g. `["main"]` and current branch is `feat/foo`) → allowed without consent.
544
+ 6. Attempt `git commit` or `git push` while detached (`git checkout <sha>`) → denied with explicit "Detached HEAD" message.
530
545
 
531
546
  ---
532
547
 
@@ -576,9 +591,9 @@ Until `/init-project` runs, this section stays empty. Once populated, every fiel
576
591
 
577
592
  ## §17 — Skill provenance and the baseline manifest
578
593
 
579
- Every skill at `.claude/skills/<slug>/SKILL.md` SHALL declare ownership in its YAML frontmatter as `owner: baseline` or `owner: user`. Baseline-owned skills are those that ship with the baseline; user-owned skills are those a project adds locally. The build script `scripts/build-manifest.mjs` reads each `owner:` value at release time and emits the canonical baseline-skill set into `obj/template/manifest.json` under `owners.skills` (a JSON object mapping slug → `"baseline"`). The CLI mirrors this manifest verbatim to `<target>/.claude/.baseline-manifest.json` on `freshInstall`/`forceInstall`/`merge`.
594
+ A skill at `.claude/skills/<slug>/SKILL.md` is **baseline-owned** iff its YAML frontmatter declares `owner: baseline`. Baseline-owned skills are those that ship with the baseline; every other skill on disk — those without an `owner:` field, or those declaring `owner: user` — is user/third-party and out-of-scope of baseline audit checks. Absence-of-`owner` is the deliberate default so a project that already has its own skills can install the baseline without annotating any of those files. The build script `scripts/build-manifest.mjs` reads each `owner:` value at release time and emits the canonical baseline-skill set into `obj/template/manifest.json` under `owners.skills` (a JSON object mapping slug → `"baseline"`). The CLI mirrors this manifest verbatim to `<target>/.claude/.baseline-manifest.json` on `freshInstall`/`forceInstall`/`merge`.
580
595
 
581
- The audit at `.claude/skills/audit-baseline/audit.sh` consumes `manifest.owners.skills` as the canonical baseline-skill enumeration (replacing the previous hard-coded `EXPECTED_SKILLS` set). For every baseline-owned skill, the audit re-derives sha256 hashes from `manifest.files` and compares against on-disk content; a mismatch is reported as `hash mismatch at <path>` against the named slug. A baseline skill present in the manifest but absent from disk is reported as `baseline skill missing`. A SKILL.md missing the `owner:` field, or carrying an invalid value, is reported as `missing owner frontmatter` or `invalid owner=<value>`. User-owned skills (`owner: user`) are excluded from the baseline count and the names-match check, so adding a local skill does not break the audit.
596
+ The audit at `.claude/skills/audit-baseline/audit.sh` consumes `manifest.owners.skills` as the canonical baseline-skill enumeration (replacing the previous hard-coded `EXPECTED_SKILLS` set). For every baseline-owned skill, the audit re-derives sha256 hashes from `manifest.files` and compares against on-disk content; a mismatch is reported as `hash mismatch at <path>` against the named slug. A baseline skill present in the manifest but absent from disk is reported as `baseline skill missing`. A SKILL.md whose `owner:` field is present but carries an invalid value (anything other than `baseline` or `user`) is reported as `invalid owner=<value>`. SKILL.md files without an `owner:` field are treated as user/third-party and silently skipped — they are excluded from the baseline count, the names-match check, and the hash-drift check, so installing the baseline into a project that already has its own skills never breaks the audit.
582
597
 
583
598
  The audit also verifies constitutional citation: CLAUDE.md SHALL contain the literal string "Article XI" and a reference to the manifest, and `docs/init/seed.md` SHALL contain "§17" and a manifest reference. Missing citations trigger FAIL with `CLAUDE.md missing Article XI citation` or `seed.md missing §17 citation`.
584
599
 
@@ -7,7 +7,7 @@
7
7
  "matcher": "Bash",
8
8
  "hooks": [
9
9
  { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/destructive_cmd_guard.sh" },
10
- { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/git_commit_guard.sh" },
10
+ { "type": "command", "command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/git_commit_guard.mjs" },
11
11
  { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/process_lifecycle_guard.sh" }
12
12
  ]
13
13
  },
@@ -18,7 +18,7 @@
18
18
  { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/env_guard.sh" },
19
19
  { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/spec_approval_guard.sh" },
20
20
  { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/swarm_approval_guard.sh" },
21
- { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/git_commit_guard.sh" },
21
+ { "type": "command", "command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/git_commit_guard.mjs" },
22
22
  { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/verify_pass_guard.sh" },
23
23
  { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/track_guard.sh" },
24
24
  { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/artifact_template_guard.sh" },
@@ -38,7 +38,7 @@
38
38
  "UserPromptSubmit": [
39
39
  {
40
40
  "hooks": [
41
- { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/consent_gate_grant.sh" }
41
+ { "type": "command", "command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/consent_gate_grant.mjs" }
42
42
  ]
43
43
  }
44
44
  ],
@@ -90,7 +90,6 @@
90
90
  "Bash(git blame:*)"
91
91
  ],
92
92
  "deny": [
93
- "Bash(git push:*)",
94
93
  "Bash(git commit --amend:*)",
95
94
  "Bash(git reset --hard:*)",
96
95
  "Bash(git clean -f:*)",
@@ -1,89 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Consent Gate Grant — UserPromptSubmit
3
- #
4
- # When the user types one of the three consent-gate slash commands —
5
- # /approve-spec, /approve-swarm, /grant-commit — this hook fires BEFORE the
6
- # model is invoked. It writes a short-lived consent marker to
7
- # .claude/state/.<gate>_grant.
8
- #
9
- # The marker is what makes the corresponding approval-token write succeed:
10
- # the gate-specific PreToolUse guard (spec_approval_guard, swarm_approval_guard,
11
- # git_commit_guard) reads the marker and allows Claude's write only if a
12
- # fresh, slug-matched marker is on disk.
13
- #
14
- # Why the marker is unforgeable by Claude:
15
- # - This hook runs on UserPromptSubmit, OUTSIDE Claude's tool boundary.
16
- # - The PreToolUse guards block Claude from writing the marker file.
17
- # - Markers expire after consent.gate_marker_ttl_seconds (default 60).
18
- #
19
- # Marker shapes (also documented in lib/common.sh validate_consent_marker):
20
- # .spec_approval_grant line 1: basename of spec path (slug)
21
- # line 2: epoch
22
- # line 3: absolute spec path
23
- # .swarm_approval_grant line 1: slug · line 2: epoch
24
- # .commit_consent_grant line 1: epoch · line 2: optional note
25
-
26
- # shellcheck source=./lib/common.sh
27
- . "${BASH_SOURCE[0]%/*}/lib/common.sh"
28
- read_payload
29
-
30
- # Fast-path: glob-match against the raw payload to rule out 99% of prompts
31
- # before any json/regex parsing. False positives are tolerated; the regex
32
- # dispatch below would no-op anyway.
33
- case "$HOOK_PAYLOAD" in
34
- *'"prompt":'*/approve-spec*) ;;
35
- *'"prompt":'*/approve-swarm*) ;;
36
- *'"prompt":'*/grant-commit*) ;;
37
- *) exit 0 ;;
38
- esac
39
-
40
- PROMPT="$(payload_get .prompt)"
41
- [ -n "$PROMPT" ] || exit 0
42
-
43
- first_line="${PROMPT%%$'\n'*}"
44
- trimmed="${first_line#"${first_line%%[![:space:]]*}"}"
45
-
46
- NOW="$(date +%s)"
47
-
48
- write_marker_atomic() {
49
- local marker="$1"
50
- shift
51
- local tmp="${marker}.tmp.$$"
52
- if printf '%s\n' "$@" >"$tmp" 2>/dev/null && mv -f "$tmp" "$marker" 2>/dev/null; then
53
- return 0
54
- fi
55
- rm -f "$tmp" 2>/dev/null || true
56
- return 1
57
- }
58
-
59
- if [[ "$trimmed" =~ ^/approve-spec[[:space:]]+([^[:space:]]+) ]]; then
60
- arg="${BASH_REMATCH[1]}"
61
- slug="$(canonical_slug "$arg")"
62
- case "$arg" in
63
- /*) abs_path="$arg" ;;
64
- */*) abs_path="$CLAUDE_PROJECT_ROOT/$arg" ;;
65
- *) abs_path="$CLAUDE_PROJECT_ROOT/docs/specs/$slug.md" ;;
66
- esac
67
- if write_marker_atomic "$CONSENT_MARKER_SPEC" "$slug" "$NOW" "$abs_path"; then
68
- log_line consent_gate_grant "wrote spec_approval_grant slug=$slug path=$abs_path"
69
- else
70
- log_line consent_gate_grant "FAILED write spec_approval_grant slug=$slug"
71
- fi
72
- elif [[ "$trimmed" =~ ^/approve-swarm[[:space:]]+([^[:space:]]+) ]]; then
73
- slug="$(canonical_slug "${BASH_REMATCH[1]}")"
74
- if write_marker_atomic "$CONSENT_MARKER_SWARM" "$slug" "$NOW"; then
75
- log_line consent_gate_grant "wrote swarm_approval_grant slug=$slug"
76
- else
77
- log_line consent_gate_grant "FAILED write swarm_approval_grant slug=$slug"
78
- fi
79
- elif [[ "$trimmed" =~ ^/grant-commit([[:space:]].*)?$ ]]; then
80
- note="${BASH_REMATCH[1]:-}"
81
- note="${note#"${note%%[![:space:]]*}"}"
82
- if write_marker_atomic "$CONSENT_MARKER_COMMIT" "$NOW" "$note"; then
83
- log_line consent_gate_grant "wrote commit_consent_grant note=$note"
84
- else
85
- log_line consent_gate_grant "FAILED write commit_consent_grant"
86
- fi
87
- fi
88
-
89
- exit 0