11---
2- summary : " CLI reference for `openclaw policy` channel conformance checks"
2+ summary : " CLI reference for `openclaw policy` conformance checks"
33read_when :
44 - You want to check OpenClaw settings against an authored policy.jsonc
55 - You want policy findings in doctor lint
@@ -10,14 +10,23 @@ title: "Policy"
1010# ` openclaw policy `
1111
1212` openclaw policy ` is provided by the bundled Policy plugin. Policy is an
13- enterprise conformance layer over existing OpenClaw settings: ` policy.jsonc `
14- defines authored requirements, OpenClaw observes the active workspace as
15- evidence, and policy health checks report drift through ` doctor --lint ` .
16-
17- This first policy slice manages configured channels. For example, IT can record
18- that Telegram is not approved, then ` doctor --lint ` reports any enabled Telegram
19- channel and ` doctor --fix ` can turn it off when workspace repairs are explicitly
20- enabled.
13+ enterprise conformance layer over existing OpenClaw settings. It does not add a
14+ second configuration system. ` policy.jsonc ` defines authored requirements,
15+ OpenClaw observes the active workspace as evidence, and policy health checks
16+ report drift through ` doctor --lint ` . The final conformance signal is a clean
17+ ` doctor --lint ` run; policy contributes findings to that shared lint surface
18+ instead of creating a separate health gate.
19+
20+ Policy currently manages configured channels and governed tool declarations.
21+ For example, IT or a workspace operator can record that Telegram is not an
22+ approved channel provider, require governed tools to carry risk and sensitivity
23+ metadata, then use ` doctor --lint ` as the shared conformance gate.
24+
25+ Use policy when a workspace needs a durable statement such as "these channels
26+ must not be enabled" or "governed tools must declare approval metadata" and a
27+ repeatable way to prove that OpenClaw still conforms to that statement. Use
28+ regular config and workspace docs alone when you only need local behavior and
29+ do not need policy findings or attestation output.
2130
2231## Quick start
2332
@@ -32,7 +41,7 @@ arbitrary plugins. The plugin remains enabled if `policy.jsonc` is missing, so
3241doctor can report the missing artifact.
3342
3443Policy is authored, not generated from the user's current settings. A minimal
35- channel policy looks like this:
44+ policy for channels and tool metadata looks like this:
3645
3746``` jsonc
3847{
@@ -45,12 +54,16 @@ channel policy looks like this:
4554 },
4655 ],
4756 },
57+ " tools" : {
58+ " requireMetadata" : [" risk" , " sensitivity" , " owner" ],
59+ },
4860}
4961```
5062
5163The rules are the authority. A category block is only a namespace; checks run
5264when a concrete rule is present. OpenClaw reads current ` channels.* ` settings
53- and reports settings that do not conform.
65+ and ` TOOLS.md ` declarations as evidence, then reports observed state that does
66+ not conform.
5467
5568Run policy-only checks during authoring:
5669
@@ -122,12 +135,64 @@ Policy config lives under `plugins.entries.policy.config`.
122135Set ` plugins.entries.policy.config.enabled ` to ` false ` to disable policy checks
123136for a workspace while leaving the plugin installed.
124137
138+ Tool metadata requirements are authored in ` policy.jsonc ` with
139+ ` tools.requireMetadata ` , for example ` ["risk", "sensitivity", "owner"] ` .
140+
125141## Accept policy state
126142
127- The attestation hash identifies the stable claim: policy hash, evidence hash,
128- findings hash, and whether the result was clean. It intentionally does not
129- include ` checkedAt ` , so the same policy state produces the same attestation
130- across repeated checks.
143+ Example JSON output:
144+
145+ ``` json
146+ {
147+ "ok" : true ,
148+ "attestation" : {
149+ "checkedAt" : " 2026-05-10T20:00:00.000Z" ,
150+ "policy" : {
151+ "path" : " policy.jsonc" ,
152+ "hash" : " sha256:..."
153+ },
154+ "workspace" : {
155+ "scope" : " policy" ,
156+ "hash" : " sha256:..."
157+ },
158+ "findingsHash" : " sha256:..." ,
159+ "attestationHash" : " sha256:..."
160+ },
161+ "evidence" : {
162+ "channels" : [
163+ {
164+ "id" : " telegram" ,
165+ "provider" : " telegram" ,
166+ "source" : " oc://openclaw.config/channels/telegram" ,
167+ "enabled" : false
168+ }
169+ ],
170+ "tools" : [
171+ {
172+ "id" : " deploy" ,
173+ "source" : " oc://TOOLS.md/tools/deploy" ,
174+ "line" : 12 ,
175+ "risk" : " critical" ,
176+ "sensitivity" : " restricted" ,
177+ "capabilities" : [" IRREVERSIBLE_EXTERNAL" ]
178+ }
179+ ]
180+ },
181+ "checksRun" : 6 ,
182+ "checksSkipped" : 0 ,
183+ "findings" : []
184+ }
185+ ```
186+
187+ The policy hash identifies the authored rule artifact. The evidence block
188+ records the observed OpenClaw state used by the policy checks. The
189+ ` workspace.hash ` value identifies that evidence payload for the checked scope.
190+ The findings hash identifies the exact finding set returned by the check.
191+ ` checkedAt ` records when the evaluation ran. The attestation hash identifies
192+ the stable claim: policy hash, evidence hash, findings hash, and whether the
193+ result was clean. It intentionally does not include ` checkedAt ` , so the same
194+ policy state produces the same attestation across repeated checks. Together,
195+ these form the audit tuple for this policy check.
131196
132197If a later gateway or supervisor uses policy to block, approve, or annotate a
133198runtime action, it should record the attestation hash from the last clean policy
@@ -146,20 +211,71 @@ If policy rules change intentionally, update both accepted hashes from a clean
146211check. If workspace settings change intentionally but policy stays the same,
147212only ` expectedAttestationHash ` usually changes.
148213
214+ ` openclaw policy watch ` runs the same check repeatedly and reports when the
215+ current evidence no longer matches ` expectedAttestationHash ` :
216+
217+ ``` bash
218+ openclaw policy watch --json
219+ ```
220+
221+ Use ` --once ` in CI or scripts that only need one drift evaluation. Without
222+ ` --once ` , the command polls every two seconds by default; use ` --interval-ms ` to
223+ choose a different interval.
224+
149225## Findings
150226
151227Policy currently verifies:
152228
153- | Check id | Finding |
154- | ---------------------------------- | ------------------------------------------------------------------- |
155- | ` policy/policy-jsonc-missing ` | Policy is enabled but ` policy.jsonc ` is missing. |
156- | ` policy/policy-jsonc-invalid ` | Policy cannot be parsed or has malformed rules. |
157- | ` policy/policy-hash-mismatch ` | Policy does not match configured ` expectedHash ` . |
158- | ` policy/attestation-hash-mismatch ` | Current policy evidence no longer matches the accepted attestation. |
159- | ` policy/channels-denied-provider ` | An enabled channel matches a channel deny rule. |
229+ | Check id | Finding |
230+ | ---------------------------------------- | ------------------------------------------------------------------- |
231+ | ` policy/policy-jsonc-missing ` | Policy is enabled but ` policy.jsonc ` is missing. |
232+ | ` policy/policy-jsonc-invalid ` | Policy cannot be parsed or has malformed rules. |
233+ | ` policy/policy-hash-mismatch ` | Policy does not match configured ` expectedHash ` . |
234+ | ` policy/attestation-hash-mismatch ` | Current policy evidence no longer matches the accepted attestation. |
235+ | ` policy/channels-denied-provider ` | An enabled channel matches a channel deny rule. |
236+ | ` policy/tools-missing-owner ` | A governed tool declaration is missing owner metadata. |
237+ | ` policy/tools-missing-risk-level ` | A governed tool declaration is missing risk metadata. |
238+ | ` policy/tools-missing-sensitivity-token ` | A governed tool declaration is missing sensitivity metadata. |
239+ | ` policy/tools-unknown-risk-level ` | A governed tool declaration uses an unknown risk value. |
240+ | ` policy/tools-unknown-sensitivity-token ` | A governed tool declaration uses an unknown sensitivity value. |
241+
242+ Policy findings can include both ` target ` and ` requirement ` . ` target ` is the
243+ observed workspace thing that does not conform. ` requirement ` is the authored
244+ policy rule that made it a finding. Both values are addresses today, usually
245+ ` oc:// ` paths, but the field names describe their policy role rather than the
246+ address format.
247+
248+ Example JSON finding:
249+
250+ ``` json
251+ {
252+ "checkId" : " policy/channels-denied-provider" ,
253+ "severity" : " error" ,
254+ "message" : " Channel 'telegram' uses denied provider 'telegram'." ,
255+ "source" : " policy" ,
256+ "path" : " openclaw config" ,
257+ "ocPath" : " oc://openclaw.config/channels/telegram" ,
258+ "target" : " oc://openclaw.config/channels/telegram" ,
259+ "requirement" : " oc://policy.jsonc/channels/denyRules/#0" ,
260+ "fixHint" : " Telegram is not approved for this workspace."
261+ }
262+ ```
160263
161- Policy findings can include ` target ` and ` requirement ` : the observed workspace
162- thing that does not conform, and the authored rule that made it a finding.
264+ Example tool finding:
265+
266+ ``` json
267+ {
268+ "checkId" : " policy/tools-missing-risk-level" ,
269+ "severity" : " error" ,
270+ "message" : " TOOLS.md tool 'deploy' has no explicit risk classification." ,
271+ "source" : " policy" ,
272+ "path" : " TOOLS.md" ,
273+ "line" : 12 ,
274+ "ocPath" : " oc://TOOLS.md/tools/deploy" ,
275+ "target" : " oc://TOOLS.md/tools/deploy" ,
276+ "requirement" : " oc://policy.jsonc/tools/requireMetadata"
277+ }
278+ ```
163279
164280## Repair
165281
@@ -190,5 +306,12 @@ configured channel:
190306
191307## Exit codes
192308
193- ` policy check ` exits ` 0 ` when there are no findings at the threshold, ` 1 ` when
194- findings are present, and ` 2 ` for argument or runtime failures.
309+ | Command | ` 0 ` | ` 1 ` | ` 2 ` |
310+ | -------------- | ----------------------------------------- | ------------------------------------------------ | ---------------------------- |
311+ | ` policy check ` | No findings at the threshold. | One or more findings met the threshold. | Argument or runtime failure. |
312+ | ` policy watch ` | No findings and accepted hash is current. | Findings exist or accepted attestation is stale. | Argument or runtime failure. |
313+
314+ ## Related
315+
316+ - [ Doctor lint mode] ( /cli/doctor#lint-mode )
317+ - [ Path CLI] ( /cli/path )
0 commit comments