Skip to documentation
Documentation navigation

Documentation navigation

Documentation / guides

Overview

Persist conversation history and events, restore sessions by ID, and manage live session shutdown.

developer

A session is the lifetime boundary around one execution identity. The public session.Session view submits content, selects loops, receives events, answers gates, and interrupts work. session.SessionController adds trusted mutations and teardown. Package rig is the only public constructor; it wires the session store, a single-writer lease, the journal, and the loop topology before the controller becomes reachable.

Session ownership

The runtime owns four pieces of state together:

StateOwnerDurable or liveConsumer surface
Session and loop identitysession runtimedurable SessionStarted/LoopStarted, live registrySessionID, Loop, ActiveLoop
Commands and turn executionloop actors, admitted by the sessioncommand intent records plus live actor stateSubmit, SubmitToLoop, loop controller
Enduring event historyjournal and hub durable tapdurable journal, live event.DeliverySubscribeEvents, replay through sessionstore
Teardown and ownershipsession runtime and injected lease hookslifecycle events and lease fencesShutdown, restore/new lifecycle

The runtime never exposes a loop’s command channel. A caller gets an immutable loop.Handle or the trusted loop.Controller returned by SessionController.LoopController; the actor remains the sole owner of queue admission and committed loop state.

Live and durable views

The live hub is not a replay source. It fans out public events to bounded subscriptions and carries the assigned journal sequence only on live delivery. The durable journal is the source for restore and history. This split matters: an Ephemeral token delta can be useful to a renderer and still have no durable record, while an Enduring event is appended before it changes hub state or is delivered.

%%{init: {"theme":"dark"}}%%
flowchart LR
    C[Caller] -->|Submit / control| S[Session controller]
    S --> L[Loop actor and input queue]
    L -->|public events| H[Session hub]
    H -->|bounded Delivery| SUB[Subscription]
    H -->|Enduring append before apply| J[Session journal]
    J --> K[Session store ledger]
    K -->|ordered replay| R[Restore or history reader]
    R --> S

Lifecycle at a glance

PhaseAdmissionDurable boundary
Newone root loop is built; SessionStarted and root LoopStarted must commitopening fence, then start events
Activesubmits queue or start turns; gates and subscriptions are liveevery Enduring event is appended before publication
Interruptedcurrent turns are cancelled; accepted user input waits behind the interrupt barrierTurnInterrupted and idle edge are durable
ClosingNewLoop, active-loop changes, and new work are refusedshutdown sends every loop a command, then appends SessionStopped
Restoredold events are folded; open turns are crash-closed; loops are rebuilt idleRestoreStarted precedes repair, RestoreDone is the commit point

Start with the controller contract, then create and restore. For persistence details, see session persistence.

Source and proof

disk, err := fsstore.Open(fsstore.Options{Root: "./agent-data"})
if err != nil { return err }
sessions, err := sessionstore.Open(disk.Backend())
if err != nil { return err }
restored, err := runtime.RestoreSession(ctx, savedSessionID)

Start with Create and restore, then read Session persistence and the pkg/session source.

← back to documentation