▶ runtime-narrative

SQLite Persistence & CLI

SqliteStoryRenderer writes every story, stage, and failure to a SQLite database as it happens. The bundled runtime-narrative CLI reads that database back for post-hoc inspection, and since it's plain SQLite you can also query it directly.

Schema

SqliteStoryRenderer creates three tables on first use.

stories — one row per story

ColumnTypeDescription
story_idTEXT PKUUID
nameTEXTStory name
started_atTEXTISO-8601 timestamp
completed_atTEXTISO-8601 timestamp
successINTEGER1 = success, 0 = failed
duration_secondsREALComputed from timestamps via julianday

stages — one row per stage execution

ColumnTypeDescription
idINTEGER PKAuto-increment
story_idTEXTFK to stories
stage_nameTEXTStage name
stage_indexINTEGERPosition in story
parent_stage_nameTEXTNull for top-level stages
started_atTEXT
completed_atTEXT
duration_secondsREAL
completedINTEGER1 when StageCompleted emitted
failedINTEGER1 when FailureOccurred emitted

failures — one row per failure

ColumnTypeDescription
idINTEGER PKAuto-increment
story_idTEXTFK to stories
stage_nameTEXTStage where failure occurred
error_typeTEXTException class name
error_messageTEXTstr(exc)
filenameTEXTPrimary frame path
linenoINTEGERPrimary frame line number
functionTEXTPrimary frame function name
source_lineTEXTFailing source line
traceback_textTEXTFull traceback
exception_chainTEXT
llm_analysisTEXTNull until LLMAnalysisReady back-fills it
occurred_atTEXTdatetime('now')

Wiring up the renderer

python
from runtime_narrative import story, stage
from runtime_narrative.renderer.persistence_renderer import SqliteStoryRenderer

db = SqliteStoryRenderer("narrative.db")

with story("User Import", renderers=[db], total_stages=2):
    with stage("Fetch"):
        users = [{"id": 1, "name": "Alice"}]
    with stage("Upsert"):
        pass

CLI

The runtime-narrative CLI is registered as a console script at install time.

List recent failures

bash
# Last 10 failures in the default database
runtime-narrative failures

# Last 25 failures in a custom database
runtime-narrative failures --db narrative.db --last 25

# Filter by stage name
runtime-narrative failures --stage "Upsert"

# Filter by story name
runtime-narrative failures --story "User Import"

# Combine filters
runtime-narrative failures --stage "Charge Card" --story "Order%" --last 5

Show full details for a specific story

bash
runtime-narrative story <story_id>
runtime-narrative story a1b2c3d4 --db narrative.db

The story subcommand prints the story summary, a table of all stages with status and duration, and full failure details including LLM analysis when available.

Direct SQL access

Since the database is plain SQLite you can query it directly with any tool.

python
import sqlite3

conn = sqlite3.connect("narrative.db")

# Failed stories in the last hour
rows = conn.execute("""
    SELECT name, duration_seconds, completed_at
    FROM stories
    WHERE success = 0
      AND completed_at > datetime('now', '-1 hour')
    ORDER BY completed_at DESC
""").fetchall()

# Most common failure types
rows = conn.execute("""
    SELECT error_type, COUNT(*) as count
    FROM failures
    GROUP BY error_type
    ORDER BY count DESC
""").fetchall()

Next step

See Testing with StoryRecorder for asserting on stage completion and failures in unit tests, without needing a database at all.