Skip to content

Session activity streams

While an agent works, Nexus records what it is doing — reply text, reasoning, tool calls, plans — as ordered agent.update rows. That stream is what makes a session watchable live and replayable afterwards.

The daemon is a thin pass-through at the stream boundary. It translates the harness’s own session updates and forwards them in order; it does not reinterpret them.

flowchart LR
  harness[Harness session update] --> engine[AcpEngine translate]
  engine --> service[Agent service]
  service --> stream[(mem.stream_events agent.update)]
  stream --> materialized[(agent_session_* history)]
  stream --> gateway[Gateway session history]

There are seven. Five come straight from the harness stream; two are produced by the daemon, because no harness emits them.

agent.update.kind Carries
text Assistant reply chunks
thinking Reasoning chunks
tool_call Tool call start and update payloads, merged by id by consumers
plan Plan entries
commands The harness’s own slash commands, name and description only

Anything else the harness sends — mode, config, session-info, and usage bookkeeping — is dropped rather than forwarded. It keeps the stream alive but carries no session content.

agent.update.kind Carries
user_input A user-role turn the session received, so an attached terminal and a browser view show the same thing
turn_end The turn is complete. No content; consumers use it to close the streaming row

turn_end is emitted on every turn, success or failure, so a viewer never streams forever waiting on a turn that already errored.

One endpoint serves the stream, in three views:

GET /api/v1/agent-sessions/<session-id>/events?view=nexus|terminal

view=nexus returns the normalized Nexus events this page describes; view=terminal returns the raw terminal bytes. Both are server-sent event streams. Keep the last cursor you accepted and reconnect with after=<cursor> to resume inside the bounded replay window; if the server answers with a resync or reports a gap, treat it as a presentation discontinuity rather than as lost history.

The raw lane is mem.stream_events, a volatile attached schema rather than a migrated table: it is boot-scoped, and rows are evicted at turn end once the materializer has folded the turn. The daemon folds raw rows into compact agent_session_turns and agent_session_messages for durable replay. The raw stream stays the live and debug source; the materialized rows are the stable history projection.

Piece Path
Contract event core/crates/nexus-contracts/src/events.rs
Pure transform core/crates/nexus-acp-stream/src/lib.rs
Engine buffering core/crates/nexus-agent/src/adapter/engine.rs
Service write core/crates/nexus-agent/src/service.rs
Raw to materialized, and the mem.stream_events eviction core/crates/nexus/src/daemon/agent_session_materializer.rs
agent_session_turns table core/migrations/0001_init.sql
agent_session_messages table core/migrations/0001_init.sql