Skip to content
Agentic Control Plane

Which coding agent has the best native controls?

Every harness now ships something — approval prompts, an allowlist, a sandbox, hooks. None ships everything, the defaults differ wildly, and the docs rarely say what happens in the cases that matter (approval times out; agent runs headless; someone passes the yolo flag). This page compares the native control surfaces of the major harnesses as of August 2026, judged on seven questions:

  1. Approvals — is there a native ask, and what are its modes?
  2. Rules — can you write allow/deny policy, and how expressive is it?
  3. Sandbox — is there OS-level isolation, and is it on by default?
  4. Interception — can a third party stand on the call path, and does it see every tool call?
  5. Audit — what record exists that the agent didn’t author?
  6. Escape hatch — what single flag disables the controls?
  7. Empty chair — what happens to an approval when nobody is there to answer it?

This is the native-controls companion to our coverage matrix (which documents what our layer intercepts per harness). Deep pages per harness are linked in each row as we publish them. Corrections welcome — every claim links to its source, and this page changes when the harnesses do.

The short version

  • Strongest defaults: Muse Code and DeepSeek Harness. Muse Code ships an OS sandbox (Seatbelt/bubblewrap) and an append-only event log, both on by default — with the documented caveat that hooks and MCP servers run outside its sandbox. dsh defaults its native sandbox to read-only, fails unanswerable approvals closed, and keeps an append-only session log with a runtime-enforced invariant: model-visible means logged.
  • Most mature rule system: Claude Code. Layered settings with managed (org) scope, pattern rules, hooks on every call, and now a classifier-based auto mode that derives a trust profile from your own usage.
  • Cleanest architecture: DeepSeek Harness. One pipeline, typed interception points covering everything including MCP tools and Code Mode sub-calls, the only native ask-denies-itself headless posture, and subagents whose prompts auto-reject by default. Core ships architecture, not rules — the deep page explains the trade.
  • Most expressive rules, least available: Gemini CLI. Its TOML policy engine (per-mode rules, five priority tiers, root-owned admin policy files, and ask_user resolving to deny in non-interactive mode) is the high-water mark for rule design — and Google ended free access in June 2026, pointing individuals at the closed-source Antigravity CLI.
  • Best approval hardening: OpenClaw — approvals bind exact command/cwd, approved scripts bind to on-disk snapshots, inline-interpreter forms force approval, and prompts detect invisible-Unicode obfuscation. Also the most permissive default posture: exec security: "full", ask: "off", on an agent built to run unattended. Both facts on the deep page.
  • The honest zero: pi. Mario Zechner and Armin Ronacher’s ~80k-star minimal harness ships four tools and no permission system at all — deliberately, documented, with containment patterns (micro-VM extension, Docker, OpenShell) offered instead. It’s the cleanest possible statement that in a minimal-core design, control is an extension — which also means the extension seam is where control has to arrive.
  • Most dangerous defaults elsewhere: Amp and Cline. Amp defaults to no approval prompts; Cline’s yolo is a literal approve-everything, and its “safe commands” tier trusts the model’s own requires_approval self-classification — the classifier is the thing being governed.

The comparison

Harness Approvals Rules Sandbox Interception Native audit Escape hatch Empty chair
Claude Code (deep page) Six modes incl. auto — classifier-screened, default for Pro/Max/Team since 08-14 permissions.allow/ask/deny patterns; user + project + local + managed scopes; deny at any scope wins; autoMode.* prose rules Available, off by default (Seatbelt / bubblewrap; credential masking) Hooks on every tool call; deny overrides allow; fail-open on timeout JSONL transcripts + opt-in OTel tool_decision (decision + source) --dangerously-skip-permissions — but deny rules, hooks, and an rm -rf circuit breaker still hold; refuses root Defined: dontAsk mode auto-denies; unresolvable headless asks deny and continue
Codex CLI (deep page) untrusted / on-request / never (on-failure removed 0.143) + Guardian reviewer agent (--approve-for-me, fail-closed, 0.147) Layered TOML + permission profiles (path→read/write/deny maps, network domains) + enterprise requirements.toml; approved_with_amendment persists approvals as reviewable rules Native on all three OSes — Seatbelt / bubblewrap+seccomp / native Windows sandbox; workspace-write networks off by default Full hooks system, on by default — PreToolUse / PermissionRequest / PostToolUse, Claude Code-compatible schema, /import migrates Session rollouts (JSONL + state DB); --ephemeral and codex delete erase --yolo (sandbox + approvals both off) Defined: exec never prompts — blocked actions fail back to the model
Cursor / Cursor CLI (deep page) Run Modes: Auto-review (allowlist → sandbox → LLM classifier; recommended default), Allowlist, Run Everything permissions.json takes natural-language allow/block instructions; allowlist officially “best-effort, not a security boundary” (3 bypass CVEs); .cursor/rules are steering, not enforcement Seatbelt / Landlock+seccomp (WSL2 on Windows); network blocked by default; sandbox.json Rich hook events; ask honored only for shell/MCP events; failClosed defaults to false None on any tier — DIY via hooks Run Everything mode; CLI --force (alias --yolo) Cloud agents skip Run Modes entirely — auto-run inside a VM
DeepSeek Harness (dsh) (deep page) Approval service, mounted per composition None shipped — policy arrives as a plugin None Typed tools/pre-execute / post-execute on one pipeline covering everything, incl. Code Mode sub-calls; post can rewrite output Trajectory log No flag — an uncontrolled composition Ask resolves to deny, natively
Muse Code (Meta) Approvals on by default; staged review of compound shell commands; workspace trust prompt On-request / untrusted modes Seatbelt / bubblewrap, on by default; refuses shell if sandbox unverifiable Hooks on tool use, permission requests, model calls, subagent lifecycle; fleet-managed hooks via central setting Append-only local event log of every model call, tool run, approval, edit Training-opt-out pricing aside, documented caveat: hooks + MCP run outside the sandbox Not yet documented
Grok Build (xAI) Ask / Auto (classifier) / Always-approve --allow 'Bash(git *)' granular rules; reuses .claude/settings.json format --sandbox read-only PreToolUse hooks that still fire in always-approve Session log --permission-mode dontAsk Undefined
Gemini CLI (→ Antigravity) default / auto_edit / yolo / plan TOML policy engine: per-mode rules, priority hierarchy, admin policy files; --allowed-tools "ShellTool(git status)" Antigravity: enableTerminalSandbox (nsjail / sandbox-exec / AppContainer) Antigravity plugins bundle hooks (closed source) yolo (CLI-flag-only, deliberately); Antigravity: --dangerously-skip-permissions Undefined
Goose (Block / LF) auto / smart_approve (LLM judge + read_only_hint) / approve / chat Extension allowlist via GOOSE_ALLOWLIST URL; ~35 danger patterns exist but are off by default and prompt-only None None — extensibility is MCP-shaped, no tool-call hook GOOSE_MODE=auto (the default) Undefined
opencode (guide) Native ask via permission config allow/ask/deny, last-match-wins, per-tool + bash patterns ("rm *": "deny") None JS/TS plugin hooks incl. the permission system (reliability caveats reported) Session log --auto (denies still enforced) Undefined
Hermes Agent (deep page) Inline prompt on ~47 dangerous patterns Published blocklist: 12 hardline patterns that hold in every mode, quoting-hardened (our read) None pre_tool_call / post_tool_call on every tool, in-process; hook API is deny-only, post is observational Session log yolo mode (hardline tier survives it) Prompt with no answerer — halt
Amp (Sourcegraph) Default: no approval prompts amp.permissions (allow/ask/reject, glob matches, per-thread/subagent context); amp.guardedFiles.allowlist None Plugin API amp.dangerouslyAllowAll Undefined
Cline (guide) Per-category auto-approve toggles Safe-command classification None Hooks via stdin (open bug: hooks execute even when permissions disabled) CLI default: auto-approve ON Auto-approve
Crush (Charm) Permission service on side-effectful calls permissions.allowed_tools; options.disabled_tools None No hook system --yolo (still hard-blocks ssh/scp/rsync) Undefined
OpenHands Confirmation mode default-on; --llm-approve risk analyzer ConfirmRisky policy, configurable threshold Sandboxed runtime SDK-level pluggable SecurityAnalyzer + ConfirmationPolicy --always-approve / --yolo Undefined
pi (earendil-works) None — by design. No permission prompts of any kind None. “Pi does not include a built-in permission system” — the docs say so plainly and point you at containment None built in; documented patterns: Gondolin micro-VM extension, Docker, OpenShell TypeScript extensions can mediate tool execution (Gondolin reroutes the built-in tools; hook API undocumented) The default is full access N/A — there is nothing to resolve

Sources: each harness’s official docs, linked from its deep page or row; adoption and behavior claims for harnesses we haven’t integrated come from vendor documentation and are marked where uncertain. Kilo (Cline lineage), Qwen Code (Gemini CLI fork), and Mistral Vibe track their parents’ models and are omitted from the table until we’ve verified their divergences; Devin CLI ships JSON hooks in .devin/ and reads .claude/ hook directories. Aider remains git-diff-review by design — with one elegant exception worth stealing: under --yes-always, shell execution is auto-denied, not auto-approved. This table extends our July primary-source read of eleven harnesses’ guardrails, where the escape-hatch column is examined in depth.

What the table actually says

Interception is the dividing line. Read the Interception column and the ecosystem splits in two: harnesses where a third party can stand on the call path and see everything (Claude Code, Codex as of its 2026 hooks system, dsh, Hermes, Muse Code, Grok Build, Cursor), and harnesses where it can’t (Goose and Crush, principally). Every other control can be added from outside if interception is complete; nothing can be added if it isn’t. If you’re choosing a harness with control in mind, this column outweighs the rest of the table.

Convergence on Claude Code’s hook contract. Codex’s new hooks are deliberately Claude Code-compatible and codex /import migrates Claude Code configs wholesale; Cursor and Hermes honor exit-code-2 blocking and the JSON decision shapes; Grok Build reuses .claude/settings.json outright; Devin CLI auto-discovers .claude/ hooks; dsh ships a hooks-claude-code bridge. The PreToolUse contract is becoming the ecosystem’s POSIX — which means a control layer built against it ports cheaply, and so does a permission-model bug (the same settings-format bypass has been reproduced in two different harnesses).

Classifiers took over the approval loop this season — ledgers didn’t follow. All three majors now put a model where the human prompt was: Claude Code’s auto mode (default-on for paid personal accounts since August 14), Codex’s Guardian reviewer (0.147), Cursor’s Auto-review (3.6). Hermes made LLM smart approvals its default in July; Grok Build, Goose, and OpenHands have their own variants; Cline goes furthest and trusts the governed model’s own risk flag. The fatigue math is real — Anthropic’s published numbers have humans catching 13.6% of dangerous commands at the prompt versus 89% for the classifier. But exactly two harnesses (dsh, Muse Code) added an independent append-only record of what ran, and none added a queryable trail of what their classifier decided or why. The ecosystem is spending fast on making attended sessions quieter and almost nothing on making decisions explainable afterwards.

The empty chair is being answered — by the newest designs. dsh resolves unanswerable asks to deny; Codex exec never prompts and fails blocked actions back to the model; Claude Code ships dontAsk; Gemini CLI’s policy engine resolves ask_user to deny non-interactively; Hermes denies flagged commands in cron and one-shot modes. That’s real convergence on the right answer, and it’s recent. The counterexamples are the ones to check before unattended use: Cline’s yolo, Cursor’s cloud agents (auto-run inside a VM), and OpenClaw’s default posture on an agent designed to run unattended. The reasoning is in the empty-chair test.

Where every native model ends

Grade any row generously and the same four gaps remain, because they’re structural rather than missing features:

  1. The record is self-authored. Transcripts and trajectories are written by the process they describe, on the machine that ran it. Only Muse Code hardens this locally; nothing ships it off-machine.
  2. Policy is per-machine. Settings files, profiles, and config live with each install. Two engineers on one codebase run whatever their machines accumulated. Managed settings (Claude Code) and fleet-managed hooks (Muse Code) are the first cracks in this, for those two harnesses, org-wide.
  3. One flag undoes it. Nearly every row has an escape hatch that disables the controls and the record of the controls being disabled.
  4. Rules don’t travel. A deny you wrote in settings.json doesn’t exist in config.toml, crush.json, or permission.yaml. Every harness added means re-deriving your policy in a new dialect — or carrying one policy across all of them.

Those four are the job of a layer above the harness. The native controls are genuinely good now, and getting better fast — this page exists because choosing well matters. What none of them try to be is the same policy, enforced identically, with an independent record, on every machine and every harness you run. That’s the layer we build; the per-harness deep pages linked above say precisely where each handoff happens.