diff --git a/.blue/docs/rfcs/0041-compaction-resilient-context-injection.draft.md b/.blue/docs/rfcs/0041-compaction-resilient-context-injection.draft.md
new file mode 100644
index 0000000..5919b87
--- /dev/null
+++ b/.blue/docs/rfcs/0041-compaction-resilient-context-injection.draft.md
@@ -0,0 +1,425 @@
+# RFC 0041: Compaction-Resilient Context Injection
+
+| | |
+|---|---|
+| **Status** | Draft |
+| **Date** | 2026-01-30 |
+| **Related** | RFC 0016 (Context Injection Architecture), RFC 0038 (SDLC Workflow Discipline) |
+| **Problem** | SDLC discipline drift after conversation compaction |
+
+---
+
+## Summary
+
+Establish a compaction-resilient context injection architecture by: (1) consolidating dual-source hook configuration into `~/.claude/settings.json`, (2) using `PreCompact` hooks to inject survival context before compaction so it enters the summary, and (3) using `SessionStart` with `compact` matcher to re-run targeted injection scripts (not CLAUDE.md files).
+
+## Problem
+
+After conversation compaction, Claude exhibits "SDLC drift"—forgetting workflow discipline, knowledge injection, and project-specific behavior patterns. Investigation reveals three root causes:
+
+### 1. Dual-Source Hook Configuration Conflict
+
+| File | Written By | Contents | Status |
+|------|------------|----------|--------|
+| `~/.claude/hooks.json` | `install.sh` | Blue's `hooks/session-start` | **Ignored** |
+| `~/.claude/settings.json` | Manual | Compact-matcher SessionStart | **Active** |
+
+The `install.sh` script writes hooks to `hooks.json`, but Claude Code reads from `settings.json`. Blue's session-start hook never fires.
+
+### 2. No PostCompact Hook Exists
+
+Claude Code provides:
+- `PreCompact` — fires BEFORE compaction
+- `SessionStart` with `matcher: "compact"` — fires when session RESUMES after compaction
+
+But there is no `PostCompact` hook. When compaction occurs mid-session, the context injected at SessionStart is lost and only restored if the session is paused and resumed.
+
+### 3. Knowledge Files Not Injected
+
+Blue has five knowledge files that should shape Claude's behavior:
+- `knowledge/alignment-measure.md` — ALIGNMENT scoring framework
+- `knowledge/blue-adrs.md` — Architecture decision records digest
+- `knowledge/expert-pools.md` — Expert persona definitions
+- `knowledge/task-sync.md` — Claude Code task integration
+- `knowledge/workflow-creation.md` — Workflow file guidance
+
+Due to the hook conflict, these files never reach Claude's context.
+
+### Observable Symptoms
+
+- Claude forgets to use `blue_*` MCP tools mid-conversation
+- SDLC discipline (worktree enforcement, RFC-driven development) degrades
+- Task sync patterns stop working
+- ADR adherence drops
+
+## Goals
+
+1. Single authoritative source for hook configuration
+2. Critical context survives conversation compaction
+3. Knowledge files reliably reach Claude's context
+4. Graceful degradation when hooks fail
+5. Audit trail for context injection events
+
+## Non-Goals
+
+- Changing Claude Code's hook architecture
+- Eliminating compaction (it's necessary for long conversations)
+- Real-time context refresh during conversation (MCP Resources handle this)
+
+## Design
+
+### Architecture Overview
+
+```
+┌─────────────────────────────────────────────────────────────────┐
+│ ~/.claude/settings.json │
+│ ┌─────────────────────────────────────────────────────────────┐│
+│ │ SessionStart (always) → hooks/session-start (full) ││
+│ │ SessionStart (compact) → hooks/context-restore (targeted)││
+│ │ PreCompact → hooks/pre-compact (survival) ││
+│ │ PreToolUse (blue_*) → blue session-heartbeat ││
+│ │ SessionEnd → blue session-end ││
+│ └─────────────────────────────────────────────────────────────┘│
+└─────────────────────────────────────────────────────────────────┘
+ │
+ ▼
+┌─────────────────────────────────────────────────────────────────┐
+│ knowledge/*.md (source of truth) │
+│ ┌─────────────────────────────────────────────────────────────┐│
+│ │ alignment-measure.md → ALIGNMENT scoring framework ││
+│ │ blue-adrs.md → Architecture decision digest ││
+│ │ expert-pools.md → Expert persona definitions ││
+│ │ task-sync.md → Claude Code task integration ││
+│ │ workflow-creation.md → Workflow file guidance ││
+│ └─────────────────────────────────────────────────────────────┘│
+└─────────────────────────────────────────────────────────────────┘
+```
+
+### Hook Configuration (Consolidated)
+
+All hooks consolidated into `~/.claude/settings.json`:
+
+```json
+{
+ "hooks": {
+ "SessionStart": [
+ {
+ "matcher": "",
+ "hooks": [
+ {
+ "type": "command",
+ "command": "/path/to/blue/hooks/session-start"
+ }
+ ]
+ },
+ {
+ "matcher": "compact",
+ "hooks": [
+ {
+ "type": "command",
+ "command": "/path/to/blue/hooks/context-restore"
+ }
+ ]
+ }
+ ],
+ "PreCompact": [
+ {
+ "matcher": "",
+ "hooks": [
+ {
+ "type": "command",
+ "command": "/path/to/blue/hooks/pre-compact"
+ }
+ ]
+ }
+ ],
+ "PreToolUse": [
+ {
+ "matcher": "blue_*",
+ "hooks": [
+ {
+ "type": "command",
+ "command": "blue session-heartbeat"
+ }
+ ]
+ }
+ ],
+ "SessionEnd": [
+ {
+ "matcher": "",
+ "hooks": [
+ {
+ "type": "command",
+ "command": "blue session-end"
+ }
+ ]
+ }
+ ]
+ }
+}
+```
+
+**Note**: Paths are written as absolute paths during `install.sh` execution.
+
+### PreCompact Hook Strategy
+
+The `PreCompact` hook fires BEFORE compaction, injecting context that becomes part of the compacted summary:
+
+```bash
+#!/bin/bash
+# hooks/pre-compact
+# Inject survival context before compaction
+
+cat << 'EOF'
+
+## Critical Context for Post-Compaction
+
+This project uses Blue MCP tools. After compaction, remember:
+
+1. **MCP Tools Available**: blue_status, blue_next, blue_rfc_*, blue_worktree_*, blue_pr_*
+2. **SDLC Discipline**: Use worktrees for code changes, RFCs for planning
+3. **Task Sync**: Tasks with blue_rfc metadata sync to .plan.md files
+4. **Active State**: Run `blue_status` to see current RFC/worktree
+
+If you notice workflow drift, run `blue_status` to restore context.
+
+EOF
+```
+
+This context becomes part of the compaction summary, ensuring Claude retains awareness of Blue's existence.
+
+### Context-Restore Hook (Post-Compaction)
+
+A targeted script that re-injects critical context after compaction. Lighter than full session-start:
+
+```bash
+#!/bin/bash
+# hooks/context-restore
+# Targeted context restoration after compaction
+# Lighter than session-start - only critical awareness
+
+BLUE_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
+
+cat << 'EOF'
+
+## Blue MCP Tools Available
+
+This project uses Blue for SDLC workflow management. Key tools:
+- `blue_status` - Current RFC, worktree, and session state
+- `blue_next` - Recommended next action
+- `blue_rfc_*` - RFC lifecycle management
+- `blue_worktree_*` - Isolated development environments
+
+## Workflow Discipline
+
+1. Code changes require active worktrees (RFC 0038)
+2. RFCs drive planning; worktrees isolate implementation
+3. Tasks with `blue_rfc` metadata sync to .plan.md files
+
+Run `blue_status` to see current project state.
+
+EOF
+
+# Optionally inject project-specific workflow if it exists
+if [ -f ".blue/workflow.md" ]; then
+ echo ""
+ cat ".blue/workflow.md"
+ echo ""
+fi
+```
+
+This hook is deliberately minimal (~150 tokens) to avoid bloating post-compaction context while ensuring Claude remembers Blue exists.
+
+### Three-Layer Injection Model
+
+| Layer | Hook | Matcher | Script | Tokens | Survives Compaction? |
+|-------|------|---------|--------|--------|---------------------|
+| **Bootstrap** | SessionStart | (none) | `session-start` | ~800 | No (restored on resume) |
+| **Restoration** | SessionStart | compact | `context-restore` | ~150 | Yes (re-injected) |
+| **Survival** | PreCompact | (none) | `pre-compact` | ~200 | Yes (enters summary) |
+
+**Why three layers?**
+
+- **Bootstrap**: Full knowledge injection when session starts fresh. Expensive but comprehensive.
+- **Survival**: Injected BEFORE compaction so critical awareness enters the compacted summary. Claude "remembers" Blue exists.
+- **Restoration**: Targeted re-injection when session resumes after compaction. Lighter than bootstrap.
+
+### Installation Script Updates
+
+Update `install.sh` to configure hooks in `settings.json` (not `hooks.json`):
+
+```bash
+# install.sh changes
+
+SETTINGS_FILE="$HOME/.claude/settings.json"
+BLUE_ROOT="$(cd "$(dirname "$0")" && pwd)"
+
+# Ensure settings.json exists with hooks structure
+if [ ! -f "$SETTINGS_FILE" ]; then
+ echo '{"hooks":{}}' > "$SETTINGS_FILE"
+fi
+
+# Merge blue hooks into settings.json
+if command -v jq &> /dev/null; then
+ jq --arg blue_root "$BLUE_ROOT" '
+ .hooks.SessionStart = [
+ {
+ "matcher": "",
+ "hooks": [{"type": "command", "command": ($blue_root + "/hooks/session-start")}]
+ },
+ {
+ "matcher": "compact",
+ "hooks": [{"type": "command", "command": ($blue_root + "/hooks/context-restore")}]
+ }
+ ] |
+ .hooks.PreCompact = [
+ {
+ "matcher": "",
+ "hooks": [{"type": "command", "command": ($blue_root + "/hooks/pre-compact")}]
+ }
+ ] |
+ .hooks.PreToolUse = (.hooks.PreToolUse // []) + [
+ {
+ "matcher": "blue_*",
+ "hooks": [{"type": "command", "command": "blue session-heartbeat"}]
+ }
+ ] |
+ .hooks.SessionEnd = [
+ {
+ "matcher": "",
+ "hooks": [{"type": "command", "command": "blue session-end"}]
+ }
+ ]
+ ' "$SETTINGS_FILE" > "$SETTINGS_FILE.tmp" && mv "$SETTINGS_FILE.tmp" "$SETTINGS_FILE"
+fi
+```
+
+### Migration from hooks.json
+
+For users with existing `~/.claude/hooks.json`:
+
+```bash
+# Detect and migrate hooks.json → settings.json
+if [ -f "$HOME/.claude/hooks.json" ] && [ -f "$HOME/.claude/settings.json" ]; then
+ echo "Migrating hooks.json to settings.json..."
+ jq -s '.[0] * .[1]' "$HOME/.claude/settings.json" "$HOME/.claude/hooks.json" > "$HOME/.claude/settings.json.tmp"
+ mv "$HOME/.claude/settings.json.tmp" "$HOME/.claude/settings.json"
+ mv "$HOME/.claude/hooks.json" "$HOME/.claude/hooks.json.migrated"
+ echo "Migration complete. Old file preserved as hooks.json.migrated"
+fi
+```
+
+### Audit Trail
+
+Add injection logging to `blue.db`:
+
+```sql
+CREATE TABLE IF NOT EXISTS context_injections (
+ id INTEGER PRIMARY KEY,
+ session_id TEXT NOT NULL,
+ timestamp TEXT NOT NULL DEFAULT (datetime('now')),
+ hook_type TEXT NOT NULL, -- SessionStart, PreCompact, etc.
+ matcher TEXT, -- compact, blue_*, etc.
+ content_hash TEXT, -- SHA-256 of injected content
+ token_estimate INTEGER, -- Approximate token count
+ FOREIGN KEY (session_id) REFERENCES sessions(id)
+);
+```
+
+## Implementation Plan
+
+### Phase 1: Hook Scripts & Configuration
+1. Create `hooks/pre-compact` script with survival context
+2. Create `hooks/context-restore` script for post-compaction restoration
+3. Update `install.sh` to write to `settings.json` instead of `hooks.json`
+4. Add migration logic: detect `hooks.json` and merge into `settings.json`
+5. Test hook firing with `blue context test` command
+
+### Phase 2: Audit & Observability
+6. Add `context_injections` table to schema
+7. Update all hooks to log injections via `blue context log`
+8. Add `blue context audit` command to view injection history
+9. Add `blue context test` command to verify hooks fire correctly
+
+### Phase 3: Documentation & Refinement
+10. Document hook customization for per-project needs
+11. Add `.blue/context-restore.md` override support (optional per-project restoration)
+12. Tune token budgets based on production usage
+
+## Test Plan
+
+### Hook Configuration
+- [ ] `install.sh` writes to `settings.json`, not `hooks.json`
+- [ ] Existing `settings.json` hooks preserved during install
+- [ ] `hooks.json` contents migrated to `settings.json`
+- [ ] SessionStart hook fires on new session
+- [ ] SessionStart (compact) hook fires after compaction
+- [ ] PreCompact hook fires before compaction
+- [ ] PreToolUse hook fires only for blue_* tools
+
+### Context Injection
+- [ ] Knowledge files injected at SessionStart via `session-start` hook
+- [ ] `context-restore` hook fires after compaction with targeted content
+- [ ] `pre-compact` survival context appears in compaction summary
+- [ ] Claude retains Blue awareness after compaction (manual verification)
+
+### Audit Trail
+- [ ] Injections logged to context_injections table
+- [ ] `blue context audit` shows injection history
+- [ ] `blue context test` verifies hook configuration
+
+### Per-Project Override
+- [ ] `.blue/context-restore.md` content appended if present
+- [ ] Missing override file handled gracefully
+
+## Alternatives Considered
+
+### A. Request PostCompact Hook from Anthropic
+
+**Deferred**: Would be ideal but requires upstream changes. PreCompact + SessionStart(compact) provides equivalent functionality today.
+
+### B. MCP Resource for Context Refresh
+
+**Complementary**: RFC 0016's MCP Resources (`blue://context/*`) provide on-demand refresh. This RFC addresses the gap where Claude forgets MCP tools exist.
+
+### C. Periodic Context Re-injection via UserPromptSubmit
+
+**Rejected**: Would inject on every user message, wasting tokens. PreCompact is more efficient—fires only when needed.
+
+### D. Use CLAUDE.md Files
+
+**Rejected**: Adds file management overhead. Direct hook scripts are simpler—no generated artifacts to maintain, no sync issues between knowledge files and CLAUDE.md.
+
+### E. Re-run Full session-start on Compact
+
+**Rejected**: Too heavy (~800 tokens). The `context-restore` hook is deliberately minimal (~150 tokens) to avoid bloating post-compaction context.
+
+## Consequences
+
+### Positive
+- SDLC discipline survives conversation compaction
+- Single authoritative hook configuration in `settings.json`
+- Audit trail for debugging injection issues
+- No generated files to maintain (no CLAUDE.md sync issues)
+- Targeted restoration (~150 tokens) vs full re-injection (~800 tokens)
+
+### Negative
+- Requires manual migration for existing users
+- PreCompact adds ~200 tokens before each compaction
+- Three hooks to maintain instead of one
+
+### Neutral
+- Shifts from hooks.json to settings.json (Claude Code's actual config)
+- Knowledge files remain source of truth; hooks read them directly
+
+## References
+
+- [RFC 0016: Context Injection Architecture](0016-context-injection-architecture.draft.md) — Three-tier model
+- [RFC 0038: SDLC Workflow Discipline](0038-sdlc-workflow-discipline.draft.md) — What needs to survive
+- [Claude Code Hooks Documentation](https://docs.anthropic.com/en/docs/claude-code/hooks) — Available hook events
+
+---
+
+*"Context flows through explicit boundaries; survival requires deliberate architecture."*
+
+— Blue
diff --git a/hooks/context-restore b/hooks/context-restore
new file mode 100755
index 0000000..baec5f8
--- /dev/null
+++ b/hooks/context-restore
@@ -0,0 +1,31 @@
+#!/bin/bash
+# Blue Context-Restore Hook
+# Targeted context restoration after compaction
+# Lighter than session-start (~150 tokens vs ~800 tokens)
+
+cat << 'EOF'
+
+## Blue MCP Tools Available
+
+This project uses Blue for SDLC workflow management. Key tools:
+- `blue_status` - Current RFC, worktree, and session state
+- `blue_next` - Recommended next action
+- `blue_rfc_*` - RFC lifecycle management
+- `blue_worktree_*` - Isolated development environments
+
+## Workflow Discipline
+
+1. Code changes require active worktrees (RFC 0038)
+2. RFCs drive planning; worktrees isolate implementation
+3. Tasks with `blue_rfc` metadata sync to .plan.md files
+
+Run `blue_status` to see current project state.
+
+EOF
+
+# Optionally inject project-specific workflow if it exists
+if [ -f ".blue/workflow.md" ]; then
+ echo ""
+ cat ".blue/workflow.md"
+ echo ""
+fi
diff --git a/hooks/pre-compact b/hooks/pre-compact
new file mode 100755
index 0000000..6956ba1
--- /dev/null
+++ b/hooks/pre-compact
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Blue PreCompact Hook
+# Injects survival context BEFORE compaction so it enters the summary
+# This ensures Claude retains awareness of Blue after compaction
+
+cat << 'EOF'
+
+## Critical Context for Post-Compaction
+
+This project uses Blue MCP tools. After compaction, remember:
+
+1. **MCP Tools Available**: blue_status, blue_next, blue_rfc_*, blue_worktree_*, blue_pr_*
+2. **SDLC Discipline**: Use worktrees for code changes, RFCs for planning
+3. **Task Sync**: Tasks with blue_rfc metadata sync to .plan.md files
+4. **Active State**: Run `blue_status` to see current RFC/worktree
+
+If you notice workflow drift, run `blue_status` to restore context.
+
+EOF
diff --git a/install.sh b/install.sh
index d8c620f..04eae1e 100755
--- a/install.sh
+++ b/install.sh
@@ -58,9 +58,9 @@ if [ -f "$MCP_CONFIG" ]; then
fi
fi
-# Install Blue skills to Claude Code
+# Install Blue skills to Claude Code (symlink, not copy)
SKILLS_DIR="$HOME/.claude/skills"
-BLUE_SKILLS_DIR="$(dirname "$0")/skills"
+BLUE_SKILLS_DIR="$(cd "$(dirname "$0")" && pwd)/skills"
if [ -d "$BLUE_SKILLS_DIR" ] && [ -d "$HOME/.claude" ]; then
echo ""
@@ -70,15 +70,19 @@ if [ -d "$BLUE_SKILLS_DIR" ] && [ -d "$HOME/.claude" ]; then
for skill in "$BLUE_SKILLS_DIR"/*; do
if [ -d "$skill" ]; then
skill_name=$(basename "$skill")
- cp -r "$skill" "$SKILLS_DIR/"
- echo " Installed skill: $skill_name"
+ target="$SKILLS_DIR/$skill_name"
+ # Remove existing symlink, file, or directory
+ rm -rf "$target" 2>/dev/null
+ ln -s "$skill" "$target"
+ echo " Linked skill: $skill_name -> $skill"
fi
done
- echo -e "${GREEN}Skills installed to $SKILLS_DIR${NC}"
+ echo -e "${GREEN}Skills linked to $SKILLS_DIR${NC}"
fi
-# Install Blue hooks to Claude Code
+# Install Blue hooks to Claude Code (RFC 0041: write to settings.json, not hooks.json)
+SETTINGS_FILE="$HOME/.claude/settings.json"
HOOKS_FILE="$HOME/.claude/hooks.json"
BLUE_ROOT="$(cd "$(dirname "$0")" && pwd)"
@@ -86,34 +90,59 @@ if [ -d "$HOME/.claude" ]; then
echo ""
echo "Configuring Blue hooks..."
- # Create hooks.json if it doesn't exist
- if [ ! -f "$HOOKS_FILE" ]; then
- echo '{"hooks":{}}' > "$HOOKS_FILE"
+ # Migrate hooks.json to settings.json if both exist (RFC 0041)
+ if [ -f "$HOOKS_FILE" ] && [ -f "$SETTINGS_FILE" ]; then
+ echo " Migrating hooks.json to settings.json..."
+ if command -v jq &> /dev/null; then
+ jq -s '.[0] * .[1]' "$SETTINGS_FILE" "$HOOKS_FILE" > "$SETTINGS_FILE.tmp" && mv "$SETTINGS_FILE.tmp" "$SETTINGS_FILE"
+ mv "$HOOKS_FILE" "$HOOKS_FILE.migrated"
+ echo -e " ${GREEN}Migration complete (old file: hooks.json.migrated)${NC}"
+ else
+ echo -e " ${RED}Install jq to migrate hooks.json${NC}"
+ fi
fi
- # Update hooks using jq if available, otherwise create fresh
+ # Ensure settings.json exists with hooks structure
+ if [ ! -f "$SETTINGS_FILE" ]; then
+ echo '{"hooks":{}}' > "$SETTINGS_FILE"
+ fi
+
+ # Update hooks in settings.json using jq if available
if command -v jq &> /dev/null; then
- jq --arg blue_root "$BLUE_ROOT" '.hooks.SessionStart.command = ($blue_root + "/hooks/session-start") | .hooks.SessionEnd.command = ($blue_root + "/target/release/blue session-end") | .hooks.PreToolUse.command = ($blue_root + "/target/release/blue session-heartbeat") | .hooks.PreToolUse.match = "blue_*"' "$HOOKS_FILE" > "$HOOKS_FILE.tmp" && mv "$HOOKS_FILE.tmp" "$HOOKS_FILE"
- echo -e "${GREEN}Hooks configured${NC}"
+ jq --arg blue_root "$BLUE_ROOT" '
+ .hooks.SessionStart = [
+ {
+ "matcher": "",
+ "hooks": [{"type": "command", "command": ($blue_root + "/hooks/session-start")}]
+ },
+ {
+ "matcher": "compact",
+ "hooks": [{"type": "command", "command": ($blue_root + "/hooks/context-restore")}]
+ }
+ ] |
+ .hooks.PreCompact = [
+ {
+ "matcher": "",
+ "hooks": [{"type": "command", "command": ($blue_root + "/hooks/pre-compact")}]
+ }
+ ] |
+ .hooks.PreToolUse = [
+ {
+ "matcher": "blue_*",
+ "hooks": [{"type": "command", "command": "blue session-heartbeat"}]
+ }
+ ] |
+ .hooks.SessionEnd = [
+ {
+ "matcher": "",
+ "hooks": [{"type": "command", "command": "blue session-end"}]
+ }
+ ]
+ ' "$SETTINGS_FILE" > "$SETTINGS_FILE.tmp" && mv "$SETTINGS_FILE.tmp" "$SETTINGS_FILE"
+ echo -e "${GREEN}Hooks configured in settings.json${NC}"
else
- # Fallback: write hooks directly
- cat > "$HOOKS_FILE" << EOF
-{
- "hooks": {
- "SessionStart": {
- "command": "$BLUE_ROOT/hooks/session-start"
- },
- "SessionEnd": {
- "command": "$BLUE_ROOT/target/release/blue session-end"
- },
- "PreToolUse": {
- "command": "$BLUE_ROOT/target/release/blue session-heartbeat",
- "match": "blue_*"
- }
- }
-}
-EOF
- echo -e "${GREEN}Hooks configured (install jq for safer merging)${NC}"
+ echo -e "${RED}jq is required for hook configuration${NC}"
+ echo "Install jq: brew install jq (macOS) or apt install jq (Linux)"
fi
fi