archive/skills/hermes-remote-backup/SKILL.md
Remote Hermes Agent backup from macOS to any Linux host via official `hermes backup` CLI. Trigger when user says backup/restore sg01/sg02, Hermes backup, disaster recovery, or migrating Hermes state. Prerequisite: run setup-remote-user.sh to create a non-root user with passwordless sudo before running backups as non-root. Uses only official CLI commands: `hermes backup` (full) or `hermes backup --quick` (snapshot).
npx skillsauth add karlorz/agent-skills hermes-remote-backupInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Backup and restore a remote Hermes Agent host from macOS via SSH. Uses only the official Hermes CLI (hermes backup, hermes import). No custom tier logic, no rsync/cp of HERMES_HOME internals.
Before running backups as a non-root user, set up the target host with an automation user:
# One-time bootstrap (connects as root, creates "agent" user)
bash scripts/setup-remote-user.sh sg02 --ssh-config
This script:
sg02)agent user (customizable via --user)agent to the sudo group/etc/sudoers.d/agent~agent/.ssh/authorized_keys~/.ssh/config entry for <host>-agentAfter setup, add the SSH config alias to ~/.ssh/config (or use --ssh-config):
Host sg02-agent
HostName <IP-of-sg02>
User agent
Port 22
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
PreferredAuthentications publickey
Then use sg02-agent as the host alias for all backup commands.
Also supports direct connection: ssh agent@sg02 if the IP/hostname routes correctly.
Security note: After verifying non-root access works, consider disabling root SSH login:
ssh sg02 'sed -i "s/^PermitRootLogin yes/PermitRootLogin prohibit-password/" /etc/ssh/sshd_config && systemctl restart sshd'
hermes backup # Full backup (config, skills, sessions, state.db, .env, auth)
hermes backup --quick # Quick snapshot (config, state.db, .env, auth, cron only)
hermes backup -o /path.zip # Custom output path
hermes import [--force] zip # Restore from backup
Key facts:
hermes backup is SQLite-safe — handles WAL mode correctly--tier flag (use --quick or no flag)See compound/hermes-backup-trigger-reference in the vault for the complete map of all Hermes Agent backup mechanisms, trigger events, and coverage gaps. Key points:
hermes backup), quick-snapshot (--quick), curator snapshot (skills only)hermes backup, --quick, /snapshot), 2 event-driven (update, migrate)setup-remote-cron.sh to fill this gaphermes backup excludes profiles, projects, systemd, and rclone configbash scripts/remote-backup.sh sg01 --mode full--include-profiles --include-systemd for full coveragebash scripts/remote-restore.sh archive.zip --target sg01# Full backup
bash scripts/host-backup-cli.sh --host sg01 --mode full
# Quick snapshot
bash scripts/host-backup-cli.sh --host sg01 --mode quick
After running setup-remote-user.sh --ssh-config, use the <host>-agent alias:
# Full backup as non-root user
bash scripts/host-backup-cli.sh --host sg02-agent --mode full
# Quick snapshot as non-root user
bash scripts/host-backup-cli.sh --host sg02-agent --mode quick
# Direct connection (if DNS resolves hostname)
bash scripts/host-backup-cli.sh --host agent@sg02 --mode full
bash scripts/host-backup-cli.sh --host sg01 --mode full --include-profiles --include-systemd
bash scripts/host-restore-cli.sh --archive ~/Desktop/backups/sg01/hermes-20260516-full.zip --target sg01
## What each mode covers
| Mode | `hermes backup` | Profiles | Systemd | Rclone config |
|------|-----------------|----------|---------|---------------|
| `quick` | `--quick` snapshot | ✗ | ✗ | ✗ |
| `full` | Full backup | ✗ | ✗ | ✗ |
| `full --include-profiles` | Full backup | ✓ | ✗ | ✗ |
| `full --include-profiles --include-systemd` | Full backup | ✓ | ✓ | ✗ |
| `full --include-rclone-config` | Full backup | ✗ | ✗ | ✓ |
| All+ | Full backup | ✓ | ✓ | ✓ |
## Retention (`prune-backups.sh`)
Keep N most recent backup sets per host, removing older archives:
```bash
# Keep 7 most recent per host
bash scripts/prune-backups.sh ~/Desktop/backups --retain 7
# Preview without deleting
bash scripts/prune-backups.sh ~/Desktop/backups --retain 7 --dry-run
Automatically runs after backup when --retain <N> flag is passed:
bash scripts/remote-backup.sh sg01 --mode full --retain 7
--upload flag)After backup download, sync to S3/cloud via rclone on macOS:
# Requires rclone configured on macOS (brew install rclone)
bash scripts/remote-backup.sh sg01 --mode full --upload idrive:hermes-backups/sg01/
bash scripts/host-backup-cli.sh --host sg01 --mode full --upload idrive:hermes-backups/sg01/
Uses --backup-dir for archive rotation on the remote. Non-blocking — backup is still saved locally if upload fails.
setup-remote-cron.sh)Fill the "no routine backup" gap by installing a daily hermes backup cron job directly on the remote host:
# Daily quick snapshot at 4am HKT, 7-day retention
bash scripts/setup-remote-cron.sh sg02-agent --quick
# Daily full backup + rclone sync to S3
bash scripts/setup-remote-cron.sh sg02-agent --full --rclone-dest "idrive:hermes-backups/sg02/"
# Custom time and retention
bash scripts/setup-remote-cron.sh sg02-agent --time 02:30 --retain-days 14
# Preview without installing
bash scripts/setup-remote-cron.sh sg02-agent --dry-run
The script:
hermes-auto-backup.sh to ~/.hermes/scripts/ on remote/var/log/hermes-auto-backup.loghermes backup --tier standard silently fails. Correct: --quick or nothing.hermes backup skips profiles — add --include-profiles if needed..env/auth.json. Encrypt for remote storage.~/wiki is an S3 rclone mount, verify it's active before restore. A broken mount (noauto in fstab) silently writes files to local ext4 — they never reach S3, no alert fires. The test scripts pre-inspect.sh (check #7, hard fail) and restore-validate.sh (check #11, warn) catch this. Manual check: df -T ~/wiki | grep fuse.rclone.hermes backup has no built-in verify command. Validate externally:
# 1. Zip integrity
unzip -t archive.zip
# 2. SQLite integrity on state.db
unzip -p archive.zip state.db > /tmp/state.db
sqlite3 /tmp/state.db "PRAGMA integrity_check;"
rm /tmp/state.db
# 3. Content manifest (verify expected files exist)
unzip -l archive.zip | grep -E '(config\.yaml|\.env|auth\.json|state\.db|skills/)'
# 4. SHA256 checksum
sha256sum archive.zip > archive.zip.sha256
For comprehensive validation including archive integrity, SQLite PRAGMA checks, content manifest, and test restore dry-run, see queries/hermes-backup-validation-restore-preinspection in the vault.
Before restoring to a target, verify readiness. Two target types:
# Quick discovery (reuses discover-remote.sh)
bash scripts/discover-remote.sh <host> --verbose
# Manual checklist:
ssh <host> "uname -m" # Must be aarch64
ssh <host> "python3 --version" # Must be 3.10+
ssh <host> "curl --version | head -1"
ssh <host> "df -h ~" # Need >5GB free
ssh <host> "free -h" # Need >2GB RAM
ssh <host> "hermes --version 2>/dev/null || echo NOT_INSTALLED"
ssh <host> "df -T ~/wiki 2>/dev/null | grep fuse.rclone || echo WARN: ~/wiki not on S3 mount" # Only if ~/wiki exists
Key constraints (verified 2026-05-16 on live VM):
devsh sync — NOT supported ("not supported for pve-lxc instances yet")devsh ssh — NOT supported ("ssh is not supported for pve-lxc instances")systemctl --user — FAILS (no systemd user bus in LXC container)devsh exec — NOT supporteddevsh exec, HTTP file transfer, and systemd system mode all work# Pre-inspect via devsh exec
VM_ID=$(devsh ls --json | python3 -c "import json,sys; vms=[v for v in json.load(sys.stdin) if v['provider']=='pve-lxc' and v['status']=='stopped']; print(vms[0]['id'] if vms else '')")
devsh resume "$VM_ID"
devsh exec "$VM_ID" "uname -m" # x86_64 (not ARM64!)
devsh exec "$VM_ID" "python3 --version" # Must be 3.10+
devsh exec "$VM_ID" "df -h /" # Need >5GB free
devsh exec "$VM_ID" "free -h" # Need >2GB RAM
devsh exec "$VM_ID" "hermes --version 2>/dev/null || echo NOT_INSTALLED"
devsh exec "$VM_ID" "systemctl --user status 2>&1 | head -3" # Expected to fail
# File transfer: HTTP serve from macOS
MAC_IP=$(ipconfig getifaddr en1 2>/dev/null || ifconfig | grep 'inet ' | grep -v 127.0.0.1 | awk '{print $2}' | head -1)
cd /path/to/backups && python3 -m http.server 19999 &
devsh exec "$VM_ID" "curl -s -o /tmp/hermes-backup.zip http://${MAC_IP}:19999/archive.zip"
# Service validation (no --user flag, use system services or direct exec)
devsh exec "$VM_ID" "hermes --version && hermes doctor"
devsh exec "$VM_ID" "curl -s http://127.0.0.1:8642/health"
pve-lxc VMs are x86_64 (not ARM64), have 8GB RAM, 32GB disk, Ubuntu 24.04, run as root. For full access, use morph provider instead.
After hermes import --force, run this sequence:
# 1. CLI health
ssh <target> "hermes --version && hermes doctor"
# 2. Services
ssh <target> "systemctl --user status hermes-gateway.service --no-pager | head -10"
ssh <target> "sudo systemctl status hermes-dashboard.service --no-pager | head -10"
# 3. Health endpoint (direct, bypasses Caddy)
ssh <target> "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8642/health"
# Expected: 200
# 4. API models
API_KEY=$(ssh <target> "grep '^API_SERVER_KEY=' ~/.hermes/.env | cut -d= -f2")
ssh <target> "curl -s -H 'Authorization: Bearer $API_KEY' http://127.0.0.1:8642/v1/models" | python3 -c "import sys,json; d=json.load(sys.stdin); print(f'{len(d.get(\"data\",d))} models')"
# 5. Content
ssh <target> "du -sh ~/.hermes/state.db && echo 'Skills:' && ls ~/.hermes/skills/ | wc -l"
ssh <target> "cat ~/.hermes/cron/jobs.json 2>/dev/null | python3 -c 'import sys,json; print(len(json.load(sys.stdin)), \"cron jobs\")' 2>/dev/null || echo 'No cron jobs'"
For a complete automated validation, use restore-validate.sh from the vault's deep research.
| Check | Expected |
|-------|----------|
| state.db | ~427 MB |
| skills/ | ~115 MB |
| HERMES_HOME total | ~2.2 GB (full) |
| hermes doctor warnings | Custom provider + optional keys (non-critical) |
| Gateway flags | --replace --accept-hooks |
development
Review and simplify recently changed code for reuse, clarity, and efficiency while preserving behavior. Use when the user asks to simplify, refine, polish, clean up, or make code clearer, or after finishing a logical chunk of implementation that should be tightened before commit.
tools
Use this skill when the user asks to open a browser, browse a website, scrape a page, automate Chrome, take a screenshot, fill out a form, click a button, or otherwise interact with a website. Includes a browser-worker agent (model: sonnet) for mechanical Chrome lifecycle and interaction tasks.
development
Host-level backup and restore with profile system (presets + custom YAML profiles), model-aware agents (sonnet worker for mechanical tasks), post-discovery research, and skillwiki infrastructure capture. Uses rsync with partial-dir for resumable WAN transfers. Use when backing up or restoring Caddy reverse-proxy domains, databases (postgres, mysql, redis, mongodb, sqlite), systemd services, full SSH identity/config, Tailscale state/config, and Hermes agent state on remote Linux hosts.
tools
Hermes Agent CLI commands reference. Use when the user asks about hermes-agent CLI usage, commands, flags, or subcommands. Covers the full hermes terminal command surface.