All Agent Engineering

Spec file

Claude Code permission modes: which mode a session starts in, and what to write for CI

Work out the starting mode from the documented order, separate terminal, -p and CI defaults, and model a few common settings.

AI Nav CityWritten / Updated

The same settings can give different permission modes in an interactive terminal and in claude -p, and the result depends on the Claude Code version: the docs say the built-in starting mode is auto in the terminal and VS Code from v2.1.283, and that claude -p with no mode set starts in Manual (config value default) from v2.1.302. This guide organizes the documented order for deciding the starting mode, models a few common settings with a small self-written model, and lists what to check for CI. The expected result is a record of which mode your session will start in. The model only evaluates documented rules: Claude Code was not started, your settings were not read and no model was called.

Verified
· Not tested by us
Applies to
  • Claude Code Applies to Claude Code in a local terminal. The VS Code extension, desktop app and cloud sessions have their own rules, and the official page states version cut-offs (v2.1.283, v2.1.302).[1]

File locations

PathScopeHow it is read
~/.claude/settings.jsonUser-level permissions.defaultMode that affects terminal sessions on this machine.Read at startup; a non-auto value here keeps applying when no other settings file sets defaultMode.[1]
./.claude/settings.jsonProject-shared permissions.defaultMode.Terminal sessions honor every value except auto and bypassPermissions; sessions started by the VS Code extension do not read the starting mode from project settings.[1]
./.claude/settings.local.jsonPersonal permissions.defaultMode for the current project.Same as shared project settings: auto and bypassPermissions do not take effect, other values do.[1]

When to use

  • You need to confirm which permission mode a session or CI job starts in, or want to find out why behavior changed after an upgrade.[1]

When not to use

  • You need the starting mode for the VS Code extension, desktop app or cloud sessions, which follow their own lists and are not covered here.[1]

How the starting mode is chosen

  • When you start a new terminal session, Claude Code takes the first source that applies: (1) the --permission-mode flag or --dangerously-skip-permissions; (2) permissions.defaultMode in a settings file; (3) the built-in default.
  • A value of "auto" in .claude/settings.json or .claude/settings.local.json does not take effect, and Claude Code falls back to the built-in default instead of using a defaultMode from ~/.claude/settings.json. "bypassPermissions" in those two files likewise does not take effect and the session starts in Manual. Other values apply from any settings file.
  • When several settings files set defaultMode, settings precedence decides, and a project or managed value outranks ~/.claude/settings.json.
  • The built-in default depends on how you run it: default when any settings file sets disableAutoMode to "disable"; default for claude -p or the Agent SDK; auto in the terminal or VS Code extension from v2.1.283, while earlier versions use auto only on some plans in sessions that fetch feature flags and default otherwise.
  • When auto is selected but not available to the session (for example a setting turns it off, the model does not support it or the server has temporarily disabled it), the session starts in Manual instead.

[1]

Model a few common settings

The function below writes the order above as code: a flag wins; otherwise the highest-precedence settings layer is used (the caller orders the layers by settings precedence); an auto value from a project or local layer falls back to the built-in default and bypassPermissions falls back to default; with no settings the built-in default applies. For terminal sessions the built-in default is written as "built-in default" (auto from v2.1.283 per the docs) and for -p as default. The eight assertions are the worked examples.[1]

Example: original modeling script, run offline and not Claude Code
import assert from "node:assert/strict";

// layers: defaultMode values from settings files, highest precedence first.
// source: "managed" | "user" | "project" | "local". Terminal sessions only.
export function startMode({ flag, layers = [], print = false }) {
  if (flag) return flag;
  const builtIn = print ? "default" : "built-in default"; // -p: Manual since v2.1.302
  const top = layers[0];
  if (top) {
    const shared = top.source === "project" || top.source === "local";
    if (shared && top.value === "auto") return builtIn;
    if (shared && top.value === "bypassPermissions") return "default";
    return top.value;
  }
  return builtIn;
}

const user = { source: "user", value: "acceptEdits" };
assert.equal(startMode({ flag: "plan", layers: [user] }), "plan");
assert.equal(startMode({ layers: [user] }), "acceptEdits");
assert.equal(startMode({ layers: [{ source: "project", value: "auto" }, user] }), "built-in default");
assert.equal(startMode({ layers: [{ source: "local", value: "bypassPermissions" }, user] }), "default");
assert.equal(startMode({ layers: [{ source: "project", value: "dontAsk" }] }), "dontAsk");
assert.equal(startMode({ print: true }), "default");
assert.equal(startMode({}), "built-in default");
assert.equal(startMode({ print: true, layers: [{ source: "project", value: "auto" }] }), "default");
console.log("start-mode model: all assertions passed");

[1]

What the model leaves out matters as much: disableAutoMode and the HIPAA configuration, the availability conditions for auto, the VS Code extension's own order, the desktop app and cloud sessions, the mode on session resume, and where --settings and managed settings sit in settings precedence. For -p the docs say "no permission mode set", and the model treats a defaultMode as set; that point needs to be checked on your version. The docs also state that before v2.1.302 such non-interactive runs could start in auto mode when they did not fetch feature flags, for example on a third-party provider or with DISABLE_TELEMETRY. The built-in auto default requires v2.1.228 or later on macOS, Linux and WSL and v2.1.233 or later on native Windows; on earlier versions the built-in default is Manual. The same command can therefore start in different modes on older versions.[1]

What to state explicitly in CI and scripts

The docs say that from v2.1.302 claude -p with no mode set starts in Manual, and calls that need approval are denied unless an allow rule, hook, canUseTool callback or --permission-prompt-tool approves them. Unattended jobs should therefore state the mode explicitly. The docs give two forms: pass --permission-mode auto to claude -p so a classifier model reviews calls, or use dontAsk with an exact allow list. dontAsk automatically denies every call that would otherwise prompt (the docs add that an installed mod can still approve some of them). The CI example below comes from the docs and was not executed here.[1]

Example: the CI form shown in the official docs; not executed here
claude -p "run the test suite" --permission-mode dontAsk --allowedTools "Bash(npm test)" "Read"

[1]

  • Version: pin the Claude Code version in the CI image, and use the version cut-offs above to check whether defaults change on upgrade.
  • Mode: pass --permission-mode on the command line instead of relying on settings files or the built-in default; the docs say cloud sessions ignore dontAsk and bypassPermissions from settings files.
  • Scope: under dontAsk, actions that need no approval (such as reads inside the working directory) and calls matching allow rules still run and everything else is denied; the docs reserve bypassPermissions for isolated containers or VMs and say it gives no protection against prompt injection.
  • Rules: deny rules apply in every mode including bypassPermissions, while allow rules have no effect in bypassPermissions.

[1]

When the starting mode differs from expectations, stop the job, check the version first, then inspect the flag, the settings files and the built-in default in turn, and do not widen to bypassPermissions to keep the job going. Only the official description was checked and the documented rules modeled here: Claude Code was not started, your settings were not read and no model was called. Cost depends on the model and services you actually use, and no quota is certified.[1]

Sources

All links are official pages; verification dates are listed per source, and links point to the version checked.

  1. Anthropic · Choose a permission mode

Found an error? Tell us →