Sessions & Terminal
What is a Session?
Section titled “What is a Session?”A session (called a “run” in the data model) represents a single agent execution. Each session includes:
- A PTY terminal running the CLI (Claude or Codex) in a real pseudo-terminal
- A git worktree with an isolated branch for the agent to work in
- An event stream tracking tool calls, status changes, and notifications
- Hooks that report agent activity back to Abbado in real-time
Terminal Architecture
Section titled “Terminal Architecture”Abbado uses xterm.js in the browser connected to a portable-pty process on the server via WebSocket.
Browser (xterm.js) ←→ WebSocket ←→ PTY (portable-pty) ←→ CLI (claude/codex)This gives you a real terminal experience: colors, cursor movement, copy/paste, resize — everything works exactly like a local terminal.
Key Properties
Section titled “Key Properties”- Server-side PTY — the CLI process runs on the server, not in the browser
- Output buffering — the server keeps a 100KB rolling buffer of terminal output
- Reconnect replay — when you reconnect, the buffer is replayed so you see recent output
- Session survival — closing the browser tab does NOT kill the CLI process; the PTY keeps running
Session Lifecycle
Section titled “Session Lifecycle”Every session goes through these states:
queued → running → paused → running → paused → ... → completed ↑ | └────────────────────────────────────┘ (continue)States
Section titled “States”| Status | Meaning |
|---|---|
| queued | Run created, PTY spawned, waiting for the user to type a prompt |
| running | Agent is actively processing (triggered by UserPromptSubmit hook) |
| paused | Agent finished responding, session still alive, waiting for next prompt (triggered by Stop hook) |
| completed | Session ended — user quit the CLI or session terminated (triggered by SessionEnd hook or PTY exit) |
| failed | Agent encountered an error (triggered by StopFailure hook) |
| cancelled | User explicitly cancelled the run via the UI |
State Transitions
Section titled “State Transitions”State transitions happen through two mechanisms:
- Hooks — the CLI calls Abbado’s hook endpoint on lifecycle events (most transitions)
- PTY exit — when the CLI process exits, Abbado marks active runs as completed (fallback)
WebSocket Connection
Section titled “WebSocket Connection”The terminal WebSocket endpoint is GET /api/terminal?run_id=<uuid>.
Connection Flow
Section titled “Connection Flow”- Client opens WebSocket to
/api/terminal?run_id=<run-id> - Server looks up the PTY session for this run
- If no session exists and the run is active, server spawns a new PTY
- Server replays the output buffer (up to 100KB)
- Server subscribes the WebSocket to the PTY output broadcast channel
- Client sends keystrokes → server writes to PTY stdin
- PTY stdout → broadcast → all connected WebSockets
Multiple Viewers
Section titled “Multiple Viewers”Multiple browser tabs can connect to the same session simultaneously. All viewers see the same output in real-time via a broadcast channel. Any viewer can send input.
Terminal Resize
Section titled “Terminal Resize”The client sends resize events as escape sequences:
\x1b[RESIZE:<cols>:<rows>The server intercepts these and resizes the PTY accordingly. Default size is 120 columns by 30 rows.
Disconnection
Section titled “Disconnection”When a WebSocket disconnects:
- The PTY process keeps running
- The output buffer keeps accumulating
- Other viewers (if any) are unaffected
- Reconnecting replays the buffer and resumes live output
Session Data
Section titled “Session Data”Each session stores data in the filesystem:
$IA_IDE_DATA_DIR/runs/<run-id>/├── worktree/<repo-name>/ # Git worktree (isolated branch)├── cli-state/ # CLI session state (for resume)├── hook.sh # Hook script that calls Abbado└── claude-hooks.json # Hook configuration for the CLIEvents
Section titled “Events”All session events are persisted in the SQLite database and available via:
- REST API:
GET /api/runs/{id}/events - SSE stream:
GET /api/runs/{id}/events/stream?last_event_id=0
The SSE stream replays missed events and then switches to live streaming — no events are lost between replay and live.
Pausing and Resuming
Section titled “Pausing and Resuming”Pausing a run (via the UI or POST /api/runs/{id}/pause):
- Kills the CLI process
- Commits any uncommitted changes as a checkpoint
- Marks the run as “paused”
Continue
Section titled “Continue”Continuing a completed/paused/failed run (via POST /api/runs/{id}/continue):
- Re-creates the worktree if needed
- Launches the CLI with the session ID for resume
- Sends the continuation message as the initial prompt
- Marks the run as “running”
| Endpoint | Method | Description |
|---|---|---|
/api/terminal | GET (WebSocket) | Connect to a terminal session |
/api/runs/{id} | GET | Get run status and metadata |
/api/runs/{id}/events | GET | Get all events for a run |
/api/runs/{id}/events/stream | GET (SSE) | Stream events in real-time |
/api/runs/{id}/cancel | POST | Cancel a running session |
/api/runs/{id}/pause | POST | Pause a running session |
/api/runs/{id}/continue | POST | Resume a completed/paused session |