backups-restore
Use when backing up or restoring agent or server state. What to include (config, env files, state, keyring file, signer keys, skills), explicit-include archives, 3-2-1 copies, provider snapshots, encr
SKILL.mdiclone/skills/backups-restore/SKILL.md
GitHubBackups and restore — a backup counts only after a restore worked
When to use
- Before an upgrade, a migration, a rebuild, or any change the owner cannot undo.
- On a schedule for every server that runs an agent.
- When state was lost and must come back.
tar, rsync, sqlite3, sha256sum, gpg and age are system or third-party tools: their man pages are the truth.
Prerequisites
- A
<backup-dir>with mode 700 owned by the service user, and a second place off the host (ssh-accessalias, object storage). - Writing archives needs
fileWriting; a restore overwrites state: ask through the consent door (~/.iclone-os/bin/acp consent request fileWriting --reason "…"), name what will be replaced, and wait for the owner's yes. A scheduled backup also needsscheduledTasks(cron-timers).
Quick reference — what to include
| Item | Typical place | Note |
|---|---|---|
| Hermes home | ~/.hermes |
hermes backup zips it |
| Env files | /etc/<agent>/*.env, .env |
secrets: encrypt before it leaves the host |
| State DBs | <state-dir>/*.db |
copy with sqlite3 .backup, not cp of a live file |
| acp CLI config + keyring file | the ACP_CONFIG_DIR in use, ~/.config/keyring |
needed to stay logged in |
| Signer keys | ~/.local/share/acp-cli/signer-keys.json |
same machine only (acp-troubleshooting E3) |
| Units, timers, crontabs | /etc/systemd/system/<agent>*, crontab -l |
rebuild the box in minutes |
| Custom skills, code not in git | <agent-dir> |
— |
Leave out what can be rebuilt (venvs, node_modules, caches) by listing what you include, never by excluding whole trees: excluding ~/.local as "cache" once lost the signer keys.
Procedure
- Hermes home (any machine):
f=<backup-dir>/hermes-$(date +%F).zip && hermes backup -o "$f" && chmod 600 "$f" # example
- Live SQLite databases:
sqlite3 <state-dir>/<name>.db ".backup '<backup-dir>/<name>.db'" # example
- Everything else from an explicit list (
<include-list>holds one path per line, relative to/).tarwrites to stdout and your shell creates the file, so the archive is yours and step 4'schmodworks:
sudo tar -czf - -C / --files-from=<include-list> > <backup-dir>/<agent>-$(date +%F).tgz # example
- Checksum and encrypt anything that holds secrets, then lock the files:
cd <backup-dir> && sha256sum <archive> > <archive>.sha256 && chmod 600 <archive> <archive>.sha256 # example
gpg --symmetric --cipher-algo AES256 <archive> # example
On macOS use shasum -a 256 where this skill says sha256sum (same file format, same -c). Hermes zips hold the .env too: encrypt them the same way. The owner types the passphrase and keeps it in their password manager, never next to the archive. Only the .gpg files leave the host.
5. Copy off the host (3-2-1: three copies, two kinds of storage, one elsewhere). A provider snapshot is one copy, not the whole plan: it lives in the same account.
chmod 700 <backup-dir> && chmod 600 <backup-dir>/*.gpg <backup-dir>/*.sha256 # example
rsync -a --chmod=go-rwx --include='*.gpg' --include='*.sha256' --exclude='*' <backup-dir>/ <alias>:<remote-backup-dir>/ # example
The local chmod is what keeps the copy private: rsync -a carries the 600 files and the 700 <backup-dir> (the trailing /) to the remote dir, on GNU rsync and on macOS openrsync alike. Do not rely on --chmod alone (openrsync accepts it but may not apply it; it rejects F600,D700).
6. Restore drill, at least once per setup and after every change to the list. Test the copy that survives a lost host: fetch the off-host .gpg into a scratch dir (never over live state), decrypt it (the owner types the passphrase), check it, extract it:
umask 077 && mkdir -p <scratch-dir> && cd <scratch-dir> # example
rsync -a <alias>:<remote-backup-dir>/<archive>.gpg <alias>:<remote-backup-dir>/<archive>.sha256 ./ # example
gpg -d -o <archive> <archive>.gpg # example
sha256sum -c <archive>.sha256 && tar -xzf <archive> -C <scratch-dir> # example
A Hermes zip is checked the same way, then listed with unzip -l <archive>.
7. Real restore (owner's yes): stop the service → move the current state aside (never delete it) → extract → fix owners and modes (env files 0600) → start → verify. Hermes homes come back with hermes import <zip>.
Pitfalls
- A backup never restored is a hope. Record the date of the last successful drill.
- Restoring tokens or a signer onto a second machine while the first still runs breaks both (acp-troubleshooting E14, E17).
tarof a database that is being written gives a corrupt copy; use step 2 or stop the service.- Backups readable by everyone leak every secret in them.
Never
- Never send unencrypted secrets off the host.
- Never restore over live state without moving it aside first, and never delete the only copy.
- Never use
hermes import --forceor overwrite files without the owner's yes.
Verification
Run in <scratch-dir> right after the drill (step 6):
sha256sum -c <archive>.sha256 && tar -tzf <archive> | wc -l && wc -l < <include-list> # example
ssh <alias> "ls -la <remote-backup-dir>" # example
Pass = <archive>: OK, a file count of at least the include-list lines (a listed directory adds its contents), one listed file read back from <scratch-dir> with the expected content, and the remote listing shows only .gpg/.sha256 files, -rw-------, in a drwx------ dir.
Delete <scratch-dir> only after this check: it holds decrypted secrets.