feat: PreCompact Hook Integration for Context Preservation #73

Closed
opened 2026-01-22 16:52:38 +00:00 by jack · 0 comments
Owner

Summary

Implement PreCompact hook support to preserve context before Claude Code's automatic compaction, enabling intelligent context re-injection after compaction occurs. Additionally, investigate the potential to block compaction entirely using exit code 2.

Problem Statement

Claude Code automatically compacts conversation context when the token limit is reached. This causes:

  • Loss of important observations that were captured during the session
  • Context discontinuity where Claude "forgets" what was discussed
  • Reduced effectiveness of claude-mem's memory system since injected context gets compacted away

Currently, claude-mem has no visibility into when compaction occurs and cannot preserve or restore context around this event.

Key Discovery: Compaction Blocking May Be Possible

The claude-flow cache-optimizer project claims:

"Discovered exit code 2 mechanism in Claude Code CLI to prevent both manual and automatic compaction events."

This contradicts the official documentation which states PreCompact hooks cannot block compaction. This needs investigation:

  1. Is exit code 2 from PreCompact actually blocking? (undocumented behavior)
  2. Is it achieved via a different hook? (e.g., UserPromptSubmit detecting imminent compaction)
  3. Is it preventive rather than blocking? (keeping utilization low enough that compaction never triggers)

If compaction CAN be blocked, this changes the implementation strategy significantly.

Proposed Solution

Phase 0: Investigation (Priority)

  1. Test if PreCompact with exit code 2 actually blocks compaction
  2. Analyze claude-flow's implementation to understand their approach
  3. Document findings for the community

Phase 1: PreCompact Hook (Reactive Approach)

If blocking is NOT possible, implement reactive preservation:

  1. Captures the full transcript before compaction
  2. Extracts key observations that might be lost
  3. Marks a "compaction boundary" in the database
  4. Prepares context for re-injection on the next UserPromptSubmit
{
  "PreCompact": [
    {
      "matcher": "auto|manual",
      "hooks": [
        {
          "type": "command",
          "command": "bun \"${CLAUDE_PLUGIN_ROOT}/scripts/worker-service.cjs\" hook claude-code pre-compact",
          "timeout": 120
        }
      ]
    }
  ]
}

Phase 1b: Compaction Blocking (If Possible)

If exit code 2 works, implement intelligent blocking:

  1. Analyze context utilization when PreCompact fires
  2. Decide whether to block based on importance of current context
  3. Proactively prune low-relevance content to reduce utilization
  4. Allow compaction only when truly necessary
// Pseudo-code for blocking logic
async function handlePreCompact(input: PreCompactInput): Promise<number> {
  const utilization = await analyzeContextUtilization(input.transcript_path);
  
  if (utilization < 0.9 && hasImportantContext()) {
    // Block compaction, prune low-relevance content instead
    await pruneContext();
    return 2; // Exit code 2 = block
  }
  
  // Allow compaction but preserve critical context
  await preserveBeforeCompaction(input);
  return 0;
}

Hook Input (from Claude Code)

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../session.jsonl",
  "hook_event_name": "PreCompact",
  "trigger": "auto",  // or "manual"
  "custom_instructions": ""  // only populated for manual /compact
}

Implementation Details

Worker Endpoint: POST /api/hooks/pre-compact

Actions:

  1. Parse transcript from transcript_path
  2. Extract unprocessed tool uses and observations
  3. Store a compaction event with timestamp and session context
  4. Mark relevant observations for priority re-injection
  5. Optionally: Generate a condensed summary of the session so far
  6. If blocking is possible: Return exit code 2 to prevent compaction

Post-Compaction Recovery:
On the next UserPromptSubmit, detect if a recent compaction occurred and inject:

  • High-priority observations from before compaction
  • Session continuity context ("You were working on X...")
  • Any custom instructions from manual /compact

Technical Background

PreCompact Hook - Official vs Discovered Behavior

Official Documentation says:

  • Cannot block compaction
  • Cannot modify compaction parameters
  • Can only observe and prepare

claude-flow claims:

  • Exit code 2 blocks both manual and automatic compaction
  • Achieved 90.3% reduction in compaction events

This discrepancy needs verification.

Hook Blocking Matrix (Official)

Hook Can Block? Method
UserPromptSubmit Yes Exit code 2
PreToolUse Yes Exit code 2 or JSON
Stop Yes JSON decision
PreCompact Unknown Exit code 2?
PostToolUse No -

Future Enhancements (Phase 2)

Preventive Context Management

Implement proactive context optimization:

  1. Token Budget Tracking: Monitor injected context size
  2. Relevance-Based Pruning: Remove low-relevance observations before they trigger compaction
  3. Temporal Tier Compression: Hot/warm/cold tiers for context (inspired by claude-flow)
  4. Target Utilization Profiles: Keep context under configurable threshold (e.g., 75%)

Performance potential (from claude-flow benchmarks):

WITHOUT Optimization: 149.2% utilization → COMPACTION TRIGGERED
WITH Optimization:    58.9% utilization → COMPACTION PREVENTED

Acceptance Criteria

  • Phase 0: Verify if exit code 2 blocks compaction
  • PreCompact hook registered in hooks.json
  • Worker endpoint /api/hooks/pre-compact implemented
  • Transcript parsing extracts relevant observations
  • Compaction events stored in database with metadata
  • If blocking works: Implement intelligent block/allow logic
  • If blocking doesn't work: UserPromptSubmit re-injects context
  • Documentation updated with findings and new hook behavior

References

## Summary Implement PreCompact hook support to preserve context before Claude Code's automatic compaction, enabling intelligent context re-injection after compaction occurs. Additionally, investigate the potential to **block compaction entirely** using exit code 2. ## Problem Statement Claude Code automatically compacts conversation context when the token limit is reached. This causes: - **Loss of important observations** that were captured during the session - **Context discontinuity** where Claude "forgets" what was discussed - **Reduced effectiveness** of claude-mem's memory system since injected context gets compacted away Currently, claude-mem has no visibility into when compaction occurs and cannot preserve or restore context around this event. ## Key Discovery: Compaction Blocking May Be Possible The [claude-flow cache-optimizer](https://github.com/ruvnet/claude-flow/issues/965) project claims: > **"Discovered exit code 2 mechanism in Claude Code CLI to prevent both manual and automatic compaction events."** This contradicts the official documentation which states PreCompact hooks cannot block compaction. This needs investigation: 1. **Is exit code 2 from PreCompact actually blocking?** (undocumented behavior) 2. **Is it achieved via a different hook?** (e.g., UserPromptSubmit detecting imminent compaction) 3. **Is it preventive rather than blocking?** (keeping utilization low enough that compaction never triggers) If compaction CAN be blocked, this changes the implementation strategy significantly. ## Proposed Solution ### Phase 0: Investigation (Priority) 1. Test if PreCompact with exit code 2 actually blocks compaction 2. Analyze claude-flow's implementation to understand their approach 3. Document findings for the community ### Phase 1: PreCompact Hook (Reactive Approach) If blocking is NOT possible, implement reactive preservation: 1. **Captures the full transcript** before compaction 2. **Extracts key observations** that might be lost 3. **Marks a "compaction boundary"** in the database 4. **Prepares context for re-injection** on the next UserPromptSubmit ```json { "PreCompact": [ { "matcher": "auto|manual", "hooks": [ { "type": "command", "command": "bun \"${CLAUDE_PLUGIN_ROOT}/scripts/worker-service.cjs\" hook claude-code pre-compact", "timeout": 120 } ] } ] } ``` ### Phase 1b: Compaction Blocking (If Possible) If exit code 2 works, implement intelligent blocking: 1. **Analyze context utilization** when PreCompact fires 2. **Decide whether to block** based on importance of current context 3. **Proactively prune** low-relevance content to reduce utilization 4. **Allow compaction** only when truly necessary ```typescript // Pseudo-code for blocking logic async function handlePreCompact(input: PreCompactInput): Promise<number> { const utilization = await analyzeContextUtilization(input.transcript_path); if (utilization < 0.9 && hasImportantContext()) { // Block compaction, prune low-relevance content instead await pruneContext(); return 2; // Exit code 2 = block } // Allow compaction but preserve critical context await preserveBeforeCompaction(input); return 0; } ``` ### Hook Input (from Claude Code) ```json { "session_id": "abc123", "transcript_path": "~/.claude/projects/.../session.jsonl", "hook_event_name": "PreCompact", "trigger": "auto", // or "manual" "custom_instructions": "" // only populated for manual /compact } ``` ### Implementation Details **Worker Endpoint:** `POST /api/hooks/pre-compact` **Actions:** 1. Parse transcript from `transcript_path` 2. Extract unprocessed tool uses and observations 3. Store a compaction event with timestamp and session context 4. Mark relevant observations for priority re-injection 5. Optionally: Generate a condensed summary of the session so far 6. **If blocking is possible:** Return exit code 2 to prevent compaction **Post-Compaction Recovery:** On the next `UserPromptSubmit`, detect if a recent compaction occurred and inject: - High-priority observations from before compaction - Session continuity context ("You were working on X...") - Any custom instructions from manual `/compact` ## Technical Background ### PreCompact Hook - Official vs Discovered Behavior **Official Documentation says:** - Cannot block compaction - Cannot modify compaction parameters - Can only observe and prepare **claude-flow claims:** - Exit code 2 blocks both manual and automatic compaction - Achieved 90.3% reduction in compaction events This discrepancy needs verification. ### Hook Blocking Matrix (Official) | Hook | Can Block? | Method | |------|-----------|--------| | UserPromptSubmit | ✅ Yes | Exit code 2 | | PreToolUse | ✅ Yes | Exit code 2 or JSON | | Stop | ✅ Yes | JSON decision | | **PreCompact** | ❓ Unknown | Exit code 2? | | PostToolUse | ❌ No | - | ### Related Projects & Research - **[context-forge](https://github.com/webdevtodayjason/context-forge)**: Uses PreCompact for transcript backup and ContextRotation for file management - **[claude-flow cache-optimizer](https://github.com/ruvnet/claude-flow/issues/965)**: Claims exit code 2 blocks compaction, preventive approach maintaining context under 75% utilization - **[claude-code-hooks-mastery](https://github.com/disler/claude-code-hooks-mastery)**: Comprehensive hook documentation ## Future Enhancements (Phase 2) ### Preventive Context Management Implement proactive context optimization: 1. **Token Budget Tracking**: Monitor injected context size 2. **Relevance-Based Pruning**: Remove low-relevance observations before they trigger compaction 3. **Temporal Tier Compression**: Hot/warm/cold tiers for context (inspired by claude-flow) 4. **Target Utilization Profiles**: Keep context under configurable threshold (e.g., 75%) Performance potential (from claude-flow benchmarks): ``` WITHOUT Optimization: 149.2% utilization → COMPACTION TRIGGERED WITH Optimization: 58.9% utilization → COMPACTION PREVENTED ``` ## Acceptance Criteria - [ ] **Phase 0:** Verify if exit code 2 blocks compaction - [ ] PreCompact hook registered in `hooks.json` - [ ] Worker endpoint `/api/hooks/pre-compact` implemented - [ ] Transcript parsing extracts relevant observations - [ ] Compaction events stored in database with metadata - [ ] If blocking works: Implement intelligent block/allow logic - [ ] If blocking doesn't work: UserPromptSubmit re-injects context - [ ] Documentation updated with findings and new hook behavior ## References - [Claude Code PreCompact Documentation](https://code.claude.com/docs/en/hooks#precompact) - [Claude Code Slash Commands - /compact](https://code.claude.com/docs/en/interactive-mode) - [context-forge GitHub](https://github.com/webdevtodayjason/context-forge) - [claude-flow cache-optimizer #965](https://github.com/ruvnet/claude-flow/issues/965) - **Claims exit code 2 blocks compaction** - [claude-code-hooks-mastery](https://github.com/disler/claude-code-hooks-mastery)
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
customable/claude-mem#73
No description provided.