# Unified Terminal Plugin Specification

## Overview

**Replace**: `background_tasks` plugin + existing subprocess-based terminal execution

**With**: Enhanced `tmux` plugin as the single unified terminal solution

All terminal commands now use tmux as the execution backend. This provides:
- Full terminal capabilities (TTY, interactive tools, TUI apps)
- Unified execution model (both foreground and background)
- Collaborative visibility (user and AI can see/access sessions)
- Simplified architecture (one plugin instead of two)

## Goals

1. **Simplify Architecture**: Remove bg-tasks plugin, unify on tmux
2. **Enable Interactive Tools**: btop, htop, vim, debuggers work correctly
3. **Collaborative Debugging**: User and AI share visibility of sessions
4. **Backward Compatible**: `<terminal>` works as before when not using background

## Current Architecture (To Be Replaced)

```
LLM -> <terminal>cmd</terminal> -> ResponseParser -> ToolExecutor -> ShellExecutor
                                              -> asyncio subprocess (no TTY)

Background Tasks Plugin (separate):
LLM -> <bg>cmd</bg> -> BackgroundTasksPlugin -> ProcessExecutor
                                              -> asyncio subprocess (no TTY)

Tmux Plugin (separate):
User -> /terminal command -> TmuxPlugin -> tmux subprocess (TTY)
```

## New Architecture (Unified)

```
LLM -> <terminal background="true" name="session">cmd</terminal>
     -> ResponseParser -> ToolExecutor -> TmuxTerminalExecutor
                                        -> tmux new-session (TTY)

User -> /terminal list/view/kill -> TmuxPlugin -> tmux commands
```

All terminal execution goes through tmux, just with different lifecycles.

## XML Syntax

### Foreground Execution (default behavior)

```xml
<terminal>ls -la</terminal>
<terminal>cat file.py</terminal>
<terminal background="false">pytest tests/</terminal>
```

Behavior:
- Creates temporary tmux session (random name like "kollab-temp-abc123")
- Runs command in session
- Captures output when command exits
- Returns output to LLM
- **Session is destroyed** after capture
- No user visibility (just like current behavior)

### Background Execution

```xml
<terminal background="true" name="dev-server">npm run dev</terminal>
<terminal background="true" name="monitor">btop</terminal>
<terminal background="true" name="build" timeout="5m">npm run build:prod</terminal>
<terminal background="true">npm run dev</terminal>  <!-- auto-generated name -->
```

Attributes:
- `background="true"`: Mark as persistent background session
- `name="session-name"`: Optional. If omitted, auto-generated from first 10 chars of command + timestamp (e.g., "npm-run-dev-1737123456")
- `timeout="5m"`: Optional auto-kill after duration
- `cwd="/app"`: Optional working directory

Behavior:
- Creates named tmux session (persistent)
- Command runs in background
- LLM gets confirmation message, not output
- User can view with `/terminal view dev-server`
- User can interact live in modal view
- AI can capture snapshots or send keys
- Session persists until explicitly killed

### Background Status/Output

```xml
<terminal-status>*</terminal-status>        <!-- list all sessions -->
<terminal-status>dev-server</terminal-status>   <!-- specific session -->
<terminal-output lines="50">dev-server</terminal-output>   <!-- get output -->
<terminal-kill>dev-server</terminal-kill>                <!-- kill one -->
<terminal-kill>*</terminal-kill>                 <!-- kill all -->
```

Note: These are **optional** - user can also use `/terminal` slash commands.

## Examples

### Example 1: Simple Command (No Change)

```xml
User: "list files in current directory"

LLM: <terminal>ls -la</terminal>

[System executes]
- Creates temp tmux session: "kollab-temp-abc123"
- Runs: `ls -la`
- Captures output
- Destroys session
- Returns to LLM

[Response to LLM]
total 48
drwxr-xr-x@  15 malmazan  staff   480 Jan 17 17:27 .
drwxr-xr-x  156 malmazan  staff  4992 Jan 15 13:35 ..
...
```

### Example 2: Background Dev Server

```xml
User: "start the dev server"

LLM: <terminal background="true" name="dev-server">npm run dev</terminal>

[System executes]
- Creates named tmux session: "dev-server"
- Runs: `npm run dev` in background
- Session persists

[Response to LLM]
[started: dev-server] npm run dev...
The dev server is running in the background. 
Type '/terminal view dev-server' to see it live.

[User can now]
- Type: /terminal view dev-server
- See live logs in modal
- Use arrow keys, Ctrl+C to interact
- Press Esc to return to conversation
```

### Example 3: Interactive Tool (btop)

```xml
User: "run btop so we can monitor cpu while debugging"

LLM: <terminal background="true" name="monitor">btop</terminal>

[System executes]
- Creates named tmux session: "monitor"
- Runs: `btop` (requires terminal, now works correctly)
- Session persists with full terminal capabilities

[Response to LLM]
[started: monitor] btop...
btop is running. Type '/terminal view monitor' to see the live interface.
I can also capture snapshots or interact with it.

[User types]
User: /terminal view monitor

[Sees live btop interface in modal]
- Arrow keys navigate, q to quit
- Alt+Left/Right to switch to other sessions
- Esc to return to conversation

[LLM can also interact]
LLM: Let me switch to memory view.
<terminal-send-keys>monitor k Enter</terminal-send-keys>

[System sends keys to session]
</terminal-send-keys> becomes optional XML tag for AI control
```

### Example 4: Collaborative Debugging

```xml
User: "I'm seeing errors in the build. Let's run it and watch together."

LLM: <terminal background="true" name="build" timeout="15m">npm run build:prod</terminal>

[started: build] npm run build:prod...

[User watches live]
User: /terminal view build

[Sees build progress, errors appear]

User: "Hey, look at the errors!"

LLM: <terminal-output lines="30">build</terminal-output>

[Captures snapshot]
[output: build, 30 lines]
✓ Built in 24.3s
✗ Module not found: '@types/react'
...
error: Command failed with exit code 1.

LLM: I see the issue. Missing TypeScript types. Let me fix that.
<terminal>npm install --save-dev @types/react @types/react-dom</terminal>

[Fix applied]
LLM: Try running the build again.

User: /terminal view build
[Now sees build passing]
```

### Example 5: Session Management

```xml
User: "What's running in the background?"

LLM: <terminal-status>*</terminal-status>

[bg-sessions]
  [*] dev-server    running    5m23s
  [*] monitor       running    2m10s
  [*] build         failed     0m45s

User: "Kill the monitor, I'm done debugging."

LLM: <terminal-kill>monitor</terminal-kill>

[killed: monitor]

User: "Check what's left."

LLM: <terminal-status>*</terminal-status>

[bg-sessions]
  [*] dev-server    running    5m28s
  [ ] build         failed     0m50s
```

## Implementation Details

### Session Naming Strategy

**Background Sessions (persistent):**
```python
# Pattern: {sanitized_command[:8]}-{timestamp}
import time
import re

def generate_session_name(command: str) -> str:
    sanitized = re.sub(r'[^a-zA-Z0-9]', '-', command)[:8]
    timestamp = str(int(time.time()))[-6:]  # Last 6 digits
    return f"{sanitized}-{timestamp}"

Examples:
  "npm run dev"      -> "npm-run-d-7123456"
  "pytest tests/"     -> "pytest-t-7123456"
  "python -m http.server" -> "python-m--7123456"
```

**Foreground Sessions (temporary):**
```python
# Pattern: kollab-temp-{random_8_chars}
import secrets

def generate_temp_name() -> str:
    return f"kollab-temp-{secrets.token_hex(4)}"

Examples:
  "kollab-temp-a3f2b1c9"
  "kollab-temp-7e8d3f2a1"
```

### Configuration Structure

**New Section: `config.terminal`**
```json
{
  "terminal": {
    "timeout": 90,
    "tmux_server": "kollabor",
    "use_separate_server": true,
    "kill_on_shutdown": false,
    "capture_lines": 200,
    "refresh_rate": 2.0
  }
}
```

**Migration Path:**
```python
# In TmuxPlugin.__init__
def _get_tmux_server(self) -> str:
    # Try new location first (spec-defined)
    if self.config.get("terminal.tmux_server"):
        return self.config.get("terminal.tmux_server")
    # Fall back to old location (backward compatibility)
    return self.config.get("plugins.tmux.socket_name", "kollabor")
```

### Integration Pattern: Delegation

**TmuxPlugin Public API:**
```python
class TmuxPlugin:
    def __init__(...):
        self.sessions = {}  # Central registry for all sessions
    
    # Public API for ToolExecutor
    def create_session(self, name: str, command: str, 
                    timeout: str = None, cwd: str = None) -> dict:
        """Create tmux session, add to registry."""
        # Implementation details...
    
    def execute_foreground(self, command: str, timeout: int) -> dict:
        """Execute command in temp session, capture output, destroy."""
        # Implementation details...
    
    def get_session(self, name: str) -> Optional[dict]:
        """Get session from registry."""
        return self.sessions.get(name)
    
    def capture_output(self, name: str, lines: int = 50) -> list:
        """Capture pane content."""
        # Implementation details...
    
    def send_keys(self, name: str, keys: str) -> None:
        """Send keys to session."""
        # Implementation details...
    
    def kill_session(self, name: str, signal: str = "SIGTERM") -> bool:
        """Kill session, remove from registry."""
        # Implementation details...
```

**ToolExecutor Integration:**
```python
class ToolExecutor:
    def __init__(..., tmux_plugin: TmuxPlugin):
        self.tmux = tmux_plugin  # Dependency injected
    
    async def _execute_terminal_command(self, tool_data: dict):
        command = tool_data.get("command")
        
        if tool_data.get("background"):
            # Persistent session
            result = await self.tmux.create_session(
                name=tool_data.get("name") or self._generate_name(command),
                command=command,
                timeout=tool_data.get("timeout"),
                cwd=tool_data.get("cwd")
            )
            return ToolExecutionResult(
                tool_id="terminal",
                tool_type="terminal",
                success=result["success"],
                output=f"[started: {result['name']}] {command[:50]}..."
            )
        else:
            # Foreground execution
            result = await self.tmux.execute_foreground(
                command=command,
                timeout=self.terminal_timeout
            )
            return ToolExecutionResult(
                tool_id="terminal",
                tool_type="terminal",
                success=result["success"],
                output=result["output"],
                error=result.get("error")
            )
```

### Attribute Parsing Strategy

**Regex-based Parsing (consistent with existing patterns):**
```python
# In ResponseParser
TERMINAL_ATTR_PATTERN = re.compile(
    r'<terminal\s+([^>]*?)>(.*?)</terminal>',
    re.DOTALL | re.IGNORECASE
)

def _parse_terminal_tag(self, match) -> dict:
    attrs_str = match.group(1)
    command = match.group(2)
    
    # Extract attributes
    background = re.search(r'background\s*=\s*["\']([^"\']+)["\']', attrs_str)
    name = re.search(r'name\s*=\s*["\']([^"\']+)["\']', attrs_str)
    timeout = re.search(r'timeout\s*=\s*["\']([^"\']+)["\']', attrs_str)
    cwd = re.search(r'cwd\s*=\s*["\']([^"\']+)["\']', attrs_str)
    
    return {
        "background": bool(background.group(1) == "true") if background else False,
        "name": name.group(1) if name else None,
        "timeout": timeout.group(1) if timeout else None,
        "cwd": cwd.group(1) if cwd else None,
        "command": command.strip()
    }
```

### Implementation Phases

**All phases implemented together (atomic refactor):**

```
Phase 1: Core Changes
  1. Update ResponseParser (add attribute extraction)
  2. Create TmuxTerminalExecutor (delegates to TmuxPlugin)
  3. Update ToolExecutor (use TmuxTerminalExecutor)

Phase 2: TmuxPlugin Integration
  1. Add public API methods to TmuxPlugin
  2. Wire ToolExecutor to TmuxPlugin (dependency injection)
  3. Update event emissions

Phase 3: Cleanup
  1. Remove bg-tasks plugin references
  2. Update configuration handling (migration path)
  3. Delete plugins/background_tasks/
```

Rationale for atomic implementation:
- Spec treats this as single breaking change
- Phases are interdependent (parser -> executor -> tmux integration)
- Incremental changes leave broken intermediate state
- Easier to test as complete unit

## User Commands (Slash)

These remain **unchanged** from current tmux plugin:

### `/terminal` (aliases: `/term`, `/tmux`, `/t`)

```
/terminal list                          # List background sessions
/terminal view [name]                   # View session live (modal)
/terminal kill <name>                   # Kill session
/terminal new <name> <command>          # Create background session manually
```

## Implementation Plan

### Phase 1: Core Changes

1. **Modify ResponseParser**
   - Update `terminal_pattern` to extract `background`, `name`, `timeout`, `cwd` attributes
   - Add new patterns: `terminal-status`, `terminal-output`, `terminal-kill`, `terminal-send-keys`

2. **Create TmuxTerminalExecutor**
   - Replace ShellExecutor for terminal tool execution
   - Methods:
     - `execute_foreground(command, cwd)` - temp session, capture, destroy
     - `execute_background(name, command, timeout, cwd)` - persistent session
     - `get_status(name)` - check session state
     - `get_output(name, lines)` - capture pane
     - `kill_session(name, signal)` - kill session
     - `send_keys(name, keys)` - send input to session

3. **Update ToolExecutor**
   - Replace `ShellExecutor` with `TmuxTerminalExecutor`
   - Handle foreground/background modes
   - Emit appropriate events

### Phase 2: Integrate with TmuxPlugin

1. **Shared Registry**
   - TmuxPlugin becomes the central session registry
   - ToolExecutor delegates to TmuxPlugin for session management
   - Both user commands and LLM tools access same sessions

2. **Event Integration**
   - Session started/killed events
   - Status updates for UI widgets

3. **Cleanup**
   - Delete `plugins/background_tasks/` directory
   - Remove bg-tasks plugin references from config
   - Update documentation

### Phase 3: XML Tag Expansion

Optional tags for AI interaction:

```xml
<terminal-send-keys>session-name keys-to-send</terminal-send-keys>
```

Allows AI to send keys to background sessions (e.g., navigating btop, restarting services).

## Migration Guide

### For LLM System Prompt

Replace bg-tasks instructions with unified terminal instructions:

```xml
<sys_msg>
terminal commands

run shell commands using the <terminal> tag.

simple commands (foreground):
  <terminal>ls -la</terminal>
  <terminal>cat file.py</terminal>
  [output returned directly to response]

background tasks (persistent sessions):
  <terminal background="true" name="dev-server">npm run dev</terminal>
  <terminal background="true">btop</terminal>  [name auto-generated: "btop-1737123456"]
  [session persists, user can view with /terminal view]

attributes:
  background   "true" = persistent session, "false" = one-shot (default)
  name         session identifier (optional for background, auto-generated if omitted)
  timeout       auto-kill after duration (30s, 5m, 1h)
  cwd           working directory

session management:
  <terminal-status>*</terminal-status>                          list all sessions
  <terminal-status>session-name</terminal-status>   specific session status
  <terminal-output lines="50">session</terminal-output>   get output
  <terminal-kill>session</terminal-kill>               kill session
</sys_msg>
```

### For Users

No change in behavior for simple commands:
- `<terminal>ls</terminal>` works exactly as before

New capability for interactive/background:
- Can now run btop, htop, vim, debuggers
- User can view live sessions with `/terminal view`
- Collaborative debugging possible

### For Developers

- Remove dependency on bg-tasks plugin
- All terminal logic now in tmux plugin
- Single source of truth for session management

## Comparison: Before vs After

### Before (Separate Systems)

```
Simple Commands:
  <terminal>ls</terminal>
  -> ShellExecutor -> subprocess (no TTY)
  -> Returns output directly

Background Tasks:
  <bg>npm run dev</bg>
  -> BackgroundTasksPlugin -> ProcessExecutor -> subprocess (no TTY)
  -> Buffered output, no viewing, no interaction

Tmux Sessions:
  /terminal new server npm run dev
  -> TmuxPlugin -> tmux (TTY)
  -> Live viewing, but separate from LLM workflow
```

Limitations:
- bg-tasks can't run interactive tools
- No collaborative visibility between LLM and user
- Three separate code paths to maintain
- Confusing which tool to use when

### After (Unified)

```
All Commands via Tmux:

  <terminal>ls</terminal>
  -> TmuxTerminalExecutor -> temp tmux session (TTY)
  -> Captures output, destroys session
  -> Returns output (identical behavior)

  <terminal background="true" name="dev-server">npm run dev</terminal>
  -> TmuxTerminalExecutor -> named tmux session (TTY)
  -> Session persists
  -> User views with /terminal view, LLM can capture/snapshot

  <terminal background="true" name="monitor">btop</terminal>
  -> TmuxTerminalExecutor -> named tmux session (TTY)
  -> btop works correctly (has terminal)
  -> Interactive live viewing
```

Benefits:
- All tools work (including TUI apps)
- User and AI share visibility
- Single code path to maintain
- Clear usage model (background attribute = persistent)

## Edge Cases

### Session Name Collision

```xml
<terminal background="true" name="server">npm run dev</terminal>
[started: server]

[Later]
<terminal background="true" name="server">python manage.py runserver</terminal>
[error: session 'server' already exists. Kill it first or use a different name.]

[Or auto-generate if no name]
<terminal background="true">npm run dev</terminal>
[started: npm-run-dev-1737123456]
```

### Foreground Timeout

```xml
<terminal>sleep 100</terminal>
[error: Command timed out after 90s]
```

(Auto-timeout remains same as current behavior)

### Background Timeout

```xml
<terminal background="true" name="task" timeout="30s">long-running-task</terminal>
[started: task] long-running-task
[auto-killed after 30s]
```

### Session Auto-Cleanup

On kollabor shutdown:
- All foreground sessions already destroyed
- Prompt user: "Kill 2 background sessions (dev-server, monitor)? [y/N]"
- Or configurable: `terminal.kill_on_shutdown: true`

## Configuration

### Configuration Options

```json
{
  "terminal": {
    "timeout": 90,                   // Foreground command timeout (seconds)
    "tmux_server": "kollabor",        // Tmux server name (default: isolated)
    "use_separate_server": true,        // Don't mix with user's tmux
    "kill_on_shutdown": false,          // Prompt or auto-kill bg sessions
    "capture_lines": 200,              // Lines to capture from foreground
    "refresh_rate": 2.0                // Live view refresh rate (seconds)
  }
}
```

### Tmux Server Options

Two settings control tmux server behavior:

1. **tmux_server**: Name of the tmux server
   - Default: "kollabor" (creates isolated server)
   - Set to empty string "" to use your main tmux
   - Set to custom name for multi-agent isolation

2. **use_separate_server**: Whether to use isolated server
   - Default: true (recommended)
   - Set to false to share sessions with your tmux

### Usage Examples

**Default setup (isolated, recommended):**
```json
{
  "terminal": {
    "tmux_server": "kollabor",
    "use_separate_server": true
  }
}
```

**Multi-agent isolation (prevent conflicts):**
```json
{
  // Agent 1
  "terminal": {
    "tmux_server": "ravenquest"
  }
}

{
  // Agent 2  
  "terminal": {
    "tmux_server": "cryptoloop"
  }
}
```

**Use your main tmux (no isolation):**
```json
{
  "terminal": {
    "tmux_server": "",
    "use_separate_server": false
  }
}
```

### Why Use Separate Server?

Benefits of isolated server:
- Multiple agents can run simultaneously without session name conflicts
- Sessions don't clutter your personal tmux session list
- Clean separation between kollabor and your tmux workflow
- Safer for automated/background processes

When to use your main tmux:
- You want to attach to sessions from outside kollabor
- You're using kollabor within an existing tmux session
- You want kollabor sessions to appear in your tmux list

## Testing

### Unit Tests

1. `TmuxTerminalExecutor` tests
   - Foreground execution with capture
   - Background session creation
   - Output capture and cleanup

2. `ResponseParser` tests
   - Attribute extraction (background, name, timeout)
   - New tag patterns (status, output, kill)

### Integration Tests

1. Simple command (no attributes)
2. Background session with interactive tool (btop)
3. Session listing and viewing
4. Collaborative debugging workflow

### Manual Tests

```bash
# Test simple command
kollab "list files" -> <terminal>ls</terminal>

# Test background server
kollab "start dev server" -> <terminal background="true" name="dev">npm run dev</terminal>
# Then: /terminal view dev

# Test interactive tool
kollab "run btop" -> <terminal background="true" name="btop">btop</terminal>
# Then: /terminal view btop, verify keys work
```

## Cleanup and Migration

### What to Remove

**Delete Background Tasks Plugin:**
```
rm -rf /Users/malmazan/dev/kollabor-cli/plugins/background_tasks/
```

**Remove from Configuration:**
- Delete `plugins.background_tasks` section from config.json
- Remove any bg-tasks related settings

**Update Documentation:**
- Remove bg-tasks plugin references from README.md
- Remove docs/specs/background-tasks-plugin-spec.md
- Remove docs/plugins/core/background_tasks_plugin_spec.md
- Update CLAUDE.md with unified terminal instructions

### What Stays Unchanged

**Agent Orchestrator Plugin:**
- Location: `plugins/agent_orchestrator/`
- Status: **No changes needed**
- Reason: Already uses tmux sessions for sub-agent management
- Behavior: Continues working exactly as before

The agent_orchestrator uses tmux for sub-agent isolation, which is
independent of the background_tasks plugin. It will continue to work
without any modifications.

## Removal Checklist

- [ ] Delete `plugins/background_tasks/` directory
  ```bash
  rm -rf /Users/malmazan/dev/kollabor-cli/plugins/background_tasks/
  ```
- [ ] Remove bg-tasks plugin from auto-discovery
- [ ] Update config defaults (remove bg-tasks section)
- [ ] Update README and documentation
- [ ] Migrate any existing bg-tasks usage examples
- [ ] Update CHANGELOG with breaking changes

### Plugin Status After Migration

**Agent Orchestrator Plugin (`plugins/agent_orchestrator/`):**
- Status: **No changes needed**
- Reason: Already uses tmux sessions for sub-agent management
- Behavior: Continues working exactly as before

The agent_orchestrator uses tmux for sub-agent isolation, which is
independent of the background_tasks plugin. It will continue to work
without any modifications.

## Success Criteria

1. `<terminal>ls</terminal>` works exactly as before (foreground, no session)
2. `<terminal background="true" name="x">cmd</terminal>` creates persistent session
3. `/terminal view x` shows live session with keyboard interaction
4. btop, htop, vim work correctly in background sessions
5. User and AI can both see and interact with same session
6. Background tasks plugin completely removed
7. Documentation updated with new syntax
