--- name: server-recovery-bundle description: "Build self-contained recovery bundles containing all config, scripts, credentials, cron jobs, and conversation history needed to restore a Hermes instance onto a brand-new server." version: 1.1.0 author: Hermes Agent license: MIT platforms: [linux] metadata: hermes: tags: [disaster-recovery, backup, migration, bootstrap, hermetic] related_skills: [email-workflows, hermes-agent, hermes-backup] --- # Server Recovery Bundle Build a single self-contained markdown file that can be pasted into a fresh Hermes agent to fully restore the instance. Think of it as a **disaster recovery envelope** — all the config, scripts, and secrets someone would need if this server died tomorrow. ## When to use - User asks for a "recovery bundle", "restore kit", "bootstrap file", or "everything I need to rebuild you" - After a server migration (document the new state) - Before a destructive upgrade or decommission - As a periodic safety net alongside regular backups ## What to include ### 1. Header section - Title, date, one-line purpose - "Paste this into a new Hermes to restore me" instruction ### 2. Bootstrap instructions - Step-by-step: install Hermes, create each file, start gateway, recreate cron jobs, verify ### 3. Credentials summary (one place, easy to find) - SMTP/IMAP password - S3 (Wasabi/AWS) keys - Cloud API tokens (Hetzner, netcup, etc.) - VPN keys or passwords - A clear note of what each credential is for - **WARNING: The recovery bundle contains cleartext secrets.** It must be treated as a credential file and stored securely (password manager, encrypted vault). If emailed, use encrypted email or delete after transfer. ### 4. Config files — verbatim - `~/.hermes/config.yaml` - `~/.hermes/.env` - `~/.aws/credentials` - `~/.hermes/SOUL.md` - `/etc/systemd/system/hermes.service` - Any other env/config files the instance depends on ### 5. SSH keys (public + private) - WISP keys, deploy keys, any SSH keys used by scripts ### 6. Cron jobs — full definition Include for each job: name, schedule, script path, skills, mode (no_agent/agent), deliver target Use `hermes cron list --json` (and fallback to text if JSON fails) ### 7. Scripts — verbatim Every file in `~/.hermes/scripts/` that isn't in `__pycache__` or starts with `.` Also include subdirectory scripts (wisp-backup/, etc.) ### 8. Today's conversation history - Get today's user sessions (not cron sessions) from the state DB - Filter by `started_at >= today_midnight AND id LIKE '20%'` (excludes cron sessions which start with `cron_`) - Include full message text from both sessions - Truncate extremely long messages (>5000 chars) with a note ## Key patterns and pitfalls ### Session filtering Cron sessions have IDs like `cron__` — filter them out by requiring `id LIKE '20%'` (user session IDs start with a date). The SQL filter: ```sql SELECT id, title, started_at, ended_at, end_reason, message_count FROM sessions WHERE started_at >= AND id LIKE '20%' ORDER BY started_at ``` ### Handling SMTP delivery failure The recovery bundle file can be large (200-500 KB). Common email pitfalls: - **Your mail server and agent server are different machines** — always verify port reachability before assuming SMTP works - Test each port separately: SMTP (587), IMAP (993). One can be open while the other is firewalled. - A CNAME or MX record can point to a totally different provider than your other infrastructure. DNS lookup: `host mail.example.com` or `python3 -c "import socket; print(socket.gethostbyname('mail.example.com'))"` - Test with: `python3 -c "import socket; s=socket.socket(); s.settimeout(5); s.connect(('', 587)); print('OK')"` - A port that **times out** (not refuses) points to a firewall drop, not a server-side block — your ISP or cloud provider may be filtering outbound SMTP - If SMTP fails: try Wasabi S3 upload as fallback (`aws s3 cp` with `--endpoint-url`) - Or deliver directly in the current chat (Telegram/WhatsApp can take large files) ### Don't fabricate Do not include password/API-key values you "reconstruct" from memory. Only include credentials you actually read from files on this machine. If a credential file doesn't exist, say so rather than leaving a placeholder. ### Message truncation Very long messages (compacted context, large JSON tool outputs) should be truncated at ~5000 chars with a note: `[truncated, was N chars]`. This keeps the bundle readable and under email size limits. ### Cron job retention from state.db After a server migration, cron jobs survive in `state.db` but the scheduler needs ~30-60s to discover them after startup. If `hermes cron list` returns empty immediately after migration, wait and retry before assuming they were lost. ### Build script pattern Rather than assembling the bundle inline in the agent's tool loop, write a Python build script (`scripts/build-recovery.py`) that: 1. Queries state.db for sessions/messages 2. Reads all config/script/credential files 3. Assembles the markdown document 4. Writes the output file This avoids context-window overflow on large state DBs and makes the bundle reproducible. ## Verification After building the recovery bundle: 1. Verify the file was written: `wc -c ` 2. Try to upload/send it (failures here are worth reporting to the user) 3. List what's in it: session count, script count, cron count 4. Report result to the user with the file location and any delivery issues ---