Skip to content

[bug] Agent terminals go blank after navigating away and back — scrollback not replayed on reconnect #418

Description

@realproject7

Problem

When the operator navigates to another page (Home, Settings, different project) and returns, agent terminal panels that were showing live output now appear blank. Only the actively-producing agent (e.g. Dev mid-task) shows content — idle agents (Head, Reviewer1, Reviewer2) show empty black panels until they produce new output.

Root cause

The terminal panel's WebSocket connection is torn down when the component unmounts (page navigation). On remount, a new WebSocket connects to the server's PTY stream, but the server only streams live output going forward — it does not replay the PTY's scrollback buffer. So any output produced before the reconnect is lost from the client's view.

The PTY process itself still has the full scrollback in memory (node-pty maintains it). The gap is that the WebSocket handler only forwards new `data` events, not historical buffer content.

Fix

Server-side: maintain a per-session scrollback ring buffer

In `server/index.js`, when creating each agent's PTY session, keep a ring buffer of the last N bytes (e.g. 32KB or 64KB) of PTY output:

```js
const SCROLLBACK_SIZE = 64 * 1024; // 64KB
session.scrollback = Buffer.alloc(0);

term.onData((data) => {
// Append to ring buffer
session.scrollback = Buffer.concat([session.scrollback, Buffer.from(data)]);
if (session.scrollback.length > SCROLLBACK_SIZE) {
session.scrollback = session.scrollback.slice(-SCROLLBACK_SIZE);
}
// Forward to connected WebSocket clients (existing behavior)
// ...
});
```

WebSocket handler: replay scrollback on connect

When a new WebSocket client connects to `/ws/terminal?project=X&agent=Y`, send the scrollback buffer before streaming live data:

```js
ws.on("open", () => {
// Replay scrollback
if (session.scrollback && session.scrollback.length > 0) {
ws.send(session.scrollback);
}
// Then stream live (existing behavior)
});
```

Client-side: no changes needed

The xterm.js terminal instance processes the replayed data the same way it processes live data — ANSI escape sequences, cursor positioning, colors all render correctly from the buffer replay. The terminal panel just needs to receive the data; xterm handles the rest.

Acceptance

  • Navigate to Home page, wait 10 seconds, navigate back to project → all 4 agent terminals show their most recent output (prompt, last command output, status line)
  • Active agent (mid-task) shows full context, not just the line being written at the moment of reconnect
  • Idle agents show their last prompt / status line, not a blank panel
  • Scrollback is bounded (64KB) so memory doesn't grow unbounded for long-running sessions
  • No duplicate output — the scrollback replay happens once on connect, then live streaming takes over

Out of scope

  • Persisting scrollback across server restarts (PTY scrollback is inherently ephemeral)
  • Infinite scrollback / searchable history
  • Terminal recording / playback

Files

  • `server/index.js` — PTY session creation (`term.onData` handler), WebSocket `/ws/terminal` handler
  • No client-side changes needed

Branch

`task/XXX-terminal-scrollback-replay`

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions