← AI Coding Guides â€ē Deep Dives
4 Approval Modes â€ĸ Wildcard Rules â€ĸ ML Classifiers â€ĸ Tool Stripping

Permission Systems: Who Decides What Runs

Every coding agent must decide: should this command run? Should this file be edited? Should this tool be allowed? This page dissects how 18 agents answer those questions — from simple YOLO modes to ML-powered auto-approval.

(Alright, ad over. Back to the serious technical analysis.)

Permission spectrum overview

How coding agents decide whether a command runs, a file gets modified, or a tool is invoked is a fundamental architecture question. The 18 agents analyzed here span an enormous range — from simple mode enums to ML-powered classifiers to rule DSLs with pattern matching. Below is a comprehensive comparison across four dimensions: the model type, available modes, auto-approval strategy, and granularity of control.

Agent Permission Model Modes Auto-Approval Granularity
Claude Code 4 modes + ML classifier default, plan, bypass, auto ML classifier for auto mode Per-operation + wildcard rules
Neovate 3 modes + 22-item ban list default, autoEdit, yolo autoEdit for edits Per-tool category
Codex execpolicy DSL + approval flow suggest, auto-edit, full-auto is_known_safe_command() fast-path Per-tool + prefix patterns + network rules
OpenCode allow/deny/ask rules Pattern-based Always-once-reject Per-permission + path/command patterns
Crush TUI permission prompts Interactive None Per-operation, user-present
DeerFlow Tool group filtering + guardrails Fail-closed default None Per-tool-group
OpenHands RISK_LEVELS dict Risk-classified None Per-tool risk level
Hermes Child agent tool stripping Parent/child None Per-agent-type
Dirac DIRAC_COMMAND_PERMISSIONS + approval Default, YOLO YOLO auto-approves all Glob pattern permissions
Qwen Code Permission decisions + shell classification Interactive Read-only detection Per-tool, read vs write
Pochi Apply-diff safety params Interactive None Per-operation safety checks
Kimi CLI Hooks-based interception Hook-driven Depends on hooks Hook-level
Pi Mono Extensions-only None (README: no permission popups) None Via extensions only
ADK-Rust RBAC + scope-based tool auth + human-in-loop Framework callbacks None Per-tool-scope + RBAC
Goose ACP protocol permissions IDE-mediated IDE decides Per-tool via ACP
Wintermolt Config-based tool enablement Config-driven None Per-tool enable/disable
Zaica Config-based Config-driven None Per-tool
Oh My Pi Permission layers Multi-layer None Extension-based layers

Claude Code: The most sophisticated permission system

Claude Code implements the most nuanced permission model in this set: four approval modes, wildcard rules, an ML classifier, and persistent rule storage. It's the only agent that attempts to learn what's safe rather than relying purely on static rules or user judgment.

Four permission modes

Mode Behavior When to use
default Prompt for every dangerous operation General development — safest default
plan Show plan, ask once for approval, then auto-approve all operations in the plan Known tasks with clear scope — balance of safety and speed
bypassPermissions Auto-approve everything Only in containers/VMs — never on host
auto ML classifier decides — auto-approve safe operations, prompt for risky ones Trusted workflows where you want ML to filter noise

Wildcard rules

Claude Code supports pattern-based permission rules that auto-approve or deny entire families of operations. The two main rule types:

PermissionRule type and architecture

The core permission abstraction is the PermissionRule type, which combines:

Rules are evaluated against a ToolPermissionContext, an in-memory cache of permission decisions that avoids re-prompting for the same operation within a session. Rules persist across sessions via settings.json, so your Bash(git *) rule survives restarts.

ML classifier integration

In auto mode, the ML classifier runs in parallel with the permission prompt. If the classifier deems an operation safe, it can upgrade the decision to auto-approve before the user even responds. This is the key UX improvement: the user sees fewer prompts because safe operations are pre-approved by the model, not because they were silenced.

Permission UI components

The BashPermissionRequest component displays to the user:

Programmatic rule changes flow through PermissionUpdate and PermissionUpdateDestination, allowing other parts of the system to modify permission rules at runtime — for instance, the plan mode temporarily upgrades all planned operations to allow.

Codex: The execpolicy rule engine

Codex takes a different philosophy: rather than modes and classifiers, it provides a programmable rule DSL through its execpolicy crate. This gives fine-grained, code-as-policy control over what commands run.

Fast-path allowlist

Before hitting the policy engine, Codex checks is_known_safe_command() — a hardcoded allowlist of read-only operations that skip all policy evaluation:

ls, cat, find, git status, head, tail, wc, grep, echo, pwd, date, whoami

This is a critical performance optimization: most agent turns involve many read-only commands, and skipping the full policy engine for them reduces latency and eliminates unnecessary prompts.

Permission profiles

Profile Behavior
suggest Prompt the user before any operation — most restrictive
auto-edit Auto-approve file edits, prompt for commands
full-auto Approve all operations — requires sandbox for safety

Runtime approval flow

The request_permissions tool is Codex's runtime approval mechanism: the agent explicitly requests permission from the user for an operation, the user approves or denies, and the decision is cached for the session. This is different from Claude Code's parallel classifier — Codex always waits for the user unless the operation matches an allowlist rule.

execpolicy rule DSL

The execpolicy crate supports:

Thread-level sandbox isolation

Each thread can have its own sandbox_mode and approval policy. This means you can run a high-trust thread with full-auto inside a sandbox, while a lower-trust thread runs with suggest on the host. The separation of approval policy from sandbox enforcement is Codex's key architectural insight: they are orthogonal concerns and should be configured independently.

OpenCode: Pattern-matching permission bus

OpenCode implements a permission system built around a permission bus — an event-driven architecture where permission requests and decisions flow through a central dispatch. This is fundamentally different from the mode-based approaches: every operation publishes a permission request, rules are evaluated in sequence, and a reply is generated.

Rule/Request/Reply architecture

Three core types define the system:

Last-match-wins evaluation

Rules are evaluated sequentially with last-match-wins semantics. This means you can set a broad allow rule and then add specific deny rules that override it. The order matters: later rules take precedence. This is a deliberate design choice — it allows users to start permissive and then carve out exceptions, rather than starting restrictive and carving out allowances.

Permission bus and ACP integration

The permission bus publishes events to all subscribers. This enables:

Configuration and rule composition

The fromConfig() function builds rule sets from configuration, and merge() combines multiple rule sets. The disabled() function creates a fully permissive rule set — useful for testing or trusted environments. Rules can be backed by a database for persistence across sessions, and per-agent overrides allow different agents to have different permission rules within the same system.

Neovate: Banned-list approach

Neovate takes the most opinionated stance: define what's not allowed, and everything else is fine. This inverted approach is simpler to reason about but requires maintaining a comprehensive ban list.

Three approval modes

Mode Behavior
default Prompt for every operation — user decides case-by-case
autoEdit Auto-approve file edits, prompt for commands
yolo Approve everything — including the ban list

The 22-item banned command list

In default mode, the following commands are always blocked:

alias, aria2c, axel, bash, chrome, curl, curlie, eval,
firefox, fish, http-prompt, httpie, links, lynx, nc,
rm, safari, sh, source, telnet, w3m, wget, xh, zsh

This list is carefully curated: it bans shells (bash, sh, fish, zsh) to prevent escape to an unrestricted shell, network tools (curl, wget, lynx, etc.) to prevent data exfiltration, and destructive commands (rm, eval, source).

High-risk pattern detection

Beyond static bans, Neovate detects dangerous patterns even in allowed commands:

rm -rf       # recursive force delete
sudo         # privilege escalation
dd if=       # raw disk access
mkfs         # filesystem creation
curl | sh    # remote code execution

Each pipeline segment is checked individually, so ls | rm -rf / is caught on the rm -rf segment even though ls is safe.

Quote-aware pipeline parser

The critical security feature is a character-level state machine that tracks quoting context before any security check:

splitPipelineSegments() uses this state machine so that 'echo "a|b"' is correctly identified as ONE segment — the pipe inside the quotes is not a pipeline separator. Similarly, hasCommandSubstitution() detects $() and backticks within quoted contexts, preventing command injection via nested substitution.

Per-tool category permissions

Beyond bash, Neovate categorizes all tools into: read, write, command, network, and ask. Each category can have independent permission rules, allowing fine-grained control like "auto-approve reads but prompt for writes."

Other notable permission approaches

Dirac: Glob-pattern permissions + YOLO escape hatch

Dirac uses the DIRAC_COMMAND_PERMISSIONS environment variable to define glob patterns for allowed commands. The default workflow is approval-based — every command requires user confirmation. The YOLO mode is an escape hatch that auto-approves everything, but the codebase also implements git checkpoints: before any risky operation, a checkpoint is created so the user can revert if things go wrong.

Crush: TUI permission prompts + SHA-256 loop detection

Crush builds permission prompts directly into its Go terminal UI. Before executing dangerous operations, the user sees an interactive prompt in the TUI. Additionally, SHA-256 loop detection computes signatures for every tool call (tool_name + input + output); if any signature repeats 5 times in a 10-step window, the agent halts as stuck.

DeerFlow: Tool group filtering + guardrail middleware

DeerFlow filters tools into groups (web, file:read, file:write, bash) with a fail-closed default — nothing is allowed unless explicitly permitted. The guardrail middleware is one layer in a 14-layer middleware chain, where permissions are enforced as a distinct concern. This is a defense-in-depth approach: even if one layer fails, others catch the violation.

OpenHands: RISK_LEVELS dictionary

OpenHands classifies every tool with a risk level via a RISK_LEVELS dictionary. All tool calls carry a security_risk attribute, and a Jinja2 security risk assessment template is included in the system prompt. This approach is more about classification than enforcement — the agent is told the risk level and expected to act accordingly, but there's no hard block on high-risk tools.

Hermes: Child agent tool stripping

Hermes removes dangerous tools from child agents at construction time — 5 tools are always stripped from children. This creates a parent/child permission asymmetry: the parent has full tool access, while children operate with a reduced surface area. This is structural safety: rather than prompting or classifying, the dangerous tools simply don't exist in the child's tool set.

ADK-Rust: RBAC + scope-based tool auth + human-in-loop

ADK-Rust implements permission control at the framework level through Role-Based Access Control (RBAC) combined with scope-based tool authorization. Human-in-the-loop callbacks allow the framework to prompt the user for permission decisions. This is not shell-level parsing — it's architectural permission control built into the agent framework itself.

Qwen Code: Read-only detection + shell classification

Qwen Code classifies shell commands and auto-approves those detected as read-only. This is a lightweight version of Claude Code's ML classifier: instead of a full model, it uses simple pattern matching to determine if a command is destructive. Read-only commands skip the prompt; writes require user confirmation.

Pochi: Apply-diff safety parameters

Pochi implements permission checks around its apply-diff operations with safety parameters that validate the proposed changes before execution. This is a content-aware approach: rather than checking the tool name, it examines the actual diff content to determine if the operation is safe.

The YOLO mode problem

Every agent with a YOLO/bypass/auto-approve mode faces the same fundamental tension: developers want zero-friction for trusted work, but any auto-approve mode is a security hole if the model is compromised.

âš ī¸

The YOLO tradeoff

YOLO mode is the most dangerous configuration in any coding agent. It removes all permission gates, trusting the model to never execute a destructive command. If the model is compromised via prompt injection, or if it hallucinates a dangerous command, there is no safety net.

Different agents approach this tension differently:

Agent YOLO Name Mitigation
Claude Code bypassPermissions Documentation warns: only use in containers/VMs
Neovate yolo Still checks high-risk patterns (rm -rf, sudo, dd)
Codex full-auto Separate approval policy from sandbox — full-auto can still be sandboxed
Dirac YOLO Git checkpoints before risky operations

Claude Code's ML classifier is the most nuanced attempt at balancing safety versus speed: instead of a binary "prompt everything" or "approve everything," it uses a model to make per-operation decisions. Codex's approach of separating approval policy from sandbox enforcement is also noteworthy — you can be in full-auto mode but still sandboxed, meaning the agent runs freely but within an isolated environment.

💡

The real answer

Auto-approve inside sandbox, prompt outside sandbox. This simple rule captures the right balance: frictionless development in a safe environment, careful gates when operating on the host machine.

Permission architecture patterns

Across all 18 agents, five distinct architectural patterns emerge for handling permissions:

Pattern 1 Approval-mode layers

Agents: Neovate, Qwen Code, Dirac, Pochi

A simple mode enum where the user picks a level of trust: prompt-all, auto-edit, or approve-everything. This is the simplest pattern to implement and the easiest to explain to users. The tradeoff is coarse granularity — you can't say "auto-approve git but prompt for builds."

Pattern 2 Policy engines

Agents: Codex, OpenCode

A rule DSL with pattern matching for fine-grained control. Users write rules like allow git * or deny curl *. This is the most flexible pattern but requires users to understand rule syntax and evaluation order. Codex's execpolicy and OpenCode's permission bus are both examples of this approach.

Pattern 3 AI-assisted classification

Agents: Claude Code

An ML classifier makes per-operation decisions, auto-approving safe operations and prompting for risky ones. This is the most sophisticated approach but also the most complex to implement. The classifier runs in parallel with the permission prompt, upgrading decisions to auto-approve when confidence is high.

Pattern 4 Tool stripping

Agents: Hermes, DeerFlow

Remove dangerous tools from sub-agents entirely. This is structural safety — rather than prompting or classifying, the dangerous tools simply don't exist in the child agent's tool set. Hermes strips 5 tools from children; DeerFlow filters by tool group with a fail-closed default.

Pattern 5 Risk classification

Agents: OpenHands

Classify tools by risk level and apply policies per risk level. The RISK_LEVELS dictionary maps each tool to a risk category, and the system prompt includes a security risk assessment template. This is more advisory than enforced — the agent is told the risk level and expected to act accordingly.

What you should build

If you're designing a permission system for a new coding agent, here are the key recommendations distilled from analyzing all 18 agents:

â„šī¸

Start with Codex's separation of concerns

Separate approval policy from sandbox enforcement. They are orthogonal concerns: approval policy decides whether to run, sandbox decides where it runs. Mixing them leads to configurations that are either too restrictive (prompt for everything in sandbox) or too permissive (auto-approve on host).

Minimum viable permission system

  1. At least 3 modes: prompt-all (safest), auto-approve-sandboxed (frictionless in isolation), and auto-approve-all (YOLO, for trusted environments). This covers the full spectrum of trust levels.
  2. Add wildcard rules early: Bash(git *) and Read(*) are safe defaults that eliminate prompt fatigue. Git operations are scoped to the repository, and reads can't modify state. These two rules alone eliminate a majority of permission prompts.
  3. Consider ML classification for auto mode: Even a simple classifier that detects read-only commands is better than all-or-nothing. You don't need Claude Code's full ML infrastructure — a pattern matcher that recognizes cat, ls, grep, and find as safe is a meaningful improvement.
  4. Never strip permissions from sub-agents without sandboxing them: If you remove tools from a child agent, also run it in a sandbox. Tool stripping alone is insufficient — the child might still access the filesystem or network through remaining tools.
  5. Make permissions persistent across sessions: Store rules in settings.json or a similar persistent format, not just in-memory. Users should not have to re-approve git * every time they restart the agent.
  6. Show users what's happening: Permission prompts should display the command, its risk level, and sandbox status. Transparency builds trust — users who understand why they're being prompted are more likely to set appropriate rules.
âš ī¸

Common mistakes to avoid

  • Don't make YOLO the default — the friction of prompt-all is better than the risk of auto-approve-all
  • Don't rely solely on ban lists — they're incomplete by definition (you can't ban what you haven't thought of)
  • Don't conflate approval policy with sandbox — they solve different problems
  • Don't strip tools without also restricting the execution environment
  • Don't forget that read-only detection is a cheap, effective classifier

Bottom line

Permission systems are the most visible security feature of any coding agent — they're what the user interacts with on every turn. A well-designed permission system balances safety and developer experience; a poorly designed one is either a security hole or a productivity black hole.

Claude Code's four-mode system with ML classifier represents the most sophisticated attempt at this balance. Codex's separation of approval policy from sandbox enforcement is the most architecturally sound. Neovate's quote-aware pipeline parser is the most defensive bash implementation. And OpenCode's permission bus is the most extensible — it can scale to distributed systems and multi-agent architectures.

The pattern that emerges from all of this: the best permission system is layered. Start with coarse modes, add wildcard rules for common operations, classify operations by risk, sandbox when possible, and persist decisions so users don't face prompt fatigue. No single pattern is sufficient on its own — production readiness requires all of them working together.