Auto mode classifier blocks tool calls while session is in bypassPermissions

Status Open
Reported on v2.1.223
Maintainer reply None cached
Activity 4 comments · opened Aug 6, 2026

Environment

  • Claude Code 2.1.223 (also observed on 2.1.221)
  • Native install, macOS (Darwin 25.x), Apple Silicon
  • permissions.defaultMode: "auto" in user settings; sessions switched to bypassPermissions interactively
  • No managed policy settings present; disableBypassPermissionsMode not set
  • No autoMode section in user settings — shipped default rules throughout

Summary

In sessions running in bypassPermissions, tool calls are intermittently refused by the auto mode classifier with toolDenialKind: "automode-blocked".

The permission-modes documentation describes bypassPermissions as skipping permission checks. If that is accurate, the classifier should not be consulted in this mode at all, and this is a bug. If instead the classifier is retained in bypassPermissions by design — the way PreToolUse hooks are — then the behavior is correct but undocumented, and the documentation should say so, because the current wording leads operators to conclude the mode is broken.

Either way the operator-visible outcome is the same: a mode chosen precisely to stop interruptions still interrupts.

Evidence

Across a 50-session window, 6 sessions ran in bypassPermissions. Four automode-blocked denials occurred inside those sessions. In each case:

  • The denial entry is main-loop, not a subagent (isSidechain: false), so this is not a subagent inheriting a different mode.
  • The most recent permissionMode value recorded before the denial — also main-loop — is bypassPermissions.
  • The session continues emitting bypassPermissions afterwards, so the mode had not been switched away and back.

One session's mode/denial sequence, with consecutive identical events collapsed:

bypassPermissions x76  ->  DENIED: automode-blocked  ->  bypassPermissions x42

A second session shows the same shape: 46 consecutive bypassPermissions events, then automode-blocked.

The blocked calls were ordinary read-only operations, including gh pr view <n> --json number,mergeStateStatus,reviewDecision. That command matches the shipped Read-Only Operations allow rule, so the block is also hard to attribute to any specific deny rule.

Steps to reproduce

Not reliably reproducible on demand — the intermittency is part of the report. Observed conditions:

  1. Set permissions.defaultMode to "auto" in ~/.claude/settings.json.
  2. Start a session, switch it to bypassPermissions.
  3. Run a long session with many tool calls, including /model switches and /compact.
  4. Intermittently a tool call is refused with automode-blocked while the mode is still bypassPermissions.

Denial records live in the session transcript JSONL: user entries carrying a top-level toolDenialKind, interleaved with entries carrying permissionMode.

Expected

In bypassPermissions, no permission check runs and no classifier is consulted; a tool call executes or fails on its own merits.

Alternatively, the documentation states plainly that the auto mode classifier and PreToolUse hooks both still apply in bypassPermissions.

Actual

The classifier runs and can refuse the call, producing a denial the operator explicitly opted out of.

Impact

This is the difference between an agent that can run a multi-hour unattended task and one that cannot. Long-horizon autonomous work is the use case bypassPermissions exists for, and an intermittent block halts the run at an arbitrary point, often on a trivially safe read.

Documentation suggestions (minor, separable)

  1. skipDangerousModePermissionPrompt: true reads as though it forces bypass mode. It suppresses the confirmation dialog only. One clarifying line in the settings reference would prevent the misreading.
  1. Hooks override bypassPermissions, and the permissions page does not say so. A PreToolUse hook returning permissionDecision: "ask" prompts even in bypassPermissions. That is defensible — it lets a project keep a hard safety net the operator cannot switch off by accident — but it is the first thing an operator suspects when bypass "does not work", and the remedy (reading the permission_mode field inside the hook and honoring it) is discoverable only from the hooks reference. Suggest cross-linking permission_mode from the permission-modes section.
  1. Denial messages do not name the rule that fired. A refusal reads "Blocked by classifier" with no rule name, and its remedy line suggests adding a Bash permission rule even when the denied call was an Edit. Naming the matched rule — e.g. "Self-Modification" — would tell the operator what consent is missing. As it stands, the only way to find out is to run claude auto-mode config and match the action against the rules by hand. For the soft_deny family this matters a lot: those rules clear when the user names the specific change, so a named rule is directly actionable.

View original on GitHub ↗

3 Comments

mmkontis · 21 days ago

Adding another repro, in the desktop app this time. The classifier kept denying calls after the session had left auto mode and was reporting bypass permissions.

Environment

  • Claude Code 2.1.236, Claude desktop app (Code tab), macOS (Darwin 25.5.0, Apple Silicon)
  • No defaultMode or autoMode set in ~/.claude/settings.json or settings.local.json

What happened

  1. The session started in auto mode. The task was filling in a third-party Google Form in the built-in browser pane (mcp__Claude_Browser__*). The user had given the values in chat and explicitly asked for the form to be filled and submitted.
  2. mcp__Claude_Browser__browser_batch (several form_input calls) was denied every time with Permission for this action was denied by the Claude Code auto mode classifier. Reason: Blocked by fast classifier.
  3. Single form_input calls were nondeterministic. The same call with the same value, on the same tab and field, was denied once and allowed on a later turn.
  4. The session then got the system reminder "Exited Auto Mode", and later "bypass permissions mode is active". Denials continued after both: the same form_input calls were still denied with the same "Blocked by fast classifier" reason.
  5. The user's explicit approvals in chat ("approve, submit", "fill the remaining ones and agree") did not clear the denials.

Observations

  • The denial never names the rule. From claude auto-mode config, the likely match is the soft-deny Browser Input Exfil, which covers "any input into a page whose most recent navigate was to an external domain". That rule is written for Chrome-MCP but seems to apply to the built-in browser MCP too.
  • The remedy line suggests adding "a Bash permission rule", which doesn't make sense for an MCP browser tool (same point as in this issue).
  • /permissions → Recently denied, run in a separate terminal claude session, shows "No recent denials". Denials from a desktop-app session don't appear there, so the user has no way to review or retry them.

Expected
After leaving auto mode, or in bypassPermissions, the classifier shouldn't run, as the permission-modes docs describe. If it does run by design, a denied call should fall back to a normal permission prompt (#92279) rather than a hard deny.

Related: #85330, #58222, #95777, #95200, #92279

shirakawa-otoya · 14 days ago

Another repro, desktop app (Code tab). This started for me with 2.1.284 and has not happened on any earlier version.

Environment

  • Claude desktop app (Code tab), bundled Claude Code 2.1.284, macOS (Darwin 25.6.0, Apple Silicon)
  • permissions.defaultMode: "bypassPermissions" in both ~/.claude/settings.json and settings.local.json
  • No autoMode section at first (see test below), no managed settings, permissions.allow includes mcp__claude-in-chrome__*
  • get_session reports permissionMode: "bypassPermissions" for the affected session

What happens
Browser tool calls are denied with Permission for this action was denied by the Claude Code auto mode classifier. Reason: Blocked by fast classifier. while the session is in bypassPermissions.

Blocked calls include:

  • mcp__claude-in-chrome__select_browser (selecting the user's own default browser)
  • mcp__claude-in-chrome__navigate to a public docs page
  • mcp__claude-in-chrome__browser_batch (typing a value into a field the user asked to change; a read-only javascript_exec)
  • mcp__Claude_Browser__preview_start for a localhost dev server and for a local file:// page

Timeline (from local transcripts) — corrected

  • Correction to my earlier wording: it is not true that there were zero denials before 2.1.284. Counting every denied by the Claude Code auto mode classifier result (not only the "fast classifier" wording), bypassPermissions sessions were already being denied sporadically since 2026-07-21 (2.1.215 → 2.1.266; 1–7 per day on the days it happened, reason text Blocked by classifier).
  • Since 2.1.284 (first seen 2026-09-28 21:22 UTC) the reason text changed to Blocked by fast classifier and the frequency jumped to 5–9 denials per day (2026-09-29 → 10-01).
  • 45 of the 48 denials are browser tools: 34 claude-in-chrome, 11 Claude_Browser (built-in browser pane).
  • Reproduced today in a fresh session confirmed as bypassPermissions: select_browser denied; opening a docs URL in the built-in pane in the same session allowed.

Likely root cause (from reading the bundled binary; the env/flag names are measured, the interpretation is mine)

  • In the permission-mode resolution, when the session mode is bypassPermissions: tools from the built-in browser servers (Claude Browser / Claude Preview) are always re-routed to auto (classifier); tools from claude-in-chrome are re-routed to auto only when chromeClassifierFloorEnabled === true.
  • chromeClassifierFloorEnabled is CLAUDE_CHROME_CLASSIFIER_FLOOR ?? growthbook("tengu_cowork_chrome_automode_default", false).
  • My ~/.claude.json cache has tengu_cowork_chrome_automode_default: true with cachedExperimentData → experimentId: "cowork_chrome_automode_default_experiment_cli", variationId: 1. So this account is in the treatment arm of an experiment that turns the Chrome classifier floor on for CLI/desktop sessions — which is what makes bypassPermissions behave differently from the permission-modes docs.
  • The jump on 2.1.284 lines up with the changelog entry that made the server-side classifier the default ("Blocked by fast classifier" = the stage-1 verdict).
  • The desktop app also passes CLAUDE_PREVIEW_CLASSIFIER_FLOOR=1 to the bundled CLI, but 2.1.284 does not contain that env name, so it looks unrelated.

autoMode.environment does not help
I added an autoMode.environment section to ~/.claude/settings.json (keeping "$defaults") describing the routine use: operating my own logged-in accounts via Claude in Chrome, selecting my own connected Chrome browser, previewing localhost/local files. claude auto-mode config from the bundled 2.1.284 binary shows the new entries loaded. The same select_browser call was still "Blocked by fast classifier" right after.

Expected
Either bypassPermissions skips the classifier as the permission-modes docs describe (including for accounts in this experiment), or the docs say the classifier still runs in bypassPermissions for browser tools and which flag/setting governs it. I will add a follow-up here after testing the CLAUDE_CHROME_CLASSIFIER_FLOOR / CLAUDE_CODE_AUTO_MODE_SERVER opt-outs in a fresh session.

shirakawa-otoya · 14 days ago

Follow-up: the opt-outs work, plus a note from the user's side

Test (fresh desktop-app session, bypassPermissions, bundled 2.1.284, 2026-10-01 03:22 UTC)

Added to ~/.claude/settings.json:

"env": {
  "CLAUDE_CHROME_CLASSIFIER_FLOOR": "0",
  "CLAUDE_CODE_AUTO_MODE_SERVER": "0"
}

Then in a new session, with no other changes:

| Step | Call | Result |
|---|---|---|
| 1 | echo of both env vars from Bash | both 0 |
| 2 | mcp__claude-in-chrome__select_browser (my own default Chrome) | allowed |
| 3 | mcp__claude-in-chrome__navigate to https://docs.zoom.us/ (the exact call denied on 09-29), then get_page_text, then tabs_close_mcp | all allowed |
| 4 | mcp__Claude_Browser__preview_start on a public docs page | allowed |

Zero Blocked by fast classifier / Blocked by classifier results. Before these two lines: 5–9 denials per day for three days on read-only browser calls. After: none so far.

So for anyone hitting this: CLAUDE_CHROME_CLASSIFIER_FLOOR=0 is the switch that gets you out of the tengu_cowork_chrome_automode_default treatment arm, and CLAUDE_CODE_AUTO_MODE_SERVER=0 turns off the server-side fast classifier. Both are opt-outs that already exist in the binary; nothing is patched.

From the user's side

I want to add this not as a bug report but as feedback, because I like this product and I want it to get better.

  • For three days, read-only browser operations (selecting my own Chrome, opening a public docs page, previewing localhost) were denied several times a day, and the work that depends on them (ad-account maintenance through the browser) stalled each time.
  • Nothing told me my account had been placed in an experiment that changes how bypassPermissions behaves. I found out only by reading the bundled binary and my own ~/.claude.json. The permission-modes docs still describe the pre-experiment behavior.
  • The denials gave no path forward. The message says "denied by the auto mode classifier" and stops. There is no hint that an env var exists, and autoMode.environment does not help because the fast classifier rejects before it is consulted.

What would have made this a non-event:

  1. When an experiment changes permission behavior, say so somewhere the user can see it (a one-line notice in the session, or the flag name in the denial message).
  2. Put the two env vars above in the permission-modes docs, next to the sentence that says bypassPermissions skips the classifier.
  3. Have the fast classifier not override an explicit bypassPermissions for read-only calls on the user's own already-connected browser.

Happy to provide transcripts or test anything else.

Showing cached comments. Read the full discussion on GitHub ↗