Introduction
Hermes' session store is a single SQLite database at ~/.hermes/state.db. That sentence carries a lot of design decisions: why a database at all, why SQLite specifically, and what guarantees you get when something goes wrong. Understanding the under-the-hood model helps you trust the store, and helps you reason about backups, migration, and recovery.
Key Concepts
state.db: The single SQLite file holding sessions, messages, memory, and metadata.- ACID writes: Every message commit is atomic, partial messages cannot sneak in after a crash.
- Single-file portability: Backing up your sessions is
cp state.db elsewhere/. Migrating is the same. - WAL mode: SQLite's write-ahead log lets readers and writers operate concurrently without blocking.
Real World Context
Suppose Hermes (or your terminal) crashes mid-message. Without ACID, you might end up with half a tool result in state.db, breaking the next resume. With ACID, and the way SQLite implements it, either the message is fully committed or it is not there at all. On the next launch, Hermes reads the last consistent state and you continue. Crash recovery is not a feature you have to think about; it is a property of the storage choice.
Deep Dive
Why a database at all
Sessions are queryable structured data: "show me sessions touched in the last week," "find sessions mentioning X," "give me the last N messages of session Y." A flat-file format would either lose query performance or duplicate that complexity. A database is the right tool.
Why SQLite specifically
textProperty Why it matters for Hermes ──────────────────────────────── ──────────────────────────────────────── Single file Trivial to back up, copy, ship No server, no daemon Hermes installs in seconds; nothing to admin ACID writes Crash-safe by construction WAL mode Concurrent read/write without locking up Mature, ubiquitous, well-tested You can trust it with years of data
A network database (Postgres, MySQL) would force users to install and run a server. Plain JSON files would lose ACID and search. SQLite is the middle path.
What survives crashes
- Every committed message and tool result.
- Every session's metadata (ID, title, timestamps, token counters).
- The lineage between resumed sessions.
What does not survive: anything in flight at the moment of the crash. If the model was streaming a response when the lights went out, the partial response is discarded, state.db shows the last fully committed state.
Backups in two commands
bashcp ~/.hermes/state.db ~/backups/state.db.$(date +%F) sqlite3 ~/.hermes/state.db ".backup ~/backups/hermes-snapshot.db"
The second form takes a consistent snapshot even while Hermes is running.
Common Pitfalls
- Editing
state.dbdirectly, Do not runUPDATEorINSERTqueries against it from outside Hermes. Use Hermes' own commands. Direct writes can corrupt the schema. - Backing up with
cpwhile Hermes is mid-write, On most systems it works, butsqlite3 .backupis the safer form for a live snapshot.
Best Practices
- Snapshot before risky changes, Before a major Hermes upgrade or a config experiment, take a
.backupsnapshot. - Trust ACID, but verify after crashes, On the rare resume after a hard crash, glance at the last few messages of the resumed session to make sure things look right.
Summary
state.dbis a single SQLite file under~/.hermes/.- ACID writes plus WAL mode give you crash safety and concurrent access.
- Backup is one file copy; restoration is the same.
- Do not touch the schema by hand, Hermes owns the DB.
Code Examples
# Live, consistent backup, works even while Hermes is running
sqlite3 ~/.hermes/state.db ".backup ~/backups/hermes-$(date +%F).db"
# Restore on a new machine
cp ~/backups/hermes-2026-05-01.db ~/.hermes/state.db
hermes sessions list # your full session library is intact and listed