Skip to content

message-stream

Provenance

  • Source: .spec/spexcode/spec-dashboard/dashboard-ui/session-console/message-stream/spec.md
  • Source SHA-256: de550ce86988d3f84e147846ce0cac6cb5c7a44e9aa8ee9bf276f46cf89dff31

message-stream

TimelineChat remains the session's durable conversation: [[session-timeline]] is still the only record of what was said and declared. A harness transcript is neither a second conversation nor a durable SpexCode record. It is an adapter-local, ephemeral observation of work in progress.

The backend derives a current-turn selector from the newest durable human send, then asks the selected adapter for exactly one latest working note and the normalized tool steps that follow it. The selector is fresh for each read and never becomes transcript state. An adapter first maps its native user boundary to that selector, then considers only later native events: a later user boundary clears the projection. It exposes the last displayable assistant working prose in that slice, skips structured/private reasoning, and attaches only its following tool steps. TimelineChat renders the note after its durable conversation history, so the current work is the newest timeline entry. The click opens a transient execution pop-out whose rows retain the adapter's chronological order, with the newest tool action at the bottom. Its fixed dummy vocabulary is: command, read, write, search, or tool, plus running/done. A row can additionally show one backend-sanitized detail. Details start collapsed: a compact row shows only its tool, state, and disclosure control, while expanding that row reveals its own allowlisted detail without opening or changing any sibling. A same-turn live revision retains expanded rows; a changed displayed turn or working note starts disclosure closed. The renderer never knows a harness id, transcript path, envelope schema, raw tool arguments, tool result, or reasoning text. Its only job is to paint the backend's small projection and choose a familiar icon for the given kind.

The phrase "latest" is literal: a later displayable working note replaces the prior note and its steps. Earlier commentary, prior turns, structured reasoning, tool arguments/results, and every other transcript field stay private. A source that cannot be read or whose current selector does not yet map to a native user boundary has no entry, rather than displaying a partial raw transcript or an invented error conversation.

GET /api/sessions/:id/execution returns the current compact projection. Its companion GET /api/sessions/:id/execution/stream writes that same projection once, then sends only changed revisions and periodic heartbeats. Reading happens only while a client is subscribed and stops on disconnect. The SSE is an update transport, not a second persistence layer: no event is appended to timeline.ndjson, no browser polls native files, and reconnect simply receives a fresh projection. The browser's existing heartbeat dead-man treats a silent stream as dropped and reopens it, so a half-open proxy cannot leave a visible note stuck. A non-governed or unknown session is a 404 on both routes.

Pane-backed adapters keep their real terminal as the full live surface. This compact trace is additive to the Conversation surface, never a raw-process door or an alternate terminal.