Events¶
Every state change in reyn emits an event. The event log is the runtime's diary: a JSONL stream that records what happened, in order, with enough detail to replay the run.
Why everything is an event¶
There is no separate logger, tracer, or telemetry hook. The same channel powers:
- Live debug output. Console reporters subscribe to the event stream and render each event as it arrives.
- Replay.
reyn events <log_file>re-renders a saved log to the console without re-invoking the LLM. - Eval analytics. Eval reports aggregate event data (token usage, phase counts, validation errors) per case.
- Crash recovery (implemented). Crash recovery reconstructs agent state from the WAL (
.reyn/state/wal.jsonl) plus seq-keyed snapshots as its substrate — not the audit log. User-facing rewind/resume (PITR + global rewind) is a separate design tracked in #1533.
If the OS is the only mutator (P3) and every mutation emits an event, the log is sufficient. There's no "what else happened" to chase down.
What gets recorded¶
Three big buckets, plus a few smaller ones:
- Lifecycle —
workflow_started,phase_started,phase_completed,workflow_finished,phase_failed,loop_limit_exceeded. - LLM and context —
context_built,llm_called,validation_error,normalization_error. - Control IR — one event per op kind (
read_file,write_file,shell_started,run_skill_started, etc.) pluspermission_denied. - Chat lifecycle —
chat_started,chat_stopped,user_message_received,skill_run_spawned,skill_spawn_refused. - Agent-to-agent messaging —
agent_message_sent,agent_request_received,agent_response_received,agent_message_refused. Each carrieschain_idso a single user request can be traced across hops.
The full taxonomy lives in the events reference.
Task subscription events — WAL, not audit log¶
Task↔session binding changes (task_subscribed, task_rebound) are recorded in the WAL (StateLog, .reyn/state/wal.jsonl) — not in the P6 audit event log. The WAL is the crash-recovery and time-travel substrate; the audit log is the per-run trace. They are separate logs with different durability contracts (see Time-travel — WAL vs audit-event separation). Do not look for task_subscribed in the audit log; it is not there.
What an event is¶
Every event has a stable envelope:
type — event type (see reference)
timestamp — ISO-8601 timestamp
data — flat dict of payload fields specific to the type
Key fields present in most events (in data):
run_id — uuid for the run (always present for workflow-execution events)
skill — workflow name (always present for workflow-execution events)
phase — current phase at emission time
Note: run_id and skill are present on lifecycle events (workflow_started,
workflow_finished, llm_called, etc.) but absent from some events emitted outside
a run context (e.g. chat_started).
Events with audit fields (FP-0021)¶
Eight event kinds are now required to carry specific
audit fields in their data dict. The authoritative registry lives in
src/reyn/core/events/event_schema.py (EVENT_AUDIT_REQUIREMENTS). A Tier 2
invariant test (tests/test_event_audit_invariants.py) verifies that each
event kind carries its declared fields on every CI run.
| Event kind | Required fields |
|---|---|
workflow_started |
run_id, skill |
workflow_finished |
run_id, skill |
llm_called |
run_id, skill |
llm_response_received |
run_id, skill |
permission_granted |
run_id, skill, phase |
permission_denied |
run_id, skill, phase |
user_intervention_requested |
run_id, skill, intervention_id |
user_intervention_received |
run_id, skill, intervention_id |
Enforcement is test-time only (not at emit() runtime) to keep
production overhead zero.
Stable shape makes the log machine-readable without a custom parser per consumer.
What events are NOT¶
- Not application logs. A workflow author shouldn't emit free-form events. The set is OS-defined.
- Not memory. Events are the runtime's per-run record; memory is across-run knowledge. See ../data-retrieval/memory.md.
- Not the source of truth for artifacts. Artifacts pass through the workspace channel; events record that they passed.
Reading events as a debugging tool¶
When something looks wrong:
- Find the run id from the run output's last line (
events saved → ...). reyn events .reyn/events/<run_id>.jsonl --conversationto see what each LLM call looked like and what it returned.- Or
--filter validation_error --filter normalization_errorto jump straight to where the OS rejected output.
You don't need a debugger; the log already has the information.
See also¶
- Reference: events — the full event taxonomy
Events are not just an audit trail — they are the substrate for crash recovery
and user-facing time-travel (/rewind). For payload-level trace inspection,
see reference/dogfood-tracing.md.