From 8d70fcb15c15e51a46ed955bb1a9830e0ff52c17 Mon Sep 17 00:00:00 2001 From: Bastien Chanot Date: Tue, 14 Jul 2026 18:46:43 +0200 Subject: [PATCH 1/2] =?UTF-8?q?chore(memory):=20BDR-065=20+=20LRN-124=20?= =?UTF-8?q?=E2=80=94=20post-merge=20capitalize=20(transient=20artifacts,?= =?UTF-8?q?=20scan-report=20leak-map)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/memory/decisions.md | 12 ++++++++++++ .claude/memory/journal.md | 1 + .claude/memory/learnings.md | 9 +++++++++ 3 files changed, 22 insertions(+) diff --git a/.claude/memory/decisions.md b/.claude/memory/decisions.md index 8b731b1..011f854 100644 --- a/.claude/memory/decisions.md +++ b/.claude/memory/decisions.md @@ -85,6 +85,7 @@ rules: | BDR-062 | 2026-07-08 | supersede BDR-031's 275 CLAUDE.md target — 305 assumed reality (extraction done at job1; more compression costs clarity > tokens); guard threshold realigned 280→320 | accepted | | BDR-063 | 2026-07-10 | GSC multi-account: OAuth2 installed-app flow + label-keyed token store, explicit (account,property) args, no global state | accepted | | BDR-064 | 2026-07-14 | global memory split: repo file → CLAUDE.global.md (deployed name unchanged), CLAUDE.md freed for project scope; consumer/maintainer wording rule | accepted | +| BDR-065 | 2026-07-14 | transient planning artifacts (superpowers spec/plan): committed during run, deleted post-merge; git history = archive; codified in project CLAUDE.md | accepted | --- @@ -963,3 +964,14 @@ rules: - **Why**: "This repo only" section + rules/README doctrine loaded in EVERY project (~40+280 tok waste + foreign-project glob over-match); repo had no project-scope memory slot — filename occupied by global content. - **Alternatives rejected**: `CLAUDE.prod.md` name ("prod" implies deploy env that doesn't exist); project `.claude/rules/repo.md` (works, less idiomatic than project CLAUDE.md, no natural home for future repo-specific content). NOT a revival of BDR-021's rejected 2-file split — that was global content in 2 SYNCED files; here scopes disjoint, zero sync. - **Reference**: feature/claude-global-md-rename (9496538 rename R98%, e9a38a0 guards), spec `docs/superpowers/specs/2026-07-12-claude-global-md-rename-design.md`. Linked [[BDR-021]], [[BDR-031]], [[BDR-062]], [[LRN-122]], [[LRN-123]]. + +--- + +## BDR-065 — Transient planning artifacts: committed during run, deleted post-merge + +- **Date**: 2026-07-14 +- **Status**: accepted +- **Decision**: superpowers spec/plan docs (`docs/superpowers/{specs,plans}/`) = run-time artifacts. Lifecycle: committed as feature branch's first commit (subagent briefs extracted from plan on disk; verifier + final review reference them; survive compaction + foreign worktrees) → DELETED in post-merge cleanup chore. Git history at the feature commits = the archive (`git show :docs/...` recovers them). Durable knowledge lives in `.claude/memory/` registries + contract files, never in spec/plan. Codified in project CLAUDE.md §Transient planning artifacts. +- **Why**: user call 2026-07-14 — registries already capture decisions; a stale plan describes a superseded intermediate state and misleads future readers; accumulation pollutes the repo. Precedent: gsc-crux cleanup (8a1fac0, 2026-07-10) did the same — this makes it law, not habit. +- **Alternatives rejected**: never-commit (gitignore docs/superpowers) — breaks mid-run: briefs, reviewers, other-machine checkouts need the files; superpowers brainstorming commits the spec by convention. Keep-forever — the drift + pollution complained about. +- **Reference**: project CLAUDE.md; cleanup commit this chore; precedent 8a1fac0. Linked [[BDR-064]], [[LRN-124]]. diff --git a/.claude/memory/journal.md b/.claude/memory/journal.md index 6363011..b35b827 100644 --- a/.claude/memory/journal.md +++ b/.claude/memory/journal.md @@ -380,3 +380,4 @@ rules: ## 2026-07-14 - `/ship-feature` feature/claude-global-md-rename (unmerged, human GO pending): global memory → CLAUDE.global.md + project-scope CLAUDE.md, 8 commits (a4ee7e1 docs → e9a38a0 guards). Full pipeline: analyzer + contract (17 criteria), brainstorm/spec/plan gates, SDD 5 tasks (all task reviews Approved), verifier CONFORME 17/17 (after user-arbitrated criterion-9 consumer-wording + FILE-SCOPE [gated] enrichment), security PASS (semgrep 43 rules, 0), final review "Yes" after 2 Important fixes (guard-test drift → 7/7; doctor exact-target check). Decided [[BDR-064]]; learned [[LRN-122]] (2-commit rename split), [[LRN-123]] (exact symlink target). `make test` green throughout. settings.json plugin toggles = session-scoped, NOT committed — restore (gstack/ui-ux-pro-max/frontend-design/emil-design-eng/darwin-skill/magic ON) after merge. +- Merges to develop: feature/claude-global-md-rename (2d54df5), chore/untrack-audit-reports (d557ee9), chore/post-merge-cleanup. /cso triage: 75 gitleaks findings → 0 real (60 git SHAs vs sourcegraph rule; gitflow-test AWS fixture; expired GitHub image JWT; presigned-URL key ids; doc placeholders; job7-purged artifacts). .gitleaks.toml → [[allowlists]] format + 8 targeted entries; `make scan-secrets` green 0+0. Makefile "safe to commit" hint root-caused → [[LRN-124]]. Transient spec+plan deleted per [[BDR-065]] (user decree, gsc-crux precedent). Mid-merge discovery: user commit 5842119 (gitignore `.audit/` + model pin fable-5) — explains the .audit-in-diff question. cso report: .gstack/security-reports/2026-07-14-secrets-triage.json. diff --git a/.claude/memory/learnings.md b/.claude/memory/learnings.md index 910ccf0..61c2b45 100644 --- a/.claude/memory/learnings.md +++ b/.claude/memory/learnings.md @@ -1232,3 +1232,12 @@ rules: - **why**: containment predicates (inside-dir, prefix-match) silently weaken the moment layout gains a second valid-looking target; exactness costs nothing. - **future application**: symlink/path health checks → assert exact expected target whenever the old target path can be re-occupied; test all three states (correct / stale / missing). - **cousin**: [[BDR-064]], [[LRN-104]] (hook message = test contract — same guard-must-follow-the-change family). + +--- + +## LRN-124 — derived scan artifacts don't belong in git; a tooling hint saying "safe to commit" manufactures the leak + +- **pattern**: gitleaks reports committed to repo (17bdd08) even with `--redact` = a MAP — secret type + file + line for anyone with repo access. Root cause traced: `make scan-secrets` echoed "already redacted — safe to inspect/commit" → the hint was obeyed. Fix: `git rm --cached` (gitignore has no effect on tracked files), reword hint to "gitignored — keep local, do NOT commit". Companion: user added `.audit/` gitignore rule (5842119) for the untracked report/patch siblings. +- **why**: redaction removes VALUES, not INTELLIGENCE. And tool output is instruction — a hint that says "safe to commit" will eventually be obeyed by a human or an agent. +- **future application**: derived security artifacts (scan reports, triage JSONs, audit findings) stay local/ignored; only the allowlist CONFIG (reviewable rules) is committed. When auditing tooling, grep its user-facing hints for wording that invites committing outputs. +- **cousin**: [[BDR-057]] (secrets by reference, redact at capture), [[BDR-065]] (transient planning artifacts — same "process artifacts ≠ repo content" family), [[LRN-103]] (re-probe before acting). From 08ab0575df836b6d34e52c2b2f462bfda0935d9c Mon Sep 17 00:00:00 2001 From: Bastien Chanot Date: Tue, 14 Jul 2026 18:46:43 +0200 Subject: [PATCH 2/2] chore(docs): drop transient spec+plan post-merge; codify artifact lifecycle (BDR-065) --- CLAUDE.md | 10 + .../2026-07-13-claude-global-md-rename.md | 365 ------------------ ...26-07-12-claude-global-md-rename-design.md | 125 ------ 3 files changed, 10 insertions(+), 490 deletions(-) delete mode 100644 docs/superpowers/plans/2026-07-13-claude-global-md-rename.md delete mode 100644 docs/superpowers/specs/2026-07-12-claude-global-md-rename-design.md diff --git a/CLAUDE.md b/CLAUDE.md index 31ca6e3..61a3c6d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -27,3 +27,13 @@ Machine-owned: `rules/context7.md` is DELETED BY DESIGN (BDR-053, install-plugins.sh STEP ctx7 purges it right after; the find-docs skill is the single ctx7 surface. If it reappears (manual `ctx7 setup`), delete it or re-run `make plugin`. + +## Transient planning artifacts + +`docs/superpowers/specs/**` and `docs/superpowers/plans/**` are run-time +artifacts of a feature pipeline (subagent briefs, reviewer references). +They are committed DURING the run and DELETED in the post-merge cleanup +(BDR-065) — git history at the feature commits is their archive. Durable +knowledge goes to `.claude/memory/` registries, never to these files. +Derived scan/audit outputs (`.audit/**`) are gitignored and never +committed, even redacted (LRN-124). diff --git a/docs/superpowers/plans/2026-07-13-claude-global-md-rename.md b/docs/superpowers/plans/2026-07-13-claude-global-md-rename.md deleted file mode 100644 index 48648fa..0000000 --- a/docs/superpowers/plans/2026-07-13-claude-global-md-rename.md +++ /dev/null @@ -1,365 +0,0 @@ -# CLAUDE.global.md Rename Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -**Goal:** Rename the repo-root global memory to `CLAUDE.global.md` and free the `CLAUDE.md` name for a real project-scope file, following every dependent script and doc. - -**Architecture:** One atomic file-split task (git mv + both file contents + link.sh retarget, so no commit leaves the tree incoherent), then a script-followers task, then docs, then a verification sweep. Spec: `docs/superpowers/specs/2026-07-12-claude-global-md-rename-design.md`. Contract: `.claude/tasks/contracts/2026-07-12-claude-global-md-rename-2342.md`. - -**Tech Stack:** bash (shellcheck-clean), markdown, git (gitflow via `~/.claude/lib/gitflow.sh`). - -## Global Constraints - -- BDR-062: line-count guard threshold stays **320**; only its path changes. -- BDR-021: `## Security`, `# Architecture decisions` content and the heading `## Design work — full toolchain (tiered by scope)` stay **byte-identical** in CLAUDE.global.md. -- BDR-031: global file must NOT grow — expected net: 305 → 301 lines (−7 tail section incl. leading blank, +3 header incl. trailing blank). -- LRN-044: edit repo paths only (`/home/bchanot/Documents/claude/...`), never through `~/.claude/CLAUDE.md`. -- Gitflow: every commit lands on `feature/claude-global-md-rename` (created Task 1). Never commit on develop. -- Shell code: ≤80 cols, shellcheck-clean (`shellcheck *.sh hooks/*.sh lib/*.sh`). -- Deployed-state note: between Task 2's `git mv` and its `bash link.sh` step, `~/.claude/CLAUDE.md` dangles — Task 2 must run to completion without interruption. - ---- - -### Task 1: Feature branch + commit spec and plan - -**Files:** -- Commit: `docs/superpowers/specs/2026-07-12-claude-global-md-rename-design.md` (exists) -- Commit: `docs/superpowers/plans/2026-07-13-claude-global-md-rename.md` (this file) - -**Interfaces:** -- Produces: branch `feature/claude-global-md-rename` off develop — all later tasks commit here. - -- [ ] **Step 1: Create the branch via the gitflow lib (never by hand)** - -Run: `bash "$HOME/.claude/lib/gitflow.sh" start feature claude-global-md-rename` -Expected: branch created off develop; `git branch --show-current` → `feature/claude-global-md-rename` - -- [ ] **Step 2: Commit the two docs** - -```bash -git add docs/superpowers/specs/2026-07-12-claude-global-md-rename-design.md \ - docs/superpowers/plans/2026-07-13-claude-global-md-rename.md -git commit -m "docs(spec): CLAUDE.global.md rename — design + implementation plan" -``` - -Expected: clean commit; `git status` shows the two files gone from untracked. -NOTE: `settings.json` is dirty with session-scoped plugin toggles — do NOT stage it in any task. - ---- - -### Task 2: Atomic file split (git mv + contents + link.sh) - -**Files:** -- Rename: `CLAUDE.md` → `CLAUDE.global.md` (git mv) -- Modify: `CLAUDE.global.md` (add header, drop tail section) -- Create: `CLAUDE.md` (project scope, new content below) -- Modify: `link.sh:20` - -**Interfaces:** -- Produces: `CLAUDE.global.md` = global memory (Task 3 scripts point here); `CLAUDE.md` = project memory (stays graphify's / GUARDED_CONFIGS' target name). - -- [ ] **Step 1: git mv** - -```bash -cd /home/bchanot/Documents/claude -git mv CLAUDE.md CLAUDE.global.md -``` - -- [ ] **Step 2: Add the scope header to CLAUDE.global.md** - -Insert at the very top, ABOVE `# Global coding preferences`: - -```markdown - - -``` - -- [ ] **Step 3: Remove the repo-only tail section from CLAUDE.global.md** - -Delete exactly these final lines (and the blank line before `# This repo only`): - -```markdown - -# This repo only (claude-config) - -Apply when working directory = the claude-config repo itself. - -## Health Stack -- shell: `shellcheck *.sh hooks/*.sh lib/*.sh` -``` - -The file now ends with the graphify section's last line: -`- After editing code → \`graphify update .\` (AST-only, free).` - -- [ ] **Step 4: Create the project-scope CLAUDE.md** - -Full content: - -```markdown - - -# claude-config — project instructions - -## Health Stack -- shell: `shellcheck *.sh hooks/*.sh lib/*.sh` - -## rules/ maintenance - -Modular instruction files loaded by Claude Code alongside the global memory. -`rules/` is symlinked to `~/.claude/rules` by `link.sh` (user scope, ALL -projects). One rule = one file = one concern. - -A rule WITH `paths:` YAML frontmatter (glob list) loads lazily — only when -Claude reads a file matching a glob; a rule WITHOUT it loads at session -start, same cost as the global memory. Extract from CLAUDE.global.md only -what can be path-scoped (the token win) or what is generated; always-on -doctrine stays in CLAUDE.global.md. `paths:` globs match against the -CURRENT project's tree — a broad glob (e.g. `rules/**`) can fire in foreign -projects; keep rule bodies tiny. -Docs: https://code.claude.com/docs/en/memory.md#path-specific-rules - -Machine-owned: `rules/context7.md` is DELETED BY DESIGN (BDR-053, -2026-07-06) — `ctx7 setup --claude --cli` still writes it, but -install-plugins.sh STEP ctx7 purges it right after; the find-docs skill is -the single ctx7 surface. If it reappears (manual `ctx7 setup`), delete it -or re-run `make plugin`. -``` - -- [ ] **Step 5: Retarget link.sh** - -`link.sh:20` — change: - -```bash -link_file "$REPO/CLAUDE.md" "$CLAUDE/CLAUDE.md" -``` - -to: - -```bash -link_file "$REPO/CLAUDE.global.md" "$CLAUDE/CLAUDE.md" -``` - -- [ ] **Step 6: Run link.sh and verify the symlink** - -```bash -bash link.sh -readlink "$HOME/.claude/CLAUDE.md" -``` - -Expected: `✅ 1 symlink(s) updated in ~/.claude/` (ln -sf replaces the stale -link) and readlink prints `/home/bchanot/Documents/claude/CLAUDE.global.md`. - -- [ ] **Step 7: Stage, then verify sizes and byte-identity of protected content** - -```bash -wc -l CLAUDE.global.md # expected: 301 (≤ 320, BDR-062 margin) -git add CLAUDE.global.md CLAUDE.md link.sh -git diff -M --cached --stat # rename CLAUDE.md→CLAUDE.global.md + new CLAUDE.md + link.sh -git diff -M --cached -- CLAUDE.global.md -``` - -Expected: rename detected (similarity ~97%); exactly TWO hunks on -CLAUDE.global.md (header insertion at top, tail-section deletion) — nothing -else. `## Security`, `# Architecture decisions`, `## Design work — full -toolchain (tiered by scope)` untouched. - -- [ ] **Step 8: shellcheck + commit** - -```bash -shellcheck link.sh -git commit -m "feat(memory): split user-scope global (CLAUDE.global.md) from project CLAUDE.md" -``` - ---- - -### Task 3: Point dependent scripts at CLAUDE.global.md - -**Files:** -- Modify: `hooks/session-start.sh:202-211` -- Modify: `doctor.sh:244,251,277` -- Modify: `install-plugins.sh:33-41,65-68` -- Modify: `lib/doc-commit.sh:44-50` - -**Interfaces:** -- Consumes: `CLAUDE.global.md` from Task 2. -- Produces: guard/stats/exclusions used by Task 5's verification sweep. - -- [ ] **Step 1: session-start.sh — line-count guard follows the file (BDR-062)** - -Replace lines 202-211: - -```bash -# CLAUDE.global.md line-count guard (anti-regression). BDR-062 supersedes -# BDR-031's 275 target: 305 is the assumed reality (extraction done at -# job1; further compression costs clarity > token gain) — warn past 320. -if [ -n "$REPO_DIR" ] && [ -f "$REPO_DIR/CLAUDE.global.md" ]; then - _claude_lines=$(wc -l < "$REPO_DIR/CLAUDE.global.md") - if [ "$_claude_lines" -gt 320 ]; then - _cmd_warn="CLAUDE.global.md ${_claude_lines}L (>320) — density pass" - printf "│ ⚠️ %-44s│\n" "${_cmd_warn:0:44}" - unset _cmd_warn - fi - unset _claude_lines -fi -``` - -(Behavior guard: without this change the check would silently measure the -NEW 30-line project CLAUDE.md and never warn again — fail-open.) - -- [ ] **Step 2: doctor.sh — stats read the global file** - -Line 244 comment: `# The passive footprint (CLAUDE.md + skill descriptions` -→ `# The passive footprint (CLAUDE.global.md + skill descriptions`. - -Line 251: - -```bash -CLAUDE_MD_CHARS=$(wc -c < "$REPO/CLAUDE.global.md" 2>/dev/null || echo 0) -``` - -Line 277 (keep the `~` column aligned — 4 spaces after the colon): - -```bash -echo " CLAUDE.global.md: ~${CLAUDE_MD_TOKENS}t" -``` - -Lines 32, 52, 65 (symlink-NAME references `~/.claude/CLAUDE.md`) unchanged. - -- [ ] **Step 3: install-plugins.sh — guard both memory files** - -Line 36: `These 3 files` → `These 4 files`. After line 40 (`— anything the -installer should add…`), append one comment line, then replace line 41: - -```bash -# CLAUDE.md = project memory (graphify's rewrite target); CLAUDE.global.md -# = user-scope global memory (deployed as ~/.claude/CLAUDE.md). -GUARDED_CONFIGS=("CLAUDE.md" "CLAUDE.global.md" ".claude/settings.json" - "settings.json") -``` - -Lines 65-68 err message: - -```bash - err "Config guard could not be created (mktemp failed) — refusing to run" \ - "unguarded: CLAUDE.md/CLAUDE.global.md/.claude/settings.json/settings.json" \ - "could be silently rewritten by the installer. Fix mktemp/TMPDIR and retry." -``` - -- [ ] **Step 4: lib/doc-commit.sh — exclude the global file (BDR-022)** - -Comment (line ~44-45): `or a CLAUDE.md (root or nested)` → `or a CLAUDE.md / -CLAUDE.global.md memory file (root or nested)`. Case patterns: - -```bash -_forbidden_path() { - case "$1" in - .claude | .claude/* | */.claude/* | CLAUDE.md | */CLAUDE.md | \ - CLAUDE.global.md | */CLAUDE.global.md) return 0 ;; - *) return 1 ;; - esac -} -``` - -- [ ] **Step 5: Lint + smoke test + commit** - -```bash -shellcheck hooks/session-start.sh doctor.sh install-plugins.sh lib/doc-commit.sh -bash doctor.sh | sed -n '/Token budget/,/────/p' # shows "CLAUDE.global.md: ~Nt", N≈3600 -git add hooks/session-start.sh doctor.sh install-plugins.sh lib/doc-commit.sh -git commit -m "feat(memory): guards, doctor stats and doc-commit exclusions follow CLAUDE.global.md" -``` - ---- - -### Task 4: rules/README.md pointer + README tree - -**Files:** -- Rewrite: `rules/README.md` -- Modify: `README.md:16` - -- [ ] **Step 1: Rewrite rules/README.md (full new content)** - -```markdown ---- -paths: ["rules/**"] ---- - -# rules/ - -User-scope rules, deployed to `~/.claude/rules` by `link.sh`. -Maintenance doctrine (what belongs here, lazy-load `paths:` semantics, -machine-owned files): see `CLAUDE.md` (project scope) at the repo root. -``` - -- [ ] **Step 2: README.md tree — show both memory files** - -Replace line 16: - -``` -├── CLAUDE.md # Global coding preferences (style, rules, workflow) -``` - -with: - -``` -├── CLAUDE.global.md # Global coding preferences — deployed as ~/.claude/CLAUDE.md -├── CLAUDE.md # Project-scope instructions (this repo only) -``` - -Lines 29, 100, 152 (per-project CLAUDE.md concept) and 189 (symlink name) -unchanged. USAGE.md / MIGRATION.md / update-all.sh audited: zero references -to the repo-root global file — no edits (contract criterion 10 satisfied -by verification). - -- [ ] **Step 3: Commit** - -```bash -git add rules/README.md README.md -git commit -m "docs: slim rules/README to a pointer; README tree lists both memory files" -``` - ---- - -### Task 5: Verification sweep (no new code) - -**Files:** none modified (fixes only if a check fails — then loop the owning task). - -- [ ] **Step 1: link.sh idempotence** - -Run: `bash link.sh` -Expected: `✅ All symlinks already up to date.` - -- [ ] **Step 2: doctor.sh green** - -Run: `bash doctor.sh` -Expected: `~/.claude/CLAUDE.md` symlink PASS (resolves inside repo); token -stats line reads `CLAUDE.global.md:`; no new FAIL vs pre-change baseline. - -- [ ] **Step 3: Residual reference grep** - -```bash -grep -rn '\$REPO/CLAUDE\.md\|\$REPO_DIR/CLAUDE\.md' -- *.sh hooks lib || echo CLEAN -grep -rn 'CLAUDE\.md' -- *.sh hooks/*.sh lib/*.sh -``` - -First: `CLEAN`. Second — every hit must be one of: link.sh `$CLAUDE/CLAUDE.md` -(dst name), session-start.sh `readlink "$HOME/.claude/CLAUDE.md"`, doctor.sh -`check_symlink "CLAUDE.md"` + name comments, install-plugins.sh -`"CLAUDE.md"` guard entry + comments, doc-commit.sh case patterns, -update-all.sh graphify comment (targets the project file — accurate). - -- [ ] **Step 4: History + guard smoke** - -```bash -git log --follow --oneline CLAUDE.global.md | tail -3 # pre-rename commits -awk '/line-count guard/,/^fi$/' hooks/session-start.sh | grep -c 'CLAUDE\.global\.md' # ≥ 2 -wc -l CLAUDE.global.md CLAUDE.md # 301 and ~31 -``` - -- [ ] **Step 5: Full Health Stack** - -Run: `shellcheck *.sh hooks/*.sh lib/*.sh` -Expected: exit 0, no findings on modified files. diff --git a/docs/superpowers/specs/2026-07-12-claude-global-md-rename-design.md b/docs/superpowers/specs/2026-07-12-claude-global-md-rename-design.md deleted file mode 100644 index 1f1c938..0000000 --- a/docs/superpowers/specs/2026-07-12-claude-global-md-rename-design.md +++ /dev/null @@ -1,125 +0,0 @@ -# Design — CLAUDE.global.md rename + project-scope CLAUDE.md - -- Date: 2026-07-12 -- Flow: /ship-feature -- Contract: `.claude/tasks/contracts/2026-07-12-claude-global-md-rename-2342.md` -- Status: approved (design gate 2026-07-12) - -## Problem - -The repo-root `CLAUDE.md` is the user-scope global memory, symlinked to -`~/.claude/CLAUDE.md` by `link.sh`. Because the filename `CLAUDE.md` is taken -by global content, this repo has no project-level CLAUDE.md — repo-only -instructions (`# This repo only (claude-config)`) ride the global file and -load in every project (~40 tok/session waste), and the `rules/` maintenance -doctrine lives in `rules/README.md`, a user-scope rule whose -`paths: ["rules/**"]` glob over-matches any foreign project with a `rules/` -directory. - -## Decision - -Rename the global source file and free the `CLAUDE.md` name for a real -project-scope file. Name arbitrated: `CLAUDE.global.md` -(`CLAUDE.prod.md` rejected — "prod" implies a deployment environment that -does not exist here). - -This does NOT contradict BDR-021's rejected "split into 2 files" alternative: -that rejection targeted splitting GLOBAL content into two synced files. Here -the scopes are disjoint — zero synchronization between the two files. - -## Changes - -### 1. File split - -- `git mv CLAUDE.md CLAUDE.global.md` (history preserved; verify with - `git log --follow`). -- `CLAUDE.global.md` drops the `# This repo only (claude-config)` section - (6 lines) and gains a scope header above the title: - - ```markdown - - ``` - - Net ≈ 301 lines — under the 320 guard (BDR-062). Security, Architecture - decisions, and the "Design work — full toolchain (tiered by scope)" heading - stay byte-identical (BDR-021: hook quotes the heading verbatim). - -- New project-scope `CLAUDE.md` (~25 lines), minimal structure (YAGNI — no - empty template sections): - - mirror scope header: project scope only; global doctrine is in - `CLAUDE.global.md`, deployed as `~/.claude/CLAUDE.md`; edit THAT file for - cross-project rules; - - `## Health Stack` — `shellcheck *.sh hooks/*.sh lib/*.sh` (moved verbatim); - - `## rules/ maintenance` — doctrine migrated from `rules/README.md`: - what belongs in `rules/` (one rule = one file = one concern), lazy-load - semantics (`paths:` frontmatter → loads on matching file read; no - `paths:` → session-start cost, keep always-on doctrine in - CLAUDE.global.md), machine-owned files note (context7.md DELETED BY - DESIGN, BDR-053), link to the docs page. - -### 2. link.sh - -Mapping line changes: link `/CLAUDE.global.md` → `~/.claude/CLAUDE.md`. -`ln -sf` in `link_file()` replaces the stale symlink cleanly. Post-condition: -`readlink ~/.claude/CLAUDE.md` = `/CLAUDE.global.md`. - -### 3. Dependent scripts (surgical) - -| File | Change | -|---|---| -| `hooks/session-start.sh:205-206` | line-count guard reads `CLAUDE.global.md`; threshold 320 unchanged (BDR-062). Repo detection via `readlink` (line 81) already works post-rename. | -| `doctor.sh:251,277` | size/token stats read `CLAUDE.global.md`. Symlink check (line 65) unchanged — link name `~/.claude/CLAUDE.md` is stable. | -| `install-plugins.sh:33-41,66` | `GUARDED_CONFIGS` KEEPS `"CLAUDE.md"` (graphify's installer targets that name — now the project file, still needs the drift guard) and ADDS `"CLAUDE.global.md"`. Comment + mktemp error message updated. | -| `lib/doc-commit.sh:48` | add `CLAUDE.global.md` to the doc-sync exclusion list (BDR-022 spirit: memory/config files are never doc-commit targets). | - -### 4. rules/README.md - -Slimmed to a 3-line pointer, frontmatter kept: - -```markdown ---- -paths: ["rules/**"] ---- -User-scope rules, deployed to `~/.claude/rules` by `link.sh`. -Maintenance doctrine (what belongs here, lazy-load semantics, machine-owned -files): see `CLAUDE.md` (project scope) at the claude-config repo root. -``` - -Over-match in foreign projects with a `rules/` dir becomes harmless (~30 tok). - -### 5. Docs - -`README.md`, `USAGE.md`, `MIGRATION.md`: update only references meaning the -repo-root GLOBAL file. References to the `~/.claude/CLAUDE.md` symlink name -and to the per-project CLAUDE.md concept are unchanged. `templates/project-CLAUDE.md` -unchanged (its "Global rules: ~/.claude/CLAUDE.md" line stays accurate). - -## Verification - -1. `shellcheck` on every modified `.sh` (repo Health Stack). -2. `bash link.sh` → `readlink ~/.claude/CLAUDE.md` resolves to - `CLAUDE.global.md`; no dangling link. -3. `bash doctor.sh` → symlink check green, stats read the new file. -4. Residual grep: no script reference to the repo-root global file under the - old name (`grep -rn 'CLAUDE\.md' *.sh hooks/*.sh lib/*.sh` reviewed). -5. Session-start guard smoke test: guard finds `CLAUDE.global.md`, no - fail-open on the old path. -6. `git log --follow CLAUDE.global.md` shows pre-rename history. - -## Constraints honored - -- **BDR-062**: guard path follows the rename, threshold 320 untouched. -- **BDR-021**: Security/Architecture verbatim; design heading byte-identical. -- **BDR-031**: global file net-shrinks (−6 +2 lines); no re-inflation. -- **LRN-044**: all edits on resolved repo paths, never through - `~/.claude/CLAUDE.md`. -- **Gitflow**: all commits on a `feature/*` branch off develop; this spec is - committed as the branch's first commit (never directly on develop). - -## Out of scope - -- graphify-section extraction from the global file (separate suggestion, - not requested here). -- Any content rewrite of the global doctrine beyond the section move and - scope header.