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.

OpenClaw Configuration: Files, Secrets, Validation, and Reloads cover illustration

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.

Transparent configuration layers being scanned before they assemble into one effective runtime block
Effective configuration is assembled from the selected file, substitutions and refs, service inputs, and the active runtime snapshot. Validate each boundary separately.

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.

Decision from the repeatThe installation was healthy enough to review, but it did not make an arbitrary edit self-activating and it did not make SecretRef migration complete. Keep the running system untouched until one exact write, activation event, forward assertion, and rollback assertion have been named.

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 shapeTypical riskReview evidenceSafer tool behavior
One scalarWrong type or wrong pathPath-scoped schema, old value, dry-run outputconfig set with strict JSON where type matters
Nested objectReplacing siblings that were not in the proposalPost-change subtree and protected-path resultRecursive patch or explicit --merge
Array or allowlistSilently dropping working entriesComplete before/after membership, not a partial snippetExplicit replacement only when the new array is complete
SecretRefValid shape but unavailable provider, shadowing, or inactive surfaceResolvability result and precedence checkBuilder mode plus dry-run; avoid exec resolution unless deliberately approved
Service-owned valueFile change loses to command-line or environment precedenceRuntime source and service definitionChange 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:

  1. dry-run and review the candidate;
  2. write atomically through a supported config command;
  3. validate the stored file again;
  4. restart only the boundary documented for the changed setting;
  5. verify the resolved value and the affected behavior;
  6. 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.

Several isolated runtime chambers receiving one controlled configuration stream through a central activation gate
Activation is a controlled state transition. The same valid candidate can be accepted, rejected, or partially degraded depending on ownership and reload policy.

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.