# The Best Ways to Control What Claude Code Can Do, Ranked (2026)

Six real options for controlling a coding agent — built-in permissions, Anthropic's sandbox runtime, devcontainers, dcg, cloud sandboxes, and a policy layer on the call path — ranked by isolation, coverage, audit, and setup friction. With the honest limits of each.

*Last updated: July 27, 2026.*

In July 2025, [Replit's agent deleted a production database during an explicit code freeze](https://www.aol.com/news/replits-ceo-apologizes-ai-agent-065312436.html). The same month, [Gemini CLI destroyed a user's files during a botched folder move and reported "I have failed you completely and catastrophically"](https://developers.slashdot.org/story/25/07/26/0642239/google-gemini-deletes-users-files-then-just-admits-i-have-failed-you-completely-and-catastrophically). In December, [Claude Code ran an `rm -rf` with a stray `~/` and wiped a developer's home directory](https://news.ycombinator.com/item?id=46268222). Different agents, same shape: the constraint lived somewhere the action didn't pass through.

So the question "how do I control what Claude Code can do" has a real option landscape now. This is the ranked list, judged on four criteria:

- **Isolation strength** — if the agent goes wrong, what's the blast radius?
- **Coverage breadth** — which actions does the control actually see? Shell only, or edits, network, and MCP calls too?
- **Audit** — afterwards, can you reconstruct what the agent did and why it was allowed?
- **Setup friction** — how far from `install` to protected?

One thing upfront: most of these aren't substitutes. A container bounds *where* the agent can act; a policy layer decides *which actions* run inside that boundary. The ranking is "where to start and what to add," not "pick one."

## The comparison

| Option | Isolation | Coverage | Audit | Setup | Best for |
|---|---|---|---|---|---|
| 1. Built-in permissions + `settings.json` | None | All native tools | Session transcript only | None — built in | The baseline everyone should configure |
| 2. Anthropic sandbox runtime | OS-level (filesystem + network) | Everything inside the boundary | No | Low | Fewer prompts without losing the boundary |
| 3. ACP (local policy + audit layer) | None | Every tool call — shell, edits, MCP — across Claude Code, Cursor, Codex | Per-call log, decisions included | One command, no account | Deciding per action, and proving what ran |
| 4. Devcontainer / Docker | Full container | Everything contained, nothing decided | No | Medium | Untrusted input; worst-case containment |
| 5. dcg (destructive-command-guard) | None | Shell commands only | No | One curl | A fast tripwire on destructive shell |
| 6. Cloud sandboxes (E2B, Modal, Daytona) | Full microVM, off your machine | Whole environment | Varies | High | Autonomous fleets, not laptops |

## 1. Built-in permission prompts + settings.json — configure this first

**Best for: everyone, as the baseline.** It ships with Claude Code, costs nothing, and most people never configure it past clicking "allow."

Claude Code asks before risky actions and reads allow/deny rules from `settings.json`:

```json
{
  "permissions": {
    "deny": ["Bash(rm:*)", "Bash(git push:*)", "WebFetch"]
  }
}
```

We've published [a full posture, argued tool by tool](/blog/which-claude-code-tools-to-deny-out-of-the-box). Do this regardless of what else you add.

The honest limits. Deny rules are string patterns, and command strings have many spellings — [the bypasses are documented](/blog/claude-code-deny-list-bypass). The rules live per machine, so they drift across a team. And the flag people reach for when they want automation, `--dangerously-skip-permissions`, [removes the prompts but not the hooks or deny rules](/blog/claude-code-dangerously-skip-permissions) — so whatever you wrote beforehand is the whole boundary at exactly the moment you stop watching. That December home-directory wipe happened with the flag on and no deny that covered it.

## 2. Anthropic's sandbox runtime — the best native upgrade

**Best for: cutting prompt fatigue without giving up a boundary.**

Anthropic's own telemetry showed users approving ~93% of permission prompts — approval fatigue makes the prompts themselves stop working. Their answer is [OS-level sandboxing](https://www.anthropic.com/engineering/claude-code-sandboxing) (Seatbelt on macOS, bubblewrap on Linux): reads allowed, writes confined to the workspace, network denied by default. Inside the boundary the agent runs without interruption; Anthropic reports an 84% reduction in permission prompts in internal use. The runtime is [open source](https://github.com/anthropic-experimental/sandbox-runtime), so the boundary is auditable. In Claude Code it's the `/sandbox` command.

The honest limits. The sandbox answers "where can the agent act," not "should this action run." A destructive command *inside* the workspace — the `DROP TABLE` you have credentials for, the force-push, the Replit-shaped write to prod through an allowed network host — is within bounds and runs. Unsandboxable commands fall back to the regular prompt flow, which is an escape hatch. And it leaves no record of what the agent did, only of where it was allowed to do it.

## 3. ACP — decide per action, and keep the record

**Best for: the question the first two don't answer — "should this specific call run, and can I prove what ran?"**

Between per-call prompts (you decide everything, live) and full isolation (the boundary decides, coarsely) there's a slot for deciding *per action, by rule, with a record*. That slot is mostly empty, and it's the one [ACP](/getting-started) sits in. One command, free, no account, nothing leaves your machine:

```bash
curl -sf https://agenticcontrolplane.com/install.sh | bash -s -- --local
```

Every tool call — shell, file edits, MCP calls, not just Bash — is checked against your policy in `~/.acp/policy.json` before it runs, and every call and decision lands in `~/.acp/audit.jsonl`. The same policy covers Claude Code, Cursor, and Codex's shell calls, so the rules don't fork per machine or per agent. When someone asks what the agent actually did last Tuesday, the answer is a log written by the layer the calls passed through — not the agent's own account of itself. In the Replit incident the agent misreported what it had done; a self-authored transcript can't settle that. A call-path log can.

The honest limits. ACP adds no isolation — a bug in an *allowed* action still executes with your credentials. If the agent handles untrusted input, keep the container (option 4); the container bounds the process, the policy layer decides the actions inside it. They're complementary, not substitutes.

## 4. Devcontainers / Docker — the right answer for untrusted input

**Best for: untrusted repos, web content in the loop, worst-case containment. If you need one answer for "the agent might be adversarially steered," this is it — nothing else on this list matches full isolation.**

Run Claude Code inside a container and the worst case is bounded by the container: the home-directory wipe becomes a wiped container filesystem, rebuilt in a minute. Anthropic maintains a [reference devcontainer](https://github.com/anthropics/claude-code/tree/main/.devcontainer) with a network firewall; any Docker image with your toolchain works.

The honest limits. Setup friction is real — your credentials, dotfiles, and services have to come along deliberately, which is the point and also the tax. And containment isn't decision-making: inside the container, with the credentials you mounted, every action is still unexamined. The Gemini CLI incident ran entirely inside the user's working directory — a container drawn around that directory contains nothing.

## 5. dcg — the best pure shell tripwire

**Best for: a dead-simple destructive-command blocker, installed in a minute, across every agent you run.**

[dcg (destructive-command-guard)](https://github.com/Dicklesworthstone/destructive_command_guard) is a Rust hook, a few thousand GitHub stars, one curl install from the README, that pattern-matches dangerous git and shell commands — `rm -rf` outside temp paths, `git reset --hard`, destructive migrations — and blocks them before execution with an explanation. Its breadth is the standout: a dozen-plus agents (Claude Code, Codex CLI, Gemini CLI, Copilot, Cursor, more) from one tool. If pure shell-blocklist simplicity is what you want, dcg is the honest pick over building the same thing yourself.

The honest limits. It sees shell commands only — file-edit tools, MCP calls, and network actions never pass through it, and the Gemini incident's `move` disaster wasn't on anyone's destructive-pattern list. It's a curated blocklist, so it's as good as its patterns, and it hard-blocks some legitimate recovery paths (`git checkout -- .`). And it fails open: if the hook is missing, misconfigured, or errors, the command runs. A tripwire, not a boundary — worth having, not worth trusting alone.

## 6. Cloud sandboxes — for fleets, not laptops

**Best for: autonomous agents at scale, where "my machine" isn't the blast radius anymore.**

[E2B](https://e2b.dev), [Modal](https://modal.com), and [Daytona](https://www.daytona.io) run each agent in its own disposable microVM. For a fleet of unattended agents this is the right substrate: per-run isolation, snapshots, no shared laptop state to destroy. It ranks last here only because the question was controlling *your* Claude Code — rearchitecting onto cloud execution is the highest-friction option on the list, and inside each microVM the per-action question returns unchanged: the sandbox bounds the run, something still has to decide and record the actions.

## What to actually do

- **Everyone:** configure `settings.json` (option 1). Ten minutes, no excuse.
- **Prompt fatigue is the pain:** add the sandbox runtime (option 2).
- **Untrusted input touches the agent:** container first (option 4) — full isolation is the right call, and nothing else here provides it.
- **You need per-action rules and a record that survives the session** — the two things isolation can't give you: add the policy layer on the call path (option 3).
- **Unattended fleet:** cloud sandbox per run (option 6), with a policy layer inside deciding the actions.

The layering follows from what each thing is. Prompts ask you. Sandboxes and containers bound where actions can land. A blocklist trips on known-bad shell. A policy layer on the call path decides each action against your rules and writes down what happened. Every incident above slipped through a gap between those layers — the fix is knowing which layer you're missing, not picking a winner.

## Frequently asked questions



## Where to read more

- [Which Claude Code tools to deny out of the box](/blog/which-claude-code-tools-to-deny-out-of-the-box) — the settings.json posture, argued from blast radius
- [Claude Code deny-list bypasses](/blog/claude-code-deny-list-bypass) — why string rules aren't a boundary
- [Claude Code vs Codex CLI: permission models compared](/blog/claude-code-vs-codex-permission-models) — the same analysis across harnesses
- [We recreated the Replit database deletion — and held it](/blog/recreated-replit-database-deletion) — the freeze-as-prompt failure, enforced in the call path
