# `Pixir.Event`
[🔗](https://github.com/Ranvier-Technologies/pixir/blob/main/lib/pixir/event.ex#L1)

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`, `:workflow_event`, `:session_fork`,
    `:branch_summary`, `:history_compaction`, `:provider_usage`, `:turn_failed`,
    `:tool_call`, `:tool_result`, `:permission_decision` — are stamped with a per-Session
    monotonic `seq`, 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 (`seq` stays `nil`).

Streaming deltas are ephemeral; canonical `:assistant_message` events remain the
durable turn record. In provider-error paths, a partial assistant message may be
preserved with metadata for diagnostics and replay safety.

# `t`

```elixir
@type t() :: %{
  id: String.t(),
  session_id: String.t(),
  seq: non_neg_integer() | nil,
  ts: String.t(),
  type: type(),
  data: map()
}
```

# `type`

```elixir
@type type() :: atom()
```

# `assistant_message`

```elixir
@spec assistant_message(String.t(), String.t(), keyword()) :: t()
```

Final assistant answer for a Turn (the persisted form of streamed text).

Optional `:metadata` is string-keyed audit context for unusual terminal paths, such
as a partial answer preserved after a Provider stream error. Provider replay uses
only the text; metadata is local evidence for diagnostics.

# `branch_summary`

```elixir
@spec branch_summary(String.t(), map(), keyword()) :: t()
```

A lossy synthesis of context carried into a Fork (ADR 0024). `data` includes `summary`,
source range, `strategy`, and explicit `limitations`. Distinct from `history_compaction`.

# `canonical?`

```elixir
@spec canonical?(t()) :: boolean()
```

True if the Event's type is canonical (must be logged).

# `canonical_types`

```elixir
@spec canonical_types() :: [type()]
```

The set of canonical (persisted) event types.

# `context_pressure`

```elixir
@spec context_pressure(String.t(), map(), keyword()) :: t()
```

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.

# `ephemeral?`

```elixir
@spec ephemeral?(t()) :: boolean()
```

True if the Event's type is ephemeral (live-only, never logged).

# `ephemeral_types`

```elixir
@spec ephemeral_types() :: [type()]
```

The set of ephemeral (live-only) event types.

# `history_compaction`

```elixir
@spec history_compaction(String.t(), map(), keyword()) :: t()
```

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.

# `new`

```elixir
@spec new(String.t(), type(), map(), keyword()) :: t()
```

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`).

# `permission_decision`

```elixir
@spec permission_decision(String.t(), String.t(), atom(), keyword()) :: t()
```

A permission decision for a gated tool call (ADR 0006).

# `plan`

```elixir
@spec plan(String.t(), [map()], keyword()) :: t()
```

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.

# `provider_usage`

```elixir
@spec provider_usage(String.t(), map(), keyword()) :: t()
```

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.

# `reasoning`

```elixir
@spec reasoning(String.t(), map(), String.t(), keyword()) :: t()
```

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.

Optional `:dialect` is additive provider evidence (for example `"anthropic"`). It
is included only when provided so old reasoning events fold byte-identically.

# `reasoning_delta`

```elixir
@spec reasoning_delta(String.t(), String.t(), keyword()) :: t()
```

A chunk of streamed reasoning text.

# `session_fork`

```elixir
@spec session_fork(String.t(), map(), keyword()) :: t()
```

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.

# `skill_activation`

```elixir
@spec skill_activation(String.t(), map(), keyword()) :: t()
```

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.

# `status`

```elixir
@spec status(String.t(), String.t(), keyword()) :: t()
```

A coarse status transition for live display (e.g. `"thinking"`).

# `subagent_event`

```elixir
@spec subagent_event(String.t(), map(), keyword()) :: t()
```

A parent-visible Subagent lifecycle event (ADR 0011). `data` carries
`subagent_id`, `child_session_id`, `event`, `status`, `agent`, `task`,
`depth`, `workspace`, and optional `summary`. Terminal events may also carry
durable operator evidence such as `reason`, `elapsed_ms`, `timeout_ms`, and
`next_actions` so parent Sessions and diagnostics can explain child outcomes
without re-running the child.

# `text_delta`

```elixir
@spec text_delta(String.t(), String.t(), keyword()) :: t()
```

A chunk of streamed assistant text.

# `tool_call`

```elixir
@spec tool_call(String.t(), String.t(), String.t(), map(), keyword()) :: t()
```

A tool/function the model asked to run. `args` is the model-supplied argument map
(string keys, as decoded from JSON).

# `tool_result`

```elixir
@spec tool_result(String.t(), String.t(), map(), keyword()) :: t()
```

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).

# `turn_failed`

```elixir
@spec turn_failed(String.t(), map(), keyword()) :: t()
```

Durable audit evidence for a Turn that ended without a clean final assistant answer.

Provider replay treats this as audit-only unless a future Prompt Contract explicitly
chooses model-visible failure text. `data` should include `terminal_status`,
`error_kind`, `error_message`, and any safe structured `details`/`next_actions`.

# `user_message`

```elixir
@spec user_message(String.t(), String.t(), keyword()) :: t()
```

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.

# `with_seq`

```elixir
@spec with_seq(t(), non_neg_integer()) :: t()
```

Return the Event with its monotonic `seq` stamped.

# `workflow_event`

```elixir
@spec workflow_event(String.t(), map(), keyword()) :: t()
```

A durable Workflow run decision (ADR 0032). `data` uses a string-keyed `kind` such as
`workflow_started`, `step_scheduled`, `checkpoint_decided`, `step_held`, or
`workflow_finished`. It records decisions and references, not live progress noise or
large duplicated artifacts.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
