LOST so you can wake the user and re-route.
Complements — does not replace — the Run-State Journal. The ledger tracks run status (queued/running/done/failed/lost); the journal tracks the per-event cursor (model decision, tool call, tool result, iteration index) so a crashed run can resume without re-executing tools or re-billing LLM calls. Use the ledger to answer “is this run alive?”; use the journal to answer “where in the loop did it die?”
~/.praisonai/runs/ledger.db.
Quick Start
1
Get the default ledger
2
Track a run
3
Reconcile on startup
recover_orphans() returns the list of records it marked LOST. It preserves each run’s channel and thread_id so the gateway can wake the same user back.How It Works
A run is recorded as it starts, updated as it progresses, and finalised with a terminal status. If a process dies while a run is still active, the next boot reconciles it toLOST.
Run statuses
RunStatus partitions every run into active (recoverable) or terminal (done).
Check the partition with the
is_active / is_terminal helpers:
RunStatus is a str enum, so RunStatus.RUNNING == "running".
Configuration Options
RunRecord
A durable record of a single run.channel and thread_id capture the origin route so the gateway can wake the user back.
to_dict() / from_dict() roundtrip a record to a JSON/SQLite-friendly dict and back.
RunLedgerProtocol
The pluggable store contract — swap in a heavier backend by implementing these four methods.SQLiteRunLedger
The zero-dependency default, backed by stdlibsqlite3.
- No new dependencies — stdlib
sqlite3only. - Thread-safe — a re-entrant lock guards a shared WAL connection.
recover_orphans()preserves the origin route and is idempotent (a second call returns[]).close()releases the connection; the file persists across restarts.
Common Patterns
Mark a run terminal on success
Wake users after a crash
List recent runs regardless of status
Best Practices
Call recover_orphans() once at boot
Call recover_orphans() once at boot
Run reconciliation on gateway startup, before accepting new work. Active runs left by the previous process become
LOST, and you get their origin routes back to notify users.Always set channel and thread_id
Always set channel and thread_id
These fields are the only way the gateway can wake the right user back. Set them when the run starts so a later
LOST reconciliation can reach the origin thread.Update status at each transition
Update status at each transition
Call
upsert() as the run moves queued → running → waiting → succeeded/failed. The more current the status, the fewer false LOST reconciliations after a restart.Swap the store for heavier backends
Swap the store for heavier backends
SQLiteRunLedger is the default, but any object implementing RunLedgerProtocol (Postgres, Redis, a hosted queue) drops in unchanged — the gateway only depends on the protocol.What The User Sees
1
User asks for a long task
A user messages a Telegram bot: “Research the top 10 databases and write a comparison.” The agent starts, and the run is recorded as
RUNNING with channel="telegram" and the user’s thread_id.2
PraisonAI restarts mid-run
The process is killed or crashes before the run finishes. In-memory state is gone, but the ledger row on disk survives.
3
The gateway wakes the user back
On boot,
recover_orphans() marks the run LOST and returns it with the original channel and thread_id. The gateway posts back to the same Telegram thread: “Your last run was interrupted — retry?”Related
Background Tasks
Run agent work in the background and collect results later.
Background Subagents
Spawn subagents that return a job ID immediately — the general-purpose ledger backs their durable state.

