The one Event type (ADR 0004): a plain tagged map with a common envelope
%{id: id, session_id: session_id, seq: seq, ts: ts, type: type, data: data}built exclusively through the constructors here. The same shape serves live
display (over Pixir.Events) and durable replay (the NDJSON Pixir.Log).
Key conventions (round-trip rule)
The envelope keys (:id, :session_id, :seq, :ts, :type, :data) are
always atoms, and :type is always an atom from the known vocabulary. The :data
payload uses string keys — the JSON wire form — so that an Event survives a
Log round-trip (append then fold) structurally unchanged. Every consumer (the
Provider folding History, the Renderer displaying live or replayed events) sees the
same shape whether the Event is fresh or reloaded.
Canonical vs ephemeral
- Canonical events —
:user_message,:assistant_message,:reasoning,:skill_activation,:subagent_event,:session_fork,:branch_summary,:history_compaction,:provider_usage,:tool_call,:tool_result,:permission_decision— are stamped with a per-Session monotonicseq, appended to the Log, and define History (a fold over them). - Ephemeral events —
:text_delta,:reasoning_delta,:status— are broadcast for live display and never persisted (seqstaysnil).
Streaming partials are always ephemeral; only the final :assistant_message is
canonical. This avoids the partial-vs-final duplication noted in ADR 0004.
Summary
Functions
Final assistant answer for a Turn (the persisted form of streamed text).
A lossy synthesis of context carried into a Fork (ADR 0024). data includes summary,
source range, strategy, and explicit limitations. Distinct from history_compaction.
True if the Event's type is canonical (must be logged).
The set of canonical (persisted) event types.
A context-pressure notice (ADR 0020): the advisory/warning/recovery output for
the human channel. data is string-keyed ("tier", gauge evidence, optional
"next_actions" / "message"). Ephemeral by construction — like :status, it
never enters the Log, so it can never reach Provider input or any replay path.
True if the Event's type is ephemeral (live-only, never logged).
The set of ephemeral (live-only) event types.
A durable History compaction checkpoint. data is a string-keyed summary with the
compacted range, deterministic summary, and audit metadata used by Provider
replay to keep context bounded without losing the Log as source of truth.
Build an Event. seq is left nil here; the owning Pixir.Session stamps it on
canonical events when appending to the Log (see with_seq/2).
A permission decision for a gated tool call (ADR 0006).
A live to-do list (ACP plan, epic D.1). entries is the COMPLETE current plan
(ACP replaces the whole list per update — never a delta); each entry is a
string-keyed %{"content" => ..., "priority" => "high|medium|low", "status" => "pending|in_progress|completed"}. Ephemeral/presentation-only — like
:status, a plan never enters the Log (ADR 0003); the Provider fold has no
notion of it.
Durable Provider accounting for one model call. data is string-keyed evidence such as
model, call index, prompt-cache key metadata, raw usage, and normalized usage summary.
This is Harness observability and is never replayed as model context.
An encrypted reasoning item (rs_…) the model produced and the Responses API
requires re-injected on subsequent turns (ADR 0007). item is the raw, opaque
provider object (string-keyed, incl. encrypted_content); model is the model id
that produced it, so replay can drop items captured under a different model.
A chunk of streamed reasoning text.
Durable fork lineage for a child Session (ADR 0024). data records the parent Session,
fork-tree root, replay boundary, workspaces, and replay evidence. Provider replay
treats this as lineage metadata, not conversational History.
A Skill selected for a Turn (ADR 0010). data is a string-keyed snapshot that
includes the Skill identity, source/scope, resolved path, content hash, and the
SKILL.md content used for that Turn.
A coarse status transition for live display (e.g. "thinking").
A parent-visible Subagent lifecycle event (ADR 0011). data carries
subagent_id, child_session_id, event, status, agent, task,
depth, workspace, and optional summary.
A chunk of streamed assistant text.
A tool/function the model asked to run. args is the model-supplied argument map
(string keys, as decoded from JSON).
The outcome of executing a tool call. result is a string-keyed map; by convention
it carries "ok" plus either "output" or a structured "error" (ADR 0005).
User input that opens a Turn.
Return the Event with its monotonic seq stamped.
Types
Functions
Final assistant answer for a Turn (the persisted form of streamed text).
A lossy synthesis of context carried into a Fork (ADR 0024). data includes summary,
source range, strategy, and explicit limitations. Distinct from history_compaction.
True if the Event's type is canonical (must be logged).
@spec canonical_types() :: [type()]
The set of canonical (persisted) event types.
A context-pressure notice (ADR 0020): the advisory/warning/recovery output for
the human channel. data is string-keyed ("tier", gauge evidence, optional
"next_actions" / "message"). Ephemeral by construction — like :status, it
never enters the Log, so it can never reach Provider input or any replay path.
True if the Event's type is ephemeral (live-only, never logged).
@spec ephemeral_types() :: [type()]
The set of ephemeral (live-only) event types.
A durable History compaction checkpoint. data is a string-keyed summary with the
compacted range, deterministic summary, and audit metadata used by Provider
replay to keep context bounded without losing the Log as source of truth.
Build an Event. seq is left nil here; the owning Pixir.Session stamps it on
canonical events when appending to the Log (see with_seq/2).
A permission decision for a gated tool call (ADR 0006).
A live to-do list (ACP plan, epic D.1). entries is the COMPLETE current plan
(ACP replaces the whole list per update — never a delta); each entry is a
string-keyed %{"content" => ..., "priority" => "high|medium|low", "status" => "pending|in_progress|completed"}. Ephemeral/presentation-only — like
:status, a plan never enters the Log (ADR 0003); the Provider fold has no
notion of it.
Durable Provider accounting for one model call. data is string-keyed evidence such as
model, call index, prompt-cache key metadata, raw usage, and normalized usage summary.
This is Harness observability and is never replayed as model context.
An encrypted reasoning item (rs_…) the model produced and the Responses API
requires re-injected on subsequent turns (ADR 0007). item is the raw, opaque
provider object (string-keyed, incl. encrypted_content); model is the model id
that produced it, so replay can drop items captured under a different model.
A chunk of streamed reasoning text.
Durable fork lineage for a child Session (ADR 0024). data records the parent Session,
fork-tree root, replay boundary, workspaces, and replay evidence. Provider replay
treats this as lineage metadata, not conversational History.
A Skill selected for a Turn (ADR 0010). data is a string-keyed snapshot that
includes the Skill identity, source/scope, resolved path, content hash, and the
SKILL.md content used for that Turn.
A coarse status transition for live display (e.g. "thinking").
A parent-visible Subagent lifecycle event (ADR 0011). data carries
subagent_id, child_session_id, event, status, agent, task,
depth, workspace, and optional summary.
A chunk of streamed assistant text.
A tool/function the model asked to run. args is the model-supplied argument map
(string keys, as decoded from JSON).
The outcome of executing a tool call. result is a string-keyed map; by convention
it carries "ok" plus either "output" or a structured "error" (ADR 0005).
User input that opens a Turn.
Optional :resources is a list of Session Resource descriptors (ADR 0021).
Descriptors contain local identity and hashes only; raw image bytes or base64
payloads must never be placed in the Log.
@spec with_seq(t(), non_neg_integer()) :: t()
Return the Event with its monotonic seq stamped.