---
title: Event System Architecture
description: Architecture of the event bus and hook system for plugin extensibility
category: architecture
status: review
last_updated: 2026-01-14
version: 1.0.0
tags:
  - level: intermediate
  - component: event-bus
  - status: stable
related:
  - ../hook-system-sdk.md
  - ../event-types-reference.md
  - system-architecture.md
---

# Event System Architecture

## Overview

The event system is the core extensibility layer of the Kollabor CLI, enabling plugins to intercept, modify, and respond to every aspect of application operation. It implements a three-phase processing model (PRE → MAIN → POST) with priority-based hook execution, comprehensive error handling, and graceful degradation.

## Purpose

This document describes the architectural design of the event system, including its four core components (EventBus, HookRegistry, HookExecutor, EventProcessor), data flow, processing phases, and integration patterns. It serves as the foundation for understanding how plugins extend and modify system behavior.

## Scope

This document covers:
- Four-component architecture and their responsibilities
- Three-phase event processing model
- Hook lifecycle and execution flow
- Error handling and retry mechanisms
- Event type mappings and data transformations
- Performance considerations and troubleshooting

This document does not cover:
- Specific EventType definitions (see event-types-reference.md)
- Plugin SDK usage patterns (see hook-system-sdk.md)
- Plugin system architecture (see plugin-system.md)
- Complete event type catalog (see event-types-reference.md)

## Prerequisites

Before reading this document, you should:
- Be familiar with Python async/await patterns
- Understand basic event-driven architecture concepts
- Have read the system architecture overview
- Know what plugins are in the Kollabor CLI context

## Table of Contents

- [Architecture Overview](#architecture-overview)
- [Core Components](#core-components)
- [Three-Phase Processing Model](#three-phase-processing-model)
- [Event Flow](#event-flow)
- [Hook Execution](#hook-execution)
- [Error Handling](#error-handling)
- [Performance Considerations](#performance-considerations)
- [Troubleshooting](#troubleshooting)
- [Related Documents](#related-documents)
- [References](#references)

## Architecture Overview

The event system follows a clean separation of concerns with four specialized components:

```mermaid
graph TB
    subgraph "Event System"
        EB[EventBus<br/>Coordinator]
        HR[HookRegistry<br/>Organization]
        HE[HookExecutor<br/>Execution]
        EP[EventProcessor<br/>Phases]
    end
    
    subgraph "External"
        P[Plugins]
        C[Core Systems]
    end
    
    P -->|register_hook| EB
    C -->|emit_with_hooks| EB
    EB --> EP
    EP --> HR
    HR --> HE
    HE --> EP
    EP --> EB
    EB --> P
```

**Component Responsibilities:**

- **EventBus**: Central coordinator and facade for the event system
- **HookRegistry**: Manages hook registration, organization, and status tracking
- **HookExecutor**: Executes individual hooks with timeout and error handling
- **EventProcessor**: Orchestrates pre/main/post phase processing

## Core Components

### EventBus (bus.py)

The EventBus is the central coordinator that provides a clean API for hook registration and event emission. It delegates specialized tasks to other components while maintaining a simple interface.

**Key Responsibilities:**
- Hook registration and unregistration
- Event emission with hook processing
- Hook status queries
- Runtime hook enable/disable

**Initialization:**

```python
# kollabor/events/bus.py:18-32
class EventBus:
    def __init__(self, config: Optional[Dict[str, Any]] = None) -> None:
        """Initialize the event bus with specialized components."""
        self.config = config or {}
        self.hook_registry = HookRegistry()
        self.hook_executor = HookExecutor(config=self.config)
        self.event_processor = EventProcessor(self.hook_registry, self.hook_executor)
```

**Public API:**

```python
# Register a hook
await event_bus.register_hook(hook)

# Unregister a hook
await event_bus.unregister_hook(plugin_name, hook_name)

# Emit event with hooks
results = await event_bus.emit_with_hooks(
    EventType.USER_INPUT,
    {"message": user_input},
    "input_handler"
)

# Query hook status
status = event_bus.get_hook_status()
stats = event_bus.get_registry_stats()

# Enable/disable hooks at runtime
event_bus.enable_hook(plugin_name, hook_name)
event_bus.disable_hook(plugin_name, hook_name)
```

### HookRegistry (registry.py)

The HookRegistry manages all hook registrations, organizes them by event type and priority, and tracks their execution status.

**Data Structures:**

```python
# Organized by event type
self.hooks: Dict[EventType, List[Hook]] = defaultdict(list)

# Status tracking
self.hook_status: Dict[str, HookStatus] = {}

# Metadata for introspection
self.hook_metadata: Dict[str, Dict[str, Any]] = {}
```

**Hook Organization:**

Hooks are stored in priority-ordered lists:

```python
# kollabor/events/registry.py:60-67
# Add hook to appropriate event type list
self.hooks[hook.event_type].append(hook)

# Sort hooks by priority (highest first)
self.hooks[hook.event_type].sort(key=lambda h: h.priority, reverse=True)
```

**Registration Process:**

```mermaid
sequenceDiagram
    participant P as Plugin
    participant EB as EventBus
    participant HR as HookRegistry
    
    P->>EB: register_hook(hook)
    EB->>HR: register_hook(hook)
    HR->>HR: Check for duplicate
    HR->>HR: Add to hooks[event_type]
    HR->>HR: Sort by priority
    HR->>HR: Track status & metadata
    HR-->>EB: success
    EB-->>P: True
```

**Query Methods:**

```python
# Get hooks for specific event (sorted by priority)
hooks = hook_registry.get_hooks_for_event(EventType.USER_INPUT)

# Get comprehensive statistics
stats = hook_registry.get_registry_stats()
# Returns: total_hooks, event_types, hooks_per_event_type,
#          priority_distribution, hooks_per_plugin, status_summary
```

### HookExecutor (executor.py)

The HookExecutor is responsible for safe execution of individual hooks, including timeout management, error handling, status tracking, and retry logic with exponential backoff.

**Safety Features:**
- Per-hook asyncio locks (prevents concurrent execution of same hook)
- Timeout enforcement with `asyncio.wait_for()`
- Retry loop with exponential backoff
- Configurable error actions ("continue" or "stop")
- Absolute maximum retry duration (5 minutes)

**Execution Flow:**

```mermaid
stateDiagram-v2
    [*] --> CheckEnabled
    CheckEnabled --> GetLock: enabled
    CheckEnabled --> ReturnDisabled: disabled
    
    GetLock --> AcquireLock
    AcquireLock --> LoadConfig: lock acquired
    LoadConfig --> ValidateConfig
    
    ValidateConfig --> ExecuteAttempt: config valid
    ValidateConfig --> SetDefaults: None values
    
    SetDefaults --> ExecuteAttempt
    
    ExecuteAttempt --> SetStatusWorking
    
    SetStatusWorking --> RunHookWithTimeout
    
    RunHookWithTimeout --> ApplyDataTransform: success
    RunHookWithTimeout --> HandleTimeout: timeout
    RunHookWithTimeout --> HandleError: exception
    
    ApplyDataTransform --> ReturnSuccess
    
    HandleTimeout --> CheckRetry: attempt < max_attempts
    HandleError --> CheckRetry: attempt < max_attempts
    
    CheckRetry --> WaitBackoff: can retry
    CheckRetry --> ReturnFailed: final attempt
    
    WaitBackoff --> ExecuteAttempt
    
    ReturnSuccess --> [*]
    ReturnFailed --> [*]
    ReturnDisabled --> [*]
```

**Key Configuration:**

```python
# kollabor/events/executor.py:14-21
DEFAULT_HOOK_TIMEOUT = 30
DEFAULT_HOOK_RETRIES = 3
DEFAULT_ERROR_ACTION = "continue"
MIN_TIMEOUT = 1
MAX_TIMEOUT = 300  # 5 minutes
MAX_TOTAL_RETRY_DURATION = 300  # 5 minutes
```

**Thread Safety:**

Each hook has its own lock to prevent concurrent execution:

```python
# kollabor/events/executor.py:42-50
async def _get_hook_lock(self, hook_key: str) -> asyncio.Lock:
    """Get or create a lock for a specific hook."""
    if hook_key not in self._hook_locks:
        async with self._locks_lock:
            if hook_key not in self._hook_locks:
                self._hook_locks[hook_key] = asyncio.Lock()
    return self._hook_locks[hook_key]
```

### EventProcessor (processor.py)

The EventProcessor orchestrates the three-phase processing model (PRE → MAIN → POST), managing data flow between phases and handling event cancellation.

**Pre/Post Mapping:**

```python
# kollabor/events/processor.py:24-33
self.pre_post_map = {
    EventType.USER_INPUT: (EventType.USER_INPUT_PRE, EventType.USER_INPUT_POST),
    EventType.KEY_PRESS: (EventType.KEY_PRESS_PRE, EventType.KEY_PRESS_POST),
    EventType.LLM_REQUEST: (EventType.LLM_REQUEST_PRE, EventType.LLM_REQUEST_POST),
    EventType.LLM_RESPONSE: (EventType.LLM_RESPONSE_PRE, EventType.LLM_RESPONSE_POST),
    EventType.TOOL_CALL: (EventType.TOOL_CALL_PRE, EventType.TOOL_CALL_POST),
}
```

**Phase Processing:**

```mermaid
sequenceDiagram
    participant EB as EventBus
    participant EP as EventProcessor
    participant HR as HookRegistry
    participant HE as HookExecutor
    
    EB->>EP: process_event_with_hooks(event_type, data, source)
    
    Note over EP: Phase 1: PRE
    EP->>HR: get_hooks_for_event(pre_event_type)
    HR-->>EP: hooks (sorted)
    loop Each hook
        EP->>HE: execute_hook(hook, event)
        HE-->>EP: result
    end
    alt Cancelled in PRE
        EP-->>EB: results (cancelled=True)
    end
    
    Note over EP: Phase 2: MAIN
    EP->>HR: get_hooks_for_event(event_type)
    HR-->>EP: hooks (sorted)
    loop Each hook
        EP->>HE: execute_hook(hook, event)
        HE-->>EP: result
    end
    alt Cancelled in MAIN
        EP-->>EB: results (cancelled=True)
    end
    
    Note over EP: Phase 3: POST
    EP->>HR: get_hooks_for_event(post_event_type)
    HR-->>EP: hooks (sorted)
    loop Each hook
        EP->>HE: execute_hook(hook, event)
        HE-->>EP: result
    end
    
    EP-->>EB: results (all phases)
```

**Data Flow:**

```python
# kollabor/events/processor.py:37-80
# Phase 1: PRE hooks
if pre_event_type:
    pre_results = await self._process_phase(pre_event_type, event_data, source, "PRE")
    results["pre"] = pre_results
    
    if pre_results.get("cancelled", False):
        results["cancelled"] = True
        return results
    
    # Update data from PRE phase
    event_data = pre_results.get("final_data", event_data)

# Phase 2: MAIN event
main_results = await self._process_phase(event_type, event_data, source, "MAIN")
results["main"] = main_results

if main_results.get("cancelled", False):
    results["cancelled"] = True
    return results

event_data = main_results.get("final_data", event_data)

# Phase 3: POST hooks
if post_event_type and not main_results.get("cancelled", False):
    post_results = await self._process_phase(post_event_type, event_data, source, "POST")
    results["post"] = post_results
```

## Three-Phase Processing Model

The event system implements a three-phase processing model for structured event handling:

### Phase 1: PRE

**Purpose:** Preprocessing, validation, data transformation before main processing

**Use Cases:**
- Input validation and sanitization
- Data transformation and enrichment
- Early cancellation based on conditions
- Setting up context for main processing

**Example:**

```python
Hook(
    name="validate_input",
    plugin_name="my_plugin",
    event_type=EventType.USER_INPUT_PRE,
    priority=HookPriority.PREPROCESSING.value,  # 500
    callback=self._validate_input
)

async def _validate_input(self, data, event):
    if len(data.get("message", "")) > 10000:
        event.cancelled = True  # Cancel before main processing
        return {"cancelled": True, "reason": "too_long"}
    return {}
```

### Phase 2: MAIN

**Purpose:** Core event processing, business logic execution

**Use Cases:**
- Primary event handling
- Response generation
- Core system operations

**Example:**

```python
Hook(
    name="log_request",
    plugin_name="my_plugin",
    event_type=EventType.USER_INPUT,
    priority=HookPriority.POSTPROCESSING.value,  # 50
    callback=self._log_request
)

async def _log_request(self, data, event):
    logger.info(f"Processing: {data.get('message')}")
    return {"logged": True}
```

### Phase 3: POST

**Purpose:** Post-processing, cleanup, logging, display updates after main processing

**Use Cases:**
- Cleanup operations
- Logging and metrics collection
- Display updates
- Side effects that shouldn't affect main flow

**Example:**

```python
Hook(
    name="update_stats",
    plugin_name="my_plugin",
    event_type=EventType.USER_INPUT_POST,
    priority=HookPriority.POSTPROCESSING.value,  # 50
    callback=self._update_stats
)

async def _update_stats(self, data, event):
    self.message_count += 1
    return {"count": self.message_count}
```

**Phase Interaction:**

```mermaid
graph LR
    subgraph "Event Processing"
        PRE[PRE Phase<br/>Validation & Transform]
        MAIN[MAIN Phase<br/>Core Processing]
        POST[POST Phase<br/>Cleanup & Logging]
    end
    
    PRE -->|modified data| MAIN
    MAIN -->|results| POST
    
    PRE -.->|cancel| END[(End)]
    MAIN -.->|cancel| END
    POST --> END
```

## Event Flow

### Complete Event Lifecycle

```mermaid
sequenceDiagram
    participant C as Core System
    participant EB as EventBus
    participant EP as EventProcessor
    participant HR as HookRegistry
    participant HE as HookExecutor
    participant H1 as Hook 1 (priority 1000)
    participant H2 as Hook 2 (priority 500)
    participant H3 as Hook 3 (priority 100)
    
    C->>EB: emit_with_hooks(event_type, data, source)
    EB->>EP: process_event_with_hooks()
    
    Note over EP: PRE Phase
    EP->>HR: get_hooks_for_event(PRE)
    HR-->>EP: [H1, H2, H3]
    EP->>HE: execute_hook(H1)
    HE->>H1: callback(data, event)
    H1-->>HE: result
    HE-->>EP: metadata
    EP->>HE: execute_hook(H2)
    HE->>H2: callback(data, event)
    H2-->>HE: result
    HE-->>EP: metadata
    EP->>HE: execute_hook(H3)
    HE->>H3: callback(data, event)
    H3-->>HE: result
    HE-->>EP: metadata
    
    Note over EP: MAIN Phase
    EP->>HR: get_hooks_for_event(MAIN)
    HR-->>EP: [H1, H2, H3]
    loop Each hook
        EP->>HE: execute_hook(hook, event)
        HE-->>EP: result
    end
    
    Note over EP: POST Phase
    EP->>HR: get_hooks_for_event(POST)
    HR-->>EP: [H1, H2, H3]
    loop Each hook
        EP->>HE: execute_hook(hook, event)
        HE-->>EP: result
    end
    
    EP-->>EB: results {pre, main, post}
    EB-->>C: results
```

### Hook Registration Flow

```mermaid
sequenceDiagram
    participant P as Plugin
    participant EB as EventBus
    participant HR as HookRegistry
    
    P->>EB: register_hook(hook)
    EB->>HR: register_hook(hook)
    
    Note over HR: Check duplicate
    alt Hook already exists
        HR->>HR: Remove old registration
    end
    
    HR->>HR: Add to hooks[event_type]
    HR->>HR: Sort by priority (desc)
    HR->>HR: Set status to PENDING
    HR->>HR: Store metadata
    
    HR-->>EB: True
    EB-->>P: True
```

### Data Transformation Flow

```mermaid
graph TB
    subgraph "Hook 1"
        A1[Input Data] -->|process| B1[Modified Data]
    end
    
    subgraph "Hook 2"
        A2[B1 Output] -->|process| B2[Modified Data]
    end
    
    subgraph "Hook 3"
        A3[B2 Output] -->|process| B3[Final Data]
    end
    
    B3 -->|final_data| EP[Next Phase or Return]
```

## Hook Execution

### Hook Structure

```python
# kollabor/events/models.py:126-155
@dataclass
class Hook:
    """Hook definition for the event system."""
    name: str                    # Unique hook name
    plugin_name: str            # Owning plugin name
    event_type: EventType       # Event type to listen for
    priority: int               # Execution order (higher = earlier)
    callback: Callable          # Async function to execute
    enabled: bool = True        # Can be toggled on/off
    timeout: Optional[int] = None      # Max execution time in seconds
    retry_attempts: Optional[int] = None  # Retry count on failure
    error_action: Optional[str] = None   # "continue" or "stop"
    status: HookStatus = HookStatus.PENDING
    status_area: str = "A"
    icon_set: Dict[str, str] = field(default_factory=lambda: {
        "thinking": "[think]", 
        "processing": "[proc]", 
        "complete": "[ok]", 
        "error": "[err]"
    })
```

### Hook Callback Signature

```python
async def my_hook_callback(
    data: Dict[str, Any],    # Event data (can be modified)
    event: Event             # Full event object
) -> Dict[str, Any]:
    """
    Returns a dict with optional keys:
    - "data": modified event data (applies to event.data)
    - "cancel": True to cancel the event (sets event.cancelled)
    - "result": arbitrary result data (sets event.result)
    """
    # Process event
    return {"status": "ok"}
```

### Data Transformation

Hooks can modify event data by returning `"data"` in their result:

```python
async def _enhance_input(self, data: Dict[str, Any], event: Event) -> Dict[str, Any]:
    """Transform input data."""
    
    # Transform the data
    if isinstance(data.get('message'), str):
        data['timestamp'] = datetime.now().isoformat()
        data['message'] = f"[{self.plugin_name}] {data['message']}"
    
    # Return modified data to pass to next hooks
    return {
        "data": data,  # This updates the event data
        "status": "transformed"
    }
```

### Event Cancellation

Hooks can cancel the entire event chain:

```python
async def _validate_input(self, data: Dict[str, Any], event: Event) -> Dict[str, Any]:
    """Validate input and potentially cancel event."""
    message = data.get('message', '')
    
    if self._is_spam(message):
        event.cancelled = True  # Cancel the entire event chain
        return {"cancelled": True, "reason": "spam_detected"}
    
    return {"status": "validated"}
```

### Priority Execution

Hooks are executed in priority order (highest first):

```python
# Priorities from HookPriority enum
SYSTEM = 1000          # Core system operations
SECURITY = 900         # Security validation
PREPROCESSING = 500    # Data transformation
LLM = 100             # LLM operations
POSTPROCESSING = 50   # Response formatting
DISPLAY = 10          # UI updates
```

Example with multiple hooks:

```python
hooks = [
    Hook(name="system_check", priority=1000, ...),   # Executes first
    Hook(name="security_check", priority=900, ...), # Second
    Hook(name="validate", priority=500, ...),        # Third
    Hook(name="log", priority=50, ...),              # Fourth
    Hook(name="display", priority=10, ...),          # Last
]
```

## Error Handling

### Retry Logic

Hooks support retry with exponential backoff:

```python
# Hook configuration
Hook(
    name="external_api_call",
    plugin_name="my_plugin",
    event_type=EventType.USER_INPUT,
    priority=HookPriority.LLM.value,
    callback=self._call_external_api,
    timeout=30,
    retry_attempts=3,  # 3 retries after initial attempt
    error_action="continue"  # Continue on final failure
)
```

**Retry Behavior:**
- Initial attempt + retry_attempts total attempts
- Exponential backoff: 2^attempt seconds (max 30s)
- Timeout applies to each individual attempt
- Absolute max duration: 5 minutes total

```mermaid
stateDiagram-v2
    [*] --> Attempt1
    Attempt1 --> Attempt2: timeout/error
    Attempt2 --> Attempt3: timeout/error
    Attempt3 --> [*]: success
    Attempt3 --> [*]: failure (max retries)
```

### Error Actions

Two error actions control behavior on final hook failure:

**"continue" (default):**
- Hook fails but event continues
- Event.result contains error info
- Other hooks continue executing

**"stop":**
- Hook fails causes event cancellation
- Processing stops immediately
- `event.cancelled = True`

```python
# Stop on error
Hook(
    name="critical_validation",
    error_action="stop",  # Cancel event if this fails
    ...
)

# Continue on error
Hook(
    name="logging",
    error_action="continue",  # Keep going if logging fails
    ...
)
```

### Timeout Handling

Hooks time out if they exceed configured duration:

```python
# kollabor/events/executor.py:108-117
try:
    result = await asyncio.wait_for(
        hook.callback(event.data, event),
        timeout=timeout
    )
    # Success handling
except asyncio.TimeoutError:
    hook.status = HookStatus.TIMEOUT
    logger.warning(f"Hook {hook_key} timed out after {timeout}s")
    # Retry or error handling based on config
```

**Timeout Behavior:**
- Timeout applies to single execution attempt
- Hook can retry after timeout (if retry_attempts > 0)
- Final timeout is treated as error based on error_action

### Status Tracking

Hook execution status is tracked in real-time:

```python
# kollabor/events/executor.py:110-111
hook.status = HookStatus.WORKING  # Before execution
hook.status = HookStatus.COMPLETED  # On success
hook.status = HookStatus.FAILED  # On exception
hook.status = HookStatus.TIMEOUT  # On timeout
```

**Query Hook Status:**

```python
# Get all hook statuses
status_summary = event_bus.get_hook_status()
# Returns: {
#   "total_hooks": 15,
#   "status_counts": {"pending": 5, "working": 2, "completed": 8},
#   "hook_details": {...}
# }

# Get registry statistics
stats = event_bus.get_registry_stats()
# Returns: {
#   "total_hooks": 15,
#   "event_types": 8,
#   "hooks_per_event_type": {...},
#   "priority_distribution": {...},
#   "hooks_per_plugin": {...},
#   "status_summary": {...}
# }
```

## Performance Considerations

### Hook Execution Time

**Impact on System:**
- Hooks execute synchronously in the event pipeline
- Slow hooks block event processing
- Long-running hooks should use timeout protection

**Best Practices:**
- Keep hooks fast (target < 100ms)
- Use async I/O operations
- Cache expensive computations
- Set appropriate timeouts

**Monitoring:**

```python
# Hook returns timing metadata
result = {
    "hook_key": "my_plugin.my_hook",
    "success": True,
    "duration_ms": 45,
    "retry_count": 0,
    "attempts": [...]
}

# Aggregate statistics
stats = hook_executor.get_execution_stats(hook_results)
# Returns: {
#   "total_hooks": 5,
#   "successful": 4,
#   "failed": 1,
#   "timed_out": 0,
#   "total_duration_ms": 250,
#   "avg_duration_ms": 50
# }
```

### Hook Count

**Impact on System:**
- Each event type runs all registered hooks
- Many hooks on same event = slower processing
- Hooks with same priority can interfere

**Best Practices:**
- Minimize hooks per event type
- Use appropriate priorities
- Consider combining related logic
- Use conditional registration

**Analysis:**

```python
# Check hook density
stats = event_bus.get_registry_stats()
print(f"Hooks for USER_INPUT: {stats['hooks_per_event_type']['user_input']}")
print(f"Average hooks per event: {stats['total_hooks'] / stats['event_types']:.1f}")
```

### Memory Considerations

**Impact on System:**
- Event data copied between phases
- Hook metadata stored in registry
- Lock objects per hook

**Best Practices:**
- Avoid large data structures in event.data
- Clean up resources in POST phase
- Use weak references for plugin state
- Limit history/buffer sizes

## Troubleshooting

### Hook Not Executing

**Symptoms:**
- Hook registered but callback never called
- Plugin code runs but no effect

**Diagnosis:**

```python
# Check if hook is registered
stats = event_bus.get_registry_stats()
print(f"Total hooks: {stats['total_hooks']}")
print(f"My plugin hooks: {stats['hooks_per_plugin'].get('my_plugin', 0)}")

# Check hook status
status = event_bus.get_hook_status()
print(f"My hook status: {status['hook_details'].get('my_plugin.my_hook')}")
```

**Common Causes:**
1. Hook not registered (plugin.initialize() failed)
2. Hook disabled (enabled=False or manually disabled)
3. Wrong event type
4. Event type not emitted (check event-types-reference.md)
5. Event cancelled by earlier hook

**Solutions:**

```python
# Verify hook registration
hooks = event_bus.get_hooks_for_event(EventType.USER_INPUT)
for hook in hooks:
    if hook.plugin_name == "my_plugin":
        print(f"Found: {hook.name}, enabled: {hook.enabled}")

# Check if event is actually emitted
# Add logging in emit_with_hooks caller
```

### Event Cancellation Unexpected

**Symptoms:**
- Event processing stops mid-flow
- Some hooks not executing

**Diagnosis:**

```python
# Enable debug logging
logging.getLogger("kollabor.events").setLevel(logging.DEBUG)

# Check hook priorities
hooks = event_bus.get_hooks_for_event(EventType.USER_INPUT)
for hook in hooks:
    print(f"{hook.plugin_name}.{hook.name}: priority={hook.priority}")
```

**Common Causes:**
1. Security hook cancelled event
2. Validation hook cancelled event
3. Earlier hook set event.cancelled = True
4. Hook with error_action="stop" failed

**Solutions:**

```python
# Review high-priority hooks
# SECURITY (900) and SYSTEM (1000) should be checked

# Check error_action settings
# "stop" cancels entire event on failure
```

### Performance Issues

**Symptoms:**
- System laggy during input
- Slow response times
- High CPU usage

**Diagnosis:**

```python
# Get execution statistics
# Add timing logging to hooks
# Use Hook Monitoring Plugin
```

**Common Causes:**
1. Hook timeout too high
2. Too many hooks on hot events
3. Blocking operations in hooks
4. Expensive computations repeated

**Solutions:**

```python
# Reduce hook timeout
Hook(
    name="fast_hook",
    timeout=5,  # Lower timeout
    ...
)

# Add performance monitoring
import time
start = time.time()
# ... hook logic ...
duration = (time.time() - start) * 1000
if duration > 100:
    logger.warning(f"Slow hook: {duration:.1f}ms")
```

### Hook Fails Silently

**Symptoms:**
- Hook error in logs but system continues
- Unexpected behavior

**Diagnosis:**

```python
# Check log level - errors should be visible
# Look for "Hook failed" messages
# Check hook status: should be "failed"

status = event_bus.get_hook_status()
hook_status = status['hook_details'].get('my_plugin.my_hook')
print(f"Status: {hook_status['status']}")
```

**Common Causes:**
1. Exception in hook callback
2. Invalid data types in hook result
3. Missing required fields in event.data

**Solutions:**

```python
# Add robust error handling in hook
async def _robust_hook(self, data, event):
    try:
        # Validate input
        if not isinstance(data, dict):
            logger.error("Invalid data type")
            return {"error": "invalid_data"}
        
        # Main logic
        result = self._process(data)
        return {"data": result}
    except Exception as e:
        logger.error(f"Hook failed: {e}", exc_info=True)
        return {"error": str(e)}
```

### Retry Loop Not Stopping

**Symptoms:**
- Hook keeps retrying indefinitely
- Event processing hangs

**Diagnosis:**

```python
# Check retry_attempts setting
# Check MAX_TOTAL_RETRY_DURATION (5 min max)
# Look for "max_retry_duration_exceeded" in logs
```

**Common Causes:**
1. retry_attempts set too high
2. Hook always fails but no final error
3. Absolute timeout not enforcing

**Solutions:**

```python
# Verify retry configuration
Hook(
    retry_attempts=3,  # Reasonable value
    timeout=10,        # Per-attempt timeout
    ...
)

# Check for 5-minute max enforcement
# kollabor/events/executor.py:75-80
if elapsed_time > MAX_TOTAL_RETRY_DURATION:
    logger.error("Exceeded maximum total retry duration")
    break
```

## Related Documents

- [Hook System SDK](../hook-system-sdk.md) - Complete guide for plugin developers
- [Event Types Reference](../event-types-reference.md) - All event types and payloads
- [System Architecture](system-architecture.md) - High-level system design
- [Plugin System Architecture](../core-systems/plugin-system.md) - Plugin lifecycle and discovery

## References

### Source Files

- **EventBus**: `kollabor/events/bus.py` (139 lines)
- **HookRegistry**: `kollabor/events/registry.py` (289 lines)
- **HookExecutor**: `kollabor/events/executor.py` (285 lines)
- **EventProcessor**: `kollabor/events/processor.py` (176 lines)
- **Data Models**: `kollabor/events/models.py` (283 lines)

### Key Classes

- `EventBus` - Central coordinator (bus.py:15-121)
- `HookRegistry` - Hook management (registry.py:14-289)
- `HookExecutor` - Safe execution (executor.py:28-285)
- `EventProcessor` - Phase orchestration (processor.py:14-176)
- `Hook` - Hook definition (models.py:126-155)
- `Event` - Event structure (models.py:158-176)
- `EventType` - Event type enum (models.py:35-118)
- `HookPriority` - Priority levels (models.py:13-19)
- `HookStatus` - Execution states (models.py:22-28)

### Key Methods

- `EventBus.register_hook()` - Register hook (bus.py:34-49)
- `EventBus.emit_with_hooks()` - Emit event (bus.py:57-62)
- `HookRegistry.get_hooks_for_event()` - Query hooks (registry.py:102-112)
- `HookExecutor.execute_hook()` - Execute hook (executor.py:52-250)
- `EventProcessor.process_event_with_phases()` - Process event (processor.py:36-80)

### Usage Examples

See complete plugin examples in:
- `plugins/hook_monitoring_plugin.py` - Monitoring and introspection
- `plugins/enhanced_input_plugin.py` - Input enhancement hooks
- `docs/reference/hook-system-sdk.md` - SDK usage patterns
- `docs/reference/plugin-development-tutorial.md` - Tutorial examples

---

**Document Version**: 1.0.0  
**Last Updated**: 2026-01-14  
**Status**: Review - Ready for technical review
