Skip to main content

Tool policy

Tool policy is the hard stop that controls what an agent can do. deny always wins. If allow is non-empty, every unlisted tool is blocked. Configuration layers from global → per-agent → exec approvals file — stricter always wins.

Profiles

A profile is a predefined baseline that enables a curated tool set:
Profiles are a starting point. Add specific tools with alsoAllow, or remove them with deny.

Allow and deny

allow and alsoAllow cannot coexist in the same scope — the schema rejects the combination. Use one or the other:
  • alsoAllow — additive: extends a profile without replacing it
  • allow — explicit: replaces the profile; only listed tools are available

Explicit allowlist

When allow is set and non-empty, every tool not listed is blocked, including tools from any profile. Use deny on top of allow if you want belt-and-suspenders blocking even for listed tools.

Tool name reference

Entry values are exact strings — no glob syntax: Plugin tools use the form <plugin-id>/<tool-name>. List available names with openclaw tools list.

Per-provider overrides

Restrict tool access by which AI provider is active for a given turn:
Keys can be a provider name ("anthropic") or a "provider/model" pair for model-specific rules.

Global vs per-agent

Global tool config

tools.* applies to all agents unless overridden:

Per-agent override

agents.list[*].tools applies only to that agent and takes precedence over the global config:
Per-agent tool config is not a full replacement of global — it is evaluated alongside global. The policy resolver uses the more specific scope (per-agent) when both define the same setting. deny from either scope wins.

Where per-agent config cannot appear

Per-agent tools supports allow, alsoAllow, deny, profile, byProvider, and exec.* — but does not expose the web, media, links, message, agentToAgent, sessions, or subagents sub-objects (those are global-only).

Exec security

tools.exec controls whether and how the agent can run shell commands.

security modes

ask modes

Safe bins

Safe bins are binaries the agent can run without an approval prompt in allowlist or full mode. They must match a known-safe argument profile.
Built-in safe bins (always available without config): jq, cut, uniq, head, tail, tr, wc. Default trusted directories for path resolution: /bin, /usr/bin only. Binaries in /usr/local/bin, /opt/homebrew/bin, etc. require adding those dirs to safeBinTrustedDirs.

Additional exec keys

Exec approvals file

The exec approvals file (~/.openclaw/exec-approvals.json) is the host-local persistent record of approved binaries. It exists independently of openclaw.json and is written by the runtime when a user approves an exec prompt.

Allowlist entry format

  • Glob patterns matched against the resolved binary path (symlinks followed).
  • Basename-only entries are ignored — patterns must resolve to an absolute path or glob.
  • Per-agent: scoped under agents.<agentId>.allowlist.
  • Valid examples: /usr/local/bin/rg, ~/Projects/**/bin/*, /opt/homebrew/bin/*.

Config vs approvals file — precedence

The effective policy is always the stricter of the two sources: Examples:
  • Config security: "full" + approvals security: "deny" → effective: "deny"
  • Config ask: "off" + approvals ask: "always" → effective: "always"
Within the approvals file: agents.<id> overrides defaults; per-agent is more specific.
The approvals file is owned by the host process. In multi-user or shared-gateway setups, each user’s gateway process has its own approvals file. Config-level tools.exec.security is the shared baseline; the approvals file is the per-user additive record.

Skill allowlist

Global bundled skill filter

allowBundled controls which bundled (built-in) skills are active. Workspace skills loaded from load.extraDirs and managed skills are not affected — control those via skills.entries.<name>.enabled.

Per-agent skill filter

agents.list[*].skills is a simple string array of skill names. It takes precedence over global config for that agent. An empty array ([]) disables all skills.
Skills can only be restricted here — you cannot add a skill to an agent that is not already globally available. If a skill is disabled globally via skills.entries.<name>.enabled: false, per-agent config cannot re-enable it.

Per-skill config

Individual skills can be toggled and configured under skills.entries:

Config hierarchy and implications

Settings cascade from most general to most specific. More specific always wins — except for deny, which wins everywhere.

What happens when a key is set in one place but not another

Common footguns

Using both allow and alsoAllow at the same config level is a schema validation error. If you want to extend a profile, use alsoAllow. If you want an explicit list, use allow alone.
If global sets tools.allow: ["exec", "read"] and a per-agent sets tools.allow: ["write"], the per-agent has only write. The lists do not merge — per-agent allow replaces the global allow for that agent.
tools.deny: ["exec"] globally blocks exec for all agents even if agents.list.dev.tools.allow: ["exec"]. deny is evaluated after all allow resolution and wins.
If you set tools.exec.security: "full" in config but the approvals file for that agent says security: "deny", the agent cannot run exec. The approvals file cannot grant permissions that config has not already given — it can only restrict.
Setting agents.list[*].skills: [] removes skills from the agent’s prompt context and disables skill invocation — but plugin-registered hook handlers for skill events still run. This is expected behaviour.

Debugging effective policy