Tool Policy

One-line summary

The tool policy system filters which tools are available to the LLM on each call, directly controlling the JSON schema token cost via a 7-step cascading policy pipeline.

Responsibilities

  • Filter available tools through a 7-step policy cascade (profile → provider → global → agent → group)
  • Expand plugin tool groups into individual tool names
  • Enforce sub-agent tool restrictions (hardcoded deny lists by depth)
  • Apply owner-only tool policies for security-sensitive operations
  • Warn about unknown allowlist entries (plugin tools without matching plugins)

Architecture diagram

Key source files

FileLinesRole
src/agents/tool-policy-pipeline.ts108Pipeline orchestrator: buildDefaultToolPolicyPipelineSteps(), applyToolPolicyPipeline()
src/agents/tool-policy.ts205Policy utilities: buildPluginToolGroups(), expandPluginGroups(), stripPluginOnlyAllowlist(), normalizeToolName()
src/agents/pi-tools.policy.ts315Policy resolution: resolveEffectiveToolPolicy(), resolveSubagentToolPolicy(), filterToolsByPolicy(), resolveGroupToolPolicy()

Data flow

Inbound

From runEmbeddedAttempt():
  ├── tools: AnyAgentTool[] (all registered tools)
  ├── config: OpenClawConfig (policy rules)
  ├── provider: string (current model provider)
  └── agentId: string

Processing

For each of 7 steps:
  1. Check if policy exists for this step
  2. Strip plugin-only allowlist entries (warn if unknown)
  3. Expand plugin tool groups (group:git → individual tools)
  4. Apply filterToolsByPolicy() → remaining tools

Outbound

Filtered AnyAgentTool[]

Serialized as JSON schemas → sent with LLM API call

Also summarized in system prompt (buildAgentSystemPrompt)

Token optimization impact

MechanismToken savingsDetails
Per-agent allowlistUp to 80% of tool tokensRestrict agent to only needed tools
Sub-agent deny lists~30-50% for sub-agentsHardcoded denials for nested agents
Provider-specific policiesVariableDifferent models may need different tool sets
Group policiesVariableReduce tools in group chat contexts

Quantified impact

24 core tools × ~150 tokens/schema = ~3,600 tokens
+ plugin tools (~50-200 tokens each)
+ skill tools

With restrictive policy (10 tools allowed):
  10 × ~150 = ~1,500 tokens (saving ~2,100)

With sub-agent policy (6 tools):
  6 × ~150 = ~900 tokens (saving ~2,700)

How it connects to other modules

  • Depends on:

    • config/ — policy configuration (tools.allow, tools.deny, byProvider)
    • plugins/ — plugin tool metadata for group expansion
  • Depended by:

    • agents/pi-embedded-runner/run/attempt.ts — calls pipeline before each LLM call
    • system-prompt.ts — filtered tools determine tool summaries section

My blind spots

  • Exact list of SUBAGENT_TOOL_DENY_ALWAYS and SUBAGENT_TOOL_DENY_LEAF tools
  • Whether tool schemas are cached or regenerated per call
  • tools.alsoAllow — additive plugin tool enablement mentioned in warnings
  • How resolveGroupToolPolicy() interacts with channel capabilities
  • None yet

Change frequency

  • tool-policy-pipeline.ts: Low — the 7-step cascade is stable
  • tool-policy.ts: Low — utility functions rarely change
  • pi-tools.policy.ts: Medium — sub-agent restrictions and group policies evolve with features