Wiki · Features in depth
Backups and restore
A backup you have never restored is not a backup. Practical: what to back up, how to restore, and what to do when sessions break.
What to back up
Everything that matters lives in one folder — the Hermes home directory (~/.hermes/).
| Item | Why it matters |
|---|---|
config.yaml, .env, auth.json | Settings, model keys and sign-in. Without them a restore gives you an empty agent |
state.db (+ -wal, -shm) | Every conversation, session and related data |
skills/, memories/ | What the agent learned and what it remembers about you |
cron/ | Scheduled jobs — without them the agent forgets what it does every day |
SOUL.md, profiles | The agent's personality and all additional profiles |
With several profiles, each has its own state.db and folder. Backing up the
whole ~/.hermes/ is therefore safer than copying just “yours”.
One-command backup
| Property | How it behaves |
|---|---|
| Safe while running | Copying goes through SQLite's backup() API, so it is consistent even mid-conversation (WAL mode) |
| Not in the archive | The agent code itself, models and runtimes (tens of GB, downloadable again), caches, checkpoints and older backups |
| Exit status | 0 = everything included; 1 = some files were skipped (the zip is kept so the rest can be restored); 2 = another backup was already running |
Exit code 1 matters: if a cron job runs the backup, it must be able to tell that the
archive is incomplete. That is also why --keep does not prune older (complete) archives in that case.
Restore
The archive is decompressed and CRC-checked before anything is written. A damaged archive stops with an error and writes nothing. Files that could not be restored are listed and the command exits 1, so a partial restore never reports success.
Backup versus profile export
| hermes backup | hermes profile export | |
|---|---|---|
| Use case | Whole-machine migration, disaster recovery | Porting or sharing a single profile |
| Scope | All profiles, global config, keys, sessions | One profile: SOUL.md, memory, sessions, skills |
| Credentials | Included (.env, auth.json) | Excluded — stripped for safe sharing |
| Format | .zip | .tar.gz |
Practical consequence: never send a hermes backup archive to anyone —
it contains your keys. Use a profile export for sharing.
When sessions break (and what never to do)
Hermes keeps every conversation in one state.db per profile. If you see a message about
“another process holding an old copy of the write-ahead log”, nothing was lost — the
agent stopped writing to protect the file. Three steps fix it:
| Never | Because |
|---|---|
Delete state.db-wal or state.db-shm | The log holds conversations not yet in the main file — deleting it loses them for good |
Copy state.db on its own with cp | The three files are one image; use hermes backup or hermes sessions recover |
Run hermes doctor --fix while processes run | It can become the second writer that caused the problem |
Run sessions optimize under a live gateway | It rewrites the database (VACUUM, index rebuild), so the command detects a writer and refuses — printing the processes that hold it. --dry-run is always allowed; --force works but only when you know those processes are idle |
sessions prune under a live gateway | This one is safe: the preview is read-only and the gateway itself does the deleting (skipping sessions with a running turn). It refuses only when no gateway runs and another process holds the database |
Diagnosing and repairing a damaged file
Next to state.db you may find files such as state.db.pre-update-emergency-*.bak
(a pre-update snapshot) or state.db.corrupt.*.bak (a copy of a damaged file). The first is
useful for recovery; never put the second back over state.db — it carries the same damage.
How we do it on our server
| Habit | Why |
|---|---|
Snapshot before every update: hermes backup --quick --label "pre-upgrade" | Rollback is one command and you do not have to work out what changed |
| Daily full backup off the machine (another folder, another host) | A backup on the same disk as the data is not a backup |
| Restores are tested into a scratch profile, not production | You prove the archive works without breaking the running agent |
| Websites and apps have their own backup (git, database dump) | The Hermes backup covers the agent, not your sites — ŠipkyLiga replicates its database, sites live in git |
Check the hermes path with which hermes — cron does not see the
same PATH as your interactive shell.
Common mistakes
| Symptom | Cause and fix |
|---|---|
Backup reports Backup incomplete | Something could not be read (often a socket or a network drive). The archive is kept; check which files are listed |
| The agent “forgot” its scheduled jobs after a restore | cron/ was not in the archive (e.g. a profile export was used) — cloning a profile does not move cron jobs |
| Restore ended with exit code 1 | Some files were not restored (see Warnings) — check what is missing before deleting the original data |
