5.4 KiB
| name | description | version | metadata | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| hermes-state-backup | Push a full Hermes state snapshot to a git backup repo. For merging between instances, use hermes-state-merge instead. | 1.0.0 |
|
Hermes State Backup
Push a full snapshot of the current Hermes instance state to a git remote backup repository. This is a one-way push — the backup repo is the destination, not the source. For pulling state from backup (merging between instances), use hermes-state-merge.
When to Use
- Periodic backup of the current instance's skills, memory, config, and cron
- Before major changes (Hermes upgrade, config overhaul, skill reorganization)
- When the user explicitly asks to back up
Trigger
User says "back up Hermes", "backup now", "push to backup repo", or similar.
What Gets Backed Up
| Path | Included? | Notes |
|---|---|---|
skills/ |
YES | rsync --delete to mirror current |
memories/ |
YES | MEMORY.md + USER.md |
memory_store.db |
YES | ~250K, small enough for git |
config.yaml |
YES | Copy directly |
SOUL.md |
YES | Copy directly |
cron/ |
YES | rsync --delete, includes jobs.json + output/ |
.env |
NO | Secrets — never commit to git |
state.db |
NO | 600MB+, git cannot delta-compress, already in .gitignore |
auth.json |
NO | OAuth tokens, instance-specific |
sessions/ |
NO | Too large, regenerable |
checkpoints/, logs/, *_cache/ |
NO | Runtime artifacts |
Workflow
The backup repo lives as a permanent working copy at ~/.hermes/backup-repo. Do NOT clone to a temp directory — use the existing clone.
Step 1: Clean and Pull
cd ~/.hermes/backup-repo
git fetch origin
git reset --hard origin/main
git clean -fdx -e .git
The git reset --hard + git clean -fdx -e .git is critical — any uncommitted changes from a prior failed backup or concurrent cron output will abort the checkout.
Step 2: Mirror Current State
cd ~/.hermes/backup-repo
# Skills, memories, cron — full mirror with cleanup
rsync -av --delete ~/.hermes/skills/ skills/
rsync -av --delete ~/.hermes/memories/ memories/
rsync -av --delete ~/.hermes/cron/ cron/
# Single files — direct copy
cp ~/.hermes/config.yaml config.yaml
cp ~/.hermes/SOUL.md SOUL.md
cp ~/.hermes/memory_store.db memory_store.db
Step 3: Update Manifest
NOW=$(date '+%Y-%m-%d %H:%M:%S %z')
HOST=$(hostname)
printf 'Hermes state backup\nGenerated: %s\nHost: %s\nHermes home: %s\nRemote: <repo-url>\nIncluded:\n- skills/\n- memories/\n- memory_store.db\n- config.yaml\n- SOUL.md\n- cron/\n' "$NOW" "$HOST" "$HOME/.hermes" > BACKUP_MANIFEST.txt
printf 'Source file mtimes:\n' > BACKUP_SOURCES.txt
stat -c '%y %n' ~/.hermes/skills ~/.hermes/memories ~/.hermes/memory_store.db \
~/.hermes/config.yaml ~/.hermes/SOUL.md ~/.hermes/cron >> BACKUP_SOURCES.txt
Step 4: Commit and Push
git add -A
git commit -m "Auto backup: $(date '+%Y-%m-%d %H:%M:%S %z')"
git push origin main
Pitfalls
- Never include
state.db— it's 600MB+ per snapshot, git cannot delta-compress. Already in.gitignorebut verify afterrsync --deletethat it wasn't accidentally picked up. - Must clean dirty tree first — if the backup-repo has uncommitted changes (e.g. from a manual edit or prior failed backup),
git checkoutor subsequent pulls will fail. Alwaysgit reset --hard+git cleanfirst. .envis blocked by user — do not attempt to redact or copy.envinto the backup repo. The user has explicitly blocked this..envcontent is already covered by memory/skills, and secrets should not be in git.- Large number of deleted cron outputs is normal — after 2+ months without backup,
git statusmay show 10,000+ deleted cron output files. This is expected cleanup, not data loss. config.yamlmay contain API keys — the copy is a raw snapshot. The user is responsible for redacting before push if needed. Do not apply sed transforms without explicit approval.
Cron Backup: Gateway Must Be Running
Cron jobs (including backup) will not fire unless the Hermes gateway background service is running. The gateway handles the scheduler ticker. CLI-only Hermes sessions do NOT automatically run cron.
Diagnosis
hermes cron status
# ✗ Gateway is not running — cron jobs will NOT fire
# ✓ Gateway is running — cron jobs will fire automatically
next_run_atstuck in the past +last_run_at= null → scheduler never firedticker_heartbeat/ticker_last_successtimestamps in~/.hermes/cron/show last tick (stale = scheduler dead)
Fix
hermes gateway install # one-time: install as systemd user service
systemctl --user status hermes-gateway # verify running
hermes cron status # confirm: ✓ Gateway is running
After gateway starts, all due cron jobs fire immediately, then follow their schedule.
Two Backup Scripts Conflict
If both backup.sh and hermes-backup.sh target the same backup-repo, they race on .git/index.lock when they fire simultaneously at gateway startup. Remove one job or use separate repos.
Related Skills
- hermes-state-merge — Pull state FROM backup repo to local (merge, not overwrite). Use after another instance pushes a backup.
- hermes-agent — General Hermes configuration, migration, and troubleshooting. See the "Migration & Backup" section for full-instance migration.