The cloud layer for OpenClaw's native backup. Wraps openclaw backup create
(config, credentials, consistent SQLite snapshots, workspace), then GPG-encrypts
and uploads the archive to any S3-compatible bucket, with retention,
verification, and staged restore.
All commands: bash "{baseDir}/scripts/cloud-backup.sh"
Act ONLY on an explicit user request about OpenClaw backups: "back up
openclaw", "restore my openclaw state", "set up cloud backups for openclaw",
"/cloud-backup", and similar.
database") are NOT for this skill. Ask what the user means before touching it.
"while you're at it".
status, list, verify, schedule, and any --dry-run) may run freely once the user has asked about backups.
Everything else follows the gates below.
Before ANY state-changing action, show the user exactly what will happen and
get an explicit yes. One gate per action — do not re-ask for things the user
just confirmed, and never batch-confirm.
| Action | What you MUST show before doing it |
|---|---|
| --- | --- |
Write config (openclaw config patch) | Every key=value you will write, verbatim. Never write secrets — see Credentials. |
| First backup to a new destination | Output of backup : scope, sensitivity verdict, encryption status, target s3://bucket/prefix. |
| Store/replace a credential | Only the file path + storage method (AWS profile / passphrase file). The secret value itself should not transit this conversation — the user runs those commands themselves. |
| Restore | Step 1: always restore and show the file list. Step 2: state which paths will be overwritten (staged restores write to a fresh directory; --in-place overwrites live state), then require an explicit yes. Never skip the dry run. |
| Prune | Output of prune --dry-run: which archives (local and remote) will be deleted, by name. |
| Schedule creation | The exact openclaw cron add ... command and full payload text (see Scheduling). |
Repeat manual backups to an already-confirmed destination need no new gate —
the user's request IS the confirmation. Still echo the one-line plan
("full backup, encrypted, → s3://bucket/prefix") before running.
A scheduled job's payload marks the run as operator-preconfirmed for backup
and prune ONLY. In unattended runs: never restore, never change config,
never create or modify schedules, never store credentials.
Echo this table when the user asks what gets backed up:
| Mode | Includes | Excludes by default | Sensitivity |
|---|---|---|---|
| --- | --- | --- | --- |
backup full (default) | openclaw.json, credentials/, secret stores, state + agent SQLite snapshots, agent memory, workspace, installed skills | session transcripts, codex caches/logs, tools/, media/, logs/, old backups | SENSITIVE — encryption forced |
backup full --everything | everything above PLUS session transcripts and codex history | previous backup archives only | SENSITIVE — encryption forced |
backup settings | openclaw.json, secret stores, credentials/, auth files | everything else | SENSITIVE — always encrypted, no opt-out |
backup workspace | workspace directories (skills, memory files) | all state/config | encrypted by default; --no-encrypt allowed here only |
"SENSITIVE — encryption forced" means the script refuses to produce a plaintext
archive for that scope (exit 14). Do not work around it; if the user explicitly
wants a plaintext-shareable archive, offer config.excludeSecrets=true instead.
Users can tune scope with config.exclude / config.include (state-relative
globs).
| Command | What it does | Gate? | ||
|---|---|---|---|---|
| --- | --- | --- | ||
| `backup [full\ | settings\ | workspace] [--everything] [--no-upload] [--dry-run] [--json]` | Create archive, encrypt, upload, apply retention | dry-run free; see gates |
list | Local + remote backups; flags failure debris | no | ||
status | Health: last backup, credential sources, sensitivity verdict, schedule, reachability | no | ||
| `verify [name\ | --latest] [--deep]` | Checksum + decrypt + listing; --deep adds openclaw backup verify | no | |
`restore | --latest> [--target DIR \ | --in-place] [--only GLOB] [--dry-run] [--yes] [--force]` | Staged restore by default | YES — two-step | |
prune [--dry-run] | Apply retention; remove failure debris | YES | ||
schedule | PRINT the opt-in cron command (creates nothing) | no | ||
setup | Setup checklist + connection test (never writes config) | config writes gated individually |
Exit codes (report them precisely, especially from cron): 0 ok ·
3 ok-with-warnings · 4 usage · 10 another run holds the lock · 11 missing
dependency · 12 insufficient disk · 13 cloud unreachable/bad credentials ·
14 encryption required but unavailable · 20-25 create/filter/encrypt/upload/
verify failures · 30 restore failure.
Follow references/setup-flow.md step by step. Summary: choose provider →
user creates a least-privilege bucket-scoped key (per provider guide) → store
credentials OUTSIDE OpenClaw config (AWS profile recommended) → write
non-secret config (gate) → test connection → enable encryption with a
generated passphrase file → first manual backup (gate) → only then offer
scheduling (gate).
Resolution order and storage rules: references/credentials.md. Hard rules:
skills.entries.cloud-backup.env.*). Backups archive that file: a plaintext
credential in config is carried inside every archive it protects.
config.profile, recommended)or operator-managed process env. The passphrase lives in a chmod-600
passphrase file (config.passphraseFile).
instead: config.accessKeyRef / config.secretKeyRef /
config.passphraseRef accept OpenClaw SecretRefs ({source: env|file|exec})
resolved against .secrets.providers — including 1Password-style exec
providers. Configured-but-broken refs abort the run; they never fall back.
runs aws configure --profile ... and the passphrase generator themselves.
credentials, surface it to the user verbatim and offer the migration in
references/credentials.md.
NEVER create, modify, or enable a cron job by default, implicitly, or because
"backups should be scheduled". Skills document cron setup; only the user
opts in.
Offer scheduling exactly once, AFTER the first successful manual backup:
> "Backup verified. Want me to schedule this daily? I'd create this cron job —
> nothing is scheduled until you confirm:"
Then run schedule to print the exact command, adjust time/timezone/delivery
to the user's setup, show it in full, and wait for an explicit yes before
running it. If the user declines: drop it, and do not re-offer on later runs
(check openclaw cron list first — if a cloud-backup job exists, never offer).
To remove a schedule: openclaw cron rm .
Never summarize an error into vagueness, never hide a WARN.
Never auto-retry restore, prune, or any openclaw cron mutation.
backup may be retried once, only after the cause is fixed and the user
agrees.
work around it with --no-encrypt or an ad-hoc passphrase. Run setup.
the user the exact leftover path.
references/credentials.md — resolution chain, v1→v2 migration, warningsreferences/setup-flow.md — guided first-time setupreferences/providers/{aws-s3,cloudflare-r2,backblaze-b2,digitalocean-spaces,minio,other}.mdreferences/security.md — threat model, restore safety, incident response共 2 个版本