Automatic encrypted backup and sync of OpenClaw state to Backblaze B2. Install the plugin, set 3 fields, restart your gateway — backups happen automatically.
OpenClaw B2 Backup is a plugin that snapshots your entire OpenClaw state directory to Backblaze B2 on a schedule. It uses incremental SHA-256 diffing and AES-256-GCM encryption so only changed files are uploaded and everything is encrypted at rest. It runs inside the gateway process, uses SQLite's .backup() API for consistent database snapshots, and pushes incremental encrypted diffs to B2.
If you've used OpenClaw for more than a week, you've probably hit one of these:
- Rebuilt from scratch after a broken config or busted channel integration, losing sessions and memory in the process
- Lost agent memory after compaction fired and your agent forgot everything you taught it
- Accidentally deleted MEMORY.md (or had your agent do it) with no way to get it back
- Wanted to move to a new machine but couldn't figure out what to copy
- Worried about compromise from a bad skill and wanted a known-good restore point
This plugin fixes all of that. It snapshots your entire OpenClaw state — config, workspace, sessions, memory, cron, hooks — and stores encrypted, timestamped copies in B2. Backup happens automatically on schedule, before compaction, and on shutdown. Sync to a new machine is automatic on first start. Rollback is one agent command from chat. No scripts, no manual tarball management, no stopping the gateway.
Anyone running OpenClaw who wants automatic off-machine backups without managing scripts, cron jobs, or external tools like restic/rclone.
- Encrypted by default — AES-256-GCM with per-file random salt/IV, key derived from your B2 application key via scrypt
- Incremental sync — SHA-256 manifest diffing; only changed files are uploaded
- Safe SQLite snapshots — uses
.backup()API, no half-written databases - Auto-restore on new machines — detects empty state dir on start, pulls latest snapshot automatically
- Safety snapshots before rollback — creates a restore point before any pull, stored out-of-band and never auto-pruned
- Compaction protection — triggers a push before compaction fires (5-minute debounce to prevent rapid-fire)
- Conversational rollback —
b2_rollbackagent tool lets you list and restore snapshots from chat - Zero runtime dependencies — hand-rolled S3 Sig V4 client, uses only
node:cryptoand OpenClaw's bundledcroner - Backward-compatible decryption — auto-detects unencrypted data and passes through, so enabling encryption doesn't break old snapshots
openclaw plugins install @openclaw/b2-backupAdd to your openclaw.json (or use the Control UI):
{
"plugins": {
"entries": {
"b2-backup": {
"enabled": true,
"config": {
"keyId": "004a...",
"applicationKey": "K004...",
"bucket": "my-openclaw-backups"
}
}
}
}
}openclaw gateway restartThat's it. Region is auto-detected, encryption is on by default, and the first backup runs at midnight.
All optional beyond the 3 required fields:
| Setting | Type | Default | Required | Description |
|---|---|---|---|---|
keyId |
string | — | Yes | B2 application key ID |
applicationKey |
string | — | Yes | B2 application key (also used as encryption key source) |
bucket |
string | — | Yes | B2 bucket name |
region |
string | Auto-detected | No | B2 region (derived from key if omitted) |
prefix |
string | "openclaw-backup" |
No | Object key prefix in the bucket |
schedule |
string | "daily" |
No | "daily", "weekly", or a cron expression |
encrypt |
boolean | true |
No | AES-256-GCM encryption before upload |
keepSnapshots |
number | 10 |
No | Snapshots retained; oldest auto-pruned |
Everything that makes your OpenClaw instance yours:
| Data | Path | Why |
|---|---|---|
| Config | openclaw.json (+.bak rotation) |
Your setup — channels, models, agent bindings |
| Workspace | workspace/**, workspace-*/** |
SOUL.md, AGENTS.md, MEMORY.md, custom instructions |
| Sessions | agents/*/sessions/*.jsonl |
Conversation history |
| Session store | agents/*/sessions/sessions.json |
Routing metadata |
| Memory DB | agents/*/memory/*.sqlite |
Long-term knowledge (vector search index) |
| Agent state | agents/*/agent/** |
Agent runtime config (minus auth profiles) |
| Cron jobs | cron/** |
Scheduled tasks |
| Hooks | hooks/** |
Custom hook scripts |
credentials/andauth-profiles.json— secrets stay per-machine; re-auth on new machinesmedia/— ephemeral (2-min TTL), not worth syncingextensions/— install plugins independently per machine*.lock,*.tmp,*-wal,*-shm— transient files
Compaction rewrites your session transcript to save context window space. If important context lived only in the chat history and wasn't captured in MEMORY.md or the memory DB, it's gone.
With this plugin, a snapshot is automatically taken before compaction fires. Roll back from chat:
"Show me my B2 backup snapshots and restore the one from before compaction"
OpenClaw memory is plain Markdown files on disk. A single misinterpreted instruction can permanently delete them. With daily snapshots in B2, you restore MEMORY.md from the last known-good version.
One bad edit and you're rebuilding from scratch — re-onboarding channels, re-pairing devices, re-teaching your agent. With this plugin, you restore the entire state directory from a snapshot instead.
Restore from a pre-compromise snapshot, rotate your secrets, and you're back to a known-good state. The timestamped snapshots in B2 give you a clear timeline of what your state looked like before and after the incident.
openclaw plugins install @openclaw/b2-backup
# Add the same 3 config fields to openclaw.json
openclaw gateway restart
# Plugin detects empty state + existing snapshots → auto-restores latestYour new machine has the same memory, sessions, config, and personality as the old one. No manual file copying.
| Trigger | When | Behavior |
|---|---|---|
| Cron schedule | Midnight daily (default) | Full incremental push |
gateway_stop |
Gateway shutdown | Final push before exit |
before_compaction |
Before session compaction | Push with 5-min debounce to prevent rapid-fire |
| Auto-restore | Service start, empty state dir | Pull latest snapshot (no safety snapshot created) |
Each sync creates a timestamped snapshot (e.g., openclaw-backup/2026-02-19T00-00-00Z/):
- Walk the state directory, collect files matching include patterns
- Create safe SQLite snapshots via
.backup()API (no half-written databases) - Compute SHA-256 hashes on plaintext, diff against last push
- Encrypt changed files with AES-256-GCM (if enabled)
- Upload changed files + unencrypted manifest
- Prune old snapshots beyond
keepSnapshotslimit
Manifest hashes are always computed on plaintext so incremental diffing works regardless of encryption (random IV/salt means identical plaintext produces different ciphertext).
Unlike external backup tools (Restic, rclone), this plugin runs inside the gateway process and doesn't require stopping the gateway.
- Push a safety snapshot to
{prefix}/safety-{timestamp}/(preserves current state before overwriting) - Fetch manifest from the selected snapshot
- Compare local files by SHA-256 hash
- Download + decrypt (if encrypted) only changed/missing files
- Verify hashes against plaintext before writing
Safety snapshots are stored out-of-band and never auto-pruned, so you can always recover from a bad rollback.
The plugin registers a b2_rollback tool that lets you manage backups conversationally:
List snapshots:
"Show me my B2 backup snapshots"
Returns all regular snapshots and safety snapshots with timestamps.
Restore a snapshot:
"Roll back to the snapshot from February 15th"
Creates a safety snapshot of current state, then restores the selected snapshot.
The tool is registered as optional so it only appears when the agent needs it.
Zero external dependencies beyond what OpenClaw already ships:
| Need | Solution |
|---|---|
| S3 API calls | Hand-rolled AWS Sig V4 signing (node:crypto) |
| Encryption | AES-256-GCM, scrypt key derivation from applicationKey |
| Scheduling | croner (already in OpenClaw core) |
| SQLite snapshots | node:sqlite .backup() API (Node 22+) |
| Push debounce | Shared timer prevents rapid-fire from overlapping triggers |
| JSON persistence | readJsonFileWithFallback / writeJsonFileAtomically from plugin SDK |
src/
types.ts # Config + manifest types, SAFETY_PREFIX
b2-client.ts # S3-compatible B2 client with Sig V4 signing
gatherer.ts # Walk state dir, collect syncable files
sqlite-snapshot.ts # Safe .backup() wrapper
manifest.ts # SHA-256 hashing + diff logic
encryption.ts # AES-256-GCM encrypt/decrypt/isEncrypted
debounce.ts # Push rate limiter
snapshots.ts # List, prune, filter snapshots in B2
push.ts # Upload changed files to B2 (with PushOptions)
pull.ts # Download + restore from B2 (with PullOptions)
service.ts # Background scheduler + auto-restore
index.ts # Plugin entry: hooks, tool registration, debounce wiring
openclaw.plugin.json # Plugin manifest
Backblaze B2 includes 10 GB of free storage — more than enough for most OpenClaw setups. Typical state is 50-500 MB, so even with 10 encrypted snapshots retained you'll comfortably stay within the free tier.
- Encryption at rest — all file data is AES-256-GCM encrypted before leaving your machine (manifests stay unencrypted as they contain only paths and hashes)
- Per-file random salt/IV — identical files produce different ciphertext
- Key derivation — encryption key is derived from your
applicationKeyvia scrypt (never stored separately) - Credentials and auth profiles are excluded from sync by design
- Use B2 application keys scoped to a single bucket for least-privilege access
openclaw plugins install -l ./extensions/b2-backup
openclaw plugins list # should show b2-backuppnpm test56 tests across 7 test files covering encryption round-trips, manifest diffing, snapshot filtering, file gathering, B2 client signing, debounce timing, and plugin registration.
MIT