# Hooks Integration for Progressive Disclosure
This document describes how to integrate session hooks with CCW's progressive disclosure system, including the new Soft Enforcement Stop Hook, Mode System, and Checkpoint/Recovery features.
## Overview
CCW supports automatic context injection via hooks. When a session starts, the system can automatically provide a progressive disclosure index showing related sessions from the same cluster.
### Key Features
- **Automatic Context Injection**: Session start hooks inject cluster context
- **Progressive Disclosure**: Shows related sessions, their summaries, and recovery commands
- **Silent Failure**: Hook failures don't block session start (< 5 seconds timeout)
- **Multiple Hook Types**: Supports `session-start`, `context`, `PreCompact`, `Stop`, and custom hooks
- **Soft Enforcement**: Stop hooks never block - they inject continuation messages instead
- **Mode System**: Keyword-based mode activation with exclusive mode conflict detection
- **Checkpoint/Recovery**: Automatic state preservation before context compaction
## Hook Configuration
### Location
Place hook configurations in `.claude/settings.json`:
```json
{
"hooks": {
"session-start": [
{
"name": "Progressive Disclosure",
"description": "Injects progressive disclosure index at session start with recovery detection",
"enabled": true,
"handler": "internal:context",
"timeout": 5000,
"failMode": "silent",
"notes": [
"Checks for recovery checkpoints and injects recovery message if found",
"Uses RecoveryHandler.checkRecovery() for session recovery"
]
}
]
}
}
```
### Hook Types
#### `session-start`
Triggered when a new session begins. Ideal for injecting context and checking for recovery checkpoints.
#### `PreCompact`
Triggered before context compaction. Creates checkpoints to preserve session state including:
- Active mode states
- Workflow progress
- TODO summaries
#### `Stop`
Triggered when a stop is requested. Uses **Soft Enforcement** - never blocks, but may inject continuation messages.
#### `UserPromptSubmit`
Triggered when a prompt is submitted. Detects mode keywords and activates corresponding execution modes.
#### `session-end`
Triggered when a session ends. Useful for:
- Updating cluster metadata
- Cleaning up mode states
- Final checkpoint creation
#### `file-modified`
Triggered when files are modified. Can be used for auto-commits or notifications.
### Hook Properties
- **`name`**: Human-readable hook name
- **`description`**: What the hook does
- **`enabled`**: Boolean to enable/disable the hook
- **`handler`**: `internal:context` for built-in context generation, or use `command` field
- **`command`**: Shell command to execute (alternative to `handler`)
- **`timeout`**: Maximum execution time in milliseconds (default: 5000)
- **`failMode`**: How to handle failures
- `silent`: Ignore errors, don't log
- `log`: Log errors but continue
- `fail`: Abort on error
- **`async`**: Run in background without blocking (default: false)
### Available Variables
In `command` fields, use these variables:
- `$SESSION_ID`: Current session ID
- `$FILE_PATH`: File path (for file-modified hooks)
- `$PROJECT_PATH`: Current project path
- `$CLUSTER_ID`: Active cluster ID (if available)
---
## Soft Enforcement Stop Hook
The Stop Hook implements **Soft Enforcement**: it never blocks stops, but injects continuation messages to encourage task completion.
### Priority Order
1. **context-limit**: Always allow (deadlock prevention)
2. **user-abort**: Respect user intent
3. **active-workflow**: Inject continuation message
4. **active-mode**: Inject continuation message via ModeRegistryService
### Configuration Example
```json
{
"hooks": {
"Stop": [
{
"name": "Soft Enforcement Stop",
"description": "Injects continuation messages for active workflows/modes",
"enabled": true,
"command": "ccw hook stop --stdin",
"timeout": 5000,
"failMode": "silent"
}
]
}
}
```
### Behavior Matrix
| Condition | continue | mode | message |
|-----------|----------|------|---------|
| Context limit reached | `true` | `context-limit` | None |
| User requested stop | `true` | `user-abort` | None |
| Active workflow | `true` | `active-workflow` | Continuation message |
| Active mode | `true` | `active-mode` | Mode-specific message |
| Normal stop | `true` | `none` | None |
### Context Limit Detection
Detected via `ContextLimitDetector`:
- `stop_reason: "context_limit_reached"`
- `stop_reason: "end_turn_limit"`
- `end_turn_reason: "max_tokens"`
- `stop_reason: "max_context"`
### User Abort Detection
Detected via `UserAbortDetector`:
- `user_requested: true`
- `stop_reason: "user_cancel"`
- `stop_reason: "cancel"`
---
## Mode System
The Mode System provides centralized mode state management with file-based persistence.
### Supported Modes
| Mode | Type | Description |
|------|------|-------------|
| `autopilot` | Exclusive | Autonomous execution mode for multi-step tasks |
| `ralph` | Non-exclusive | Research and Analysis Learning Pattern Handler |
| `ultrawork` | Non-exclusive | Ultra-focused work mode for deep tasks |
| `swarm` | Exclusive | Multi-agent swarm execution mode |
| `pipeline` | Exclusive | Pipeline execution mode for sequential tasks |
| `team` | Non-exclusive | Team collaboration mode |
| `ultraqa` | Non-exclusive | Ultra-focused QA mode |
### Exclusive Mode Conflict
Exclusive modes (`autopilot`, `swarm`, `pipeline`) cannot run concurrently. Attempting to start one while another is active will be blocked.
### Mode State Storage
Mode states are stored in `.workflow/modes/`:
```
.workflow/modes/
├── sessions/
│ ├── {session-id}/
│ │ ├── autopilot-state.json
│ │ └── ralph-state.json
│ └── ...
└── (legacy shared states)
```
### Stale Marker Cleanup
Mode markers older than 1 hour are automatically cleaned up to prevent crashed sessions from blocking indefinitely.
### Mode Activation via Keyword
Configure the `UserPromptSubmit` hook to detect keywords:
```json
{
"hooks": {
"UserPromptSubmit": [
{
"name": "Keyword Detection",
"description": "Detects mode keywords in prompts and activates corresponding modes",
"enabled": true,
"command": "ccw hook keyword --stdin",
"timeout": 5000,
"failMode": "silent"
}
]
}
}
```
### Supported Keywords
| Keyword | Mode | Aliases |
|---------|------|---------|
| `autopilot` | autopilot | - |
| `ultrawork` | ultrawork | `ulw` |
| `ralph` | ralph | - |
| `swarm` | swarm | - |
| `pipeline` | pipeline | - |
| `team` | team | - |
| `ultraqa` | ultraqa | - |
| `cancelomc` | Cancel | `stopomc` |
| `codex` | Delegate | `gpt` |
| `gemini` | Delegate | - |
---
## Checkpoint and Recovery
The Checkpoint System preserves session state before context compaction.
### Checkpoint Triggers
| Trigger | Description |
|---------|-------------|
| `manual` | User-initiated checkpoint |
| `auto` | Automatic checkpoint |
| `compact` | Before context compaction |
| `mode-switch` | When switching modes |
| `session-end` | At session termination |
### Checkpoint Storage
Checkpoints are stored in `.workflow/checkpoints/`:
```
.workflow/checkpoints/
├── 2025-02-18T10-30-45-sess123.json
├── 2025-02-18T11-15-22-sess123.json
└── ...
```
### Checkpoint Contents
```json
{
"id": "2025-02-18T10-30-45-sess123",
"created_at": "2025-02-18T10:30:45.000Z",
"trigger": "compact",
"session_id": "sess123",
"project_path": "/path/to/project",
"workflow_state": null,
"mode_states": {
"autopilot": {
"active": true,
"activatedAt": "2025-02-18T10:00:00.000Z"
}
},
"memory_context": null,
"todo_summary": {
"pending": 3,
"in_progress": 1,
"completed": 5
}
}
```
### Recovery Flow
```
┌─────────────────┐
│ Session Start │
└────────┬────────┘
│
v
┌─────────────────┐ No checkpoint
│ Check Recovery │ ──────────────────► Continue normally
└────────┬────────┘
│ Checkpoint found
v
┌─────────────────┐
│ Load Checkpoint │
└────────┬────────┘
│
v
┌─────────────────┐
│ Restore Modes │
└────────┬────────┘
│
v
┌─────────────────┐
│ Inject Message │
└─────────────────┘
```
### Automatic Cleanup
Only the last 10 checkpoints per session are retained. Older checkpoints are automatically removed.
---
## PreCompact Hook with Mutex
The PreCompact hook uses a mutex to prevent concurrent compaction operations for the same directory.
### Mutex Behavior
```
Request 1 ──► PreCompact ──► Create checkpoint ──► Return
▲
Request 2 ──► Wait for Request 1 ────────────────┘
```
This prevents race conditions when multiple subagent results arrive simultaneously (e.g., in swarm/ultrawork modes).
---
## API Endpoint
### Trigger Hook
```bash
POST http://localhost:3456/api/hook
Content-Type: application/json
{
"type": "session-start",
"sessionId": "WFS-20241218-001",
"projectPath": "/path/to/project"
}
```
### Response Format
```json
{
"success": true,
"type": "context",
"format": "markdown",
"content": "...",
"sessionId": "WFS-20241218-001"
}
```
### Query Parameters
- `?path=/project/path`: Override project path
- `?format=markdown|json`: Response format (default: markdown)
---
## Progressive Disclosure Output Format
The hook returns a structured Markdown document:
```markdown
## Related Sessions Index
### Active Cluster: {cluster_name} ({member_count} sessions)
**Intent**: {cluster_intent}
| # | Session | Type | Summary | Tokens |
|---|---------|------|---------|--------|
| 1 | WFS-001 | Workflow | Implement auth | ~1200 |
| 2 | CLI-002 | CLI | Fix login bug | ~800 |
**Resume Commands**:
```bash
# Load specific session
ccw core-memory load {session_id}
# Load entire cluster context
ccw core-memory load-cluster {cluster_id}
```
### Timeline
```
2024-12-15 -- WFS-001 (Implement auth)
│
2024-12-16 -- CLI-002 (Fix login bug) <- Current
```
---
**Tip**: Use `ccw core-memory search ` to find more sessions
```
---
## Complete Configuration Example
```json
{
"hooks": {
"session-start": [
{
"name": "Progressive Disclosure",
"description": "Injects progressive disclosure index at session start with recovery detection",
"enabled": true,
"handler": "internal:context",
"timeout": 5000,
"failMode": "silent"
}
],
"session-end": [
{
"name": "Update Cluster Metadata",
"description": "Updates cluster metadata after session ends",
"enabled": true,
"command": "ccw core-memory update-cluster --session $SESSION_ID",
"timeout": 30000,
"async": true,
"failMode": "log"
},
{
"name": "Mode State Cleanup",
"description": "Deactivates all active modes for the session",
"enabled": true,
"command": "ccw hook session-end --stdin",
"timeout": 5000,
"failMode": "silent"
}
],
"PreCompact": [
{
"name": "Create Checkpoint",
"description": "Creates checkpoint before context compaction",
"enabled": true,
"command": "ccw hook precompact --stdin",
"timeout": 10000,
"failMode": "log"
}
],
"Stop": [
{
"name": "Soft Enforcement Stop",
"description": "Injects continuation messages for active workflows/modes",
"enabled": true,
"command": "ccw hook stop --stdin",
"timeout": 5000,
"failMode": "silent"
}
],
"UserPromptSubmit": [
{
"name": "Keyword Detection",
"description": "Detects mode keywords in prompts and activates corresponding modes",
"enabled": true,
"command": "ccw hook keyword --stdin",
"timeout": 5000,
"failMode": "silent"
}
],
"file-modified": [
{
"name": "Auto Commit Checkpoint",
"description": "Creates git checkpoint on file modifications",
"enabled": false,
"command": "git add . && git commit -m \"[Auto] Checkpoint: $FILE_PATH\"",
"timeout": 10000,
"async": true,
"failMode": "log"
}
]
},
"notes": {
"handler": "Use 'internal:context' for built-in context generation, or 'command' for external commands",
"failMode": "Options: 'silent' (ignore errors), 'log' (log errors), 'fail' (abort on error)",
"variables": "Available: $SESSION_ID, $FILE_PATH, $PROJECT_PATH, $CLUSTER_ID",
"async": "Async hooks run in background and don't block the main flow",
"Stop hook": "The Stop hook uses Soft Enforcement - it never blocks but may inject continuation messages",
"PreCompact hook": "Creates checkpoint before compaction; uses mutex to prevent concurrent operations",
"UserPromptSubmit hook": "Detects mode keywords and activates corresponding execution modes",
"session-end hook": "Cleans up mode states using ModeRegistryService.deactivateMode()"
}
}
```
---
## Testing
### Test Hook Trigger
```bash
# Using curl
curl -X POST http://localhost:3456/api/hook \
-H "Content-Type: application/json" \
-d '{"type":"session-start","sessionId":"test-001"}'
# Using ccw (if CLI command exists)
ccw core-memory context --format markdown
```
### Run Integration Tests
```bash
# Run all hook integration tests
node --test tests/integration/hooks-integration.test.ts
# Run with verbose output
node --test tests/integration/hooks-integration.test.ts --test-name-pattern="INT-.*"
```
### Expected Output
If a cluster exists:
- Table of related sessions
- Resume commands
- Timeline visualization
If no cluster exists:
- Message indicating no cluster found
- Commands to search or trigger clustering
---
## Troubleshooting
### Hook Not Triggering
1. Check that hooks are enabled in `.claude/settings.json`
2. Verify the hook type matches the event
3. Ensure the server is running on the correct port
### Timeout Issues
1. Increase `timeout` value for slow operations
2. Use `async: true` for long-running commands
3. Check logs for performance issues
### Empty Context
1. Ensure clustering has been run: `ccw core-memory cluster --auto`
2. Verify session metadata exists
3. Check that the session has been added to a cluster
### Mode Not Activating
1. Check for conflicting exclusive modes
2. Verify keyword spelling (case-insensitive)
3. Check that keyword is not inside code blocks
### Checkpoint Not Created
1. Verify `.workflow/checkpoints/` directory exists
2. Check disk space
3. Review logs for error messages
### Recovery Not Working
1. Verify checkpoint exists in `.workflow/checkpoints/`
2. Check that session ID matches
3. Ensure checkpoint file is valid JSON
---
## Performance Considerations
- Progressive disclosure index generation is fast (< 1 second typical)
- Uses cached metadata to avoid full session parsing
- Timeout enforced to prevent blocking
- Failures return empty content instead of errors
- Mutex prevents concurrent compaction operations
- Stale marker cleanup runs automatically
---
## Architecture Diagram
```
┌─────────────────────────────────────────────────────────────┐
│ Claude Code Session │
└─────────────────────────────────────────────────────────────┘
│
│ Hook Events
v
┌─────────────────────────────────────────────────────────────┐
│ Hook System │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │Session Start │ │ PreCompact │ │ Stop │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
└─────────┼─────────────────┼──────────────────┼──────────────┘
│ │ │
v v v
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│RecoveryHandler │ │CheckpointService│ │ StopHandler │
│ │ │ │ │ │
│ - checkRecovery │ │ - create │ │ - SoftEnforce │
│ - formatMessage │ │ - save │ │ - detectMode │
└────────┬────────┘ └────────┬────────┘ └────────┬────────┘
│ │ │
v v v
┌─────────────────────────────────────────────────────────────┐
│ ModeRegistryService │
│ │
│ - activateMode / deactivateMode │
│ - getActiveModes / canStartMode │
│ - cleanupStaleMarkers │
│ │
│ Storage: .workflow/modes/sessions/{sessionId}/ │
└─────────────────────────────────────────────────────────────┘
│
v
┌─────────────────────────────────────────────────────────────┐
│ Checkpoint Storage │
│ │
│ .workflow/checkpoints/{checkpoint-id}.json │
│ - session_id, trigger, mode_states, workflow_state │
│ - Automatic cleanup (keep last 10 per session) │
└─────────────────────────────────────────────────────────────┘
```
---
## References
- **Session Clustering**: See `session-clustering-service.ts`
- **Core Memory Store**: See `core-memory-store.ts`
- **Hook Routes**: See `routes/hooks-routes.ts`
- **Stop Handler**: See `core/hooks/stop-handler.ts`
- **Mode Registry**: See `core/services/mode-registry-service.ts`
- **Checkpoint Service**: See `core/services/checkpoint-service.ts`
- **Recovery Handler**: See `core/hooks/recovery-handler.ts`
- **Keyword Detector**: See `core/hooks/keyword-detector.ts`
- **Example Configuration**: See `templates/hooks-config-example.json`