Quick Start
1
Simple Usage
Nothing to configure — hardening is automatic for any SQLite-backed store.
2
Custom Store
Build your own SQLite-backed store with the hardened factory.
How It Works
The factory tries WAL first, then probes the on-disk header before ever falling back — so a database another connection wrote in WAL is never downgraded.Integrity Guard
Whenguard=True, the connector runs a cheap quick_check on open and — on a malformed file — forensically backs up the bad bytes and attempts a bounded, least-destructive repair before returning a usable connection. SqliteSessionStore and SqliteTranscriptStore opt in by default so a corrupt sessions.db no longer takes the durable path down.
Corruption on open
A malformed database is detected, backed up, and repaired in place — or quarantined so a fresh empty DB opens instead of crashing. The guard treats a transientdatabase is locked / database is busy on the probe as healthy-but-busy — a peer momentarily holding the file is left exactly as-is, with no backup and no repair.
What lands on disk
The forensic backup fails closed on low disk — it needs
2 × file_size + 1 MiB free, so a corruption event never itself fills the disk. Backups are retention-capped at _MAX_FORENSIC_BACKUPS = 3 per file, and repairs are bounded at _MAX_REPAIR_ATTEMPTS = 3 per file (tracked in the .repair sidecar) so a boot-loop cannot churn a permanently-bad file. These are internal capacity constants — reason about them, but don’t override them.
Public helpers
sqlite_quick_check is a cheap PRAGMA quick_check(1) wrapper that returns False on any malformed-image / I/O error and re-raises transient lock/busy errors so callers can tell “locked” (leave alone) apart from “corrupt” (back up + repair).
Should I turn guard on?
Configuration Options
Thesqlite_connect factory forwards unknown keyword arguments to sqlite3.connect.
Common Patterns
Docker / Kubernetes / NFS deployments need no special handling — the defaultAgent(memory=True) already survives them.
synchronous="NORMAL" (safe under WAL against process crashes).
Choosing a synchronous Level
Scope
The core memory (STM/LTM), session, transcript, and generic
SQLiteBackend stores use the hardened factory today. The bot/gateway wrapper stores (_outbox, _dlq, _ingress, approval, delivery-control, and kanban) are not wired in yet.Integrity guard (guard=True) opt-in:- Guard on:
SqliteSessionStore(session index),SqliteTranscriptStore(transcript store). - Guard off (unchanged):
SQLiteBackend, memory STM, memory LTM, and the wrapper stores inpraisonai-bot/andpraisonai/persistence. These can opt in later by passingguard=Truetosqlite_connect.
Best Practices
Let the factory choose the journal mode
Let the factory choose the journal mode
Do not run
PRAGMA journal_mode=WAL yourself — sqlite_connect picks WAL where it works and DELETE where it does not.Keep synchronous=FULL unless you measured a bottleneck
Keep synchronous=FULL unless you measured a bottleneck
FULL survives an OS or power crash. Switch to NORMAL only after profiling shows a durability-vs-throughput trade-off worth making.Use sqlite_connect for custom stores
Use sqlite_connect for custom stores
For any SQLite-backed store you build, call
sqlite_connect instead of sqlite3.connect to inherit the fallback and durability defaults.Expect DELETE on hostile filesystems
Expect DELETE on hostile filesystems
On Docker Desktop, NFS, or network volumes the on-disk journal mode may be
DELETE. This is correct behaviour, not a regression, and does not change any API.Let the guard classify a locked file — it won't back it up
Let the guard classify a locked file — it won't back it up
A transient
database is locked / database is busy on the quick_check probe is treated as healthy-but-busy, and the file is left untouched. Only a genuinely malformed image triggers a backup or repair.Never rely on <file>.corrupt-* for a live copy of your data
Never rely on <file>.corrupt-* for a live copy of your data
Those are forensic snapshots of malformed bytes, not backups. If you need real backups, run
sqlite3 .backup or your platform’s snapshotting.Don't delete <file>.repair yourself
Don't delete <file>.repair yourself
The ledger caps repair attempts so a permanently-bad file doesn’t churn on every boot. Deleting it resets the budget.
Turn guard=True on for any custom durable store you build with sqlite_connect
Turn guard=True on for any custom durable store you build with sqlite_connect
This is what the shipped session/transcript stores do; anything else that must open reliably should follow.
Related
SQLite Persistence
Local file database for conversations
SQLite Transcript Store
Concurrent gateway session persistence
Memory
Short- and long-term agent memory
Session Store
Cross-session search and recall

