Backup or restore your entire OpenClaw setup including config, agents, skills, credentials, and workspace as a timestamped portable .tar.gz archive.
---
name: openclaw-backup-restore
description: >
Backup or restore a complete OpenClaw installation (config, agents, flows, skills,
credentials, memory, workspace, telegram bots) as a single portable .tar.gz archive.
Use for backup: "backup my openclaw", "snapshot my openclaw setup".
Use for restore: "restore openclaw", "migrate openclaw to this machine".
On restore, any existing ~/.openclaw is automatically preserved with a timestamp before
being replaced, so the previous state is never lost.
license: Apache-2.0
compatibility: macOS, Linux. Requires bash, tar, gzip. Optional: gpg for encrypted backups.
metadata:
author: vbrunotech
version: "1.0.0"
category: devops
domain: configuration-management
openclaw:
emoji: "🦞"
requires:
bins: ["bash", "tar", "gzip"]
install:
- id: brew-deps
kind: brew
formula: ["gnupg"]
bins: ["gpg"]
label: "Install gpg (optional, for encrypted backups)"
---
# OpenClaw Backup & Restore Skill
Snapshot and migrate your complete OpenClaw setup — config, agents, flows, skills, credentials,
memory, and workspace — as a single portable archive.
## What this skill does
- **Backup**: Archives the entire `~/.openclaw/` directory into a timestamped `.tar.gz`
(or `.tar.gz.gpg` if encrypted) — no files excluded.
- **Restore**: Extracts an archive back into `~/.openclaw/`, preserving directory structure and
permissions, so OpenClaw works immediately after extraction.
- **List**: Shows available backup archives in the configured output directory.
- **Verify**: Validates a backup archive's integrity before restore.
Use this skill when the user says:
- "backup my openclaw setup"
- "migrate openclaw to my new machine"
- "snapshot my openclaw config"
- "restore openclaw from backup"
- "what backups do I have?"
## What is backed up
The entire `~/.openclaw` directory — every file and subdirectory — is included in the archive.
No exclusions. The restored machine gets an exact copy of the original, and OpenClaw works
immediately without any missing configuration, credentials, skills, or state.
See `references/paths.md` for details on sensitive paths and restore-time permissions.
## Workflow
### Backup
1. Resolve the OpenClaw home directory (`OPENCLAW_HOME`, defaults to `~/.openclaw`).
2. Resolve the output directory (`BACKUP_DIR`, defaults to `~/openclaw-backups`).
3. Archive the full `~/.openclaw` directory into a timestamped `.tar.gz`.
4. Optionally encrypt with GPG: `--encrypt` flag or `BACKUP_GPG_RECIPIENT` env var.
5. Print the archive path and size.
### Restore
1. Validate the archive (non-empty, valid gzip, no path traversal).
2. Warn if `~/.openclaw` already exists and prompt for confirmation (or use `--force`).
3. Optionally decrypt if `.gpg` extension detected.
4. Extract to `~/.openclaw/` with `--strip-components=0`.
5. Fix permissions on sensitive files (`credentials/`, `secrets/`, `identity/`).
6. Print a summary of restored paths.
### List
Print all `.tar.gz` and `.tar.gz.gpg` files in `BACKUP_DIR` with size and date.
### Verify
Run `gzip -t` on the archive and list its top-level contents without extracting.
## Scripts
| Script | Purpose |
|---|---|
| `scripts/backup.sh` | Create a backup archive |
| `scripts/restore.sh` | Restore from a backup archive |
## Usage examples
```bash
# Create a backup in ~/openclaw-backups/
bash scripts/backup.sh
# Backup to a custom directory
bash scripts/backup.sh --output /Volumes/USB/backups
# Backup with GPG encryption
bash scripts/backup.sh --encrypt you@example.com
# List available backups
bash scripts/backup.sh --list
# Verify a backup without restoring
bash scripts/restore.sh --verify openclaw-backup-2026-05-24_120000.tar.gz
# Restore (will prompt before overwriting)
bash scripts/restore.sh openclaw-backup-2026-05-24_120000.tar.gz
# Restore without confirmation prompt
bash scripts/restore.sh --force openclaw-backup-2026-05-24_120000.tar.gz
# Restore to a custom openclaw home
bash scripts/restore.sh --home /opt/openclaw openclaw-backup-2026-05-24_120000.tar.gz
```
## Migration workflow (old machine → new machine)
1. On the **old machine**: run `bash scripts/backup.sh` — copy the `.tar.gz` to the new machine.
2. On the **new machine**: install OpenClaw binary, then run `bash scripts/restore.sh <archive>`.
3. OpenClaw will start with your full config, agents, skills, credentials, and workspace intact.
## Security notes
- `credentials/` and `secrets/` contain sensitive API keys. Keep backups in a secure location.
- Use `--encrypt` with a GPG key for backups stored in cloud storage or on shared drives.
- The restore script sets `chmod 700` on sensitive directories automatically.
## Guardrails
- Never extract archives with path components that escape `~/.openclaw/` (path traversal check).
- Always show the archive size and file count after backup so the user can sanity-check completeness.
- If OpenClaw is running during backup, warn the user — SQLite databases may be in a dirty state.
- Do not backup `identity/device-auth.json` without informing the user it contains auth tokens.
don't have the plugin yet? install it then click "run inline in claude" again.
by @clawhub
added explicit decision points for encryption, existing target handling, and running openclaw detection; added full inputs section with env vars, tools, and preconditions; expanded procedure with detailed gzip integrity checks, path traversal validation, and permission fixes; added output contract with specific file formats and success criteria; clarified outcome signals for all four workflows.
snapshot and migrate your complete openclaw setup (config, agents, flows, skills, credentials, memory, workspace) as a single portable .tar.gz archive. use this when you need to backup your entire openclaw home directory for disaster recovery, migrate to a new machine, or version your setup. on restore, any existing ~/.openclaw gets timestamped and preserved before replacement, so your previous state is never lost.
environment variables and flags:
OPENCLAW_HOME: path to openclaw directory. defaults to ~/.openclaw. can be overridden with --home flag.BACKUP_DIR: output directory for archives. defaults to ~/openclaw-backups. can be overridden with --output flag.BACKUP_GPG_RECIPIENT: email or GPG key ID for encryption. triggers encryption if set. can be overridden with --encrypt <recipient> flag.GPG_PASSPHRASE: optional passphrase if using GPG encryption (for non-interactive mode).external tools:
archive files:
openclaw-backup-YYYY-MM-DD_HHMMSS.tar.gz or .tar.gz.gpg if encrypted.preconditions:
OPENCLAW_HOME (for backup).BACKUP_DIR (for backup) or to parent of OPENCLAW_HOME (for restore).resolve directories: read OPENCLAW_HOME env var or use default ~/.openclaw. read BACKUP_DIR env var or use default ~/openclaw-backups. create BACKUP_DIR if it does not exist.
check openclaw exists: verify OPENCLAW_HOME is a readable directory. if not, exit with error "openclaw home not found at $OPENCLAW_HOME".
warn if openclaw running: attempt to detect running openclaw process (e.g., ps aux | grep openclaw). if found, print warning "openclaw appears to be running. database state may be dirty. consider stopping it before backup." do not block.
check sensitive file disclosure: if identity/device-auth.json exists in OPENCLAW_HOME, inform user "backup includes identity/device-auth.json which contains auth tokens. keep backups secure."
generate timestamp: create timestamp in format YYYY-MM-DD_HHMMSS (e.g., 2026-05-24_120000). use this for archive filename.
create archive: run tar czf $BACKUP_DIR/openclaw-backup-$TIMESTAMP.tar.gz -C ~ .openclaw/ to archive entire ~/.openclaw directory. input: OPENCLAW_HOME directory. output: $BACKUP_DIR/openclaw-backup-$TIMESTAMP.tar.gz.
optionally encrypt: if --encrypt flag or BACKUP_GPG_RECIPIENT env var is set, encrypt archive with gpg: gpg --encrypt --recipient $RECIPIENT $ARCHIVE.tar.gz. output: $ARCHIVE.tar.gz.gpg. delete unencrypted .tar.gz after encryption succeeds.
report results: print archive filename, full path, file size, and file count (use tar tzf to count entries). example: "backup complete: openclaw-backup-2026-05-24_120000.tar.gz (245 MB, 1243 files)".
validate archive path: accept archive filename or full path as input. verify file exists and is readable. if not found, exit with error "backup archive not found: $ARCHIVE".
check gzip integrity: run gzip -t $ARCHIVE (or gzip -t <(gpg --decrypt $ARCHIVE.gpg) if .gpg extension). if gzip test fails, exit with error "archive is corrupted".
check path traversal: list archive contents with tar tzf $ARCHIVE (or via gpg decrypt pipe). scan for paths containing .. or leading /. if found, exit with error "archive contains suspicious path traversal".
resolve target directory: read --home flag or OPENCLAW_HOME env var. default to ~/.openclaw. this is the target restore location.
warn if target exists: if target directory exists and is non-empty, print warning "~/.openclaw already exists. it will be backed up as ~/.openclaw-backup-$TIMESTAMP before restore." if user does not pass --force flag, prompt "continue? (y/n)". exit if user declines.
preserve existing state: if target directory exists, rename it to ~/.openclaw-backup-$TIMESTAMP where timestamp is current time. this preserves the previous state.
optionally decrypt: if archive has .gpg extension, decrypt with gpg --decrypt $ARCHIVE.gpg > $ARCHIVE.tar.gz (or use --output flag). use GPG_PASSPHRASE env var if available for non-interactive mode.
extract archive: run tar xzf $ARCHIVE.tar.gz -C ~ to extract to home directory. this creates or overwrites ~/.openclaw/. input: archive file. output: ~/.openclaw/ directory with all contents.
fix permissions: set chmod 700 on sensitive subdirectories: credentials/, secrets/, identity/, memory/. set chmod 600 on any .json files in those directories. example: find ~/.openclaw/credentials -type d -exec chmod 700 {} \;.
verify extraction: run test -d ~/.openclaw && echo "restore successful". count restored files with find ~/.openclaw -type f | wc -l.
report results: print summary "restore complete: $FILECOUNT files extracted to ~/.openclaw". if old state was preserved, print "previous state backed up to ~/.openclaw-backup-$TIMESTAMP".
resolve backup directory: read BACKUP_DIR env var or default to ~/openclaw-backups.
check directory exists: if BACKUP_DIR does not exist, print "no backups found" and exit.
list archives: run ls -lh $BACKUP_DIR/*.tar.gz $BACKUP_DIR/*.tar.gz.gpg 2>/dev/null | awk '{print $9, $5, $6, $7, $8}' to list all backup files with size and date.
handle empty results: if no archives found, print "no backups found in $BACKUP_DIR".
report results: print table with columns: filename, size, date. example output:
openclaw-backup-2026-05-24_120000.tar.gz 245 MB May 24 12:00
openclaw-backup-2026-05-25_150000.tar.gz.gpg 248 MB May 25 15:00
accept archive path: take archive filename or full path as input.
validate file: check file exists and is readable (same as restore step 1).
test gzip integrity: run gzip -t $ARCHIVE (or decrypt first if .gpg). print "archive integrity: OK" or "archive integrity: FAILED".
list top-level contents: run tar tzf $ARCHIVE | head -20 to show first 20 entries. print "archive contains:" followed by list.
count files: run tar tzf $ARCHIVE | wc -l to count total entries. print "total entries: $COUNT".
report results: print summary including integrity status, file count, and sample of top-level paths.
if openclaw is running during backup: warn user that database state may be dirty (sqlite journals may be in-flight), but do not block backup. user can choose to stop openclaw first.
if --encrypt flag or BACKUP_GPG_RECIPIENT is set: encrypt archive with gpg. if gpg is not installed, exit with error "gpg not found. install with brew install gnupg or use unencrypted backup".
if restore target (~/.openclaw) already exists: check --force flag. if --force not set, prompt user for confirmation. if confirmed, preserve existing state by renaming to ~/.openclaw-backup-$TIMESTAMP. if not confirmed, exit without restoring.
if archive is .tar.gz.gpg: auto-detect gpg encryption from file extension. if GPG_PASSPHRASE env var is set, use it for non-interactive decryption. if not set and gpg requires passphrase, prompt user interactively.
if archive fails gzip integrity test: exit immediately with error. do not attempt to extract corrupted archive.
if path traversal detected in archive: exit immediately with error. do not extract.
if BACKUP_DIR does not exist and user runs backup: create BACKUP_DIR automatically.
if BACKUP_DIR does not exist and user runs list: print "no backups found" instead of creating directory.
backup success:
$BACKUP_DIR/openclaw-backup-$TIMESTAMP.tar.gz (or .tar.gz.gpg if encrypted).gzip -t integrity test.YYYY-MM-DD_HHMMSS.restore success:
~/.openclaw/ directory exists with full directory structure intact.credentials/, secrets/, identity/ directories have chmod 700 permissions.~/.openclaw-backup-$TIMESTAMP directory exists.list success:
.tar.gz and .tar.gz.gpg files in BACKUP_DIR.verify success:
backup: user receives confirmation message with archive filename, size, and file count. archive file is immediately usable for restore or transfer to another machine.
restore: openclaw starts with full config, agents, skills, credentials, and workspace intact. user can verify by checking ~/.openclaw/ directory exists and contains expected subdirectories. if old state was backed up, user sees message with timestamp and can recover if needed.
list: user sees table of available backups and can choose which to restore.
verify: user confirms archive integrity before attempting restore, reducing risk of corrupted restore.
error cases: script exits with non-zero exit code and prints error message to stderr. user can diagnose issue and retry.
credits: skill authored by vbrunotech (clawhub).