DEV Community

~K¹yle Million
~K¹yle Million

Posted on

Claude Code Permissions: The Approval Boundary Pattern That Makes Autonomous Agents Safe

Claude Code Permissions: The Approval Boundary Pattern That Makes Autonomous Agents Safe

Most attempts at autonomous Claude Code agents fail in the same way: either the agent asks for approval at every step (not autonomous) or it does irreversible things without asking (not safe). The approval boundary pattern solves this. It's the architectural decision that separates AI assistants you have to babysit from agents you can actually walk away from.

The Core Problem

Autonomous agents break trust in one of two directions.

Over-constrained: The agent pauses on everything. "Should I write this file?" "Can I run this command?" "Is it okay to call this API?" You're reviewing more requests than you would have done the work yourself. The agent is just a slow, expensive typing assistant.

Under-constrained: The agent does whatever it thinks is right. It modifies files you didn't intend, calls APIs with write access, deletes things it considered unnecessary, pushes to production when it thought you wanted that. One wrong assumption and you're doing incident recovery.

The approval boundary is the explicit, written line between these two failure modes.

What the Approval Boundary Is

The approval boundary is a declared list — in plain English, in your CLAUDE.md — of what the agent can do autonomously versus what requires your explicit approval before proceeding.

Here's the actual production boundary from a live autonomous agent deployment:

## APPROVAL BOUNDARY

**Self-authorized:**
- All filesystem operations within ~/intuitek/
- API calls: Anthropic, ClawMart, Supabase, Stripe (read), Railway (read), Google Calendar
- Telegram notifications
- Ollama local inference
- Cron registration via system crontab (idempotent adds only)
- Writing to outputs/, logs/, capabilities/

**Kyle's approval required:**
- Production deploys of new services (updating existing: self-authorized)
- Credential rotation or changes
- Stripe charges or product changes
- Irreversible operations — deletes, drops, permanent removals
- Any edit to THIS FILE
- External writes that affect customers
Enter fullscreen mode Exit fullscreen mode

That's it. Every action the agent considers gets evaluated against this list. Inside the boundary: execute. Outside: write a proposal file and continue with safe alternatives.

The Three Axes of Permission

When you're defining what goes inside vs. outside your approval boundary, evaluate each action across three axes:

1. Reversibility. Can you undo this in under five minutes? File writes, API reads, log entries — reversible. Dropped database tables, deleted branches, sent emails, pushed production deploys — not reversible without significant effort. Default: reversible actions are self-authorized, irreversible require approval.

2. Blast radius. If this goes wrong, who's affected? Writing to a local directory affects only you. Modifying a ClawMart listing affects customers browsing your store. Triggering a Stripe charge affects someone's credit card. Default: local effects are self-authorized, external effects require judgment or approval.

3. Scope creep risk. Is this action within the stated task, or is it the agent deciding to expand the task? Agents optimizing for your stated goal will sometimes identify "while I'm in here, I should also..." opportunities. Some are good. Some cause incidents. Approval boundary enforcement catches the ones that exceed mandate.

Implementation: Three Layers

The approval boundary works through three enforcement layers in Claude Code:

Layer 1: CLAUDE.md declaration

Write the boundary explicitly. The agent reads CLAUDE.md at session start. When the boundary is written clearly, Claude Code respects it — not because of technical enforcement but because it's now part of the operating context. "Proposals go to outputs/question_for_kyle_{timestamp}.md" tells the agent exactly what to do instead of proceeding.

The constraint: Only execute within the approval boundary defined above. 
Anything outside it goes to outputs/question_for_kyle_{timestamp}.md 
as a proposal with full context. Do not stall. Proposals cost nothing.
Enter fullscreen mode Exit fullscreen mode

Layer 2: settings.json tool permissions

Claude Code's .claude/settings.json enforces which tools are available at the technical level:

{
  "permissions": {
    "allow": [
      "Bash(*)",
      "Read(*)",
      "Write(*)",
      "Edit(*)",
      "Glob(*)",
      "Grep(*)"
    ],
    "deny": []
  }
}
Enter fullscreen mode Exit fullscreen mode

For tighter control, you can scope Bash to specific commands:

{
  "permissions": {
    "allow": [
      "Bash(curl:*)",
      "Bash(python3:*)",
      "Read(*)",
      "Write(~/intuitek/*)"
    ],
    "deny": [
      "Bash(rm:*)",
      "Bash(git push:*)"
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

Layer 3: Headless mode --allowedTools

When running headless via cron or scripts, pass tools explicitly:

claude -p "$TASK_PROMPT" \
  --allowedTools "Bash(*),Read(*),Write(*),Edit(*)" \
  --output-format text
Enter fullscreen mode Exit fullscreen mode

This prevents interactive permission prompts in non-attended contexts.

The Proposal Mechanism

The approval boundary only works if the agent has a defined path for actions outside it. Without that path, the agent either stops (bad) or reasons its way to "close enough" (also bad).

The pattern: write a proposal file and continue with safe alternatives.

When I hit the approval boundary, I write:
outputs/question_for_kyle_{timestamp}.md

Contents:
- What action I wanted to take
- Why I believe it's the right next step
- What information I'd need to proceed
- What safe actions I'm continuing with instead
Enter fullscreen mode Exit fullscreen mode

This costs nothing. The agent doesn't stall. You get a queue of pending decisions you can process when you have time. The agent keeps moving on everything inside the boundary.

Why This Makes Agents More Useful

The counter-intuitive result: a well-defined approval boundary makes autonomous agents more useful, not less.

When the boundary is clear:

  • The agent executes faster on everything inside it — no hesitation, no asking
  • Trust accumulates — you see the agent respecting the boundary consistently, so you're comfortable extending it
  • The proposal files surface exactly the decisions that need your judgment — not everything, just the real edge cases
  • You can hand off more tasks knowing the blast radius is contained

When the boundary is vague:

  • The agent defaults to conservative — asks about things it could have done
  • Or defaults to optimistic — does things you wish it had asked about
  • Either way, trust erodes

The approval boundary turns "I hope the agent does the right thing" into "I know exactly what the agent will and won't do."

Practical Starting Point

If you're building an autonomous Claude Code agent and don't have a boundary defined yet, start here:

## APPROVAL BOUNDARY

**Self-authorized:**
- Reading any file in the project directory
- Writing to designated output directories only
- API calls with read-only scope
- Logging and notification

**Requires approval:**
- Any write to production systems
- Irreversible operations (deletes, drops, removals)
- API calls with write scope to external services
- Any action affecting users or customers
- Credential changes

**Default for ambiguous cases:** Write proposal to outputs/, continue with safe alternatives.
Enter fullscreen mode Exit fullscreen mode

Start conservative. Expand the boundary as you accumulate evidence of reliable behavior. The pattern scales — the boundary for a fully autonomous revenue-generating agent is just a more refined version of the same structure.


The approval boundary isn't a constraint on what your agent can do. It's the foundation that makes autonomous operation possible.

~K¹ (W. Kyle Million) / IntuiTek¹

Top comments (0)