15 KiB
Persistence Log Event Catalog
Every event type that can appear in a session's durable event log: each member of the merge-extensible SessionEventMap — the owning vocabulary in @deepseek-ai/dsh-session plus every plugin declaration merge in this repo — with the payload it carries, its surface badge, and the declaration it comes from. It complements session.md (the SessionEvent envelope, surface list, and deriveMessages() projection), persistence.md (how the log is made durable), and the cordis events catalog (the live bus wiring — a log event is NOT a cordis event; it reaches listeners via the single session/event emit).
This file is GENERATED from source (scripts/gen-persistence-catalog.ts) and verified fresh by pnpm run verify-persistence-catalog (part of doc-sync) — do not edit it by hand. Payload blocks use a ts persistence-catalog fence (skipped by doc-typecheck, since a bare payload fragment is not standalone-compilable). Type names in a payload link to the page that documents them. See the persistence-log-catalog RFC.
The on-disk envelope around every payload is SessionEvent — type, monotonic seq, epoch-ms time, the data documented here, plus surfaceOp/sourceEventSeqs on surface events only (envelope). surface marks a SurfaceEventType member: it produces an LLM message and declares how it joins the surface list. log-only marks everything else: durable, replayable record with no derived-history contribution. Every payload is JSON-serializable (enforced at Session.append), and the whole format is pinned at SESSION_FORMAT_VERSION = 0 — pre-release, no compatibility implied (the version stance). Scope: the packages in this repo; a downstream plugin can merge further event types, which are outside this catalog by construction.
Events
approval/*
approval/asked — log-only
An approval question was put to the answerer chain — log-only audit (like hook/*; NOT a surface event, carries no surfaceOp). id pairs it with the approval/decided that always follows; toolName is the tool the question is about, callId the exact tool call when the asker had one, reason the asker's human-readable explanation (e.g. a hook's permission-decision reason).
'approval/asked': { id: ApprovalRequestId; toolName: string; callId?: CallId; reason?: string }
Types: CallId
Source: packages/ui/user-approval/src/index.ts:45
approval/decided — log-only
The outcome of a prior approval/asked (same id) — log-only audit. Exactly one per ask, appended when the outcome is known: a decision, a cancellation, or the fail-closed 'unavailable'.
'approval/decided': { id: ApprovalRequestId; outcome: ApprovalOutcome }
Source: packages/ui/user-approval/src/index.ts:56
approval/policy — log-only
The session's approval policy was switched — log-only, durable, replayable, never in the model transcript (the model learns the policy from the prompt section and the narrator's notices). The LAST such event is the session's override (effectiveApprovalPolicy); who asked for it is derivable from position (an event after the log's last request/header* was a runtime switch by the user).
'approval/policy': { policy: ApprovalPolicy }
Source: packages/ui/user-approval/src/index.ts:68
assistant/*
assistant/chunk — log-only
Raw stream chunk — token-level replay fidelity.
'assistant/chunk': { turn: number; step: number; chunk: StreamChunk }
Types: StreamChunk
Source: packages/core/session/src/types.ts:239
assistant/message — surface
Assembled assistant message for one step (derived history uses this). Carries the step's usage when the adapter reported token accounting, so the model output and its accounting travel together (there is no separate usage record). usage is absent when the adapter reported none.
'assistant/message': { turn: number; step: number; content: ContentBlock[]; usage?: TokenUsage }
Types: ContentBlock · TokenUsage
Source: packages/core/session/src/types.ts:246
bash/*
bash/sandbox-mode — log-only
The session's sandbox mode was switched — log-only (like approval/*; NOT a surface event, carries no surfaceOp): durable and replayable, never in the model transcript. The LAST such event is the session's override (effectiveSandboxMode); who asked for it is derivable from position (an event after the log's last request/header* was a runtime switch by the user; see the tool layer's narrator).
'bash/sandbox-mode': { mode: SandboxMode }
Source: packages/bash/bash/src/session-mode.ts:22
compact/*
compact/end — log-only
Marks the end of a compaction — log-only, releases the lock. error set if summarization failed.
'compact/end': { turn: number; error?: string }
Source: packages/compact/compact/src/types.ts:38
compact/start — log-only
Marks the start of a compaction — log-only, holds the lock until compact/end.
'compact/start': { turn: number }
Source: packages/compact/compact/src/types.ts:15
compact/summary — log-only
Provenance record of a completed summarization — log-only, no surfaceOp. The summary content is in data.summary; the actual surface replacement is performed by a subsequent user/message event that shadows the compacted range.
'compact/summary': { summary: ContentBlock[]; shadowedRange: { start: number; end: number }; shadowedSeqs: number[]; shadowedTokenCount: number; model: string; maxTokens?: number }
Types: ContentBlock
Source: packages/compact/compact/src/types.ts:22
context/*
context/message — surface
In-session context injection (file-change notices, subdir AGENTS.md, skill content, cron notifications, …). Rendered into the derived history as tagged synthetic context — NOT a user prompt.
'context/message': { content: ContentBlock[]; source: MessageSource }
Types: ContentBlock · MessageSource
Source: packages/core/session/src/types.ts:237
hook/*
hook/invoked — log-only
A hook command was invoked at a hook point — log-only provenance (like compact/*; NOT a SurfaceEventType, carries no surfaceOp). dialect is the bridge that ran it (claude/codex), point the hook point (PreToolUse, Stop, …), matcher the matcher-group pattern that selected it (absent for match-all), handlerId a stable id for the command (so an invoked/result pair correlates). turn is the open turn the invocation lives inside.
'hook/invoked': { turn: number; point: string; dialect: HookDialect; matcher?: string; handlerId: string }
Source: packages/hooks/hook-protocol/src/types.ts:19
hook/result — log-only
Log-only outcome paired to hook/invoked by handlerId. Decision is the parsed permission result, stop for continue:false, or pass; exit code may be absent, stderr is bounded, and duration is wall-clock runtime.
'hook/result': { turn: number; point: string; handlerId: string; decision: string; exitCode?: number; stderrSummary?: string; durationMs: number }
Source: packages/hooks/hook-protocol/src/types.ts:31
prompt/*
prompt/blocked — log-only
Durable record of a prompt veto and its reason. It is log-only: the blocked prompt never enters the model-visible surface, including in a mixed batch.
'prompt/blocked': { content: ContentBlock[]; source: MessageSource; reason: string }
Types: ContentBlock · MessageSource
Source: packages/core/session/src/types.ts:231
request/*
request/header — log-only
Full EpochHeader for the next request, appended inside its step before dispatch. It is log-only and anchors subsequent deltas.
'request/header': { header: EpochHeader; reason: RequestHeaderReason }
Source: packages/core/session/src/types.ts:274
request/header-delta — log-only
Log-only amendment to the folded EpochHeader. System and tools use their delta codecs; config and prefix replace whole, with an empty prefix encoding removal. Writers verify round-trip equality or log a fallback snapshot.
'request/header-delta': { system?: SystemDelta; tools?: ToolsDelta; config?: LlmCallConfig; messagePrefix?: Message[] }
Source: packages/core/session/src/types.ts:280
steering/*
steering/message — surface
Steering content injected between steps of a running turn.
'steering/message': { turn: number; content: ContentBlock[]; source: MessageSource }
Types: ContentBlock · MessageSource
Source: packages/core/session/src/types.ts:264
step/*
step/end — log-only
Closes step step of turn turn.
'step/end': { turn: number; step: number }
Source: packages/core/session/src/types.ts:224
step/start — log-only
Opens step step of turn turn — one model call plus the tool executions it requested.
'step/start': { turn: number; step: number }
Source: packages/core/session/src/types.ts:222
todo/*
todo/write — log-only
Whole-list snapshot; the latest write wins on replay. It is log-only UI state and never enters derived model history.
'todo/write': { todos: TodoItem[] }
Types: TodoItem
Source: packages/core/session/src/types.ts:269
tool/*
tool/call — log-only
The model requested one tool invocation: name with the raw arguments JSON string exactly as the model produced it (unparsed). callId pairs the call with its tool/result.
'tool/call': { turn: number; step: number; callId: CallId; name: string; arguments: string }
Types: CallId
Source: packages/core/session/src/types.ts:252
tool/code-dispatch — log-only
One bridged sub-dispatch from a run_code program: the parent run_code call id, the deterministic sub-call id (<parent>:code:<n>), the tool name with its JSON-normalized arguments — the exact value dispatched, normalized before dispatch, so this append can never fail on payload shape — whether the sub-call errored, and a bounded resultSummary of its model-facing text.
'tool/code-dispatch': { parentCallId: CallId; subCallId: CallId; name: string; arguments: unknown; isError: boolean; resultSummary: string }
Types: CallId
Source: packages/core/tools/src/code-mode.ts:25
tool/result — surface
A completed tool call's model-facing result, plus an optional tool-private meta presentation payload. meta is opaque to the core (unknown — the producing tool owns its shape and reads it back in presentResult) but MUST be JSON-serializable: Session.append runtime-validates all event data with isJsonValue, so a non-serializable meta is rejected at the source, and the durable log reproduces the identical card on replay. Absent unless the tool attaches one (e.g. dsh-tool-fs carries its result-time contextual diff here).
'tool/result': { turn: number; step: number; callId: CallId; content: ContentBlock[]; isError: boolean; error?: { name: string; code: string }; meta?: unknown }
Types: CallId · ContentBlock
Source: packages/core/session/src/types.ts:262
turn/*
turn/end — log-only
Closes turn turn with the TurnEndReason that ended it. The loop fires the awaited session/flush checkpoint at every turn end, so the turn boundary is also the durable-commit boundary.
'turn/end': { turn: number; reason: TurnEndReason }
Types: TurnEndReason
Source: packages/core/session/src/types.ts:220
turn/start — log-only
Opens turn turn. trigger records what started it — a drained message batch or an idle-time injection. The turn is the durability/replay boundary: every event sits between a turn/start and its matching turn/end (the turn-enclosure invariant).
'turn/start': { turn: number; trigger: TurnTrigger }
Types: TurnTrigger
Source: packages/core/session/src/types.ts:214
user/*
user/message — surface
A user-visible prompt (queued message drained at turn start).
'user/message': { content: ContentBlock[]; source: MessageSource }
Types: ContentBlock · MessageSource