Events¶
reyn emits a structured event for every state change. The full event log is JSONL, written to .reyn/events/<run_id>.jsonl and replayable with reyn events <log_file>.
Event envelope¶
Every event has:
{
"ts": "2026-04-30T10:00:00.123Z",
"kind": "<event_kind>",
"phase": "<current_phase>",
"run_id": "<uuid>",
... // kind-specific payload
}
Agent ID field (all events)¶
Every event emitted from a session whose agent.id is configured (in reyn.yaml) automatically carries an agent_id field in its payload. The default value is reyn/<hostname>. This enables RBAC and multi-agent audit trails per SOC2 / ISO 27001 / METI v1.1 requirements.
See Concepts: multi-agent — "Agent ID propagation" for details.
Lifecycle events¶
| Kind | When | Key payload |
|---|---|---|
workflow_started |
First phase enters | entry_phase, input_type, default_model |
workflow_finished |
Skill completes cleanly | phase, reason, confidence, total_phase_count, final_output_keys |
phase_started |
Each phase visit begins | phase, visit_count |
phase_completed |
Each phase visit ends | phase, next_phase, decision |
phase_failed |
Phase raised an unrecoverable error | phase, error |
loop_limit_exceeded |
A phase exceeded limits.phase.max_visits |
phase, visit_count, max |
phase_budget_exceeded |
A phase exceeded its wall-clock budget (limits.phase.max_wall_seconds) |
phase, elapsed, budget |
LLM and context¶
| Kind | Key payload |
|---|---|
context_built |
phase, candidate_count, prompt_token_estimate |
llm_called |
phase, model, input_tokens, output_tokens, latency_ms |
validation_error |
What the LLM emitted that the OS rejected |
normalization_error |
LLM output couldn't be parsed at all |
Control IR¶
Each Control IR op kind emits its own event:
| Kind | When |
|---|---|
read_file, write_file, edit_file, delete_file, glob_files, grep, regenerate_index |
file op variants — all via tool_executed with op=<sub_op> |
shell_started, shell (completed), shell_timeout, shell_not_allowed |
shell op |
sandboxed_exec_started, sandboxed_exec_completed |
sandboxed_exec op — started: argv, backend; completed: argv, backend, returncode |
run_skill_started, skill_run_spawned, skill_run_failed |
run_skill op — run_skill_started carries skill_version_hash: str (sha256 hex of skill.md content at execution time; "unknown" if skill.md is absent) |
mcp_called, mcp_completed, mcp_failed |
MCP tool ops |
mcp_server_installed |
mcp_install op — name, key names only (no values) |
web_search_started, web_search_completed, web_search_failed, web_fetch_started |
search ops |
embed_progress |
embed op (Form B artifact reference only) — embedded: int, skipped: int cumulative per batch |
recall_embed_failed |
recall op — emitted when the embed sub-op fails; query, error |
index_dropped |
index_drop op — source, chunks_dropped: int |
skill_resolve_completed |
skill_resolve op — name, resolved: bool, source: "local"\|"project"\|"stdlib"\|null |
control_ir_skipped, control_ir_failed, control_ir_validation_error |
dispatch failures (control_ir_skipped reasons include shell_not_allowed, handler_not_implemented, not_allowed_in_phase) |
permission_denied |
When an op is denied by the resolver |
Credentials and OAuth¶
| Kind | Trigger | Key payload |
|---|---|---|
sub_skill_credential_scope |
Emitted by the run_skill op handler at sub-skill entry, after the OS computes the effective credential scope (intersection of the sub-skill's required_credentials with the parent scope). |
skill: str — sub-skill reference (same value as op.skill); allowed_keys: list[str] — sorted, deduplicated list of allowed secret keys, or ["*"] if the effective scope is unrestricted. |
token_refreshed |
Emitted by reyn.secrets.get_valid_token(key) after a successful OAuth refresh against the provider's token endpoint (RFC 6749 §6). |
key: str — OAuth token key (same as the ~/.reyn/oauth_tokens.json entry); expires_at: str — ISO-8601 timestamp of the new access token's expiry. |
token_refresh_failed |
Emitted by get_valid_token when the token endpoint returns a non-2xx response or the response payload is malformed. Raises OAuthRefreshError. |
key: str; error: str — short error description (HTTP status + provider error code if available). |
Notes:
- sub_skill_credential_scope is audit-grade; used to reconstruct the credential authorisation chain across nested skill runs. Pairs with run_skill_started (same skill name).
- token_refresh_failed pairs with token_refreshed — exactly one is emitted per get_valid_token call that performs a network refresh.
See also: Concepts: secret handling — OAuth lifecycle and credential scoping; Concepts: permission model — per-skill credential scoping; DSL reference: required_credentials.
Action catalog routing¶
| Kind | Trigger | Key payload |
|---|---|---|
routing_decided |
Emitted by the universal action catalog dispatch path when an action wrapper (list_actions / search_actions / describe_action / invoke_action) routes a request (FP-0034 Phase 1–3). |
action_name: str; source: str — "catalog" | "hot_alias" | "direct"; outcome: str — "dispatched" | "deflected" | "error"; chain_id: str — request chain identifier for cross-call correlation. |
Notes: enables auditing the wrapper-only routing path. Cross-correlate with chain_id across the action's downstream events.
User interaction¶
| Kind | When |
|---|---|
user_message_received |
A new user turn enters the runtime. Carries chain_id (the uuid minted by submit_user_text and propagated through any agent-to-agent messages this turn produces) |
user_intervention_received |
An ask_user op got its answer |
chat_started, chat_stopped |
Chat session lifecycle |
Skill spawning (chat)¶
| Kind | When |
|---|---|
skill_run_spawned |
A skill was launched from a router decision (run_id, skill) |
skill_spawn_refused |
_spawn_skill rejected a skill not in the agent's allowed_skills. Payload: reason="allowlist", skill, agent |
Agent-to-agent messaging¶
| Kind | When | Key payload |
|---|---|---|
agent_message_sent |
_send_to_agent or _send_agent_response delivered a payload |
kind=agent_request\|agent_response, from_agent, to_agent, depth, chain_id |
agent_request_received |
Receiving agent pulled an agent_request from its inbox |
from_agent, depth, chain_id |
agent_response_received |
Originating agent pulled an agent_response from its inbox |
from_agent, depth, chain_id |
agent_message_refused |
A send was refused (e.g. exceeded safety.loop.max_agent_hops) |
reason, to_agent, depth, chain_id |
chain_timeout |
A pending chain exceeded safety.timeout.chain_seconds and was force-resolved with a synthetic error response upstream |
chain_id, waiting_on (sorted list of agents that hadn't replied), timeout_seconds, origin_agent |
chain_id is uuid4 hex; one per top-level user submission, propagated unchanged across every hop. Cross-agent reconstruction is grep <chain_id> over each agent's events.jsonl plus history.jsonl.
Workspace¶
| Kind | When |
|---|---|
workspace_updated |
Any artifact is written |
tool / tool_executed |
Generic tool dispatch |
Skill management¶
| Kind | Payload fields | Emitted when |
|---|---|---|
skill_rolled_back |
skill: str, from_version: int, to_version: int, reason: str (default "user rollback via CLI") |
A reyn skill rollback invocation restores a prior version. Written to .reyn/events/direct/cli/<YYYY-MM-DD>.jsonl. See Reference: CLI — reyn skill rollback. |
Replay¶
Replays the log to the console with the same formatting as a live run. The LLM is not re-invoked — replay is purely for inspection.
Why everything is an event¶
Two consequences fall out of "every state change emits":
- Replayability. A saved log is a complete record of execution. Future checkpoint/resume designs (see roadmap) build on this.
- Observability with no bolt-on. No separate logger, tracer, or telemetry hook — the same channel powers debug output, replay, and (eventually) eval analytics.
See also¶
- run.md —
--eventsflag - control-ir.md — Control IR ops
- Concepts: events