# ADR-005: Hook Adapter Decomposition into Handler Modules

## Status

Proposed

## Context

`claude_code_hook_adapter.py` in `src/des/adapters/drivers/hooks/` is 1361 lines containing 4 handler functions (`handle_pre_tool_use`, `handle_subagent_stop`, `handle_post_tool_use`, `handle_pre_write`), shared protocol utilities (stdin parsing, audit logging, error handling), signal file management, transcript DES context extraction, factory functions for creating application services, skill tracking hooks, and CLI entry point routing.

The file is the single installed entry point: `python3 -m des.adapters.drivers.hooks.claude_code_hook_adapter <command>`. This invocation path is hardcoded in user-installed hooks and MUST be preserved.

Two handlers (`session_start_handler.py`, `subagent_start_handler.py`) were already extracted into separate modules, demonstrating the pattern works.

Business drivers:
- **Maintainability**: modifying one handler requires reading 1361 lines
- **Modifiability**: adding a new hook event type means editing a file that handles 4 other events
- **Consistency**: two handlers are already extracted; the remaining four should follow the same pattern

## Decision

Decompose `claude_code_hook_adapter.py` into focused modules within the existing `hooks/` package:

1. **`hook_router.py`**: CLI entry point with command-to-handler dispatch
2. **`hook_protocol.py`**: Shared protocol utilities (stdin parsing, audit logging, error handling, exit codes)
3. **`pre_tool_use_handler.py`**: `handle_pre_tool_use()` function
4. **`subagent_stop_handler.py`**: `handle_subagent_stop()` and DES context resolution
5. **`post_tool_use_handler.py`**: `handle_post_tool_use()` function
6. **`pre_write_handler.py`**: `handle_pre_write()` function
7. **`des_task_signal.py`**: Signal file create/read/remove functions
8. **`service_factory.py`**: Factory functions for creating application services
9. **`skill_tracking_hooks.py`**: Skill load tracking functions

The original `claude_code_hook_adapter.py` is preserved as a thin re-export (`from hook_router import main`) to maintain the `-m` invocation path.

## Alternatives Considered

### Alternative A: Keep single file, extract only shared utilities

Move `_read_and_parse_stdin()` and signal management to separate modules, keep all handlers in the main file.

**Rejected because**: This would reduce the file from 1361 to ~900 lines -- still too large. The handlers themselves are the largest content, and each is logically independent (different hook events, different error handling policies, different service dependencies).

### Alternative B: One module per responsibility with a handler base class

Create a `HookHandler` base class with `handle()`, `read_stdin()`, `write_response()` methods. Each handler extends it.

**Rejected because**: The handlers have deliberately different error handling policies (PreToolUse is fail-closed, PostToolUse/PreWrite are fail-open). A base class would either need complex configuration to support both policies or would force artificial uniformity. Simple functions with shared utilities are more appropriate for a protocol adapter.

### Alternative C: Leave as-is since "it works"

The file functions correctly and all tests pass.

**Rejected because**: Two handlers were already extracted, creating inconsistency. The remaining handlers are harder to modify and test than the extracted ones. The codebase is actively growing (skill tracking, session guard, execution stats were all recent additions), so the file would continue growing.

## Consequences

### Positive

- Each handler module is under 200 lines
- Consistent with already-extracted `session_start_handler.py` and `subagent_start_handler.py`
- New hook event types can be added as new modules without touching existing handlers
- Shared protocol concerns are in one place (`hook_protocol.py`)
- Backward compatible: installed hook invocation path unchanged

### Negative

- More files in the `hooks/` directory (9 vs 4)
- Developers familiar with the current file must learn the new layout
- `claude_code_hook_adapter.py` still exists as a thin wrapper, which may confuse readers expecting the full implementation there

### Quality Attribute Impact

| Attribute | Impact | Direction |
|-----------|--------|-----------|
| Maintainability (modularity) | Handlers independently modifiable | Positive |
| Modifiability | New hook types = new file, zero existing code changes | Positive |
| Analyzability | Smaller files with clear responsibility names | Positive |
| Installability | Zero impact -- same entry point preserved | Neutral |
