SessionCatalog

works.iterative.claude.core.log.SessionCatalog
trait SessionCatalog[F[_]]

Custody of one installation's session records: locate a record by its session id, read its conversation entries (main thread and sub-agent sidechains), and keep the whole tree under the custody root.

The catalog is scoped to one installation; a record kept for another is never read through it. When the catalog knows the cwd the sessions ran under, every locate and read resolves the session in the vendor tree first — keyed by the encoded cwd, never by decoding a directory name, which is ambiguous — and falls back to the kept copy once the vendor tree has been pruned. With no cwd known, only the kept copy is read, and it is found by the session id alone. The located record's root names which one won. The record is a tree (the main .jsonl plus the sub-agent .jsonl and .meta.json sidechains), so a keep copies the tree, not a single file. Entry reads tolerate vendor drift by degrading unrecognized lines to raw entries rather than losing them.

Following a session while it is being written is deliberately not here. Its shape is an interval and a stream of batches, both of which name the effect system in a way none of the reads below do, and there is one interpreter to serve. It lives on that interpreter instead — works.iterative.claude.zio.log.ZioSessionCatalog.follow — and a second interpreter is the moment to decide whether the port should carry it.

Type parameters

F

the effect type; the abstract EntryStream lets each backend pick its own streaming type.

Attributes

Graph
Supertypes
class Object
trait Matchable
class Any

Members list

Type members

Types

Value members

Abstract methods

def entries(sessionId: SessionId): EntryStream

Streams the main-thread entries of a session. Resolves vendor-then-mirror like forSession.

Streams the main-thread entries of a session. Resolves vendor-then-mirror like forSession.

Attributes

def entriesBefore(token: PageToken, limit: Int): F[EntryPage]

Reads the page of up to limit entries immediately older than token.

Reads the page of up to limit entries immediately older than token.

The token is pinned to the transcript it was minted against; if the session now resolves to a different file (the vendor tree was pruned between pages), this fails with ArchiveError.PageSourceMoved rather than reading a stale offset against the wrong file. If the session no longer resolves under either root at all, this fails with ArchiveError.SessionNotFound.

Attributes

def forSession(sessionId: SessionId): F[Option[SessionRecord]]

Locates a session by its id, resolving the live vendor tree first when the cwd is known and falling back to the kept copy; None when no main transcript exists under any root. The returned record's root names which one won.

Locates a session by its id, resolving the live vendor tree first when the cwd is known and falling back to the kept copy; None when no main transcript exists under any root. The returned record's root names which one won.

Attributes

def lastEntries(sessionId: SessionId, limit: Int): F[EntryPage]

Reads the last limit main-thread entries of a session without parsing the transcript from the start. Entries within the returned page are oldest-first; the page itself is the newest slice of the transcript. The page's older cursor pages backward through earlier, older pages. Resolves vendor-then-mirror like forSession, so a pruned session still tails from the mirror.

Reads the last limit main-thread entries of a session without parsing the transcript from the start. Entries within the returned page are oldest-first; the page itself is the newest slice of the transcript. The page's older cursor pages backward through earlier, older pages. Resolves vendor-then-mirror like forSession, so a pruned session still tails from the mirror.

Attributes

def mirror(sessionId: SessionId): F[MirrorReport]

Idempotently keeps the whole session tree in the installation's kept directory, reporting what was copied, extended, refreshed, and skipped. The first keep also writes the custody-borne facts beside the transcript (works.iterative.claude.core.log.model.CustodyFacts); a later keep never rewrites them. A keep into a key another installation already holds fails with ArchiveError.InstallationKeyTaken.

Idempotently keeps the whole session tree in the installation's kept directory, reporting what was copied, extended, refreshed, and skipped. The first keep also writes the custody-borne facts beside the transcript (works.iterative.claude.core.log.model.CustodyFacts); a later keep never rewrites them. A keep into a key another installation already holds fails with ArchiveError.InstallationKeyTaken.

Custody is one-directional: when the session resolves under works.iterative.claude.core.log.model.RecordRoot.Archive (the vendor tree is already pruned), this is a no-op returning works.iterative.claude.core.log.model.MirrorReport.empty — the archive is never truncated or recopied from nothing. Only a Vendor-resolved record is ever a mirror source. SessionNotFound is raised only when neither root holds the session.

Attributes

def subagentEntries(sessionId: SessionId, parentToolUseId: String): EntryStream

Streams a sub-agent's own sidechain entries, joined to its parent by the tool_use id recorded in the sub-agent's .meta.json. Resolves vendor-then-mirror like forSession.

Streams a sub-agent's own sidechain entries, joined to its parent by the tool_use id recorded in the sub-agent's .meta.json. Resolves vendor-then-mirror like forSession.

Attributes