Python ToolPermissionContext
The Python-side permission system centers on the ToolPermissionContext dataclass, which carries two fields for blocking tools:
deny_names is a frozenset of exact tool names that should be blocked. deny_prefixes is a tuple of string prefixes — any tool whose name starts with a listed prefix is blocked. Both fields are constructed via the from_iterables class method, which lowercases all entries to ensure case-insensitive matching.
The blocking check is implemented in the blocks() method:
The method first checks for an exact match against deny_names, then checks whether the lowercased tool name starts with any entry in deny_prefixes. This two-stage check is efficient: the frozenset lookup is O(1), and the prefix scan is O(n) over a typically small prefix list.
Rust 권한 모델
The Rust layer implements a richer permission model with three distinct modes:
The Prompt mode is the key differentiator from the Python layer. Instead of a binary allow/deny decision, the Rust permission system can pause execution and ask the user whether to allow a specific tool invocation. This is mediated through the PermissionPrompter trait:
The PermissionRequest includes both the tool name and the full input string, so the user can make an informed decision about whether to allow the specific operation. The PermissionPromptDecision enum includes an optional reason on denial, which is fed back to the model so it can understand why its tool use was rejected.
PermissionPolicy
The PermissionPolicy struct ties everything together. It defines a default_mode (applied to any tool without a specific override) and a tool_modes map (BTreeMap<String, PermissionMode>) for per-tool overrides:
The policy is constructed with new(default_mode) and customized with with_tool_mode(tool_name, mode) for individual tools. The mode_for(tool_name) method looks up the specific mode for a tool, falling back to the default if no override exists.
The authorize(tool_name, input, prompter) method executes the full authorization flow:
- Look up the mode for the tool via
mode_for - If
Allow, returnPermissionOutcome::Allowimmediately - If
Deny, returnPermissionOutcome::Denywith a static reason - If
Prompt, construct aPermissionRequestand callprompter.decide() - Map the prompter's decision to a
PermissionOutcome
The PermissionOutcome enum mirrors the decision types: Allow or Deny{reason}. This separation between policy (what mode applies) and prompting (how the user is asked) keeps the system testable — in tests, the prompter can be a mock that always allows or always denies.
CLI 권한 모드
The CLI exposes three preset permission modes via args.rs, providing convenient defaults for common use cases:
- ReadOnly — the agent can read files and search but cannot write, execute commands, or modify anything. This is the safest mode for exploratory sessions.
- WorkspaceWrite (default) — the agent can read and write files within the workspace, execute sandboxed commands, and use most tools. This is the standard mode for development work.
- DangerFullAccess — all permission checks are bypassed. The agent can execute arbitrary commands, write to any path, and use all tools without prompting. This mode is intended for trusted automation pipelines only.
기본 모드
WorkspaceWrite is the default for a reason — it provides enough capability for real development work while keeping the sandbox boundary intact. ReadOnly is useful for code review and exploration. DangerFullAccess should only be used in controlled environments where the agent is trusted.
도구 필터링
Permission filtering happens before tools reach the agent's context window. The get_tools function accepts a permission_context parameter and calls filter_tools_by_permission_context to remove any blocked tools from the list. This ensures that denied tools are never described in the system prompt — the agent literally does not know they exist.
This design is more secure than post-hoc enforcement. If a blocked tool appeared in the prompt but was rejected at execution time, the agent would waste turns attempting to use it and might try to work around the restriction. By filtering at the prompt level, the agent's decision-making is constrained to only the tools it can actually use.
심플 모드
Simple mode is the most restrictive tool configuration. When enabled, the tool pool is reduced to exactly three tools:
BashTool— shell command executionFileReadTool— file readingFileEditTool— file editing
All other tools — web access, sub-agents, search, notebooks, task management — are removed. This provides a minimal, predictable surface area for constrained environments where the full 19-tool suite would be excessive.
런타임 권한 추론
The runtime layer adds a final permission check via _infer_permission_denials. This function gates bash-like tools (any tool that can execute arbitrary commands) based on the active CLI permission mode. Even if a tool passes the ToolPermissionContext filter, the runtime inference layer can still block it based on the broader session permissions.
This layered approach — Python deny-list filtering, Rust policy engine, CLI mode presets, and runtime inference — creates defense in depth. Each layer catches cases the others might miss, ensuring that the claw code permission system is robust against configuration errors and edge cases.
보안 모델 요약
The claw code permission system provides per-tool granularity through four layers: Python deny lists (fast filtering), Rust permission policies (fine-grained control with prompting), CLI mode presets (convenient defaults), and runtime inference (final gating). Tools blocked at any layer never reach the agent.