Files
headquarter/openspec/changes/tool-terminal/specs/spec.md
T
Fusion e344e961d6 feat: implement web terminal for tool instances
- Add TerminalSession backend service for docker exec subprocess management
- Add TerminalManager for WebSocket session lifecycle management
- Create WebSocket endpoint at /ws/tool-instances/{id}/terminal
- Add session cookie authentication and instance ownership verification
- Install xterm.js with fit and web-links addons
- Create TerminalComponent with xterm.js integration
- Create TerminalPage with full-screen terminal view
- Add terminal route at /instances/:id/terminal
- Add terminal button to InstanceList for running instances
- Add terminal and arrow-left icons to icon registry
- Add comprehensive terminal CSS styles (dark theme, responsive)

Quality gates: typecheck ✓, lint ✓, build ✓, Python syntax ✓
2026-05-19 21:11:29 +02:00

3.6 KiB

Tool Terminal Specification

Requirements

Functional Requirements

  1. WebSocket Terminal: Provide terminal sessions via WebSocket at /ws/tool-instances/{instance_id}/terminal
  2. Terminal I/O: Stream stdin/stdout/stderr bidirectionally in real-time
  3. Terminal Resize: Support dynamic resize with COLS/ROWS updates
  4. Session Management: Multiple independent sessions per instance, cleanup on disconnect
  5. Access Control: Only instance owners can access, reject unauthorized with 403
  6. Shell Spawn: Spawn /bin/bash or /bin/sh inside container via docker exec

Non-Functional Requirements

  1. Latency: Character input to display < 50ms
  2. Concurrent Sessions: Support 10+ simultaneous terminal sessions
  3. Browser Support: Chrome, Firefox, Safari, Edge
  4. Container Lifecycle: Terminal closes when container stops

API Specification

WebSocket Endpoint

URL: wss://{api_host}/ws/tool-instances/{instance_id}/terminal

Protocol:

  • Connection requires valid session cookie
  • Binary frame: terminal output (stdout/stderr)
  • Text frame: control messages (JSON)

Control Messages:

Request (Client → Server):

{
  "type": "resize",
  "cols": 80,
  "rows": 24
}

Response (Server → Client):

{
  "type": "status",
  "status": "connected"
}

REST Endpoint

GET /tool-instances/{instance_id}/terminal (HTML page)

  • Returns terminal page for the instance
  • Verifies ownership
  • Returns 404 if instance not found
  • Returns 403 if unauthorized

Frontend Specification

TerminalComponent

Props:

interface TerminalProps {
  instanceId: string;
  instanceName: string;
  onClose?: () => void;
}

Features:

  • xterm.js terminal with custom theme
  • WebSocket connection management
  • Auto-fit to parent container
  • Connection status indicator
  • Reconnect on disconnect (3 retries)

TerminalPage

Route: /instances/:instanceId/terminal

  • Full-page terminal view
  • Shows instance name in header
  • Back button to instance list
  • Connection status badge

Backend Specification

TerminalManager

Methods:

class TerminalManager:
    async def create_session(
        self,
        instance_id: uuid.UUID,
        user_id: uuid.UUID,
        websocket: WebSocket
    ) -> TerminalSession
    
    async def handle_resize(
        self,
        session_id: str,
        cols: int,
        rows: int
    ) -> None
    
    async def close_session(self, session_id: str) -> None

TerminalSession

Responsibilities:

  • Manage docker exec subprocess
  • Stream I/O between WebSocket and PTY
  • Handle resize signals
  • Cleanup on disconnect

Docker Command:

async def spawn_shell(container_id: str) -> subprocess.Process:
    proc = await asyncio.create_subprocess_exec(
        "docker", "exec", "-i", container_id, "/bin/bash",
        stdin=asyncio.subprocess.PIPE,
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.STDOUT,
    )
    return proc

Dependencies

Backend:

  • FastAPI WebSocket support
  • asyncio subprocess
  • docker CLI

Frontend:

  • xterm (v5.x)
  • xterm-addon-fit
  • xterm-addon-web-links

Migration Plan

  1. Install xterm.js dependencies
  2. Create backend WebSocket endpoint
  3. Create TerminalManager and TerminalSession
  4. Create frontend TerminalComponent
  5. Add terminal route and navigation
  6. Test with running instances

Testing

  • Unit: TerminalSession I/O streaming
  • Integration: WebSocket connection lifecycle
  • Manual: Terminal functionality with real containers

Quality Gates

  • pytest
  • mypy
  • ruff
  • npm run typecheck
  • npm run lint
  • npm run build