2026-07-20
OpenClaw Configuration: Files, Secrets, Validation, and Reloads
Configure OpenClaw safely with schema-aware edits, JSON5 includes, SecretRefs, dry-run validation, hot reload planning, and rollback verification.
The active file passed schema validation and the running Gateway read that same path, but reload was still off. That combination is the useful warning: a clean diff can be valid, correctly targeted, and inert. Approve an OpenClaw configuration change only after the write shape, secret resolution, activation boundary, runtime assertion, and rollback trigger fit on one decision record.
The 23 July 2026 repeat stayed read-only on OpenClaw 2026.7.1-2. The selected document was a regular 0600 file, 15,121 bytes long, with no validation warning. CLI and daemon paths agreed; the supervised service was running; the RPC probe passed. The same pass also found two environment substitutions, one SecretRef, no include marker, reload mode off, five plaintext credentials, one shadowed ref, and one legacy residue item. “Valid” and “ready to activate” were visibly different claims.
Review redacted evidence, never the whole file. A config dump can reveal tokens, account topology, paths, plugin inventory, channel allowlists, and network exposure even when a CLI redacts known secret fields. The useful artifact is a small set of claims and counts, not openclaw.json pasted into a ticket.
Validation stopped at the file boundary
OpenClaw normally reads JSON5 from ~/.openclaw/openclaw.json, or from the path selected by OPENCLAW_CONFIG_PATH. That tells you where to begin. It does not prove what the running process uses. A service unit can supply environment variables or command-line arguments; includes can move ownership into other files; SecretRefs can resolve values at activation time; and a daemon can still be running an older snapshot.
On the inspected host, four read-only checks established the starting point:
openclaw config file
openclaw config validate --json
openclaw config get gateway.reload.mode --json
openclaw gateway status --json
The CLI and daemon again agreed on the same active path. The file was a regular 15,121-byte file rather than a symlink, its permissions were 0600, and schema validation returned no warning. A marker-only scan again counted no $include directive, two environment substitutions, and one SecretRef without printing their names or values.
The live status added two receipts: the supervised service was running and the RPC check passed. It did not erase the activation problem. With reload mode off, a later file write needs a deliberate restart boundary before a runtime assertion can mean anything.
Four receipts answer four different questions
Selection
CLI and daemon resolved the same regular config file. There was no path drift to explain different behavior.
Syntax and schema
The current document was valid with no warnings. This said nothing yet about activation or external credentials.
Activation
The service was loaded and running and RPC passed, while reload remained off. A future write would still need an explicit boundary.
Secret posture
One ref resolved and none was unresolved, while five plaintext credentials, one shadowed ref, and one legacy residue item remained.
No setting was changed to collect this evidence. The config, service, Gateway, channels, plugins, models, network exposure, and secret providers were left alone. That matters because a diagnostic that “proves” a change by making another change is a poor audit artifact.
Classify the proposed write before debating its value
The dangerous part of a config diff is often the operator used to create it. OpenClaw’s path setters and patch command do not all have the same semantics. Objects in a patch merge recursively; scalars and arrays replace. null deletes a path. Protected maps refuse destructive replacement unless the caller states that replacement is intentional.
| Change shape | Typical risk | Review evidence | Safer tool behavior |
|---|---|---|---|
| One scalar | Wrong type or wrong path | Path-scoped schema, old value, dry-run output | config set with strict JSON where type matters |
| Nested object | Replacing siblings that were not in the proposal | Post-change subtree and protected-path result | Recursive patch or explicit --merge |
| Array or allowlist | Silently dropping working entries | Complete before/after membership, not a partial snippet | Explicit replacement only when the new array is complete |
| SecretRef | Valid shape but unavailable provider, shadowing, or inactive surface | Resolvability result and precedence check | Builder mode plus dry-run; avoid exec resolution unless deliberately approved |
| Service-owned value | File change loses to command-line or environment precedence | Runtime source and service definition | Change the owning layer, not a lower-precedence copy |
A dry run should be attached to the review. For a multi-path proposal, one patch is easier to reason about than a sequence of writes:
// candidate.patch.json5
{
agents: {
defaults: {
heartbeat: { every: "2h" }
}
}
}
openclaw config patch \
--file ./candidate.patch.json5 \
--dry-run \
--json
This checks the full post-change schema and relevant SecretRef resolvability without writing the active file. It is still a preflight, not a runtime test. In particular, exec-backed secret providers are skipped unless --allow-exec is added, because “validation” can otherwise execute a provider command. That flag deserves the same scrutiny as any other code execution.
SecretRefs widen the activation boundary
A SecretRef is a pointer with an activation contract, not magic redaction dust. Supported credentials may reference env, file, or exec providers. OpenClaw resolves active references into an in-memory snapshot. Some owner failures can be isolated; some retain a last-known-good value; strict or unmapped failures reject activation. A document can therefore be valid while one owner is stale or unavailable.
The read-only audit on the inspected host produced an uncomfortable but actionable result:
- one SecretRef was checked and resolved completely;
- no reference was unresolved;
- five supported credentials were still stored as plaintext;
- one ref was shadowed by a higher-precedence credential source;
- one legacy credential artifact remained outside ordinary SecretRef migration.
No credential name, value, provider identity, account label, or storage path belongs in the article or a routine review. The counts are enough to reject the claim “we use SecretRefs, therefore secrets are handled.” Migration is complete only when plaintext residue is gone from the relevant trust boundary and openclaw secrets audit --check is clean.
Do not make a secret migration a side effect of an unrelated config change. Moving five credentials changes startup dependencies and rollback behavior. Treat that as its own reviewed operation, with backups protected as secrets and a tested provider outage path.
Testing the valid diff that never became real
The repeat still found gateway.reload.mode set to off. The reasonable conclusion is narrow: the running Gateway answered RPC from the same validated config path. It does not mean a future edit will apply automatically, and it does not prove every subsystem consumed every field.
With reload disabled, the operational sequence is explicit:
- dry-run and review the candidate;
- write atomically through a supported config command;
- validate the stored file again;
- restart only the boundary documented for the changed setting;
- verify the resolved value and the affected behavior;
- roll back if the runtime proof fails.
Hot reload reduces the gap between write and activation, but it adds states that reviews must recognize. A reload may succeed, reject the candidate and preserve the active snapshot, or keep a mapped owner on a last-known-good secret. “No crash” is not a useful success criterion.
A forward assertion must be falsifiable
Every proposal needs one observation that would falsify it. “Gateway is still running” is too broad. If the change adjusts a heartbeat interval, read back that path and observe the next heartbeat window. If it changes a channel policy, use one allowed and one denied test identity. If it changes a model default, resolve the active model and run one bounded probe. If service arguments own the setting, prove the service definition and process arguments changed.
The baseline commands are intentionally dull:
openclaw config validate --json
openclaw config get <changed.path> --json
openclaw gateway status --json
# Then run one subsystem-specific, read-only proof.
config get reads from a redacted snapshot, so it is appropriate for a narrowly scoped value. Avoid reading a large parent object when one leaf is enough. The final proof should describe the behavior, timestamp, and expected result without retaining secrets or unrelated topology.
Rollback begins at a named failed assertion
A recoverable copy matters, but a rollback plan needs more than a filename. State which failure triggers rollback, which layer will be restored, whether the restore itself requires activation, and how the previous runtime will be proven. If service arguments override the file, restoring only JSON cannot recover the old behavior.
Rollback trigger
A named failed assertion: rejected channel access, missing RPC, unresolved owner, wrong model, or absent scheduled event.
Rollback target
The actual owning layer: config path, included file, service environment, unit argument, or external secret provider.
Activation
The exact reload or restart boundary required to make the restored value effective.
Recovery proof
The same narrow observation used for the forward change, now matching the previous expected result.
Keep the backup permission-restricted and treat it as production secret material. A copied config can preserve plaintext credentials even after the active file is migrated. “We removed the token from openclaw.json” is not the same as “the token no longer exists in an agent-readable backup.”
The decision record must survive the restart
A reviewer should be able to answer these questions without opening the full config:
- Which active file and service layer own the value?
- What is the exact path-scoped schema and current redacted value?
- Does the operation merge, replace, or delete?
- Which credentials are resolved, shadowed, inactive, stale, or still plaintext?
- Will the change hot-apply, restart a subsystem, or wait for a Gateway restart?
- What single runtime observation proves success?
- What failed assertion triggers rollback, and how is recovery verified?
The repeated inspection passed file, schema, service, and RPC checks. Reload policy and the secret audit still prevented a lazy approval. That is the value of the record: it converts “looks valid” into a bounded operation with an observable forward result and an observable recovery result.
Evidence refreshed on 23 July 2026
All four first-party documents below returned HTTP 200 during the refresh and still exposed the claim-level markers recorded in the evidence artifact: config file selection, validation, scoped reads and writes, patch dry-runs, JSON5 includes and substitutions, reload behavior, field ownership, SecretRef providers, audit, and activation. The host repeat independently rechecked the running boundary without changing configuration or external state.