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