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.
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).