# Interactive Status Widget System Specification

**Version:** 1.2
**Status:** Draft - Revised
**Author:** Kollabor Team
**Date:** 2026-01-18
**Last Updated:** 2026-01-19 (Edit Mode UI Revision)

## Overview

Transform the Kollabor CLI status area from a passive display into an interactive dashboard where users can navigate between widgets, trigger actions, and control application state without leaving the terminal interface.

**Design Principles:**
- Use existing design system (solid blocks, TagBox, T() theme)
- Integrate with MessageDisplayCoordinator (no render conflicts)
- Simple, discoverable navigation (help on first run)
- Async-safe with proper locking
- Practical security (trust local scripts, validate input)

## Goals

1. **Interactive Navigation**: Tab into status area, navigate with arrow keys
2. **Widget Actions**: Click/activate widgets to trigger modals, toggles, or commands
3. **Script-Based Widgets**: User-defined widgets via simple shell scripts
4. **Zero-Code Customization**: Add custom widgets without writing Python
5. **Keyboard-Driven**: Fully accessible via keyboard shortcuts
6. **Visual Feedback**: Clear indication of interactive elements and selection state

## Non-Goals

- Mouse support (keyboard-only interface)
- Touch/gesture support
- Real-time collaborative editing
- Network-synced widget state

---

## Quick Start

**Create your first script widget in 30 seconds:**

```bash
# 1. Create widget directory
mkdir -p ~/.kollabor-cli/status-widgets

# 2. Create a simple widget script
cat > ~/.kollabor-cli/status-widgets/hello.sh <<'EOF'
#!/bin/bash
# widget-id: hello
# name: Hello Widget
# description: Shows a friendly greeting
echo "👋 Hello!"
EOF

# 3. Make it executable
chmod +x ~/.kollabor-cli/status-widgets/hello.sh

# 4. Launch Kollabor, press Tab to enter Navigation Mode
# 5. Navigate to your widget and press Enter to activate!
```

**Done!** Your widget appears in the status area automatically.

**Next steps:**
- Read "Script-Based Widgets" section for metadata options
- See "Examples" section for interactive widgets
- Press F1 in Kollabor for keyboard shortcuts

---

## Architecture

### Component Overview

```
┌─────────────────────────────────────────────────────────────┐
│                    Status Area (Top Bar)                     │
│  ┌──────┐  ┌──────────┐  ┌────────┐  ┌──────────┐          │
│  │ cwd  │  │ ⌘ default│  │ model  │  │ * Ready  │  ...     │
│  └──────┘  └──────────┘  └────────┘  └──────────┘          │
│              ▲ selected                                      │
└─────────────────────────────────────────────────────────────┘
                     │
                     │ Tab key
                     ▼
┌─────────────────────────────────────────────────────────────┐
│              Navigation Mode Active                          │
│  Arrow keys: move selection                                  │
│  Enter: activate widget                                      │
│  Esc: return to input                                        │
└─────────────────────────────────────────────────────────────┘
                     │
                     │ Enter key
                     ▼
┌─────────────────────────────────────────────────────────────┐
│                   Widget Activated                           │
│  Executes the widget's associated slash command:             │
│  - profile widget  → /profile (opens profile modal)         │
│  - agent widget    → /agent (opens agent modal)             │
│  - tmux widget     → /terminal (opens tmux modal)           │
│  - model widget    → /model (opens model selector)          │
│  This reuses existing command infrastructure.                │
└─────────────────────────────────────────────────────────────┘
```

### Core Components

1. **StatusNavigationManager** (`core/io/status/navigation_manager.py`)
   - Tracks navigation state (active, selected row/widget)
   - Handles keyboard input routing (tab, arrows, enter, esc)
   - Emits navigation events (widget_selected, widget_activated)

2. **InteractiveWidgetRegistry** (extends `StatusWidgetRegistry`)
   - Stores widget interaction metadata
   - Registers interaction handlers
   - Validates widget capabilities

3. **ScriptWidgetManager** (`core/io/status/script_widgets.py`)
   - Discovers script-based widgets
   - Executes scripts with timeout protection
   - Caches output and manages refresh schedules

4. **WidgetInteractionHandler** (`core/io/status/interaction_handler.py`)
   - Routes widget activation to appropriate handler
   - Manages modal lifecycles
   - Coordinates inline editors

---

## Navigation System

### Navigation Modes

**Input Mode** (default)
- User typing in input box
- Tab key enters Navigation Mode
- Status area shows normal rendering

**Navigation Mode**
- Input box is **hidden** (not just blurred)
- Status area shows selection highlight on widgets
- Mode indicator shows "NAVIGATE"
- Arrow keys move selection between widgets
- Enter activates selected widget (executes its slash command)
- Press `e` to enter Edit Mode
- Esc returns to Input Mode (shows input box again)

**Edit Mode** (accessible from Navigation Mode)
- Input box remains hidden
- Mode indicator shows "EDIT"
- **Slots visible**: Shows "+" slots between widgets for adding new widgets
- **Empty rows visible**: All available rows shown (even empty ones)
- Arrow keys navigate between widgets AND slots
- Enter on a **slot** opens Widget Picker to add widget at that position
- Enter on a **widget** activates it (same as Navigation Mode)
- Press `d` on a widget to delete it (with confirmation if last in row)
- Press `c` on a widget to toggle its background color
- Esc returns to Navigation Mode (hides slots and empty rows)

**Widget Activation** (not a separate mode)
- Enter on a widget executes its associated slash command
- The command opens its modal/UI (e.g., /profile opens profile selector)
- When modal closes, returns to Input Mode (navigation exits)
- This reuses existing command modals - no duplicate UI code

### Navigation State

```python
import asyncio
from dataclasses import dataclass, field
from typing import Dict, Any, Optional, List, Tuple

@dataclass
class StatusNavigationState:
    """Tracks current navigation state in status area.

    Thread-safe navigation state with asyncio.Lock to prevent
    race conditions during concurrent operations.
    """

    # Navigation active?
    active: bool = False

    # Current selection position
    selected_row: int = 0
    selected_widget_index: int = 0

    # Widget interaction state
    interaction_active: bool = False
    active_widget_id: Optional[str] = None
    interaction_data: Dict[str, Any] = field(default_factory=dict)

    # History for back navigation
    navigation_history: List[Tuple[int, int]] = field(default_factory=list)

    # Lock for async-safe state mutations
    _lock: asyncio.Lock = field(default_factory=asyncio.Lock)

    async def set_active(self, active: bool) -> None:
        """Set navigation active state (thread-safe)."""
        async with self._lock:
            self.active = active
            if not active:
                # Reset selection when exiting navigation
                self.interaction_active = False
                self.active_widget_id = None

    async def move_selection(self, delta_row: int, delta_widget: int) -> None:
        """Move selection by delta (thread-safe)."""
        async with self._lock:
            self.selected_row = max(0, self.selected_row + delta_row)
            self.selected_widget_index = max(0, self.selected_widget_index + delta_widget)

    async def activate_widget(self, widget_id: str) -> None:
        """Activate a widget (thread-safe)."""
        async with self._lock:
            self.interaction_active = True
            self.active_widget_id = widget_id
```

### Keyboard Shortcuts

**Global (any mode)**
- `Tab` - Enter Navigation Mode (hides input box)
- `F1` or `?` - Show help overlay (from any mode)

**Navigation Mode**
- `←` / `→` - Move between widgets in current row
- `↑` / `↓` - Move between rows
- `Enter` - Activate selected widget
- `e` - Enter Edit Mode (shows slots and empty rows)
- `Esc` - Return to Input Mode (shows input box)
- `Home` - Jump to first widget
- `End` - Jump to last widget
- `1-9` - Quick jump to widget N in row (if available)
- `Space` - Quick toggle (for toggle-type widgets)

**Edit Mode** (from Navigation Mode)
- `←` / `→` - Move between widgets AND slots
- `↑` / `↓` - Move between rows (including empty rows)
- `Enter` on widget - Activate widget
- `Enter` on slot - Open Widget Picker to add widget
- `d` - Delete selected widget (confirmation if last in row)
- `c` - Toggle widget background color
- `Esc` - Return to Navigation Mode (hides slots/empty rows)

**Interaction Mode** (widget-specific)
- Defined by individual widget types
- Common: `Esc` exits, `Enter` confirms

---

## Widget Types and Interactions

### Design Principle: Reuse Slash Commands

**Widgets execute their corresponding slash commands** rather than implementing custom modals. This ensures:
- Consistent UI (same modal for `/profile` and clicking profile widget)
- No duplicate code
- Existing commands "just work" when activated via widget

### Widget-to-Command Mapping

| Widget ID | Slash Command | Description |
|-----------|---------------|-------------|
| profile   | /profile      | LLM profile selector |
| agent     | /agent        | Agent switcher |
| model     | /model        | Model selector |
| tmux      | /terminal     | Tmux session manager |
| cwd       | /cd           | Directory navigator |
| skill     | /skill        | Skill selector |

### 1. Command Widgets (Primary Type)

Execute a slash command when activated.

```python
# Widget definition
registry.register(
    id="profile",
    name="Profile",
    description="Active LLM profile",
    render_fn=render_profile,
    interactive=True,
    interaction_type="command",
    command="/profile",  # Executes this command on Enter
)
```

The command opens its existing modal/UI. No custom activation handler needed.

### 2. Toggle Widgets

Click to toggle between states (boolean or cyclic).

**Example: Thinking Mode Widget**

```python
registry.register(
    id="thinking-mode",
    name="Thinking Mode",
    description="Toggle thinking tag display",
    render_fn=render_thinking_mode,
    interactive=True,
    interaction_type="toggle",
    on_activate=toggle_thinking_mode,
    states=["hidden", "collapsed", "expanded"],
)

async def toggle_thinking_mode(widget_id: str, context: Any):
    """Cycle through thinking mode states."""
    current = context.config.get("thinking_mode", "hidden")
    states = ["hidden", "collapsed", "expanded"]
    next_idx = (states.index(current) + 1) % len(states)
    context.config.set("thinking_mode", states[next_idx])
    return {"new_state": states[next_idx]}
```

**Toggle Shortcuts**
- `Space` - Quick toggle (in navigation mode)
- `Enter` - Activate with confirmation modal
- `←` / `→` - Cycle states (when activated)

### 3. Inline Edit Widgets

Edit value directly in status area (no modal).

**Example: Temperature Widget**

```python
registry.register(
    id="temperature",
    name="Temperature",
    description="Model temperature setting",
    render_fn=render_temperature,
    interactive=True,
    interaction_type="inline_edit",
    on_activate=edit_temperature,
    edit_config={
        "min": 0.0,
        "max": 2.0,
        "step": 0.1,
        "presets": [0.1, 0.5, 0.7, 1.0, 1.5],
    }
)

async def edit_temperature(widget_id: str, context: Any):
    """Open inline slider for temperature."""
    return {
        "type": "slider",
        "current": context.profile_manager.get_temperature(),
        "min": 0.0,
        "max": 2.0,
        "step": 0.1,
    }
```

**Inline Edit Shortcuts**
- `←` / `→` - Adjust value by step
- `↑` / `↓` - Adjust by 10x step
- `1-9` - Jump to preset N
- `Enter` - Confirm and save
- `Esc` - Cancel and revert

### 4. Action Widgets

Execute command or function directly.

**Example: Open Logs Widget**

```python
registry.register(
    id="session-name",
    name="Session Name",
    description="Project session identifier",
    render_fn=render_session_name,
    interactive=True,
    interaction_type="action",
    on_activate=open_session_actions,
    actions=[
        {"key": "l", "label": "Open Logs", "action": "open_logs"},
        {"key": "c", "label": "View Conversations", "action": "open_conversations"},
        {"key": "d", "label": "Open Directory", "action": "open_directory"},
    ]
)

async def open_session_actions(widget_id: str, context: Any):
    """Show quick actions for session."""
    return {
        "type": "action_menu",
        "actions": [
            {
                "label": "[l] Open Logs Directory",
                "command": ["open", str(get_logs_dir())],
            },
            {
                "label": "[c] View Conversations",
                "command": ["ls", "-lh", str(get_conversations_dir())],
            },
            {
                "label": "[d] Open Project Directory",
                "command": ["open", str(Path.cwd())],
            },
        ]
    }
```

**Action Shortcuts**
- Single-key shortcuts (defined in widget)
- `Enter` - Execute default action
- `Esc` - Cancel

---

## Script-Based Widgets

### Directory Structure

```
~/.kollabor-cli/status-widgets/       # Global widgets
├── git-branch.sh
├── docker-status.sh
├── python-env.sh
└── custom-widget.py

.kollabor-cli/status-widgets/         # Project-specific widgets
├── project-health.sh
└── deployment-status.sh
```

### Script Widget Format

#### Option A: Comment Headers (Recommended)

**Simple, single-file format with metadata in script comments**

```bash
#!/bin/bash
# widget-id: git-branch
# name: Git Branch
# description: Shows current git branch with dirty indicator
# category: git
# interactive: true
# interaction-type: modal
# on-activate: git-branch-modal.sh
# refresh: 5s
# hooks: post_user_input, pre_api_request
# min-width: 15
# timeout: 3s

# Render function (stdout becomes widget content)
branch=$(git branch --show-current 2>/dev/null || echo "no-git")
dirty=$(git diff --quiet 2>/dev/null || echo "*")
echo "⎇ ${branch}${dirty}"
```

#### Option B: JSON Sidecar (Advanced)

**Separate metadata file for complex configuration**

`git-branch.json`:
```json
{
  "id": "git-branch",
  "name": "Git Branch",
  "description": "Shows current git branch with dirty indicator",
  "category": "git",
  "interactive": true,
  "interaction_type": "modal",
  "on_activate": "./git-branch-modal.sh",
  "refresh": "5s",
  "hooks": ["post_user_input", "pre_api_request"],
  "min_width": 15,
  "timeout": 3000,
  "keyboard_shortcuts": {
    "g": "git_status",
    "p": "git_pull",
    "P": "git_push"
  }
}
```

`git-branch.sh`:
```bash
#!/bin/bash
branch=$(git branch --show-current 2>/dev/null || echo "no-git")
dirty=$(git diff --quiet 2>/dev/null || echo "*")
echo "⎇ ${branch}${dirty}"
```

### Script Metadata Fields

| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `widget-id` | string | Yes | - | Unique identifier (kebab-case) |
| `name` | string | Yes | - | Display name in picker |
| `description` | string | Yes | - | Brief description |
| `category` | string | No | `"custom"` | Widget category (git, docker, python, etc.) |
| `interactive` | boolean | No | `false` | Widget is clickable |
| `interaction-type` | string | No | - | modal, toggle, action, inline_edit |
| `on-activate` | string | No | - | Script to run on activation (path) |
| `refresh` | string | No | `"manual"` | Refresh strategy (see below) |
| `hooks` | string | No | - | Comma-separated hook names |
| `min-width` | int | No | `10` | Minimum width in characters |
| `timeout` | string | No | `"5s"` | Max execution time |
| `color` | boolean | No | `true` | Allow ANSI color codes |

### Refresh Strategies

**Manual** (default)
```bash
# refresh: manual
# Only updates when user triggers refresh or event fires
```

**Time-Based Polling**
```bash
# refresh: 5s          # Every 5 seconds
# refresh: 1m          # Every 1 minute
# refresh: 30s         # Every 30 seconds
```

**Hook-Based**
```bash
# refresh: on-event
# hooks: post_user_input, pre_api_request
# Runs when specific events fire
```

**Once**
```bash
# refresh: once
# Runs once at startup, never again
```

**Smart** (time + hooks)
```bash
# refresh: 10s
# hooks: post_user_input
# Runs every 10s AND when hooks fire
```

### Interactive Script Widgets

#### Modal Script Widget

**Main widget** (`git-branch.sh`):
```bash
#!/bin/bash
# widget-id: git-branch
# interactive: true
# interaction-type: modal
# on-activate: ./git-branch-modal.sh

branch=$(git branch --show-current 2>/dev/null || echo "no-git")
echo "⎇ ${branch}"
```

**Modal handler** (`git-branch-modal.sh`):
```bash
#!/bin/bash
# Returns JSON defining modal options

cat <<EOF
{
  "title": "Git Branch Actions",
  "options": [
    {
      "label": "View Status",
      "command": ["git", "status"],
      "display": "terminal"
    },
    {
      "label": "Switch Branch",
      "command": ["git", "branch", "-a"],
      "input": "branch_name",
      "action": ["git", "checkout", "{input}"]
    },
    {
      "label": "Pull Latest",
      "command": ["git", "pull"],
      "confirm": true
    }
  ]
}
EOF
```

#### Action Script Widget

```bash
#!/bin/bash
# widget-id: docker-status
# interactive: true
# interaction-type: action
# on-activate: ./docker-actions.sh

running=$(docker ps -q | wc -l)
echo "🐳 ${running}"
```

**Action handler** (`docker-actions.sh`):
```bash
#!/bin/bash
# Takes argument: $1 = action key pressed

case "$1" in
  "l")  # List containers
    docker ps -a
    ;;
  "s")  # Stop all
    docker stop $(docker ps -q)
    ;;
  "c")  # Clean up
    docker system prune -f
    ;;
  *)
    echo "Unknown action: $1"
    exit 1
    ;;
esac
```

---

## Visual Design

**CRITICAL: Use Existing Design System**

All visual rendering MUST use the design system from `core/ui/design_system`:
- `from core.ui.design_system import T, S, C, Box, TagBox, solid, solid_fg, gradient`
- Solid block style (▄▀) NOT ASCII box-drawing (╭╮╰╯│─)
- Colors via `T()` theme, never hardcoded ANSI codes
- Follow existing status_v2 patterns from `core/io/core_status_views.py`

### Selection States

**Normal (non-interactive widget)**
```python
# Simple text rendering - NO triangle indicator
cwd = _fg("cwd", T().ai_tag) + " " + _fg("~/dev/project", T().text)
```

**Interactive (not selected)**
```python
# No triangle indicator - clean appearance
profile = _fg("⌘", T().secondary[0]) + " " + _fg("default", T().text)
# NOTE: Removed ▸ triangle indicator per v1.2 spec
```

**Selected (navigation mode)** - Using Solid Blocks
```python
# Solid block highlight, NOT ASCII brackets
from core.ui.design_system import solid, solid_fg, T

def render_selected_widget(text: str, width: int) -> str:
    """Render widget with solid block selection highlight."""
    # Top border
    top = solid_fg("▄" * width, T().primary[0])

    # Content with solid background
    content = solid(f" {text:<{width-2}} ", T().primary[0], T().text_dark, width)

    # Bottom border
    bottom = solid_fg("▀" * width, T().primary[0])

    return f"{top}\n{content}\n{bottom}"
```

**Slot (edit mode only)** - Plus symbol between widgets
```python
def render_slot(selected: bool, width: int = 3) -> str:
    """Render slot for adding widgets (only visible in edit mode)."""
    if selected:
        # Highlighted slot
        return solid(" + ", T().primary[0], T().text_dark, width)
    else:
        # Normal slot
        return _fg(" + ", T().text_dim)
```

**Activated (interaction mode)**
```python
# Show activation indicator
profile = solid(" ⌘ default ▼ ", T().ai_tag, T().text_dark, width)
# Uses ai_tag color + dropdown indicator C['arrow_down']
```

### Mode Indicator (Always Visible)

Show current mode in status area to avoid confusion:

```python
def render_mode_indicator(nav_state: StatusNavigationState) -> str:
    """Render mode indicator using design system."""
    if nav_state.active:
        if nav_state.edit_mode:
            mode = " EDIT "
            bg, fg = T().warning[0], T().text_dark
        else:
            mode = " NAVIGATE "
            bg, fg = T().ai_tag, T().text_dark
    else:
        mode = " INPUT "
        bg, fg = T().dark[0], T().text

    return solid(mode, bg, fg, len(mode))
```

**Display:** Always show mode indicator at right edge of status bar.

**Mode Transitions:**
```
INPUT --[Tab]--> NAVIGATE --[e]--> EDIT
                    |                |
                    |<---[Esc]-------|
                    |
INPUT <---[Esc]-----|
```

### Color Scheme

Using existing design system (`core.ui.design_system`):

- **Normal widget**: `T().text`
- **Selected widget background**: `T().primary[0]`
- **Slot indicator**: `T().text_dim` (normal), `T().primary[0]` (selected)
- **Activated widget**: `T().ai_tag` background
- **Error state**: `T().error`
- **Mode indicator**: `T().ai_tag` (navigate), `T().warning[0]` (edit)

### Widget Background Color Toggle

Widgets can have their background color toggled using the `c` key in Edit Mode:

```python
# Color options for widget backgrounds (cycled with 'c' key)
WIDGET_BG_COLORS = [
    None,           # Default (transparent/dark)
    T().dark[0],    # Dark background
    T().dark[1],    # Slightly lighter
    T().primary[0], # Primary accent
    T().secondary[0], # Secondary accent
]

def toggle_widget_color(widget_id: str, current_color_index: int) -> int:
    """Cycle to next background color for widget."""
    return (current_color_index + 1) % len(WIDGET_BG_COLORS)
```

### Visual Indicators Using Design System

**NOTE:** The triangle indicator (▸) has been removed in v1.2 for cleaner appearance.

**Selection Using TagBox Pattern**
```python
from core.ui.design_system import TagBox, T

def render_selected_widget_tagbox(widget_text: str, width: int) -> List[str]:
    """Render selected widget using TagBox pattern."""
    return TagBox.render(
        lines=[widget_text],
        tag_bg=T().primary[0],
        tag_fg=T().text_dark,
        tag_width=3,
        content_colors=T().response_bg[0],
        content_fg=T().text,
        content_width=width - 7,
        tag_chars=[" > "],
    )
```

---

## First-Run Discovery & Help

### Startup Help (First Run Only)

On first run after feature is added, show help modal explaining navigation:

```python
async def show_first_run_help() -> None:
    """Show help modal on first run (once per user)."""
    if config.get("status.navigation.help_shown", False):
        return

    modal = {
        "title": "NEW: Interactive Status Widgets",
        "content": [
            "You can now interact with the status bar!",
            "",
            "Press Tab to enter Navigation Mode",
            "  ← → to move between widgets",
            "  Enter to activate widget",
            "  Esc to return to input",
            "",
            "Press F1 or ? anytime for help",
            "",
            "[Enter] Got it!  [D] Don't show again",
        ]
    }

    await show_modal(modal)
    config.set("status.navigation.help_shown", True)
```

### Help Overlay (F1 or ?)

Accessible from any mode, shows quick reference:

```
╔══════════════════════════════════════════════╗
║     Interactive Status Widgets - Help       ║
╠══════════════════════════════════════════════╣
║ Tab        Enter Navigation Mode             ║
║ ← →        Move between widgets              ║
║ ↑ ↓        Move between rows                 ║
║ Enter      Activate selected widget          ║
║ Esc        Return to Input Mode              ║
║ F1 or ?    Show this help                    ║
║ Ctrl+Z     Undo last action                  ║
║ 1-9        Quick jump to widget              ║
║ Space      Quick toggle (toggle widgets)     ║
╠══════════════════════════════════════════════╣
║ Current Mode: INPUT                          ║
╚══════════════════════════════════════════════╝
```

---

## MessageDisplayCoordinator Integration

**CRITICAL: Prevent Render State Conflicts**

The navigation system MUST integrate with `MessageDisplayCoordinator` to avoid render conflicts during LLM streaming and modal operations.

### Integration Points

```python
class StatusNavigationManager:
    """Manages navigation state with MessageDisplayCoordinator awareness."""

    def __init__(self, renderer, coordinator: MessageDisplayCoordinator):
        self.renderer = renderer
        self.coordinator = coordinator
        self.state = StatusNavigationState()

    async def enter_navigation_mode(self) -> None:
        """Enter navigation mode (coordinated with message display)."""
        # Check if LLM is streaming or messages are queued
        if self.coordinator.is_writing_messages():
            logger.warning("Cannot enter navigation during message display")
            return

        # Acquire lock to prevent conflicts
        async with self.state._lock:
            await self.state.set_active(True)

            # Signal coordinator: navigation active, pause message renders
            self.coordinator.set_navigation_active(True)

            # Render initial selection
            await self.render_navigation_state()

    async def exit_navigation_mode(self) -> None:
        """Exit navigation mode (restore message display)."""
        async with self.state._lock:
            await self.state.set_active(False)

            # Signal coordinator: navigation done, resume message renders
            self.coordinator.set_navigation_active(False)

            # Restore normal status rendering
            await self.renderer.render_status()

    async def activate_widget(self, widget: StatusWidget) -> None:
        """Activate widget (modal/toggle/edit) with coordinator awareness."""
        # For modals: use coordinator's buffer management
        if widget.interaction_type == "modal":
            # Enter alternate buffer via coordinator
            await self.coordinator.enter_alternate_buffer()

            try:
                # Show modal
                result = await widget.on_activate(widget.id, context)
                await self.show_modal(result)
            finally:
                # Exit alternate buffer, restore state cleanly
                await self.coordinator.exit_alternate_buffer()
                await self.exit_navigation_mode()
```

### Coordinator Extensions

Add to `MessageDisplayCoordinator`:

```python
class MessageDisplayCoordinator:
    """Extended with navigation awareness."""

    def __init__(self):
        # ... existing fields ...
        self.navigation_active: bool = False

    def set_navigation_active(self, active: bool) -> None:
        """Set navigation active state (pauses message rendering)."""
        self.navigation_active = active

    def is_writing_messages(self) -> bool:
        """Check if currently writing messages or navigation active."""
        return self.writing_messages or self.navigation_active

    async def display_queued_messages(self):
        """Display queued messages (skip if navigation active)."""
        if self.navigation_active:
            logger.debug("Skipping message display: navigation active")
            return

        # ... existing logic ...
```

---

## Implementation Plan

### Phase 1: Basic Navigation (Week 1-2)

**Components to build:**
1. `StatusNavigationManager`
   - Track navigation state with asyncio.Lock
   - Handle Tab key toggle
   - Arrow key navigation
   - ESC to exit (always returns to Input Mode)
   - Integrate with MessageDisplayCoordinator

2. `StatusRenderer` updates
   - Render selection highlights using solid blocks
   - Show interactive indicators (▸)
   - Show mode indicator (INPUT/NAVIGATE/INTERACT)
   - Update on navigation state change

3. `InputHandler` integration
   - Route Tab key to navigation manager
   - Route F1/? to help overlay
   - Disable input when navigation active
   - Pass arrow keys when in navigation mode

4. First-run help system
   - Show help modal on first run
   - Store help_shown flag in config
   - F1/? help overlay

**Deliverable:** User can Tab into status area, move selection with arrows, ESC to exit, mode indicator visible, no render conflicts.

### Phase 2: Modal Interactions (Week 2)

**Components to build:**
1. `WidgetInteractionHandler`
   - Route Enter key to widget activation
   - Manage modal lifecycle
   - Handle modal keyboard input

2. Modal definitions for core widgets:
   - Profile switcher modal
   - Git branch actions modal
   - Tmux session list modal

3. Event integration
   - `widget_activated` event
   - `widget_action_executed` event
   - Hook into existing event bus

**Deliverable:** Enter key opens modals, modals are navigable, actions execute.

### Phase 3: Inline Interactions (Week 3)

**Components to build:**
1. Inline editors
   - Slider widget (temperature, max_tokens)
   - Text input widget (search, filter)
   - Dropdown widget (profile selection)

2. Interactive widgets:
   - Temperature slider
   - Max tokens editor
   - Profile quick-switcher

**Deliverable:** Inline editing works, values save, ESC/Enter behave correctly.

### Phase 4: Script Widgets (Week 4)

**Components to build:**
1. `ScriptWidgetManager`
   - Discover scripts in directories
   - Parse metadata (comments or JSON)
   - Execute with timeout protection
   - Cache output

2. `ScriptWidgetRefreshScheduler`
   - Handle time-based refresh
   - Hook-based refresh
   - Smart refresh (combined)

3. Script execution engine
   - Timeout enforcement (default 5s)
   - Error handling
   - Output caching
   - ANSI color support

**Deliverable:** Users can drop scripts in `~/.kollabor-cli/status-widgets/`, they appear in picker, refresh works.

### Phase 5: Interactive Script Widgets (Week 5)

**Components to build:**
1. Script modal handlers
   - Execute on-activate scripts
   - Parse JSON output
   - Render modal from script output

2. Script action handlers
   - Key-based action routing
   - Command execution
   - Result display

3. Documentation and examples
   - Example script widgets
   - Template scripts
   - Best practices guide

**Deliverable:** Script widgets can be interactive, modals/actions work, comprehensive examples.

---

## API Reference

### Widget Registration (Python)

```python
# Register an interactive widget
registry.register(
    id="my-widget",
    name="My Widget",
    description="Does something cool",
    render_fn=render_my_widget,
    category=WidgetCategory.PLUGIN,
    interactive=True,
    interaction_type="modal",
    on_activate=handle_activation,
    keyboard_shortcuts={
        "r": "refresh",
        "c": "clear",
    },
    min_width=15,
)

# Activation handler signature
async def handle_activation(
    widget_id: str,
    context: WidgetContext,
) -> Dict[str, Any]:
    """Handle widget activation.

    Args:
        widget_id: ID of activated widget
        context: Widget context with services

    Returns:
        Activation result (modal definition, new state, etc.)
    """
    return {
        "type": "modal",
        "title": "My Widget Actions",
        "options": [
            {"label": "Action 1", "action": "action_1"},
            {"label": "Action 2", "action": "action_2"},
        ]
    }
```

### Widget Registration (Script)

```bash
#!/bin/bash
# widget-id: my-widget
# name: My Widget
# description: Does something cool
# category: custom
# interactive: true
# interaction-type: action
# on-activate: ./my-widget-actions.sh
# refresh: 10s
# hooks: post_user_input
# min-width: 12
# timeout: 5s

# Your widget rendering code
echo "📊 $(my-command)"
```

### Navigation Manager API

```python
class StatusNavigationManager:
    """Manages navigation state in status area."""

    def activate_navigation(self) -> None:
        """Enter navigation mode (Tab pressed)."""

    def deactivate_navigation(self) -> None:
        """Exit navigation mode (ESC pressed)."""

    def move_selection(self, direction: str) -> None:
        """Move selection (up/down/left/right)."""

    def activate_widget(self) -> None:
        """Activate selected widget (Enter pressed)."""

    def get_selected_widget(self) -> Optional[StatusWidget]:
        """Get currently selected widget."""

    def handle_keypress(self, key: KeyPress) -> bool:
        """Handle keyboard input in navigation mode.

        Returns:
            True if key was handled, False otherwise
        """
```

### Script Output Format

**Simple text output:**
```bash
echo "⎇ main"
```

**ANSI color output:**
```bash
echo "\033[32m⎇ main\033[0m"  # Green branch name
```

**Modal definition (JSON):**
```json
{
  "type": "modal",
  "title": "Actions",
  "options": [
    {
      "label": "Do Thing",
      "command": ["script.sh", "arg"],
      "confirm": true,
      "display": "terminal"
    }
  ]
}
```

**Action result (JSON):**
```json
{
  "success": true,
  "message": "Action completed",
  "output": "Command output here..."
}
```

---

## Security Considerations

**Security Model: Trust Local Scripts, Validate Input**

This is a local development tool for developers. Security approach is practical, not paranoid.

### Script Execution Safety

1. **Timeout Protection** (Implemented)
   - All scripts run with 5s default timeout (configurable)
   - Process killed with SIGTERM, then SIGKILL if needed
   - Prevents runaway scripts from blocking terminal

2. **Input Validation** (Implemented)
   - User input sanitized before passing to scripts
   - Whitelist approach for action commands
   - No shell interpolation of user input

3. **Path Restrictions** (Implemented)
   - Scripts must be in designated directories:
     - `~/.kollabor-cli/status-widgets/` (global)
     - `.kollabor-cli/status-widgets/` (project)
   - No symlinks to system directories
   - Validate shebang exists and is executable

4. **Command Injection Prevention**
   - Action widgets use parameterized commands, NOT shell expansion
   - Example: `["git", "checkout", input]` ✓ (safe)
   - Example: `f"git checkout {input}"` ✗ (NEVER do this)

### User Trust Model

**Local developer tool assumptions:**
- User writes their own scripts OR reviews downloaded scripts
- Scripts run with user's permissions (like any shell script)
- Users who want sandboxing can run Kollabor in Docker/VM
- No enterprise-grade sandboxing needed for personal dev tool

**What we DO protect against:**
- Accidental infinite loops (timeout)
- Command injection from user input (parameterized commands)
- Typos in destructive commands (confirmation prompts)

**What we DON'T protect against:**
- Malicious scripts user intentionally runs
- User downloading untrusted scripts
- Fork bombs or resource exhaustion (user's responsibility)

**Future enhancements (if community requests):**
- Script signing/verification
- Community widget repository with reviews
- Opt-in sandboxing (cgroups, namespaces)

### Practical Security Guidelines

For users creating widgets:

```bash
#!/bin/bash
# widget-id: safe-example

# GOOD: Validate inputs
if [[ ! "$1" =~ ^[a-zA-Z0-9_-]+$ ]]; then
    echo "Invalid input"
    exit 1
fi

# GOOD: Use parameterized commands
git checkout "$1"

# BAD: Shell expansion (command injection risk)
# eval "git checkout $1"  # NEVER DO THIS
```

For Kollabor implementation:

```python
# GOOD: Parameterized subprocess call
await subprocess.run(["git", "checkout", user_input])

# BAD: Shell interpolation
# await subprocess.run(f"git checkout {user_input}", shell=True)
```

---

## Configuration

### User Configuration

`~/.kollabor-cli/config.json`:
```json
{
  "status_widgets": {
    "script_directories": [
      "~/.kollabor-cli/status-widgets",
      ".kollabor-cli/status-widgets"
    ],
    "script_timeout_ms": 5000,
    "enable_ansi_colors": true,
    "navigation": {
      "tab_key_enabled": true,
      "show_interactive_indicators": true,
      "selection_highlight_style": "box"
    },
    "refresh": {
      "max_concurrent_scripts": 5,
      "cache_ttl_seconds": 60
    }
  }
}
```

### Widget Configuration

Per-widget config in layout manager:
```json
{
  "rows": [
    {
      "widgets": [
        {
          "id": "git-branch",
          "width": null,
          "config": {
            "show_dirty": true,
            "show_ahead_behind": true,
            "refresh_interval": "5s"
          }
        }
      ]
    }
  ]
}
```

---

## Examples

### Example 1: Git Status Widget

**Script:** `~/.kollabor-cli/status-widgets/git-status.sh`
```bash
#!/bin/bash
# widget-id: git-status
# name: Git Status
# description: Shows git repository status
# category: git
# interactive: true
# interaction-type: modal
# on-activate: ./git-status-modal.sh
# refresh: on-event
# hooks: post_user_input
# min-width: 20

if ! git rev-parse --git-dir > /dev/null 2>&1; then
    echo "no git"
    exit 0
fi

# Get branch name or detached HEAD state
branch=$(git branch --show-current 2>/dev/null)
if [ -z "$branch" ]; then
    # Detached HEAD - show short commit hash
    branch=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")
    branch="detached@${branch}"
fi

dirty=""
ahead=""
behind=""

# Check for uncommitted changes (working tree + index)
if ! git diff --quiet 2>/dev/null || ! git diff --cached --quiet 2>/dev/null; then
    dirty="*"
fi

# Check for ahead/behind (skip if detached)
if [[ ! "$branch" =~ ^detached@ ]]; then
    upstream=$(git rev-parse --abbrev-ref --symbolic-full-name @{u} 2>/dev/null)
    if [ -n "$upstream" ]; then
        ahead_count=$(git rev-list --count "${upstream}..HEAD" 2>/dev/null || echo "0")
        behind_count=$(git rev-list --count "HEAD..${upstream}" 2>/dev/null || echo "0")

        [ "$ahead_count" != "0" ] && ahead="↑$ahead_count"
        [ "$behind_count" != "0" ] && behind="↓$behind_count"
    fi
fi

# NOTE: Use design system theme colors in production
# For scripts, get colors from environment or config
# This example shows hardcoded colors for clarity
GREEN='\033[32m'
RED='\033[31m'
YELLOW='\033[33m'
RESET='\033[0m'

echo -e "${GREEN}⎇${RESET} ${branch}${RED}${dirty}${RESET} ${YELLOW}${ahead}${behind}${RESET}"
```

**Modal:** `git-status-modal.sh`
```bash
#!/bin/bash

cat <<EOF
{
  "title": "Git Status & Actions",
  "options": [
    {
      "label": "View Full Status",
      "command": ["git", "status"],
      "display": "terminal"
    },
    {
      "label": "View Diff",
      "command": ["git", "diff"],
      "display": "terminal"
    },
    {
      "label": "Pull Latest",
      "command": ["git", "pull"],
      "confirm": true,
      "message": "Pull from remote?"
    },
    {
      "label": "Push Changes",
      "command": ["git", "push"],
      "confirm": true,
      "message": "Push to remote?"
    },
    {
      "label": "Commit All",
      "input": "commit_message",
      "input_label": "Commit message:",
      "action": ["git", "commit", "-am", "{input}"]
    }
  ]
}
EOF
```

### Example 2: Docker Status Widget

**Script:** `~/.kollabor-cli/status-widgets/docker-status.sh`
```bash
#!/bin/bash
# widget-id: docker-status
# name: Docker Status
# description: Shows running container count
# category: docker
# interactive: true
# interaction-type: action
# on-activate: ./docker-actions.sh
# refresh: 10s
# min-width: 10

if ! command -v docker &> /dev/null; then
    echo "no docker"
    exit 0
fi

running=$(docker ps -q 2>/dev/null | wc -l | tr -d ' ')
total=$(docker ps -aq 2>/dev/null | wc -l | tr -d ' ')

BLUE='\033[34m'
RESET='\033[0m'

echo -e "${BLUE}🐳${RESET} ${running}/${total}"
```

**Actions:** `docker-actions.sh`
```bash
#!/bin/bash
# $1 = action key

case "$1" in
  "l")  # List containers
    docker ps -a
    ;;
  "s")  # Stop all running
    read -p "Stop all containers? (y/N) " confirm
    if [ "$confirm" = "y" ]; then
        docker stop $(docker ps -q)
        echo "All containers stopped"
    fi
    ;;
  "c")  # Clean up stopped
    docker container prune -f
    echo "Stopped containers removed"
    ;;
  *)
    cat <<EOF
Docker Actions:
  [l] List all containers
  [s] Stop all running containers
  [c] Clean up stopped containers
EOF
    ;;
esac
```

### Example 3: Python Environment Widget

**Script:** `~/.kollabor-cli/status-widgets/python-env.sh`
```bash
#!/bin/bash
# widget-id: python-env
# name: Python Environment
# description: Shows active Python environment
# category: python
# interactive: false
# refresh: once
# min-width: 15

if [ -n "$VIRTUAL_ENV" ]; then
    env_name=$(basename "$VIRTUAL_ENV")
    python_ver=$(python --version 2>&1 | cut -d' ' -f2)
    echo "🐍 ${env_name} (${python_ver})"
elif [ -n "$CONDA_DEFAULT_ENV" ]; then
    python_ver=$(python --version 2>&1 | cut -d' ' -f2)
    echo "🐍 ${CONDA_DEFAULT_ENV} (${python_ver})"
else
    echo "🐍 system"
fi
```

### Example 4: Custom Project Health Widget

**Script:** `.kollabor-cli/status-widgets/project-health.sh`
```bash
#!/bin/bash
# widget-id: project-health
# name: Project Health
# description: Shows project health metrics
# category: project
# interactive: true
# interaction-type: modal
# on-activate: ./project-health-modal.sh
# refresh: 30s
# min-width: 20

# Calculate health score based on various factors
score=100

# Check for uncommitted changes (-10)
if ! git diff --quiet 2>/dev/null; then
    score=$((score - 10))
fi

# Check for failing tests (-20)
if [ -f "pytest.ini" ]; then
    if ! pytest --quiet 2>/dev/null; then
        score=$((score - 20))
    fi
fi

# Check for TODO/FIXME count (-1 per 10)
todo_count=$(grep -r "TODO\|FIXME" . --exclude-dir=node_modules --exclude-dir=.git 2>/dev/null | wc -l)
score=$((score - (todo_count / 10)))

# Clamp to 0-100
score=$((score < 0 ? 0 : score))

# Color based on score
if [ $score -ge 80 ]; then
    color='\033[32m'  # Green
elif [ $score -ge 50 ]; then
    color='\033[33m'  # Yellow
else
    color='\033[31m'  # Red
fi

echo -e "${color}❤️ ${score}%\033[0m health"
```

---

## Testing

### Unit Tests

```python
# tests/unit/test_status_navigation.py

class TestStatusNavigation:
    def test_tab_activates_navigation(self):
        """Tab key should activate navigation mode."""
        manager = StatusNavigationManager()
        assert not manager.state.active

        manager.handle_keypress(KeyPress(name="Tab"))
        assert manager.state.active

    def test_arrow_keys_move_selection(self):
        """Arrow keys should move selection."""
        manager = StatusNavigationManager()
        manager.activate_navigation()

        initial_row = manager.state.selected_row
        manager.move_selection("down")
        assert manager.state.selected_row == initial_row + 1

    def test_enter_activates_widget(self):
        """Enter should activate selected widget."""
        manager = StatusNavigationManager()
        manager.activate_navigation()

        activated = []
        manager.on_widget_activated.subscribe(
            lambda w: activated.append(w)
        )

        manager.activate_widget()
        assert len(activated) == 1
```

### Integration Tests

```python
# tests/integration/test_script_widgets.py

class TestScriptWidgets:
    def test_script_discovery(self, tmp_path):
        """Scripts should be discovered from directory."""
        script_dir = tmp_path / "status-widgets"
        script_dir.mkdir()

        script = script_dir / "test-widget.sh"
        script.write_text("""#!/bin/bash
# widget-id: test-widget
# name: Test Widget
echo "test output"
""")
        script.chmod(0o755)

        manager = ScriptWidgetManager([str(script_dir)])
        widgets = manager.discover_widgets()

        assert len(widgets) == 1
        assert widgets[0].id == "test-widget"

    def test_script_execution(self, tmp_path):
        """Script should execute and return output."""
        script = tmp_path / "widget.sh"
        script.write_text("""#!/bin/bash
echo "hello world"
""")
        script.chmod(0o755)

        manager = ScriptWidgetManager()
        output = manager.execute_script(str(script))

        assert output.strip() == "hello world"

    def test_script_timeout(self, tmp_path):
        """Script should timeout if too slow."""
        script = tmp_path / "slow.sh"
        script.write_text("""#!/bin/bash
sleep 10
echo "done"
""")
        script.chmod(0o755)

        manager = ScriptWidgetManager(timeout=1)
        with pytest.raises(TimeoutError):
            manager.execute_script(str(script))
```

---

## Documentation

### User Guide

Location: `docs/user-guide/interactive-status-widgets.md`

Content:
- How to navigate status area
- How to activate widgets
- Available keyboard shortcuts
- Creating custom script widgets
- Examples and templates

### Developer Guide

Location: `docs/developer-guide/creating-interactive-widgets.md`

Content:
- Widget API reference
- Creating widgets in Python
- Creating script-based widgets
- Best practices
- Security considerations

### Migration Guide

Location: `docs/migration/status-widget-migration.md`

Content:
- Migrating existing status views to new system
- Compatibility notes
- Deprecation timeline

---

## Future Enhancements

### Phase 6: Advanced Features

1. **Widget Groups**
   - Collapsible widget groups
   - Tabbed widget areas
   - Custom layouts

2. **Widget Communication**
   - Widgets can send events to each other
   - Shared state between widgets
   - Widget dependencies

3. **Remote Widgets**
   - HTTP endpoint widgets
   - WebSocket real-time widgets
   - Cloud-based widget registry

4. **Widget Marketplace**
   - Community widget repository
   - One-click installation
   - Rating and reviews
   - Automatic updates

5. **Advanced Interactions**
   - Drag-and-drop reordering
   - Split-screen widget views
   - Mini-chart widgets (sparklines)
   - Progress bar widgets

---

## Success Metrics

### User Adoption
- % of users with custom script widgets
- Average number of widgets per user
- Widget interaction frequency

### Performance
- Script execution time (p50, p95, p99)
- Navigation responsiveness (<50ms)
- Memory usage (<10MB overhead)

### Reliability
- Script failure rate
- Timeout frequency
- Error recovery success rate

---

## Appendix

### Appendix A: Complete Script Template

```bash
#!/bin/bash
# ========================================
# Kollabor Status Widget Template
# ========================================
# Copy this template to create custom widgets

# REQUIRED METADATA
# widget-id: my-unique-widget-id
# name: My Widget Name
# description: Brief description of what this widget shows

# OPTIONAL METADATA
# category: custom
# interactive: false
# interaction-type: modal
# on-activate: ./my-widget-modal.sh
# refresh: manual
# hooks:
# min-width: 10
# timeout: 5s
# color: true

# ========================================
# Widget Rendering Logic
# ========================================
# Output to stdout becomes widget content
# Use ANSI color codes if color: true
# Keep output concise (fits in min-width)

# Example:
echo "📊 42"

# With colors:
# GREEN='\033[32m'
# RESET='\033[0m'
# echo -e "${GREEN}✓${RESET} ready"
```

### Appendix B: Modal Handler Template

```bash
#!/bin/bash
# Modal handler for interactive widget
# Output JSON defining modal structure

cat <<EOF
{
  "title": "Widget Actions",
  "options": [
    {
      "label": "Action 1",
      "command": ["echo", "Hello"],
      "display": "terminal"
    },
    {
      "label": "Action 2 (with confirmation)",
      "command": ["rm", "-rf", "/tmp/test"],
      "confirm": true,
      "message": "Are you sure?"
    },
    {
      "label": "Action 3 (with input)",
      "input": "user_input",
      "input_label": "Enter value:",
      "action": ["echo", "You entered: {input}"]
    }
  ]
}
EOF
```

### Appendix C: Error Handling Examples

```bash
#!/bin/bash
# widget-id: robust-widget
# Error handling best practices

# Exit code meanings:
# 0 = success
# 1 = general error (widget shows error state)
# 2 = temporary error (widget shows last good value)
# 3 = not applicable (widget hidden)

# Check if command exists
if ! command -v git &> /dev/null; then
    echo "git not installed"
    exit 3  # Hide widget
fi

# Check if we're in a git repo
if ! git rev-parse --git-dir > /dev/null 2>&1; then
    echo "no git"
    exit 0  # Show "no git" message
fi

# Try to get branch, handle errors
branch=$(git branch --show-current 2>/dev/null)
if [ $? -ne 0 ]; then
    echo "git error"
    exit 1  # Show error state
fi

echo "⎇ ${branch}"
exit 0
```

---

## Changelog

**v1.2 (2026-01-19) - Edit Mode UI Revision**

Major UI/UX improvements based on user feedback:

**Navigation Mode Changes:**
- Input box now **hidden** when in navigation mode (not just blurred)
- Tab moves to status area and immediately hides input box
- Esc from navigation returns to input mode and shows input box again

**New Edit Mode:**
- Press `e` from Navigation Mode to enter Edit Mode
- Mode indicator changes from "NAVIGATE" to "EDIT"
- Slots (+ symbols) appear between widgets for adding new widgets
- Empty rows become visible (all available rows shown)
- Arrow keys navigate between both widgets AND slots
- Enter on a slot opens Widget Picker to add widget at that position
- `d` key deletes selected widget (with confirmation if last in row)
- `c` key toggles widget background color (cycles through color options)
- Esc returns to Navigation Mode (hides slots and empty rows)

**Visual Design Changes:**
- Removed triangle indicator (▸) from interactive widgets for cleaner appearance
- Added slot rendering with "+" symbol (only visible in Edit Mode)
- Added widget background color toggle functionality
- Updated mode indicator to show INPUT/NAVIGATE/EDIT states

**Mode Transition Diagram:**
```
INPUT --[Tab]--> NAVIGATE --[e]--> EDIT
                    |                |
                    |<---[Esc]-------|
                    |
INPUT <---[Esc]-----|
```

---

**v1.1 (2026-01-18) - Critical Review Integration**

Based on comprehensive review by 10 specialized agents, major revisions:

**Architecture & State Management:**
- Added asyncio.Lock to StatusNavigationState for thread-safe mutations
- Defined MessageDisplayCoordinator integration to prevent render conflicts
- Added navigation_active flag to coordinator
- Documented state machine transitions

**Visual Design:**
- Rewritten to use existing design system (solid(), TagBox, T() theme)
- Replaced ASCII brackets with solid block selection highlights
- Added mode indicator (INPUT/NAVIGATE/INTERACT) always visible
- Fixed all visual examples to use design system correctly

**User Experience:**
- Added First-Run Help modal (shows once)
- Added F1/? help overlay (accessible anytime)
- Added Ctrl+Z undo for toggles/edits
- Fixed Esc behavior (always returns to Input Mode, single-level)
- Added Quick Start section (30-second widget creation)

**Security:**
- Updated security model to practical "trust local scripts" approach
- Emphasized input validation and parameterized commands
- Removed over-engineering (sandboxing deferred to future/optional)
- Added practical security guidelines for widget creators

**Examples:**
- Fixed git-status.sh to handle detached HEAD correctly
- Added staged changes check (--cached)
- Fixed ahead/behind count syntax
- Added note about design system colors in scripts

**Documentation:**
- Added Quick Start section at beginning
- Added First-Run Discovery & Help section
- Added MessageDisplayCoordinator Integration section
- Updated implementation timeline (Week 1-2 instead of Week 1)
- Improved code examples with proper imports

**Implementation Plan:**
- Phase 1 extended to 1-2 weeks (from 1 week)
- Added MessageDisplayCoordinator integration to Phase 1
- Added first-run help to Phase 1 deliverables
- Emphasized design system compliance throughout

**v1.0 (2026-01-18) - Initial Specification**
- Complete navigation system design
- Four widget interaction types
- Script-based widget system
- Implementation plan with 5 phases
- Comprehensive examples and templates

---

## References

- [Status Widget Registry](../../core/io/status/widget_registry.py)
- [Status Setup Plugin](../../plugins/fullscreen/status_setup_plugin.py)
- [Core Status Widgets](../../core/io/status/core_widgets.py)
- [Input Handler](../../core/io/input_handler.py)
- [Event Bus](../../core/events/bus.py)
- [Design System](../../core/ui/design_system/)
- [Message Display Coordinator](../../core/io/message_coordinator.py)

---

**End of Specification**
