- Add docs/features/terminal.md with user guide, connection states, keyboard shortcuts, protocol details, and troubleshooting - Update docs/architecture/frontend.md with terminal component stack, connection hook behavior, and data flow diagrams - Update docs/architecture/backend.md with terminal system architecture, protocol reference, message batching, and reconnect behavior - Update docs/README.md to include terminal in feature list
8.5 KiB
Web Terminal
Overview
The web terminal provides an interactive shell session inside running tool instances directly from your browser. It uses xterm.js to render a full terminal emulator connected via WebSocket to a PTY-backed docker exec session.
The terminal is designed to feel as close to a local terminal as possible, with features for network resilience, low-latency typing, and session continuity.
How to Use
Opening a Terminal
- Navigate to a project and select a repository
- Go to the repository workspace
- Start or select a tool instance that supports the terminal interface
- Click the "Open Terminal" button
The terminal opens in full-page mode with a status bar at the top.
Terminal Layout
┌─────────────────────────────────────────────┐
│ ● Connected [Reconnect] [×] │
├─────────────────────────────────────────────┤
│ │
│ user@container:~$ ls -la │
│ total 128 │
│ drwxr-xr-x 5 user user 4096 May 27 10:00 │
│ ... │
│ │
└─────────────────────────────────────────────┘
Status bar (top):
- Connection dot — color indicates connection health
- Status text — shows current state and latency
- Reconnect button — appears when disconnected
- Close button — returns to the previous page
Connection States
| Indicator | Meaning | Action |
|---|---|---|
| 🟡 Yellow dot + "Connecting..." | Opening WebSocket | Wait or check network |
| 🟢 Green dot + "Connected" | Healthy connection (<100ms) | Ready to use |
| 🟡 Yellow dot + "Slow (150ms)" | Elevated latency | Connection usable but laggy |
| 🟡 Yellow dot + "Reconnecting (2)" | Connection lost, retrying | Wait for auto-reconnect |
| ⚪ Gray dot + "Disconnected" | Max retries exceeded | Click Reconnect or refresh |
Hover the status dot to see the current round-trip latency in milliseconds.
Typing
Type normally as you would in a local terminal. The terminal supports:
- Printable characters appear instantly (local echo)
- Special keys (Tab, Enter, Ctrl+C, arrow keys) are sent to the server
- Password prompts automatically suppress local echo
- Unicode input and output
Reconnecting
The terminal automatically reconnects if the WebSocket drops:
- Brief disconnects (WiFi hiccups, proxy timeouts) are recovered within 1–5 seconds
- Up to 10 reconnection attempts with exponential backoff
- Scrollback is preserved across reconnects
- A visual divider (
--- Reconnected ---) separates old and new output
Manual reconnect:
- Click the Reconnect button in the status bar
- Or press Ctrl+Shift+R anywhere in the terminal page
Session Ended
When the container process exits (e.g., you run exit or the container stops), the terminal shows an overlay:
┌─────────────────────────┐
│ Session Ended │
│ The container process │
│ has exited. │
│ │
│ [Reconnect] [Go Back] │
└─────────────────────────┘
- Reconnect — spawns a new shell session in the same container
- Go Back — returns to the workspace page
Keyboard Shortcuts
| Shortcut | Action |
|---|---|
Ctrl+Shift+R |
Force reconnect (bypasses backoff) |
| Standard terminal shortcuts | Ctrl+C, Ctrl+D, Ctrl+L, Tab completion, etc. |
Technical Details
WebSocket Protocol
The terminal communicates over a binary WebSocket with mixed JSON control messages.
Connection:
ws://api.example.com/ws/tool-instances/{instance_id}/terminal
Binary frames carry raw terminal I/O. Text (JSON) frames carry control messages:
Client → Server:
{"type":"ping","id":n}— heartbeat ping{"type":"resize","cols":120,"rows":40}— terminal resize- Raw bytes — keystroke input
Server → Client:
{"type":"pong","id":n}— heartbeat response{"type":"status","status":"connected"}— session ready{"type":"set_echo_state","enabled":false}— disable local echo{"type":"session_ended","reason":"process_exit"}— session ended- Raw bytes — terminal output
Architecture
Browser Backend
┌──────────────────────┐ ┌─────────────────────────────┐
│ TerminalComponent │ │ terminal.py (WS endpoint) │
│ ├─ xterm.js │◄───────►│ ├─ auth + session mgmt │
│ ├─ FitAddon │ WS │ └─ echo state detection │
│ ├─ SerializeAddon │ │ │
│ └─ useTerminalConn. │ │ TerminalManager │
│ ├─ heartbeat │ │ ├─ read_loop (batching) │
│ ├─ reconnect │ │ ├─ write_loop │
│ ├─ local echo │ │ └─ heartbeat_loop │
│ └─ resize throttle│ │ │
│ │ │ TerminalSession │
│ sessionStorage │ │ ├─ PTY + docker exec │
│ (scrollback backup) │ │ └─ termios echo detection │
└──────────────────────┘ └─────────────────────────────┘
Reconnect Behavior
On disconnect:
- The client serializes terminal scrollback to
sessionStorage - Backoff timer starts (1s, 2s, 4s, 8s, 16s, then caps at 30s)
- On reconnect, scrollback is restored + divider line
- A new
docker execsession is spawned transparently
Note: The underlying docker exec PTY is not resumable. Reconnect creates a new shell, but scrollback continuity makes this transparent.
Performance
- Local echo makes printable characters appear in <1ms
- Message batching on the backend reduces WebSocket frame overhead
- Resize debouncing (200ms) + throttling (500ms) prevents server spam
- Heartbeat interval is 15s to balance detection speed with server load
Troubleshooting
"Connecting..." stays yellow
Issue: WebSocket cannot open Check:
- Is the API server running?
- Is the tool instance in "running" status?
- Check browser console for connection errors
- Verify the
VITE_API_BASE_URLpoints to the correct API
"Reconnecting" loops forever
Issue: Max reconnection attempts exceeded Check:
- Is the container still running? (
docker ps) - Did the container crash or get stopped?
- Check server logs for
Terminal session error
Typing feels slow
Issue: High latency or no local echo Check:
- Hover the status dot — latency >100ms is shown as "Slow"
- Local echo only works for printable ASCII characters
- Password prompts intentionally disable echo
- Very high latency may indicate a congested network
Terminal is blank after reconnect
Issue: Scrollback not restored Check:
sessionStoragemay have been cleared (new browser session)- The scrollback cap is 10,000 lines — very long sessions may truncate
- Browser privacy settings may block
sessionStorage
"Session Ended" immediately
Issue: Container process exits right away Check:
- The container's default command may have finished
- Check the tool type's Docker Compose template
- Some tools (like one-off scripts) are not meant for persistent terminal sessions
Configuration
No additional configuration is required. The terminal adapts automatically to:
- Browser window size (via ResizeObserver)
- System light/dark theme preference
- Network conditions (reconnect backoff)
Related Features
- Workspace — Open the terminal from the repository workspace
- Tool Types — Configure which tools expose a terminal interface
- SSH Keys — Manage SSH keys for repository access from within the terminal