# Event Types Reference

Complete reference of all EventType enum values in `core/events/models.py` that are actually emitted in the codebase.

## Quick Reference Table

| Category | Events | Priority Range |
|----------|--------|----------------|
| **Input** | USER_INPUT, KEY_PRESS, INPUT_RENDER, CANCEL_REQUEST | PREPROCESSING (500) to DISPLAY (10) |
| **Command** | SLASH_COMMAND_DETECTED, SLASH_COMMAND_EXECUTE, SLASH_COMMAND_COMPLETE, SLASH_COMMAND_ERROR, COMMAND_MENU_SHOW, COMMAND_MENU_HIDE, COMMAND_MENU_RENDER, COMMAND_MENU_FILTER, COMMAND_OUTPUT_DISPLAY | PREPROCESSING (500) to DISPLAY (10) |
| **Tool** | TOOL_CALL_PRE, TOOL_CALL_POST | PREPROCESSING (500) to POSTPROCESSING (50) |
| **Modal** | MODAL_TRIGGER, MODAL_HIDE, STATUS_MODAL_TRIGGER, STATUS_MODAL_RENDER, LIVE_MODAL_TRIGGER, MODAL_COMMAND_SELECTED, FULLSCREEN_INPUT | PREPROCESSING (500) to DISPLAY (10) |
| **Status** | STATUS_VIEW_CHANGED, STATUS_CONTENT_UPDATE | DISPLAY (10) |
| **Message** | ADD_MESSAGE (hook-only) | POSTPROCESSING (50) |
| **Lifecycle** | SYSTEM_STARTUP, SYSTEM_SHUTDOWN (hook-only) | SYSTEM (1000) |

**Note:** This reference only includes events that are actually emitted via `emit_with_hooks()` or `fire_event()` in the codebase. Some events defined in the EventType enum (like `LLM_REQUEST_*`, `LLM_RESPONSE_*`, `PASTE_DETECTED`, pre/post variants) are not currently emitted.

## Hook Priority Levels

| Priority | Value | Use Case |
|----------|-------|----------|
| SYSTEM | 1000 | Core system initialization, security checks |
| SECURITY | 900 | Input validation, security filtering |
| PREPROCESSING | 500 | Data transformation, validation before main processing |
| LLM | 100 | LLM-specific operations, tool calling |
| POSTPROCESSING | 50 | Cleanup, logging, post-processing |
| DISPLAY | 10 | UI rendering, display updates |

---

## Input Events

Events related to user input, keyboard handling, and input rendering.

### USER_INPUT

Fires when user submits input (presses Enter).

**When it fires:**
- User presses Enter to submit input
- Input has been expanded (paste placeholders, etc.)
- Before command parsing

**Payload structure:**
```python
{
    "message": str,              # Expanded input message
    "validation_errors": List[str]  # Any validation errors (empty if none)
}
```

**Emitted by:** `KeyPressHandler` (core/io/input/key_press_handler.py:453-460)

**Recommended priority:** PREPROCESSING (500)

**Example usage:**
```python
Hook(
    name="validate_input",
    plugin_name="my_plugin",
    event_type=EventType.USER_INPUT,
    priority=HookPriority.PREPROCESSING.value,
    callback=self._validate_input
)

async def _validate_input(self, data: Dict[str, Any], event: Event) -> Dict[str, Any]:
    message = data.get("message", "")
    if len(message) > 10000:
        event.cancelled = True
        return {"error": "Input too long"}
    return {}
```

---

### KEY_PRESS

Fires when a key is pressed.

**When it fires:**
- Any key is pressed
- Before input buffer modification

**Payload structure:**
```python
{
    "key": str,                  # Key name (e.g., "a", "Enter", "Escape")
    "char_code": int,            # Character code
    "key_type": str,             # Key type value from KeyType enum
    "modifiers": Dict[str, bool] # Modifier key states ("ctrl", "alt", "shift")
}
```

**Emitted by:** `KeyPressHandler` (core/io/input/key_press_handler.py:209-218)

**Recommended priority:** PREPROCESSING (500)

**Example usage:**
```python
async def _intercept_hotkey(self, data: Dict[str, Any], event: Event) -> Dict[str, Any]:
    key = data.get("key", "")
    modifiers = data.get("modifiers", {})
    if key == "F1" or (key == "q" and modifiers.get("ctrl")):
        # Trigger custom action
        return {"cancel": True}
    return {}
```

---

### INPUT_RENDER

Fires during input box rendering.

**When it fires:**
- Input display is being rendered
- Main hook for custom input styling

**Payload structure:**
```python
{
    "input_buffer": str          # Current input buffer content
}
```

**Emitted by:** `TerminalRenderer` (core/io/terminal_renderer.py:229, 346)

**Recommended priority:** DISPLAY (10)

**Example usage:**
```python
async def _render_custom_input(self, data: Dict[str, Any], event: Event) -> Dict[str, Any]:
    input_text = data.get("input_buffer", "")
    custom_lines = [
        "+----------------------+",
        f"| {input_text:<20} |",
        "+----------------------+"
    ]
    return {"fancy_input_lines": custom_lines}
```

---

### CANCEL_REQUEST

Fires when user cancels via Escape key.

**When it fires:**
- User presses Escape during LLM processing
- Request cancellation is triggered

**Payload structure:**
```python
{
    "reason": str,               # Always "user_escape"
    "source": str                # Always "input_handler"
}
```

**Emitted by:** `KeyPressHandler` (core/io/input/key_press_handler.py:484-488)

**Recommended priority:** LLM (100)

---

## Command Events

Events related to slash command parsing, execution, and menu interaction.

### SLASH_COMMAND_DETECTED

Fires when a slash command is detected in input.

**When it fires:**
- Command has been parsed
- Before validation and execution

**Payload structure:**
```python
{
    "command_name": str,         # Name of detected command
    "args": List[str],           # Command arguments
    "raw_input": str             # Full raw input string
}
```

**Emitted by:** `SlashCommandExecutor` (core/commands/executor.py:41-49)

**Recommended priority:** PREPROCESSING (500)

**Example usage:**
```python
async def _log_command_detected(self, data: Dict[str, Any], event: Event) -> Dict[str, Any]:
    cmd = data.get("command_name", "")
    logger.info(f"Command detected: /{cmd}")
    return {}
```

---

### SLASH_COMMAND_EXECUTE

Fires when a slash command is about to execute.

**When it fires:**
- Command has been validated and enabled check passed
- Handler is about to be called

**Payload structure:**
```python
{
    "command": SlashCommand,         # Parsed command object
    "command_def": CommandDefinition,  # Command definition
    "mode": str                      # Command mode value (e.g., "normal", "modal")
}
```

**Emitted by:** `SlashCommandExecutor` (core/commands/executor.py:73-81)

**Recommended priority:** PREPROCESSING (500)

**Example usage:**
```python
async def _pre_command_hook(self, data: Dict[str, Any], event: Event) -> Dict[str, Any]:
    cmd = data.get("command")
    logger.info(f"Executing /{cmd.name} with args: {cmd.args}")
    return {}
```

---

### SLASH_COMMAND_COMPLETE

Fires after a slash command completes successfully.

**When it fires:**
- Command handler returned success
- Result is being processed

**Payload structure:**
```python
{
    "command": SlashCommand,
    "command_def": CommandDefinition,
    "result": CommandResult      # Execution result
}
```

**Emitted by:** `SlashCommandExecutor` (core/commands/executor.py:101-109)

**Recommended priority:** POSTPROCESSING (50)

**Example usage:**
```python
async def _post_command_hook(self, data: Dict[str, Any], event: Event) -> Dict[str, Any]:
    result = data.get("result")
    if result.success:
        logger.info(f"Command completed: {result.message}")
    return {}
```

---

### SLASH_COMMAND_ERROR

Fires when a slash command encounters an error.

**When it fires:**
- Command not found, disabled, or handler raised exception

**Payload structure:**
```python
{
    "command": SlashCommand,
    "error_type": str,            # "command_not_found", "handler_error", etc.
    "result": CommandResult       # Error result details
}
```

**Emitted by:** `SlashCommandExecutor` (core/commands/executor.py:160-168)

**Recommended priority:** POSTPROCESSING (50)

**Example usage:**
```python
async def _handle_command_error(self, data: Dict[str, Any], event: Event) -> Dict[str, Any]:
    error_type = data.get("error_type", "unknown")
    logger.error(f"Command error: {error_type}")
    return {}
```

---

### COMMAND_MENU_SHOW

Fires when the command menu is displayed.

**When it fires:**
- User types `/` to show command menu
- Menu overlay is rendered

**Payload structure:**
```python
{
    "available_commands": List[CommandDefinition],  # All available commands
    "filter_text": str              # Current filter text (empty on `/`)
}
```

**Emitted by:** `CommandModeHandler` (core/io/input/command_mode_handler.py:141-145)

**Recommended priority:** DISPLAY (10)

---

### COMMAND_MENU_HIDE

Fires when command menu is hidden.

**When it fires:**
- User presses Escape
- Menu is dismissed

**Payload structure:**
```python
{
    "reason": str                  # "manual_exit" or similar
}
```

**Emitted by:** `CommandModeHandler` (core/io/input/command_mode_handler.py:170-174)

**Recommended priority:** DISPLAY (10)

---

### COMMAND_MENU_RENDER

Fires during command menu rendering.

**When it fires:**
- Menu content is being rendered
- For custom menu styling

**Payload structure:**
```python
{
    "request": str                 # Always "get_menu_lines"
}
```

**Emitted by:** `TerminalRenderer` (core/io/terminal_renderer.py:437-441)

**Recommended priority:** DISPLAY (10)

**Note:** This is a render request event. Hook returns `menu_lines` in result.

---

### COMMAND_MENU_FILTER

Fires when command menu filter changes.

**When it fires:**
- User types after `/`
- Filter text is updated

**Payload structure:**
```python
{
    "filter_text": str,
    "available_commands": List[CommandDefinition],  # All commands
    "filtered_commands": List[CommandDefinition]    # Filtered results
}
```

**Emitted by:** `CommandModeHandler` (core/io/input/command_mode_handler.py:524-532)

**Recommended priority:** PREPROCESSING (500)

---

### COMMAND_OUTPUT_DISPLAY

Fires when command output should be displayed.

**When it fires:**
- Command produces output message
- Non-modal command result display

**Payload structure:**
```python
{
    "message": str,                # Output message
    "display_type": str,           # "info", "success", "warning", "error"
    "success": bool,
    "data": Dict[str, Any]         # Additional data
}
```

**Emitted by:** `SlashCommandExecutor` (core/commands/executor.py:193-202)

**Recommended priority:** DISPLAY (10)

**Example usage:**
```python
async def _display_command_output(self, data: Dict[str, Any], event: Event) -> Dict[str, Any]:
    msg_type = data.get("display_type", "info")
    message = data.get("message", "")
    # Custom output formatting
    return {}
```

---

## Tool Events

Events related to tool/function calling.

### TOOL_CALL_PRE

Fires before a tool/function call is executed.

**When it fires:**
- Tool call detected in LLM response
- Before execution

**Payload structure:**
```python
{
    "tool_data": Dict[str, Any]    # Contains all tool info:
                                   # - tool_name: str
                                   # - tool_id: str
                                   # - arguments: Dict
                                   # - tool_type: str ("mcp", "native", etc.)
}
```

**Emitted by:** `ToolExecutor` (core/llm/tool_executor.py:120-124)

**Recommended priority:** PREPROCESSING (500)

**Example usage:**
```python
async def _validate_tool_pre(self, data: Dict[str, Any], event: Event) -> Dict[str, Any]:
    tool_data = data.get("tool_data", {})
    tool_name = tool_data.get("tool_name", "")
    if tool_name in ["rm", "delete", "format"]:
        event.cancelled = True
        return {"blocked": "Dangerous tool"}
    return {}
```

---

### TOOL_CALL_POST

Fires after tool call completes.

**When it fires:**
- Tool execution finished
- Result available

**Payload structure:**
```python
{
    "tool_data": Dict[str, Any],   # Same tool info as PRE
    "result": Dict[str, Any]       # Contains:
                                   # - tool_id: str
                                   # - tool_type: str
                                   # - success: bool
                                   # - output: str
                                   # - error: str or None
                                   # - execution_time: float
}
```

**Emitted by:** `ToolExecutor` (core/llm/tool_executor.py:172-179)

**Recommended priority:** POSTPROCESSING (50)

**Example usage:**
```python
async def _log_tool_post(self, data: Dict[str, Any], event: Event) -> Dict[str, Any]:
    tool_data = data.get("tool_data", {})
    result = data.get("result", {})
    tool_name = tool_data.get("tool_name", "")
    success = result.get("success", False)
    exec_time = result.get("execution_time", 0)
    logger.info(f"Tool {tool_name}: {'OK' if success else 'FAIL'} ({exec_time}s)")
    return {}
```

---

## Modal Events

Events related to modal overlays and dialog interactions.

### MODAL_TRIGGER

Fires when a modal is triggered.

**When it fires:**
- Command requests modal display
- Modal is about to be shown

**Payload structure:** Varies by source. Typical structure:
```python
{
    "ui_config": UIConfig          # Full UI configuration
}
```

**Emitted by:** `SlashCommandExecutor` (commands/executor.py:216), `FullScreenManager` (plugins/fullscreen/manager.py:224)

**Recommended priority:** PREPROCESSING (500)

---

### MODAL_HIDE

Fires when a modal is hidden/closed.

**When it fires:**
- Fullscreen modal completes
- Modal is dismissed

**Payload structure:**
```python
{
    "source": str,                 # Source plugin name
    "plugin_name": str,
    "completed": bool              # Whether modal completed successfully
}
```

**Emitted by:** `FullScreenManager` (plugins/fullscreen/manager.py:248)

**Recommended priority:** DISPLAY (10)

---

### STATUS_MODAL_TRIGGER

Fires when a status-area modal is triggered.

**When it fires:**
- Command requests status modal
- Modal appears in status area

**Payload structure:**
```python
{
    "ui_config": UIConfig,         # UI configuration
    "action": str                  # Always "show_status_modal"
}
```

**Emitted by:** `SlashCommandExecutor` (commands/executor.py:237-244)

**Recommended priority:** PREPROCESSING (500)

---

### STATUS_MODAL_RENDER

Fires during status modal rendering.

**When it fires:**
- Status modal content is rendered
- Each frame update

**Payload structure:**
```python
{
    "request": str                 # Always "get_status_modal_lines"
}
```

**Emitted by:** `TerminalRenderer` (core/io/terminal_renderer.py:473-477)

**Recommended priority:** DISPLAY (10)

**Note:** This is a render request event. Hook returns `status_modal_lines` in result.

---

### LIVE_MODAL_TRIGGER

Fires when a live-updating modal is triggered.

**When it fires:**
- Real-time data modal requested
- Live data stream begins

**Payload structure:** Varies by plugin usage.

**Emitted by:** Plugin code (e.g., tmux_plugin.py)

**Recommended priority:** PREPROCESSING (500)

**Example:** The Tmux plugin uses this for live tmux session viewing.

---

### MODAL_COMMAND_SELECTED

Fires when a command is selected from a modal.

**When it fires:**
- User selects item from command list modal
- Command is about to execute

**Payload structure:** Varies by modal context.

**Emitted by:** `ModalController` (core/ui/modal_controller.py:270, 339, 903)

**Recommended priority:** DISPLAY (10)

---

### FULLSCREEN_INPUT

Fires when fullscreen input mode is triggered.

**When it fires:**
- User action triggers fullscreen input
- Before entering fullscreen mode

**Payload structure:**
```python
{
    "key_press": KeyPress,         # The key press that triggered this
    "source": str                  # Always "input_handler"
}
```

**Emitted by:** `ModalController` (core/ui/modal_controller.py:213-217)

**Recommended priority:** DISPLAY (10)

---

## Status Events

Events related to status display and status area management.

### STATUS_VIEW_CHANGED

Fires when the active status view changes.

**When it fires:**
- User cycles through status views
- New view becomes active

**Payload structure:**
```python
{
    "view_name": str,              # Name of new view
    "direction": str               # "next" or "previous"
}
```

**Emitted by:** `StatusViewRegistry` (core/io/status_renderer.py:98-103, 128-136)

**Recommended priority:** DISPLAY (10)

**Note:** Uses `fire_event()` not `emit_with_hooks()` - simpler event path.

**Example usage:**
```python
async def _status_view_changed(self, data: Dict[str, Any], event: Event) -> Dict[str, Any]:
    view = data.get("view_name", "")
    logger.info(f"Status view changed to: {view}")
    return {}
```

---

### STATUS_CONTENT_UPDATE

Fires when status content is updated.

**When it fires:**
- Status view content changes
- Dynamic status updates

**Payload structure:** Varies by source.

**Emitted by:** `ConfigStatusView` (core/io/config_status_view.py:189-193)

**Recommended priority:** DISPLAY (10)

---

## Message Events

Events related to message display and injection.

### ADD_MESSAGE

Hook-registered event for message injection.

**Status:** Hook-only (registered in llm_service.py:218-221)

**When it fires:** Not directly emitted. Hooks are registered but event is not fired in current codebase.

**Intended payload structure:**
```python
{
    "role": str,                   # "user", "assistant", "system", "tool"
    "content": str,
    "display_only": bool,          # If True, don't add to conversation history
    "timestamp": datetime,
    "metadata": Dict[str, Any]     # Additional metadata
}
```

**Recommended priority:** POSTPROCESSING (50)

**Note:** This event is defined and hooks are registered, but not currently emitted in the code flow.

---

## Lifecycle Events

Events related to application startup and shutdown.

### SYSTEM_STARTUP

Hook-registered event for system startup.

**Status:** Hook-only (registered in hook_system.py:108-111)

**When it fires:** Not directly emitted. Hooks are registered but event is not fired in current codebase.

**Intended payload structure:**
```python
{
    "version": str,
    "config_loaded": bool,
    "plugins_detected": int,
    "startup_time": float
}
```

**Recommended priority:** SYSTEM (1000)

**Note:** This event is defined and hooks are registered, but not currently emitted.

---

### SYSTEM_SHUTDOWN

Hook-registered event for system shutdown.

**Status:** Hook-only (registered in hook_system.py:114-118)

**When it fires:** Not directly emitted. Hooks are registered but event is not fired in current codebase.

**Intended payload structure:**
```python
{
    "reason": str,
    "uptime_seconds": float,
    "total_messages": int
}
```

**Recommended priority:** SYSTEM (1000)

**Note:** This event is defined and hooks are registered, but not currently emitted.

---

## Events NOT Currently Emitted

The following events are defined in `EventType` enum but are NOT emitted in the current codebase:

**Input:**
- `USER_INPUT_PRE`, `USER_INPUT_POST` - only `USER_INPUT` is emitted
- `KEY_PRESS_PRE`, `KEY_PRESS_POST` - only `KEY_PRESS` is emitted
- `INPUT_RENDER_PRE`, `INPUT_RENDER_POST` - only `INPUT_RENDER` is emitted
- `PASTE_DETECTED` - paste detection exists but event is never fired

**LLM:**
- `LLM_REQUEST_PRE`, `LLM_REQUEST`, `LLM_REQUEST_POST` - hooks registered but never emitted
- `LLM_RESPONSE_PRE`, `LLM_RESPONSE`, `LLM_RESPONSE_POST` - hooks registered but never emitted
- `LLM_THINKING` - hooks registered but never emitted

**Tool:**
- `TOOL_CALL` - only `TOOL_CALL_PRE` and `TOOL_CALL_POST` are emitted

**Command:**
- `COMMAND_MENU_NAVIGATE`, `COMMAND_MENU_SELECT`, `COMMAND_MENU_ACTIVATE` - navigation handled internally

**Modal:**
- `MODAL_SHOW`, `MODAL_SAVE` - not emitted

**Rendering:**
- `RENDER_FRAME`, `PAUSE_RENDERING`, `RESUME_RENDERING` - not emitted

**Status:**
- `STATUS_BLOCK_RESIZE` - not emitted
- `STATUS_TAKEOVER_START`, `STATUS_TAKEOVER_NAVIGATE`, `STATUS_TAKEOVER_ACTION`, `STATUS_TAKEOVER_END` - not emitted

---

## Event Data Structure

All events carry the following base structure:

```python
from core.events.models import Event, EventType

event = Event(
    type=EventType.USER_INPUT,      # The event type
    data={...},                      # Event-specific data
    source="input_handler",          # Source of the event
    timestamp=datetime.now(),        # When event was created
    processed=False,                 # Whether event has been processed
    cancelled=False,                 # Whether event was cancelled
    result={}                        # Results from hook processing
)
```

---

## Hook Callback Signature

Hook callbacks should follow this signature:

```python
async def my_hook_callback(
    data: Dict[str, Any],    # Event data (can be modified)
    event: Event             # Full event object (read-only)
) -> 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"}
```

---

## Hook Priority Guidelines

- **SYSTEM (1000)**: Core initialization, critical cleanup
- **SECURITY (900)**: Input validation, security checks
- **PREPROCESSING (500)**: Data transformation, validation, modification
- **LLM (100)**: LLM-specific operations, tool handling
- **POSTPROCESSING (50)**: Logging, metrics, side effects
- **DISPLAY (10)**: UI rendering, display updates

---

## Event Cancellation

Hooks can cancel events by setting `event.cancelled = True`:

```python
async def cancel_if_too_long(self, data: Dict[str, Any], event: Event) -> Dict[str, Any]:
    if len(data.get("message", "")) > 10000:
        event.cancelled = True
        return {"cancelled": True, "reason": "Input too long"}
    return {}
```

---

## Emitting Events

To emit events from your plugin or code:

```python
# Using event bus with hooks
await self.event_bus.emit_with_hooks(
    EventType.MY_EVENT,
    {
        "key": "value",
        "data": {...}
    },
    source="my_plugin"
)

# For simple events without hooks
from core.events.models import Event, EventType
event = Event(
    type=EventType.MY_EVENT,
    data={"key": "value"},
    source="my_plugin"
)
self.event_bus.fire_event(event)
```

---

## Best Practices

1. **Use appropriate priorities**: Don't use SYSTEM priority for non-critical hooks
2. **Keep hooks fast**: Long-running hooks block the event pipeline
3. **Handle errors gracefully**: Hook failures shouldn't crash the application
4. **Test hook interactions**: Multiple hooks on the same event can interfere
5. **Document data mutations**: Clearly document when your hook modifies event data
6. **Check before implementing**: Before implementing hooks for events like `LLM_REQUEST_PRE`, verify they are actually emitted in the codebase

---

## Source Files

- **EventType enum:** `core/events/models.py:30-118`
- **Event processor:** `core/events/processor.py`
- **Event executor:** `core/events/executor.py`
- **Event bus:** `core/events/bus.py`
- **Input events:** `core/io/input/key_press_handler.py`, `command_mode_handler.py`
- **Command events:** `core/commands/executor.py`
- **Tool events:** `core/llm/tool_executor.py`
- **Modal events:** `core/ui/modal_controller.py`
- **Status events:** `core/io/status_renderer.py`
