Skip to content

Separate dashboard transcripts from turn-session checkpoints #447

@dcramer

Description

@dcramer

Problem

Junior's dashboard currently reads turn-session checkpoints as if they were the user-facing transcript. That leaks an internal recovery shape into the UI and makes turns look wrong:

  • a single turn can appear to contain prior conversation history
  • checkpointed runtime context such as <runtime-turn-context> appears as normal user transcript text
  • active turns can look empty/expired until a checkpoint is materialized
  • checkpoint snapshots are doing double duty as resume state and dashboard history

The result is confusing: operators expect conversations to be ordered collections of turns, and each turn to show only what happened during that turn.

Current State

Junior already has the better primitive under the checkpoint metadata:

  • Pi session messages are persisted incrementally in pi-session-message-store
  • turn-session checkpoint metadata stores messageCount, state, checkpoint version, slice id, resume reason, etc.
  • getAgentTurnSessionCheckpoint materializes a checkpoint by loading the Pi message prefix through that cursor

The dashboard problem is that reporting consumes the materialized checkpoint as the visible transcript.

Recommended Direction

Make the append-only Pi/session message log the canonical record for dashboard transcript/history, and keep checkpoints as small resume metadata only.

The model should be:

  • conversation: metadata and ordered turn ids
  • turn transcript/event log: append-only records for user messages, assistant messages, tool calls/results, usage, timestamps, and partial/live progress
  • checkpoint: cursor/lease metadata for resumability, not a visible transcript

Checkpoint metadata should remain useful for:

  • active/idle state
  • stale callback rejection via checkpointVersion
  • timeout/auth resume
  • slice tracking
  • last safe committed Pi message cursor
  • dynamic restore metadata such as loaded skill names

But dashboard transcript rendering should read the transcript/event log, not checkpoint recovery state.

Prior Art

Pi coding-agent documents sessions as append-only JSONL conversation trees with message/custom/compaction entries, and builds context by walking the current branch:

Codex resumes sessions by replaying persisted thread/session events and restoring state from history rather than treating a checkpoint blob as the UI transcript:

Both point toward an append-only event/history log as the source of truth, with resumability metadata layered on top.

Proposed Work

  1. Define a turn transcript/event schema for dashboard consumption.
  2. Append transcript events in real time during a turn:
    • turn started
    • user prompt received
    • assistant message started
    • text deltas or committed assistant message
    • tool call started
    • tool result committed
    • usage/timing updates
    • turn paused/resumed/failed/ended
  3. Store enough ordering data to render conversations oldest-to-newest and turns in exact event order.
  4. Use the last contiguous valid event/message prefix for resume and UI repair when the tail is incomplete.
  5. Keep checkpoint metadata as a cursor/version over committed Pi/session state.
  6. Update dashboard reporting to read transcript/event logs and use checkpoint state only for active/idle/resume metadata.
  7. Hide or separately label runtime context blocks so internal injected context does not render as normal user-authored transcript text.

Acceptance Criteria

  • Conversation detail renders turns oldest-to-newest.
  • A turn transcript contains only that turn's events/messages.
  • Active turns update before completion without relying on completed checkpoints.
  • Runtime context is not displayed as ordinary user transcript text.
  • Checkpoint metadata remains sufficient to resume timeout/auth-paused turns.
  • Dashboard APIs do not expose raw checkpoint payloads as transcript.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions