# Ready Message Hook System

The ready message system allows plugins and core components to contribute statistics and information to the startup "Ready!" message displayed when Kollabor initializes.

## Overview

When Kollabor starts, it displays a ready message like:

```
Ready! (24 system prompt modules, 85 hooks active, 15 plugins loaded, 8 status views available) Type your message and press Enter.
```

This message is dynamically generated by collecting stats from:
- Core components (system prompt, hooks, plugins, status views)
- Plugins (via SYSTEM_READY event hook)

## Architecture

### Components

1. **ReadyMessageCollector** (`kollabor/events/ready_message.py`)
   - Collects ready message items from core and plugins
   - Sorts by priority (highest first)
   - Formats for display with configurable max items

2. **SYSTEM_READY Event** (`EventType.SYSTEM_READY`)
   - Emitted during application startup
   - Passes ReadyMessageCollector in event data
   - Plugins hook into this to contribute stats

3. **Application Integration** (`kollabor/application.py`)
   - Creates ReadyMessageCollector during startup
   - Adds core stats (system prompt modules, hooks, plugins, status views)
   - Emits SYSTEM_READY event for plugins
   - Displays formatted message

## Usage for Plugins

### Registering a Ready Message Hook

Plugins can hook into the `SYSTEM_READY` event to contribute stats:

```python
from kollabor.plugins.base import BasePlugin
from kollabor.events.models import EventType, HookPriority

class MyPlugin(BasePlugin):
    def register_hooks(self) -> None:
        """Register hooks for this plugin."""
        self.event_bus.register_hook(
            name="my_plugin_ready_stats",
            plugin_name=self.name,
            event_type=EventType.SYSTEM_READY,
            callback=self._add_ready_stats,
            priority=HookPriority.SYSTEM
        )

    async def _add_ready_stats(self, event):
        """Add plugin stats to ready message collector.

        Args:
            event: SYSTEM_READY event with collector in event.data
        """
        collector = event.data.get("collector")
        if not collector:
            return event

        # Add your plugin's stats
        collector.add(
            category="custom triggers",
            count=4,
            label="configured",
            priority=600,  # Display priority
            source=self.name
        )

        collector.add(
            category="api endpoints",
            count=12,
            label="registered",
            priority=500,
            source=self.name
        )

        return event
```

### ReadyMessageCollector.add() Parameters

```python
collector.add(
    category: str,        # Category name (e.g., "hooks", "plugins")
    count: Optional[int], # Numeric count or None for non-numeric
    label: str,           # Description (e.g., "active", "loaded")
    priority: int = 100,  # Display priority (higher = shown first)
    source: str = "core"  # Plugin/component name
)
```

### Priority Guidelines

Use these priority ranges for consistent ordering:

- **1000+** - Critical system stats (system prompt)
- **900-999** - Hook system stats
- **800-899** - Plugin and component counts
- **700-799** - Feature availability stats
- **600-699** - Custom plugin features
- **500-599** - Secondary stats
- **0-499** - Low priority / debug info

## Core Stats Collected

The core automatically adds these stats:

1. **System Prompt Modules** (priority 1000)
   - Count of modular sections loaded from `sections/`
   - Example: "24 system prompt modules"

2. **Hooks Active** (priority 900)
   - Total number of registered hooks across all event types
   - Example: "85 hooks active"

3. **Plugins Loaded** (priority 800)
   - Number of successfully loaded plugins
   - Example: "15 plugins loaded"

4. **Status Views Available** (priority 700)
   - Number of registered status views
   - Example: "8 status views available"

## Display Behavior

### Max Items

By default, only the top 6 items (by priority) are displayed. If more items exist:

```
Ready! (24 system prompt modules, 85 hooks active, 15 plugins loaded, 8 status views available, 4 custom triggers configured, 12 api endpoints registered) Type your message and press Enter.
```

If truncated (more than 6 items):

```
Ready! (24 system prompt modules, 85 hooks active, 15 plugins loaded, 8 status views available, 4 custom triggers configured, 12 api endpoints registered, and 3 more) Type your message and press Enter.
```

### Empty Stats

If no stats are collected, the message falls back to:

```
Ready! Type your message and press Enter.
```

## Examples

### Example 1: Plugin Contributing Single Stat

```python
async def _add_ready_stats(self, event):
    """Add MCP server count to ready message."""
    collector = event.data.get("collector")
    if not collector:
        return event

    server_count = len(self.mcp_servers)
    if server_count > 0:
        collector.add(
            category="MCP servers",
            count=server_count,
            label="connected",
            priority=650,
            source="mcp_plugin"
        )

    return event
```

Result: `"3 MCP servers connected"`

### Example 2: Plugin Contributing Multiple Stats

```python
async def _add_ready_stats(self, event):
    """Add tmux session stats to ready message."""
    collector = event.data.get("collector")
    if not collector:
        return event

    active_sessions = self.get_active_sessions()
    collector.add(
        category="tmux sessions",
        count=len(active_sessions),
        label="active",
        priority=550,
        source="tmux_plugin"
    )

    monitored = sum(1 for s in active_sessions if s.is_monitored)
    if monitored > 0:
        collector.add(
            category="monitored sessions",
            count=monitored,
            label="live",
            priority=540,
            source="tmux_plugin"
        )

    return event
```

Result: `"5 tmux sessions active, 2 monitored sessions live"`

### Example 3: Non-Numeric Stat

```python
async def _add_ready_stats(self, event):
    """Add agent status to ready message."""
    collector = event.data.get("collector")
    if not collector:
        return event

    if self.agent_mode_enabled:
        collector.add(
            category="agent mode",
            count=None,  # No count
            label="enabled",
            priority=700,
            source="agent_plugin"
        )

    return event
```

Result: `"agent mode enabled"`

## Implementation Details

### Event Flow

1. Application startup (`application.py`)
2. Create `ReadyMessageCollector()`
3. Add core stats via `_add_core_ready_stats()`
4. Emit `EventType.SYSTEM_READY` event with collector
5. Plugins receive event and add their stats
6. Format messages via `collector.format_for_display(max_items=6)`
7. Display in ready message

### Error Handling

- Core stat collection errors are logged but don't crash startup
- Plugin hook errors are handled by the event bus (logged, execution continues)
- Empty collector results in simple "Ready!" message

### Performance

- Collector is created once per startup
- Stats collection is synchronous (fast operations only)
- Formatting is done once before display
- No impact on runtime performance

## Testing

### Unit Test Example

```python
from kollabor.events.ready_message import ReadyMessageCollector

def test_ready_message_collector():
    collector = ReadyMessageCollector()

    collector.add("hooks", 85, "active", priority=900, source="core")
    collector.add("plugins", 15, "loaded", priority=800, source="core")

    messages = collector.get_formatted_messages()
    assert messages == ["85 hooks active", "15 plugins loaded"]

    formatted = collector.format_for_display(max_items=2)
    assert formatted == "85 hooks active, 15 plugins loaded"
```

### Integration Test Example

```python
async def test_system_ready_event():
    """Test that SYSTEM_READY event is emitted with collector."""
    event_received = False
    collector_received = None

    async def test_hook(event):
        nonlocal event_received, collector_received
        event_received = True
        collector_received = event.data.get("collector")
        return event

    # Register hook
    event_bus.register_hook(
        name="test_ready",
        plugin_name="test",
        event_type=EventType.SYSTEM_READY,
        callback=test_hook,
        priority=HookPriority.SYSTEM
    )

    # Trigger startup
    await app.initialize()

    assert event_received
    assert collector_received is not None
    assert isinstance(collector_received, ReadyMessageCollector)
```

## See Also

- Event System Documentation: `docs/architecture/event-system.md`
- Plugin Development Guide: `docs/development/plugin-guide.md`
- Hook Priority Guidelines: `docs/reference/hook-priorities.md`
