Skip to content

[bug] Terminal history is session-scoped, and every finished run ends the session — so history looks lost while sitting in D1 #257

Description

@serge-ivo

The complaint

Why do I always see "Start a session" in the Terminal tab? Why do sessions expire all the time?
I should see history in the terminal forever — it should be from the DB, not streamed like tmux.

Correct on every point. The history is in the database. The UI just cannot reach it.

Why sessions keep ending

Three callers of endSession, two of them automatic:

  1. workflows/coding-session.ts:447 — the Pilot ends the session when its run finishes. Every
    start_work / Loop run closes the session on completion (ended, or error on
    failed/max_steps). So finishing work is what removes your terminal.
  2. lib/coding-store.ts:437 — the orphan reaper. Any active session the runner is not
    tracking, older than a 3-minute grace, is marked ended. Every pags up restart reaps them.
  3. routes/coding.ts:1384 — the explicit Kill, which is the only one the user asked for.

Live example: FWS platform Coder had 13 sessions, all ended/error, 0 active — with a healthy
runner online.

Why the history looks lost

It is not lost. coding_timeline (migration 0023) is append-only and stores exactly what is
wanted — terminal, command, chat_user, chat_assistant, brain, outcome — in D1.

The problem is scoping:

session_id  TEXT NOT NULL REFERENCES coding_sessions(id),
instance_id TEXT NOT NULL REFERENCES agent_instances(id),
...
CREATE INDEX idx_coding_timeline_session      ON coding_timeline(session_id, seq);
CREATE INDEX idx_coding_timeline_session_type ON coding_timeline(session_id, type, seq);

Both indexes are per session. instance_id is on the row, so a per-instance or per-repo read
is perfectly possible — nothing asks for one. The Terminal view renders the open session's rows,
and with no open session CodingTab.tsx:840 renders "No session running / Start a session"
instead of any history at all.

So each completed run starts a fresh session id, a fresh empty timeline, and the previous work
becomes unreachable through the UI while sitting intact in D1.

What it should be

Terminal history should be a property of the repo, not of a session:

  • Read the timeline by (instance_id, repo) and render it continuously, with session boundaries
    as separators rather than as the unit of retrieval. An index on (instance_id, seq) makes this
    a one-line query change.
  • Show history whenever it exists, with "Start a session" as an action alongside it, never
    instead of it. (Same shape as [bug] Coding tab's offline state is unrecoverable — it hides the only control that could clear it #241, where the offline message replaced the only control that
    could clear it.)
  • Reconsider (1) above: does a finished Pilot run need to end the session, or only mark the run
    done? Ending it is what forces a new session — and therefore a new empty timeline — for the next
    piece of work on the same repo.

Verification

  • Finish a Loop run, stay on the Terminal tab: the transcript remains.
  • Restart pags up: history survives, and starting a new session appends rather than replaces.
  • Open a repo with no live session: previous output is visible, with a Start action available.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions