Multi-terminal live session sharing for Pi. Open the same Pi session in multiple terminal windows and they stay in sync — user input, streaming responses, tool calls, and status updates all mirror across attached terminals in real time. Late-joining terminals hydrate from session state.
pi --session <session-id-or-path>
# in another terminal
pi --session <same-session-id-or-path>Both terminals attach to the same live session/sync channel and render the same conversation/tool/status stream.
Two Pi terminals attached to the same session should behave like two views of one live session:
- user input in one view appears in both
- assistant streaming deltas appear in both
- tool calls/results/status updates appear in both
- late joiners hydrate from session JSONL + live sync state
- one active agent turn per session/sync channel unless explicitly forked
pi-sync owns sync identity, the live runtime registry, host ownership, and coordination. Generalize the event capture/context machinery from pi-manager:
- capture
message_update,tool_call,tool_result,tool_execution_start/update/end,input,agent_start/end - publish events to a same-session bus
- attached UIs subscribe and render the shared event stream
- control/input is coordinated through a session leader/lease so agents do not double-run
index.ts is a Pi extension/runtime bus, and bin/pi-sync-host.js is the first per-session host process:
- auto-starts a fresh per-session/same-sync
pi-sync-hostonsession_start - host writes heartbeat/status to
~/.pi/lane/sessions/{sessionKey}/lanes/{sync}/sync/host.json - host listens on a short macOS-safe Unix socket under
$TMPDIR/pi-sync-*.sockand records host lifecycle/prompt queue events - host now owns
AgentSessionexecution: normal terminal input is intercepted by attached UIs and forwarded topi-sync-host - attached terminals replay host-owned native AgentSession events; terminal Pi processes are now UI clients for normal prompts
- explicit
-e/--extensiontest/local extensions are propagated into the host viaPI_SYNC_HOST_EXTENSIONS - uses the sync root/session key/sync channel as shared storage
- appends live events to
~/.pi/lane/sessions/{sessionKey}/lanes/{sync}/sync/events.jsonl - attached same-session/same-sync peers poll the bus and de-duplicate event IDs
- with the
pi-syncPi core patch installed, peers replay remote agent events throughctx.ui.replayAgentEvent(event), i.e. Pi's native interactive renderer - without the core patch,
pi-syncfails during UI startup; native replay is a hard requirement, not a fallback path - late joiners replay from the current active turn's
turnStartOffset - one active agent turn per session/sync channel is enforced with an atomic
turn.lock/owner.jsonlease and heartbeat, with stale-lock recovery - competing attached-terminal input is published as
queued_inputand delivered by the active owner as a follow-up instead of starting a second peer model call - followers refresh their session manager from disk before accepting input and after remote turn completion
- remote replay is serialized/awaited to preserve native renderer ordering
- exports primary
PI_SYNC_*identity variables, still reads legacyPI_LANE_*, and shipspisync/pi-syncCLIs plus a deprecatedpilalias
This is now a host-owned same-session sync substrate: normal prompts run inside pi-sync-host, and terminals are UI clients. Remaining hardening is around full Pi command parity, explicit host shutdown/cleanup policy, and background-job ownership details for every extension/tool edge case.
npm run bench:latency -- 100,25,10
npm run record:side-by-sidescripts/benchmark-latency.mjsmeasures local-vs-attached render latency under differentPI_SYNC_POLL_MSvalues.scripts/record-side-by-side.mjsuses pi-mock SVG screenshots, macOSsips, ImageMagick, and ffmpeg to createartifacts/pi-sync-side-by-side.mp4.
test/current-no-live-mirror.test.mjsdocuments current Pi behavior without pi-sync: two Pi processes using the same session file do not mirror live output.test/installed-native-replay-smoke.test.mjsproves the installed Pi stack exposes native replay before hosted prompts run.test/native-live-sync.test.mjsproves pi-sync publishes native updates from one same-session terminal to another and keeps tree navigation on the main sync channel without hidden branch channels.test/late-join-active-turn.test.mjsproves a new attached terminal hydrates an already-active turn.test/tool-mirror.test.mjsproves tool execution output/final response mirror to an attached terminal.test/turn-lease.test.mjsproves a follower cannot start a competing same-session agent turn while another attached terminal owns the turn lease.