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
tags
backup
state
git
snapshot
skills
memory
config
cron

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

  1. Never include state.db — it's 600MB+ per snapshot, git cannot delta-compress. Already in .gitignore but verify after rsync --delete that it wasn't accidentally picked up.
  2. Must clean dirty tree first — if the backup-repo has uncommitted changes (e.g. from a manual edit or prior failed backup), git checkout or subsequent pulls will fail. Always git reset --hard + git clean first.
  3. .env is blocked by user — do not attempt to redact or copy .env into the backup repo. The user has explicitly blocked this. .env content is already covered by memory/skills, and secrets should not be in git.
  4. Large number of deleted cron outputs is normal — after 2+ months without backup, git status may show 10,000+ deleted cron output files. This is expected cleanup, not data loss.
  5. config.yaml may 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_at stuck in the past + last_run_at = null → scheduler never fired
  • ticker_heartbeat / ticker_last_success timestamps 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.

  • 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.