🐾 claw-stack

Last updated: March 2026 Β· Source: openclaw-backup

Encrypted State Archive

Automated encrypted, deduplicated backup of the OpenClaw workspace and local projects to Google Drive β€” using restic for encryption and snapshot management, rclone for transport, with the encryption password stored in macOS Keychain.

← Module Overview

What

openclaw-backup creates incremental, encrypted, point-in-time snapshots of the OpenClaw workspace and local project directories and stores them on Google Drive. Each backup run adds a new snapshot; unchanged blocks are deduplicated so only changed data is uploaded. A retention policy automatically prunes old snapshots. The encryption password never touches disk β€” it's retrieved from macOS Keychain on each run.

Why

An agent system accumulates state that's difficult to reconstruct: memory files built up over months of sessions, project code in progress, configuration that took time to tune. Disk failure, accidental deletion, or a corrupted workspace without backups means complete loss of that state.

Standard cloud sync tools (iCloud, Dropbox) don't encrypt before upload, don't track snapshot history, and don't deduplicate. A user can't restore to "the state of my workspace three days ago" β€” only to the current synced state. restic solves all three problems: client-side encryption (Google Drive only ever sees ciphertext), content-addressed deduplication (fast incrementals), and immutable point-in-time snapshots with a configurable retention policy.

Architecture

Two layers collaborate on each backup run:

restic β€” encryption + deduplication + snapshot management

restic creates content-addressed, encrypted snapshots. Only changed blocks are stored; unchanged blocks reference existing data. The encryption password is read from macOS Keychain on each run β€” never written to disk.

rclone β€” Google Drive transport

rclone provides the backend that restic writes to. It handles Google Drive OAuth and the file transfer layer. The OAuth token lives in a config file that is excluded from git.

~/.openclaw/  ──┐
               β”œβ”€β”€β–Ά restic (encrypt + dedup) ──▢ rclone ──▢ Google Drive
~/projects/   β”€β”€β”˜

What gets backed up:

Path Approx Size Contents
~/.openclaw/ ~2.9 GB Config, workspace, memory files, logs, media
~/projects/ ~1.3 GB Source code, experiments

Exclusions (not backed up):

  • node_modules/ β€” reinstallable from package.json
  • .venv/ β€” recreatable Python environments
  • browser/ β€” Chromium binary cache
  • .git/objects β€” already on GitHub

Retention policy:

Period Kept
Daily Last 7 days
Weekly Last 4 weeks

Older snapshots are automatically pruned at the end of each backup run.

Key Design Decisions

restic over tar/zip β€” content-addressed deduplication

restic splits files into variable-size chunks and identifies them by content hash. Only chunks that don't already exist in the repository are uploaded. This makes incremental backups fast β€” a session where only memory files changed uploads only those chunks, not the full 4 GB workspace.

macOS Keychain β€” password never on disk

The restic encryption password is stored in Keychain under a service/account key pair. The backup script retrieves it at runtime using the security CLI. No plaintext password ever appears in a config file, environment variable export, or shell history.

Active secret scanning in test.sh

The test script actively scans all git-tracked files for patterns that look like secrets (API keys, tokens, passwords). This runs before any backup to prevent accidentally committing credentials alongside the backup infrastructure code.

Immutable snapshots β€” never overwrite, always prune

Each backup run adds a new snapshot to the repository. Old snapshots are removed only by the retention policy pruning step, not by overwriting. At any point you can restore to any snapshot in the retention window β€” not just the most recent one.

How to Build Your Own

1. Use restic with any rclone-supported backend

The same architecture works with any rclone backend: S3, Backblaze B2, Azure Blob, SFTP. Google Drive is used here because it's free up to 15 GB and requires no credit card. Swap the rclone remote name in the backup script to change backends.

2. Store the encryption password in a system secrets manager

On macOS, Keychain is the right choice. On Linux, use pass (GPG-backed) or the RESTIC_PASSWORD environment variable set by a secrets manager at runtime. Never store the password in a dotfile.

3. Build a comprehensive exclusion list

node_modules, Python virtualenvs, browser caches, and compiled output can easily add several gigabytes that are fully reinstallable. Exclude them. A good rule: if a directory can be recreated from committed source (package.json, requirements.txt, etc.), exclude it.

4. Test your restore process before you need it

A backup that has never been tested is not a backup. Include a dry-run restore in your testing checklist. Restore to a temporary directory and verify that key files are present and intact. The worst time to discover a broken restore process is during an actual recovery.

5. Fire a system event notification on backup failure

Silent backup failures are the most dangerous kind. The backup script should send a notification (via OpenClaw system event, email, or any other channel you'll actually see) when a backup fails. A successful backup should log silently; a failure should be loud.

Security

  • No hardcoded secrets β€” all credentials use macOS Keychain or environment variables
  • restic encrypts all data before upload; Google Drive stores only ciphertext
  • OAuth tokens in rclone config are excluded from git via .gitignore
  • test.sh actively scans for secrets in all git-tracked files

Frequently Asked Questions

Where is the restic encryption password stored?

In macOS Keychain under service name openclaw-backup, account restic-password. The setup script generates and stores it automatically. You can also override it with the RESTIC_PASSWORD environment variable.

Will backups overwrite each other?

No. restic creates immutable snapshots. Each backup run adds a new snapshot; old ones are only removed when the retention policy prunes them. You can restore to any historical snapshot within the retention window.

Does this work on Linux?

The Keychain integration is macOS-specific. On Linux you would need to substitute a different secret store (e.g. pass) or use the RESTIC_PASSWORD environment variable directly. The restic and rclone commands themselves are cross-platform.

Authors: Qiushi Wu & Orange 🍊