Storage Under the Hood: Why SQLite, Where It Lives

+15 Mana ✨

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

text
Property                          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

bash
cp ~/.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

  1. Editing state.db directly, Do not run UPDATE or INSERT queries against it from outside Hermes. Use Hermes' own commands. Direct writes can corrupt the schema.
  2. Backing up with cp while Hermes is mid-write, On most systems it works, but sqlite3 .backup is the safer form for a live snapshot.

Best Practices

  1. Snapshot before risky changes, Before a major Hermes upgrade or a config experiment, take a .backup snapshot.
  2. 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.db is 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

bash
# 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
✓ Completed