Skip to main content

openclaw policy

openclaw policy is provided by the bundled Policy plugin. It is an enterprise conformance layer over existing OpenClaw settings, not a second configuration system. You author requirements in policy.jsonc; OpenClaw observes the active workspace as evidence; policy reports drift through doctor --lint. Policy does not enforce tool calls or rewrite runtime behavior at request time, and it does not attest per-agent credential stores such as auth-profiles.json. Policy checks configured channels, MCP servers, model providers, network SSRF posture, ingress/channel access, Gateway exposure and node command posture, agent workspace access, sandbox posture, data-handling posture, secret provider/auth profile posture, and governed tool metadata (TOOLS.md). Use it when a workspace needs a durable, checkable statement such as “Telegram must not be enabled” or “governed tools must declare risk and owner metadata.” If you only need local behavior with no attestation or drift detection, plain config is enough.

Quick start

The plugin stays enabled even when policy.jsonc is missing, so doctor can report the missing artifact instead of silently skipping checks. Author policy.jsonc by hand; it is not generated from current settings. Each top-level section is a rule namespace: a check only runs when a concrete rule is present under it (unsupported sections or keys fail as policy/policy-jsonc-invalid instead of being silently ignored). Minimal example covering every supported section:
Cross-cutting notes not obvious from the rule tables below:
  • Omitting gateway.bind while denying non-loopback binds means you accept the runtime default; set gateway.bind: "loopback" for strict conformance.
  • For a read-only agent, set sandbox mode to all or non-main on the applicable defaults/agent and workspaceAccess to none or ro. Missing or off sandbox mode does not satisfy a read-only policy.
  • agents.workspace.denyTools accepts exec, process, write, edit, apply_patch. The config tool-deny groups group:fs (file mutation) and group:runtime (shell/process) satisfy the equivalent posture.
  • Exec-approvals checks read the live exec-approvals.json artifact only when an execApprovals rule is present; a missing or invalid artifact is unobservable evidence, not a synthetic pass.
  • Secret and auth-profile evidence records provider/source posture and SecretRef metadata only, never raw values. Policy does not read or attest per-agent credential stores such as auth-profiles.json.
  • Data-handling evidence is config-level posture only (redaction mode, telemetry capture toggle, session maintenance mode, transcript-indexing setting). It does not inspect logs, telemetry exports, transcripts, or memory files, and a clean result does not prove that no personal data or secrets exist in them.

Policy rule reference

Every rule below is optional; a check runs only when the rule is present. The observed state is existing OpenClaw config or workspace metadata.

Scoped overlays

Use scopes.<scopeName> when specific agents or channels need stricter policy than the top-level baseline. The scope name is just a label; matching uses the selector inside the scope. Overlays are additive: the global rule still runs, and the scoped rule can add its own finding against the same evidence. If an agentIds entry is not present in agents.list[], OpenClaw evaluates the scoped rule against inherited global/default posture for that runtime agent id instead of skipping it.
The same agent can appear in multiple scopes if each scope governs a different field, as above. A repeated scoped field for the same agent must be equally or more restrictive; a weaker duplicate claim is rejected (allow-lists are subsets, deny-lists are supersets, required booleans are fixed). Container posture rules (sandbox.containers.*) are checked only against evidence the matched agent’s sandbox backend can expose. If a backend cannot observe a rule you enabled for it, policy reports policy/sandbox-container-posture-unobservable instead of passing; scope container rules to the agent groups that use a backend which can expose them. Top-level ingress.session.requireDmScope stays global; session.dmScope is not channel-attributable evidence, so it cannot be scoped by channelIds. Every scope present in policy.jsonc must be valid and enforceable.

Channels

MCP servers

Model providers

Network

Ingress and channel access

Gateway

gateway.nodes.denyCommands is an exact, case-sensitive deny-superset rule. Use it when policy must prove that privileged node commands are explicitly denied by OpenClaw config. A deployment that intentionally allows a privileged node command should update policy.jsonc after review instead of relying on gateway.nodes.allowCommands alone.

Agent workspace

Sandbox posture

Policy treats missing sandbox.mode as its implicit default off, so sandbox.requireMode reports a fresh or unconfigured sandbox as outside an allowlist such as ["all"].

Data Handling

Secrets

Exec approvals

Exec-approvals checks read the runtime exec-approvals.json artifact: ~/.openclaw/exec-approvals.json by default, or $OPENCLAW_STATE_DIR/exec-approvals.json when OPENCLAW_STATE_DIR is set. Posture rules under execApprovals.defaults.* or execApprovals.agents.* require readable artifact evidence; a missing or invalid artifact reports as unobservable evidence rather than a best-effort pass. Once readable, omitted fields inherit runtime defaults: missing defaults.security is full, and missing agent security inherits that default. Evidence includes defaults, agents.*, agents.*.allowlist[].pattern, optional argPattern, effective autoAllowSkills posture, and entry source — never socket path/token, commandText, lastUsedCommand, resolved paths, or timestamps. Example: require the approvals artifact, deny permissive defaults, and allow only reviewed exec approval posture for selected agents.

Auth profiles

Tool metadata

Tool posture

Run checks

Run policy-only checks during authoring:
policy check runs only the policy check set and emits evidence, findings, and attestation hashes. The same findings also appear in openclaw doctor --lint when the Policy plugin is enabled. Compare an operator policy file against an authored baseline:
policy compare checks policy-file syntax against policy-file syntax; it does not inspect runtime state, evidence, credentials, or secrets. It uses the same rule metadata that governs scoped overlays: allowlists must stay equal or narrower, denylists must stay equal or broader, required booleans must keep their value, ordered strings may only move toward the stricter end of the configured order, and exact lists must match. The baseline can be an organization-authored policy; the checked policy may add stricter values or extra rules. A top-level checked rule can satisfy a scoped baseline rule when it is equally or more restrictive. Scope names do not need to match between files; comparison is keyed by selector (agentIds/channelIds) and field. Clean compare (--json):
Clean policy check --json output includes stable hashes an operator or supervisor can record:

Configure policy

Policy config lives under plugins.entries.policy.config.
Set plugins.entries.policy.config.enabled to false to disable policy checks for a workspace while leaving the plugin installed.

Accept policy state

Example JSON output:
attestation.policy.hash identifies the authored rule artifact. evidence records the observed OpenClaw state used by the checks, and workspace.hash identifies that evidence payload. findingsHash identifies the exact finding set. checkedAt records when the check ran. attestationHash identifies the stable claim (policy hash, evidence hash, findings hash, and clean/dirty state) and deliberately excludes checkedAt, so the same policy state always produces the same attestation hash. Together these four values form the audit tuple for one policy check. If a gateway or supervisor uses policy to block, approve, or annotate a runtime action, it should record the attestation hash from the last clean check. checkedAt stays in JSON output for audit logs but is not part of the stable hash. Lifecycle for accepting policy state:
  1. Author or review policy.jsonc.
  2. Run openclaw policy check --json.
  3. If clean, record attestation.policy.hash as expectedHash.
  4. Record attestation.attestationHash as expectedAttestationHash.
  5. Re-run openclaw doctor --lint in CI or release gates.
If policy rules change intentionally, update both accepted hashes from a clean check. If only workspace settings change (policy stays the same), typically only expectedAttestationHash changes. Enabling or upgrading agents.workspace rules adds agentWorkspace evidence to the workspace hash and attestation hash; review the new evidence and refresh accepted attestation hashes after enabling. Enabling or upgrading tool posture rules adds toolPosture evidence the same way. openclaw policy watch re-runs the check and reports when current evidence no longer matches expectedAttestationHash:
Use --once in CI or scripts that need a single drift evaluation. Without --once, it polls every two seconds by default; use --interval-ms to change the interval.

Findings

A finding can include both target (the observed workspace thing that does not conform) and requirement (the authored rule that made it a finding). Both are oc:// address strings today, but the field names describe policy role rather than address format. Example findings:

Repair

doctor --lint and policy check are read-only. doctor --fix only edits policy-managed workspace settings when workspaceRepairs is explicitly enabled; otherwise checks report what they would repair and leave settings unchanged. In this version, repair can disable channels denied by channels.denyRules and apply the automatic narrowing repairs listed below. Enable workspaceRepairs only after the policy file has been reviewed, because a valid rule can change workspace config:
  • set tools.elevated.enabled=false when a global policy forbids elevated tools
  • add missing required-deny tool ids to tools.deny or agents.list[].tools.deny when policy requires those tools to be denied
  • set insecure gateway.controlUi.* toggles to false
  • set gateway.mode=local when policy denies remote gateway mode
  • set reported gateway.http.endpoints.*.enabled paths to false when policy denies Gateway HTTP API endpoints
  • set reported channel ingress groupPolicy paths to allowlist when policy denies open group ingress
  • set reported channel ingress requireMention paths to true when policy requires group mentions
  • set logging.redactSensitive=tools when policy requires sensitive logging redaction
  • set diagnostics.otel.captureContent=false, or diagnostics.otel.captureContent.enabled=false for object-form telemetry capture settings, when policy denies telemetry content capture
Scoped elevated-tools repairs are detect-only. Scoped data-handling repairs are also skipped when the finding reports shared logging or telemetry config, because changing the shared setting would affect more than the scoped policy target. Scoped required-deny repairs are skipped when the finding reports inherited root tools.deny, because adding the required tool to root config would affect more than the scoped policy target. Agent-local required-deny repairs can update the reported agents.list[].tools.deny path. Scoped channel ingress repairs are skipped when the finding reports inherited channels.defaults.*, because changing the shared channel default would affect more than the scoped policy target. Gateway HTTP URL-fetch allowlist findings remain manual because automatic repair cannot choose the correct endpoint URL allowlist values. Gateway bind and node-command findings stay review-required. When policy/gateway-non-loopback-bind or policy/gateway-node-command-denied can be mapped to a config path, doctor --fix reports the proposed gateway.bind or gateway.nodes.denyCommands change as skipped preview guidance. It does not apply the change, and the finding does not count as repaired until an operator reviews and updates config or policy.

Exit codes