Skip to main content
Give a background agent a stable ID that survives a restart — if PraisonAI crashes mid-run, the ledger reconciles it to 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?”
No config, no new dependencies — SQLite lives at ~/.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 to LOST.

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 stdlib sqlite3.
  • No new dependencies — stdlib sqlite3 only.
  • 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

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.
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.
Call upsert() as the run moves queued → running → waiting → succeeded/failed. The more current the status, the fewer false LOST reconciliations after a restart.
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?”

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.