▶ runtime-narrative

Event Reference

All events are plain dataclasses and are part of the stable public API. Every renderer's handle(event) receives one of these seven types.

python
from runtime_narrative import (
    StoryStarted, StageStarted, StageCompleted,
    FailureOccurred, StoryCompleted, LLMAnalysisReady, LogRecorded,
    Event,   # Union[StoryStarted, StageStarted, StageCompleted, FailureOccurred, StoryCompleted, LLMAnalysisReady, LogRecorded]
)

They are emitted in a fixed sequence within each story:

text
StoryStarted → (StageStarted → StageCompleted)* → [FailureOccurred] → StoryCompleted
                                                                              ↓
                                                              [LLMAnalysisReady]  (background_analysis only)

StoryStarted

Emitted when the story context is entered.

FieldTypeDescription
story_idstrUUID for this story execution
story_namestrThe name passed to story(name)
timestampdatetimeWall-clock time at story start
parent_story_idstr | Nonestory_id of the enclosing story, or None for a root story
root_story_idstrstory_id of the top-most ancestor (itself, if this is a root story)

StageStarted

Emitted when a stage() context is entered.

FieldTypeDescription
story_idstrUUID of the enclosing story
story_namestrName of the enclosing story
stage_namestrThe name passed to stage(name)
timestampdatetimeWall-clock time at stage start
stage_indexintZero-based position of this stage in the story (default 0)
parent_stage_namestr | NoneName of the enclosing stage, or None for top-level stages
root_story_idstrstory_id of the top-most ancestor story (lets a renderer group stages by call tree, not just by story)

StageCompleted

Emitted when a stage exits without exception (or in dry_run mode even if it raised).

FieldTypeDescription
story_idstrUUID of the enclosing story
story_namestrName of the enclosing story
stage_namestrStage name
timestampdatetimeWall-clock time at stage exit
duration_secondsfloatElapsed time from stage enter to stage exit
stage_indexintZero-based position (default 0)
parent_stage_namestr | NoneName of the enclosing stage, or None
root_story_idstrstory_id of the top-most ancestor story

story_name on stage events means a renderer can filter by story without tracking a story_id → story_name side table populated from StoryStarted/StoryCompleted.

FailureOccurred

Emitted when an exception propagates out of the story block. Contains the full enriched failure payload.

FieldTypeDescription
story_idstrUUID of the story
story_namestrStory name
stage_namestrName of the stage where the failure occurred
error_typestrException class name, e.g. "ValueError"
error_messagestrstr(exc)
filenamestrSource file of the primary frame
linenointLine number of the primary frame
functionstrFunction name of the primary frame
source_linestrSource text of the failing line
exception_chainstrHuman-readable chain of chained exceptions (A <- B <- C), up to 5 levels. Follows __cause__ (raise X from Y) unconditionally; follows __context__ (implicit chaining) only when the raiser didn't suppress it with raise X from None — matching Python's own traceback output, so this never surfaces an exception the raiser deliberately hid
exact_causestrInferred one-line cause description. For TypeError: unsupported operand type(s) for OP: 'A' and 'B' in rich mode, this names the specific operands instead of restating the exception message — e.g. `promo` = {'buy': 1, ...} (dict) and `item['price']` = 29.99 (float) can't be combined with '*' - float and dict are incompatible operand types. A bare variable name or a one-level constant-key subscript (item["price"]) is resolved against the already-captured frame locals (same redaction rules as the locals section — a secret-looking name shows (type, redacted) instead of its value); anything more complex (function calls, attribute chains) shows the expression text without a value. Falls back to the generic one-line message in lean mode or for any other error shape
llm_analysisstr | NoneAnalyzer output; None if no analyzer or background_analysis=True
stage_timelinestrText summary of all stages and their states
progress_percentintPercentage of stages completed at failure time
completed_stagesintCount of StageCompleted events before this failure
total_stagesintTotal stages seen (or declared via total_stages=)
timestampdatetimeWall-clock time of failure
traceback_textstrFull formatted traceback (may be truncated in production)
diagnostics_modestr"lean" or "rich" (default "lean")
primary_frame_reasonstrWhy this frame was chosen: "leaf", "innermost_app", or "innermost_non_stdlib"
stack_frameslist[dict]Structured list of all frames; each dict has index, filename, lineno, function, kind, line, is_primary
source_snippetstr | NoneMulti-line source context around the primary frame (±snippet_context_lines lines)
compressed_stack_summarystrOne-line summary, e.g. "2 app frame(s), 5 other/hidden in full stack (7 total)"
hidden_frame_countintNumber of non-app frames in the full stack
traceback_truncatedboolTrue if traceback_text was capped
locals_by_framedict | NoneLocal variables per frame (rich mode only); keys are "frame_0", "frame_1", etc.
redaction_removed_keysintCount of local variable keys that were redacted
parent_story_idstr | Nonestory_id of the enclosing story, or None for a root story
root_story_idstrstory_id of the top-most ancestor story

StoryCompleted

Emitted unconditionally at story exit, after any FailureOccurred.

FieldTypeDescription
story_idstrUUID of the story
story_namestrStory name
successboolTrue if the story exited without exception
progress_percentintFinal percentage of stages completed
completed_stagesintFinal count of completed stages
total_stagesintTotal stages seen or declared
timestampdatetimeWall-clock time at story exit
duration_secondsfloatElapsed time from story enter to story exit
parent_story_idstr | Nonestory_id of the enclosing story, or None for a root story
root_story_idstrstory_id of the top-most ancestor story
outcomestrShort result label set via StoryRuntime.set_outcome() (e.g. "200 OK"); "" when unset. The HTTP middlewares set it automatically from the response status (http_outcome(status_code)), and ConsoleRenderer then renders a self-contained ended line: Story ended: GET /api/call - SUCCESS (200 OK, 0.023s) — making a separate server access log (e.g. uvicorn's) redundant, so it can be disabled with access_log=False.

LLMAnalysisReady

Emitted after StoryCompleted only when background_analysis=True and the analyzer returned a non-None result.

FieldTypeDescription
story_idstrUUID of the story that failed
story_namestrStory name
stage_namestrStage where the failure occurred
llm_analysisstrAnalyzer output text
timestampdatetimeWall-clock time when the analysis completed

LogRecorded

Emitted by NarrativeLogHandler when it captures a stdlib logging record while a story is active.

FieldTypeDescription
story_idstrUUID of the story active when the record was captured
story_namestrName of that story
root_story_idstrstory_id of the top-most ancestor story
stage_namestrName of the active stage, or "" if none
levelstrrecord.levelname, e.g. "WARNING"
logger_namestrrecord.name
messagestrrecord.getMessage()
timestampdatetimerecord.created as a datetime
exc_textstr | NoneFormatted exception text if the record carried exc_info
fieldsdict[str, Any]Caller-supplied extra={...} fields from the logging call, minus standard LogRecord attributes

Next step

Browse the Examples page for a runnable script demonstrating almost every event, renderer, and diagnostics feature described across these docs.