From c20ad4763a6f37b15fa2bb6d3babd8611e30520c Mon Sep 17 00:00:00 2001 From: Bastien Chanot Date: Tue, 14 Jul 2026 03:55:25 +0200 Subject: [PATCH] feat(memory): guards, doctor stats and doc-commit exclusions follow CLAUDE.global.md --- doctor.sh | 6 +++--- hooks/session-start.sh | 12 ++++++------ install-plugins.sh | 11 +++++++---- lib/doc-commit.sh | 8 +++++--- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/doctor.sh b/doctor.sh index 647a244..6cd0d7e 100644 --- a/doctor.sh +++ b/doctor.sh @@ -241,14 +241,14 @@ echo "" # 6. Token budget estimate # ──────────────────────────────────────────────────────────── echo "── Token budget estimate ──" -# The passive footprint (CLAUDE.md + skill descriptions + plugin session-injects) +# The passive footprint (CLAUDE.global.md + skill descriptions + plugin session-injects) # loads into the CONTEXT WINDOW every session — it competes with the ~200k default # context, NOT a per-session token quota (the old "~11k/5h budget" denominator was # a category error → false "92% CRITICAL", LRN-047). Measured ~11.4k post-audit # 2026-07-02 (LRN-088); the chars/4 sum below is a coarse proxy of that footprint. # Thresholds: WARNING >15% of context (~30k), CRITICAL >25% (~50k). -CLAUDE_MD_CHARS=$(wc -c < "$REPO/CLAUDE.md" 2>/dev/null || echo 0) +CLAUDE_MD_CHARS=$(wc -c < "$REPO/CLAUDE.global.md" 2>/dev/null || echo 0) CLAUDE_MD_TOKENS=$((CLAUDE_MD_CHARS / 4)) # Skill descriptions only (frontmatter description field — loaded passively at startup) @@ -274,7 +274,7 @@ CONTEXT_WINDOW=200000 # Claude Code default context window (conservative; 1M i PCT=$((TOTAL_TOKENS * 100 / CONTEXT_WINDOW)) echo "" -echo " CLAUDE.md: ~${CLAUDE_MD_TOKENS}t" +echo " CLAUDE.global.md: ~${CLAUDE_MD_TOKENS}t" echo " Skill descriptions: ~${SKILL_DESC_TOKENS}t (${SKILL_COUNT} skills)" echo " Plugin passive cost: ~${PLUGIN_TOKENS}t (active plugins)" echo " ─────────────────────────────────────────" diff --git a/hooks/session-start.sh b/hooks/session-start.sh index 4411b7f..36b9584 100644 --- a/hooks/session-start.sh +++ b/hooks/session-start.sh @@ -199,13 +199,13 @@ unset _active_count _inactive_count printf "│ 🖥️ CLI : %-40s│\n" "$GSD_STATUS" [ -n "$TOKEN_WARN" ] && printf "│ 💰 %-44s│\n" "${TOKEN_WARN:0:44}" printf "│ 📦 v%-45s│\n" "$CONFIG_VERSION" -# CLAUDE.md line-count guard (anti-regression). BDR-062 supersedes BDR-031's -# 275 target: 305 is the assumed reality (extraction already done at job1; -# further compression costs clarity > token gain) — warn only past a 320 margin. -if [ -n "$REPO_DIR" ] && [ -f "$REPO_DIR/CLAUDE.md" ]; then - _claude_lines=$(wc -l < "$REPO_DIR/CLAUDE.md") +# 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.md ${_claude_lines}L (>320) — density pass requis" + _cmd_warn="CLAUDE.global.md ${_claude_lines}L (>320) — density pass" printf "│ ⚠️ %-44s│\n" "${_cmd_warn:0:44}" unset _cmd_warn fi diff --git a/install-plugins.sh b/install-plugins.sh index d114b3f..f971e8d 100644 --- a/install-plugins.sh +++ b/install-plugins.sh @@ -33,12 +33,15 @@ source "$REPO/lib/detect-plugins.sh" # graphify's installer (Step 7) rewrites CLAUDE.md + .claude/settings.json # (clobbers the curated graphify section + injects aggressive MANDATORY # hooks), and `claude plugin install` (Step 5) flips enable-states in -# settings.json. These 3 files are maintained by hand + commit, never by +# settings.json. These 4 files are maintained by hand + commit, never by # the installer. Snapshot them now and restore on exit so a run leaves them # exactly as it found them. Pre-existing local edits are preserved; only the # installer's drift is undone. NOTE: this makes these files install-immutable # — anything the installer should add to them must be committed by hand. -GUARDED_CONFIGS=("CLAUDE.md" ".claude/settings.json" "settings.json") +# 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") CFG_SNAPSHOT="$(mktemp -d 2>/dev/null || true)" restore_curated_configs() { @@ -63,8 +66,8 @@ if [ -n "$CFG_SNAPSHOT" ]; then trap restore_curated_configs EXIT else err "Config guard could not be created (mktemp failed) — refusing to run" \ - "unguarded: CLAUDE.md/.claude/settings.json/settings.json could be" \ - "silently rewritten by the installer. Fix mktemp/TMPDIR and retry." + "unguarded: CLAUDE.md/CLAUDE.global.md/.claude/settings.json/settings.json" \ + "could be silently rewritten by the installer. Fix mktemp/TMPDIR and retry." exit 1 fi diff --git a/lib/doc-commit.sh b/lib/doc-commit.sh index 323c08c..686672f 100755 --- a/lib/doc-commit.sh +++ b/lib/doc-commit.sh @@ -41,11 +41,13 @@ _unsafe_state() { } # True (0) when a path is OUT OF SCOPE for a doc commit: anything under .claude/ -# (any depth) or a CLAUDE.md (root or nested). These are doc-syncer's read-only -# context, never sync targets (BDR-022) — their presence is an upstream anomaly. +# (any depth) or a CLAUDE.md / CLAUDE.global.md memory file (root or nested). +# These are doc-syncer's read-only context, never sync targets (BDR-022) — +# their presence is an upstream anomaly. _forbidden_path() { case "$1" in - .claude | .claude/* | */.claude/* | CLAUDE.md | */CLAUDE.md) return 0 ;; + .claude | .claude/* | */.claude/* | CLAUDE.md | */CLAUDE.md | \ + CLAUDE.global.md | */CLAUDE.global.md) return 0 ;; *) return 1 ;; esac }