state.db — Session State Store
state.db is the main SQLite database for Hermes Agent on the Agent Host. It is
the single source of truth for session history, message logs, and full-text
search. A separate file sessions.db exists but is a 0-byte placeholder —
all data lives in state.db.
Location
Section titled “Location”~/.hermes/state.db # Live database (WAL mode)~/.hermes/state-snapshots/ # Auto-snapshots (pre-update, etc.)Tables
Section titled “Tables”| Table | Purpose | ~Size |
|---|---|---|
| sessions | One row per conversation session. Stores session ID, source platform (slack/telegram/cli), model config, token usage, cost tracking, timestamps, parent session (for handoff chains), and title. | 38 rows |
| messages | Individual messages per session. Stores role (user/assistant/tool/system), content, tool call metadata, timestamps, reasoning outputs, and platform message IDs. | 2 219 rows |
| messages_fts | FTS5 virtual table over messages.content with trigram tokenizer. Powers the session_search tool for fast full-text retrieval across all sessions. | 2 219 docs |
| schema_version | Migration version counter. Used by Hermes to apply schema upgrades on startup. | 1 row |
| state_meta | Generic key-value metadata store. | 2 rows |
| compression_locks | Advisory locks for session compression. Prevents concurrent compression of the same session. | 0 rows |
| sqlite_sequence | Auto-updated by SQLite for AUTOINCREMENT on messages.id. | 1 row |
FTS5 internal tables
Section titled “FTS5 internal tables”The trigram FTS5 index creates supporting tables automatically:
messages_fts_config, messages_fts_content, messages_fts_data,
messages_fts_docsize, messages_fts_idx, plus messages_fts_trigram_*.
These are all internal to the FTS5 virtual table and should not be queried
directly.
Key indexes
Section titled “Key indexes”CREATE INDEX idx_sessions_source ON sessions(source);CREATE INDEX idx_sessions_parent ON sessions(parent_session_id);CREATE INDEX idx_sessions_started ON sessions(started_at DESC);CREATE INDEX idx_messages_session ON messages(session_id, timestamp);CREATE INDEX idx_compression_locks_expires ON compression_locks(expires_at);Schema highlights — sessions table
Section titled “Schema highlights — sessions table”| Column | Purpose |
|---|---|
id | Primary key, e.g. slack:C0B7C9ZFY4R:1780260332.893459 |
source | Platform: slack, telegram, discord, cli, … |
parent_session_id | Self-referential FK for compression handoff chains |
model, billing_provider, billing_base_url | Model/billing config at session creation time |
input_tokens, output_tokens, cache_read_tokens, cache_write_tokens, reasoning_tokens | Token consumption counters |
estimated_cost_usd, actual_cost_usd | Cost tracking (estimated vs. confirmed) |
title | Auto-generated or user-edited session title |
handoff_state, handoff_platform | Cross-platform handoff support |
Schema highlights — messages table
Section titled “Schema highlights — messages table”| Column | Purpose |
|---|---|
id | AUTOINCREMENT primary key |
session_id | FK → sessions.id |
role | user, assistant, tool, system |
content | Message text (indexed by FTS5) |
tool_calls, tool_call_id, tool_name | Tool invocation metadata |
reasoning, reasoning_content, reasoning_details | Thinking/reasoning output |
platform_message_id | Cross-platform message correlation (e.g. Slack TS) |
observed | Flag for deduplication |
Backup coverage
Section titled “Backup coverage”state.db is included in both backup mechanisms:
-
hermes backup(full zip) —state.dbis listed in_QUICK_STATE_FILES(line 489 ofhermes_cli/backup.py). The backup uses_safe_copy_db()which callssqlite3.backup()for a consistent snapshot of the WAL-mode database, avoiding corruption from copying live files. Excluded from zip:.db-wal,.db-shm,.db-journalsidecars (would pair a fresh snapshot with stale journal data). -
Quick snapshots (
_QUICK_SNAPSHOTS_DIR) —state.dbis also in the quick snapshot manifest (line 275 validation marker), meaninghermes updateand pre-flight operations snapshot it to~/.hermes/state-snapshots/<timestamp>/before mutations. A maximum of 20 snapshots are retained; state.db copies are pruned more aggressively due to their size.
Verifying backup includes state.db
Section titled “Verifying backup includes state.db”# List files in the latest full backupunzip -l ~/.hermes/backups/hermes-backup-*.zip | grep state.db
# Check latest quick snapshotls ~/.hermes/state-snapshots/*/state.dbWhy not sessions.db?
Section titled “Why not sessions.db?”The file ~/.hermes/sessions.db exists as a 0-byte file. It is a legacy
placeholder — all session data has been stored in state.db since the
hermes_state.py SQLite store replaced the per-session JSONL approach. The
backup system targets state.db explicitly and does not need sessions.db.