On this page

On this page

Agent workspace

Storage locations

Storage locations

A storage location names a destination for OpenClaw artifacts. Core storage owns location identity, encryption, and health checks. Providers transfer objects, and each consumer decides what to store and retain. Configuring a location does not schedule a backup or move existing data.

The built-in filesystem provider supports an existing directory, including an external disk or a mounted network filesystem. Additional providers come from plugins. Referencing a bundled provider in config enables its owner plugin through the normal plugin policy; an explicit disable still applies.

For Cloudflare R2 object storage, follow the Cloudflare plugin setup to create a bucket, configure SecretRefs, and initialize an r2 location.

Configure and initialize a directory

Mount the intended disk and create the destination directory on it before initializing storage. OpenClaw never creates the configured root directory. Use an absolute path as seen by the process running the CLI or Gateway.

Set OPENCLAW_STORAGE_PASSPHRASE in that process's environment and keep a recoverable copy of its value in your secret manager. Add a location to your config:

json5
{  storage: {    locations: {      archive: {        provider: "filesystem",        settings: { path: "/mnt/archive/openclaw" },        encryption: {          passphrase: {            source: "env",            provider: "default",            id: "OPENCLAW_STORAGE_PASSPHRASE",          },        },      },    },  },}

Initialize the destination explicitly, then verify a write/read/delete cycle:

bash
openclaw storage init archiveopenclaw storage test archiveopenclaw storage list --json

Initialization writes openclaw-storage.json at the location root. Running init again with the same encryption settings and passphrase is safe. Runtime operations never create this marker: an empty mountpoint must not silently become storage on the system disk.

Configuration reference

Storage is optional; omitting storage or storage.locations defines no locations. Each key under storage.locations is a name matching [a-z0-9][a-z0-9-]{0,62}: 1–63 lowercase letters, digits, or hyphens, starting with a letter or digit.

Key Required Meaning
storage.locations.<name>.provider Yes Nonempty provider id; filesystem is built in.
storage.locations.<name>.settings Yes Provider-owned JSON object, validated before opening a backend.
storage.locations.<name>.encryption Yes { passphrase: SecretInput } or the explicit string "none".
storage.locations.<name>.encryption.passphrase When encryption is enabled Passphrase string or SecretRef; prefer a reference.

The filesystem provider accepts settings: { path: "/absolute/existing/directory" }. It refuses a missing root and never overwrites an existing object key. Its probe reports free and total filesystem space when available.

Provider settings must be finite, bounded JSON: at most 32 nesting levels, 4,096 values, 512 keys per object, string lengths of 65,536, and 256 KiB when serialized. Secret-bearing settings, including accessKeyId, secretAccessKey, and nested credentials, must use valid SecretRefs. Provider-specific validation can impose additional constraints. SecretRefs remain references until the provider requests their values through the core secret resolver.

Choose encryption deliberately

With a passphrase, core storage encrypts object streams before the provider receives them and decrypts them when read. The OCSTOR1 format uses scrypt to derive a master key and authenticated AES-256-GCM segments with a separate key for every object. An incorrect passphrase produces wrong-key and refuses access. Changing the configured passphrase does not re-encrypt existing data.

Keep both the passphrase and the location marker. Losing either can make encrypted objects unreadable. Object names and the initialization marker remain visible to the storage provider; encryption protects object contents.

Set encryption: "none" only as an explicit operator choice, such as a destination already protected by disk encryption. Backups can contain credentials. Without storage encryption, anyone who can read the destination can read the stored bytes.

Share a location across installations

Backups use backups/<namespace>/ within a location. The namespace defaults to the sanitized hostname; use --namespace <name> to choose a stable, distinct name for each installation sharing the destination.

The first upload creates an owner.json claim containing the installation's durable Gateway device ID, hostname, and claim time. It uses the same location encryption settings as the archives. Backup creation checks the claim before archiving and again before retention. A different device ID refuses the backup and records a failed attempt, preventing a hostname collision from sharing retention. Retention never deletes the claim.

Pass --claim-namespace to backup create --to <location> to deliberately take over a namespace, for example after moving to new hardware. backup enable --to also accepts the flag and stores it in the scheduled command only when explicitly passed; those scheduled runs can then replace another installation's claim. Prefer a separate namespace when both installations will continue running.

Recovery remains read-only: backup list, backup verify, and backup restore with --from <location> do not require or change the claim. Listing without --namespace also shows available namespaces and their claim hostnames. A restored installation carries its original device identity and can continue its namespace. A cloned copy running concurrently shares that identity and must use its own --namespace to avoid sharing retention.

Backup status and Doctor preserve the newest attempt and newest successful result for every backup kind and target alongside the newest 200 global attempts. A busy job cannot hide an infrequent destination's last result. See Backups and the Backup CLI for commands and status details.

Diagnose a location

openclaw storage list probes configured locations. openclaw storage test <name> also writes a temporary .openclaw-probe-<uuid> object at the location root, reads and verifies it, then deletes it. Every storage command supports --json; see the CLI reference.

State Next step
ok The marker and encryption identity are valid, and the backend probe succeeded.
unavailable Reconnect the disk or restore access to the configured destination. Check that the CLI and Gateway see the same path and credentials.
uninitialized Confirm this is the intended new destination, then run openclaw storage init <name>. Never initialize an unexpected empty mountpoint.
wrong-key Restore the original passphrase or correct the SecretRef. Do not replace the marker to hide the mismatch.
error Read the returned message and correct provider settings, permissions, or the reported backend failure.

Gateway clients can list configured locations with storage.locations.list without storage I/O, and request a health check with storage.locations.probe { name }. Both require operator read scope. Initialization remains an explicit CLI operation.

See Configuration reference for other config domains and Secrets for secret provider setup.

Was this useful?