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.

✅ Verified 17. 10. 2026Source: official documentation →📋 Copy for your AI
💾
A backup you have never restored is not a backup — it is just a file on a disk. Hermes makes this reasonably easy: it can take a consistent backup while running and it refuses a damaged archive. One thing nobody can do for you: test the restore before you need it.

What to back up

Everything that matters lives in one folder — the Hermes home directory (~/.hermes/).

ItemWhy it matters
config.yaml, .env, auth.jsonSettings, 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, profilesThe 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

# full backup (default target: ~/hermes-backup-<timestamp>.zip) hermes backup # to a specific place you back up elsewhere hermes backup -o /root/backups/hermes.zip # quick snapshot of the essentials only (config, state.db, .env, cron) hermes backup --quick --label "pre-upgrade" # keep only the newest five full backups hermes backup -o /root/backups/ -k 5
PropertyHow it behaves
Safe while runningCopying goes through SQLite's backup() API, so it is consistent even mid-conversation (WAL mode)
Not in the archiveThe agent code itself, models and runtimes (tens of GB, downloadable again), caches, checkpoints and older backups
Exit status0 = 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

# restore a whole archive (stop the gateway first) hermes gateway stop hermes import /root/backups/hermes.zip # roll back the snapshot taken before an update hermes backup restore --state pre-update

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 backuphermes profile export
Use caseWhole-machine migration, disaster recoveryPorting or sharing a single profile
ScopeAll profiles, global config, keys, sessionsOne profile: SOUL.md, memory, sessions, skills
CredentialsIncluded (.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:

1) stop every process of that profile hermes gateway stop (and quit Desktop, dashboard, cron) 2) find who still holds the log hermes doctor (prints PID and command) 3) start again (one process) and resend the message
NeverBecause
Delete state.db-wal or state.db-shmThe log holds conversations not yet in the main file — deleting it loses them for good
Copy state.db on its own with cpThe three files are one image; use hermes backup or hermes sessions recover
Run hermes doctor --fix while processes runIt can become the second writer that caused the problem
Run sessions optimize under a live gatewayIt 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 gatewayThis 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

hermes gateway stop hermes sessions recover --source ~/.hermes/state.db --inspect-only # read-only diagnosis hermes sessions recover --source ~/.hermes/state.db --output ~/recovered-state.db hermes sessions repair --check-only # what would be repaired hermes sessions repair # repair (takes its own backup)

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

HabitWhy
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 productionYou 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
# example cron: quick backup daily at 3:30, full backup on Sundays 30 3 * * * /root/.local/bin/hermes backup --quick --label daily -o /root/backups/ 30 4 * * 0 /root/.local/bin/hermes backup -o /root/backups/ -k 4

Check the hermes path with which hermes — cron does not see the same PATH as your interactive shell.

Common mistakes

SymptomCause and fix
Backup reports Backup incompleteSomething 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 restorecron/ 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 1Some files were not restored (see Warnings) — check what is missing before deleting the original data

Where next

← Back to the wiki