Sane defaults

A middle ground between asking every time and skipping every check.

Out of the box your agent asks before it edits a file or runs a command. That is safe, but chatty over text, where every prompt is a buzz on your phone. At the other end, yolo mode skips every check. Sane defaults sit in between: auto-approve the safe, everyday work and keep a gate on the rest. They are opt-in, and you can widen or narrow them whenever you like.

The idea

Auto-allow the safe majority. Gate the risky minority. The working directory is treated as the sandbox: writing inside it is fine, and the moment anything reaches outside, the gate returns.

Goes throughStill asks
Reading and navigating filesWriting or reading outside the working directory
Editing files inside the working directoryArbitrary shell commands
Read-only shell commands (ls, cat, grep, find…)Deleting, moving, or overwriting files
Web search and fetchReading secrets (.env, ssh and cloud keys): denied outright

OpenCode

OpenCode reads its permissions from opencode.json. Reads, globs, and greps are already free; this block opens up in-directory edits and a read-only shell list, and keeps the gate on everything else:

{
  "permission": {
    "edit": "allow",               // writes inside the project, no prompt
    "external_directory": "ask",   // anything outside the project stops and asks
    "webfetch": "allow",
    "bash": {
      "*": "ask",                  // unknown commands ask
      "ls": "allow", "ls *": "allow",
      "cat *": "allow",
      "grep *": "allow", "find *": "allow",
      "head *": "allow", "tail *": "allow",
      "wc *": "allow", "stat *": "allow",
      "pwd": "allow", "which *": "allow"
    }
  }
}

edit: allow lets the agent write and edit files in the project without tapping you. external_directory: ask is the fence: a write or read that lands outside the project brings back the prompt. The bash map pre-approves read-only commands so routine poking around (checking a path exists, grepping a file) runs quietly, while everything else still asks.

A safelisted command only clears when the whole line qualifies. Chain something onto it and the gate comes back: ls .; rm -rf build still stops for approval, because rm is not on the list. The list is read-only on purpose; nothing that deletes, moves, or overwrites belongs on it.

Claude Code

Claude Code reads .claude/settings.json. Same shape, different syntax: allow the read-only tools and in-project editing, deny the secrets, and leave Bash asking except for a read-only handful.

{
  "permissions": {
    "allow": [
      "Read", "Grep", "Glob", "Edit", "Write", "WebFetch", "WebSearch",
      "Bash(ls:*)", "Bash(cat:*)", "Bash(grep:*)", "Bash(find:*)",
      "Bash(head:*)", "Bash(tail:*)", "Bash(pwd)", "Bash(which:*)"
    ],
    "ask": ["Bash"],
    "deny": [
      "Read(./.env)", "Read(./**/.env*)",
      "Read(~/.ssh/**)", "Read(~/.aws/**)"
    ]
  }
}

Claude Code checks each part of a chained command on its own, so the same guarantee holds: a read-only allow cannot carry a write past the gate.

The other end: yolo

Starting with -yolo (Claude Code's --dangerously-skip-permissions) drops every prompt. That is the right call for a throwaway sandbox where nothing on the box matters. It is the wrong call anywhere real credentials live, because a single bad instruction has nothing left to stop it. Sane defaults exist so you rarely need to reach for it. See Security for the full threat model.

next: Security →