# πΎ Backup The Crew: Schedules, Folders & Configuration
**Date:** July 16, 2026
**Tags:** Backups, AI Agents, GitHub, NAS, SMB, cron, Self-Hosted, Ops
---
## π― Overview
This guide documents **how the agent crew is backed up** β every folder, every schedule, every destination. The strategy has two legs:
1. **GitHub** β config + code for each agent pushed to a dedicated private repo (offsite, versioned).
2. **Local NAS (SMB2)** β full config snapshots copied to a network share (`/mnt/VM/...`) for fast local restore.
A shared **status tracker** records each run so you can see at a glance what backed up and what failed.
> β οΈ **Secrets rule:** Every credential (Telegram tokens, GitHub PATs, NAS passwords, Supabase URLs) is a `` here. The real scripts load them from `~/.hermes/.env` or a secure token file β never committed.
---
## πΊοΈ Backup Topology
```
Each agent's config dirs
β (per-schedule scripts)
βββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββ
βΌ βΌ
GitHub (offsite, versioned) Local NAS /mnt/VM (SMB2)
β HermesBot.git β OpenClaw/
β OpenClaw.git β Codex/
β Codex β OpenAI.git β OpenCode/
β PiAgent.git β PiAgent/
β OpenCode.git β Dashboards/
β gbrain-brain / gbrain-workspace
β
βΌ
backup_status.json (central run ledger)
```
---
## π§© Requirements
- **GitHub** account with one private repo per agent (or grouped repo).
- **Local NAS** exporting an SMB2 share mounted at `/mnt/VM` (credentials in `~/.hermes/.env`).
- **`git`** configured with a token helper / PAT (`` or token file).
- **`rsync`** + **`cp`** available on the VM.
- **Telegram bot token + home channel chat id** (``, ``) for notifications.
- **cron** (user crontab) and/or **Hermes no_agent cron jobs** to fire the scripts.
- **Bun** for GBrain CLI (`gbrain-brain` / `gbrain-workspace` pushes).
---
## π
Scheduling
| Job | Schedule | Mechanism |
|-----|----------|-----------|
| Hermes config daily backup | `0 0 * * *` (midnight) | system crontab β `daily-backup.sh` |
| Hermes config update | `0 8,16 * * *` (8am, 4pm) | system crontab β `update-config.sh` |
| Claude β Obsidian notes sync | `0 * * * *` (hourly) | system crontab β `claude_to_obsidian.py` |
| GitHub backups (Hermes/OpenClaw/Codex/Pi/OpenCode) | daily (date-stamped folders) | cron / Hermes no_agent jobs calling each `*-github-backup.sh` |
| NAS/SMB backups (OpenClaw/Codex/Pi/OpenCode/Dashboards) | daily (date-stamped folders) | cron / Hermes no_agent jobs calling each `*-smb-backup.sh` |
| NAS monitor | periodic | `nas-monitor.sh` / `nas-monitor.py` |
| GBrain GitHub mirror | periodic (offsite) | `gbrain-brain` + `gbrain-workspace` push |
> π‘ Date-stamped folders (`Backups/YYYYMMDD/`) mean each day is an immutable snapshot β you can roll back to any date.
---
## π What Gets Backed Up (per agent)
### π€ Hermes β GitHub `ryanthemanr0x/HermesBot`
- Source: `~/.hermes` (config, skills, plugins, cron, scripts)
- **Excluded:** heavy runtime/cache (`node/`, `venvs/`, `cache/`, `sessions/`) β regenerable.
- `.env` is **sanitized** to `.env.template` (placeholders) before push.
- Also: `hermes-backup/Backups/YYYYMMDD/` working repo.
### π¦
OpenClaw β GitHub `OpenClaw.git` + NAS `/mnt/VM/OpenClaw`
- Source: `~/.openclaw`
- Copied: `openclaw.json`, `credentials/`, `logs/`, `skills/`, `canvas/`
- Mirror script: `openclaw-github-backup.sh` (GitHub) and `openclaw-smb-backup.sh` (NAS).
### π Codex β GitHub `OpenAI.git` (Codex/Backups/NAS/YYYYMMDD) + NAS `/mnt/VM/Codex`
- Source: `~/.codex`, `~/telegram-codex`, `~/codex-workspace`
- Telegram bot: `codex-telegram-bot.service`
### π₯§ Pi β GitHub `PiAgent.git` + NAS `/mnt/VM/PiAgent/YYYYMMDD`
- Source: `~/.pi`, `~/telegram-pi`
- Notifications: **success AND failure** (Pi script is the verbose one).
### π§ OpenCode β GitHub `OpenCode.git` + NAS `/mnt/VM/OpenCode`
- Source: `~/.opencode`, `~/.config/opencode`, `~/.local/share/opencode`, `~/.local/state/opencode`, `~/.local/cache/opencode`
- **Excluded:** `node_modules/`, `*.db`, `locks/` (regenerable).
### π Dashboards β NAS `/mnt/VM/Dashboards`
- Source: `~/ramlabs-ai-dashboard`, `~/local-agent-search`, `~/.hermes/hermes-agent/hermes_cli`, `~/.hermes/node/lib/node_modules/9router`
- Subfolders per dashboard: `RamLabs/`, `Hermes/`, `9Router/`, `LocalAgentSearch/`
- **Excluded:** `__pycache__/`, `venv/`, `node_modules/`
### π§ GBrain β GitHub `gbrain-brain` + `gbrain-workspace`
- `gbrain-brain`: the brain content (pages, sources, structured memory)
- `gbrain-workspace`: working notes, drafts
- Pushed via git (Bun CLI available at `~/.bun/bin/gbrain`).
---
## π Notification Policy
| Destination | Success | Failure |
|-------------|---------|----------|
| GitHub (Hermes, OpenClaw, Codex, OpenCode) | silent | Telegram alert |
| NAS/SMB (OpenClaw, Codex, OpenCode, Dashboards) | silent | Telegram alert |
| Pi GitHub | **Telegram (both)** | **Telegram (both)** |
> π‘ Most jobs are **silent on success** (watchdog pattern) β you only hear about failures. Pi is the exception and confirms success too.
---
## π Approximate Sizes (source dirs)
| Agent / dir | Approx size |
|-------------|-------------|
| `~/.hermes` | ~6.7 GB (GitHub copy excludes caches β much smaller) |
| `~/.openclaw` | ~190 MB |
| `~/.codex` | ~200 MB |
| `~/.pi` | ~7 MB |
| `~/.opencode` | ~138 MB |
| `~/.claude` | ~13 MB |
| `~/telegram-codex` | ~26 MB |
| `~/telegram-pi` | ~40 MB |
| `gbrain-brain` | ~7.4 MB |
| `gbrain-workspace` | ~330 KB |
| `ramlabs-ai-dashboard` | ~4.6 MB |
> π Excluded dirs (node_modules, caches, session DBs) are **not** backed up β they regenerate. This keeps GitHub repos lean and under size limits.
---
## βοΈ Configuration (sanitized)
### Example: GitHub backup script shape
```bash
#!/usr/bin/env bash
set -e
# Load secrets from env (NEVER commit):
if [ -f "$HOME/.hermes/.env" ]; then
set -a; . "$HOME/.hermes/.env"; set +a
fi
GITHUB_REPO="https://github.com/ryanthemanr0x/.git"
WORK_DIR="$HOME/-github-backup"
DATE=$(date +%Y%m%d)
BACKUP_PATH="$WORK_DIR/Backups/$DATE"
# Token: from a secure token file or .env (placeholder here):
GITHUB_TOKEN=""
TELEGRAM_BOT_TOKEN=""
TELEGRAM_CHAT_ID=""
# Copy config, sanitize secrets, commit + push
rsync -av "$HOME/.hermes/" "$BACKUP_PATH/" --exclude=node_modules --exclude=cache
git -C "$WORK_DIR" add -A
git -C "$WORK_DIR" commit -m "Backup $DATE"
git -C "$WORK_DIR" push "https://${GITHUB_TOKEN}@github.com/ryanthemanr0x/.git" main
```
### Example: NAS (SMB2) backup shape
```bash
#!/usr/bin/env bash
set -e
BACKUP_DEST="/mnt/VM/"
DATE=$(date +%Y%m%d)
BACKUP_PATH="$BACKUP_DEST/$DATE"
mkdir -p "$BACKUP_PATH"
# NAS credentials mounted via /etc/fstab or .env (placeholder):
# //192.168.50.100/VM /mnt/VM cifs username=,password=,_netdev 0 0
rsync -av --copy-links "$HOME/.opencode/" "$BACKUP_PATH/"
# silent on success; Telegram alert only on failure
```
### Central status ledger
Every script calls `backup-status.sh [message]`, which appends a JSON entry to:
```
~/ramlabs-ai-dashboard/data/backup_status.json
```
Entry shape:
```json
{
"agent": "",
"destination": "github|local",
"status": "success|failure",
"ts_utc": "",
"ts_local": "",
"message": ""
}
```
---
## π©Ί Troubleshooting
| Symptom | Likely cause | Fix |
|---------|-------------|-----|
| GitHub push 401 | expired PAT | refresh `` / token file |
| NAS backup fails | share unmounted | `mount /mnt/VM` or check `_netdev` + credentials |
| Silent success, no restore tested | no dry-run | periodically test-restore a dated folder |
| `backup_status.json` missing entry | script aborted early | check the script's exit / Telegram failure alert |
---
## π Security Checklist
- [ ] All tokens in `~/.hermes/.env` / secure token files β never in repos.
- [ ] `.env` sanitized to `.env.template` before any GitHub push.
- [ ] NAS credentials in fstab with `password=` (or autofs secret), not in scripts.
- [ ] GitHub repos are **private**.
- [ ] Excluded dirs (caches, node_modules, session DBs) reduce leak surface + repo size.
---
## β
Summary
The crew is protected on **two fronts**: versioned **GitHub** repos (offsite, immutable date-stamped snapshots) and fast **local NAS** copies over **SMB2**. Schedules run daily (midnight Hermes config, 8am/4pm updates, hourly ClaudeβObsidian), notifications are silent-on-success (Pi confirms both), and a central `backup_status.json` ledger tracks every run. Restore = clone the dated folder or copy from `/mnt/VM`. π
---
*No API keys, tokens, passwords, or secrets are included β every value is a `` you supply locally. Built with Astro, GitHub, and Cloudflare Pages.*