SqliteTranscriptStore keeps every gateway session as one row in a WAL SQLite database — the default backend whenever session.persist is on.
Nothing changes for a single-user Python Agent in a script — session APIs are identical. Only the gateway changes: with session.persist: true, transcripts now live in one sessions.db with concurrent readers and indexed routing instead of per-session JSON files guarded by a FileLock.
What changed by default
Withsession.persist: true, the gateway now builds SqliteTranscriptStore unless you opt out with session.store: file.
The change is backward-compatible for API callers (public methods are identical) but visible on disk. External tools pointed at
*.json files should either read sessions.db or set session.store: file.
Quick Start
1
Default (YAML) — SQLite is on
session.persist: true is enough — store: sqlite is the default. Transcripts land in ~/.praisonai/sessions/sessions.db.2
Keep the legacy JSON layout
store: file when external tooling grep-scans the individual *.json transcripts.3
Python embedder using the store directly
session.store config field.How It Works
Two gateway processes handling the same session serialise inside SQLite, not on a directory scan — the read-modify-write window the oldFileLock could lose is closed by BEGIN IMMEDIATE.
Every read-modify-write (add_message and friends) runs its SELECT + INSERT OR REPLACE inside one BEGIN IMMEDIATE transaction, so a second gateway process cannot slip a read between this one’s read and its write.
Which backend to pick
Configuration Options
SqliteTranscriptStore constructor:
SessionConfig.store (gateway YAML):
Selection rules:
session.persist: false→ no store, regardless ofstore:.session.persist: true+store: sqlite(default) →SqliteTranscriptStore.session.persist: true+store: file→DefaultSessionStore.- An injected
session_store=…always wins — the field only applies when the gateway builds the store itself. - If
sqlite3is unavailable, the gateway falls back to the JSON store and logs a warning.
Schema (one row per session — inspect with the
sqlite3 CLI if needed):
Common Patterns
Default gateway config — SQLite is on with justpersist: true:
db_path on a shared volume — WAL + BEGIN IMMEDIATE give cross-process append-safety on a real filesystem:
Migrating from JSON to SQLite (automatic). On the first gateway boot after this change, any existing
~/.praisonai/sessions/*.json transcripts are imported once into the new sessions.db. After that, new writes go to the DB; the JSON files remain on disk but are no longer updated. To preserve the exact previous behaviour, set session.store: file before the first boot.Best Practices
Don't panic when *.json files disappear
Don't panic when *.json files disappear
On the first boot after the upgrade, legacy JSON transcripts are imported into
sessions.db once, then the JSON files stop being written to. Nothing was lost. To keep the JSON layout, set session.store: file before the first boot.Don't run sqlite3 maintenance while the gateway is up
Don't run sqlite3 maintenance while the gateway is up
WAL +
BEGIN IMMEDIATE are safe for concurrent gateway writers, but ad-hoc VACUUM/REINDEX from a separate sqlite3 process during traffic will fight for the RESERVED lock. Do maintenance in a quiet window.Prefer the config field to injection
Prefer the config field to injection
If you set
session.store in YAML and pass session_store=…, the injected store wins and the config field is ignored. This is intentional — embedders control lifecycle — but easy to be surprised by. Log the resolved store class on startup.This is not FTS
This is not FTS
SqliteTranscriptStore.search() uses LIKE — good for hundreds of sessions, not tens of thousands. For scalable cross-session recall, use SqliteSessionStore (a different class — see the note above).Related
Gateway Session Persistence
The gateway-side view of session persistence
Session Store
The Session/store API surface and
SqliteSessionStore
