[BUG] auto mode adds a fixed ~12.3s to Bash commands that skip the permission-rule fast path (controlled test: 12.32s vs 0.15s for the identical command)

Status Open
Reported on v2.1.273
Maintainer reply None cached
Activity 1 comment · opened Sep 16, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

The same command takes 12.32s in auto mode and 0.15s in Manual mode. Switching the mode back and
forth reproduces it (A-B-A). Commands covered by a permissions.allow rule are unaffected; everything
else pays a fixed ~12.3s before it starts running. For an ask-rule command the gap is 16.05s vs 1.18s
— and the Manual figure includes a human reading the prompt and pressing a key, so auto mode is
currently 14x slower than the interaction it exists to replace.

Verified on Claude Code 2.1.273. Not environmental: an independent process on the same machine recorded
zero scheduling stalls during the same window.

Summary

The same command — a python3 heredoc writing an 8-byte file — run repeatedly while switching
permission mode back and forth in a single session (A-B-A):

| Phase | Mode | n | Times | Median |
|---|---|---|---|---|
| ① | auto | 4 | 12.35 / 12.34 / 12.30 / 12.03s | 12.32s |
| ② | manual | 4 | 0.15 / 0.15 / 0.13 / 0.19s | 0.15s |
| ③ | auto (switched back) | 3 | 12.44 / 12.40 / 12.22s | 12.40s |

An 82x difference on an identical command, and the effect returns when the mode returns.
The command body writes 8 bytes; essentially all of the 12.3s is wait before execution.

A control command in the same session, grep -c . /etc/hosts, which is covered by a
permissions.allow rule, stayed fast in both modes (auto 0.12 / 0.14s, manual 0.14s). So the penalty
applies specifically to commands that do not hit the permission-rule fast path.

What decides it is the permission rule, not how heavy the command is. The same four commands,
each run in both modes:

| Command | Rule status | auto | manual | Ratio |
|---|---|---|---|---|
| grep -c . /etc/hosts | matches an allow rule | 0.13s | 0.14s | no difference |
| mkdir -p <path> | no matching rule | 12.44s | 0.14s | 89x |
| python3 - <<'PY' (writes 8 bytes) | no matching rule | 12.32s | 0.15s | 82x |
| rm -rf <empty scratch dir> | matches an ask rule | 16.05s | 1.18s | 14x |

mkdir -p is about as trivial as a command gets, and it pays the full penalty. grep is fast not
because it is lightweight but because Bash(grep *) is in the allow list.

The strongest single comparison

The rm -rf row is worth stating plainly. In Manual mode it did show the Do you want to proceed?
prompt
, and the 1.18s includes the prompt rendering and a human reading it and pressing a key.
In auto mode, the same command — with no prompt shown — took 16.05s.

Auto mode spent 14x longer deciding than it takes a person to decide manually. The feature exists
to save the user that interaction, and it currently costs an order of magnitude more than the
interaction it replaces.

Also worth noting: in auto mode the ask-rule command ran without any prompt, which is the
documented behavior for the classifier path, but it means the extra ~4s over the other commands is
pure classifier overhead rather than user interaction.

It also applies even when Manual mode does not prompt for the command: the 0.15s manual timings
leave no room for a human to read a prompt and press a key. This is not the cost of skipping a
confirmation — for the heredoc command, the confirmation was not there to begin with.

The 12.3s looks like a timeout, not inference

Across all seven auto-mode measurements in both phases, the values span 12.03–12.44s — a 0.41s
spread
. A classifier actually reading ~140k characters of context and deciding would vary far more
than that with input length and load.
A value this tight is the signature of a fixed timeout or fixed wait, i.e. something is not
answering and the code proceeds after a fixed delay, rather than something thinking for 12 seconds.

If that reading is right, this may share a root cause with the classifier temporarily unavailable
issues (#68437 and others): there the failure surfaces and blocks the command, here it appears to time
out silently and proceed.

What I ruled out

The slowdown is not environmental. Each of these was measured, not assumed:

| Hypothesis | Ruled out by |
|---|---|
| WSL / host not scheduling the process | See Side-by-side measurement below: 0 stalls over 10 minutes while Claude Code commands took 12–14s |
| Sandbox filesystem layer (bwrap mount construction) | Already disabled via filesystem.disabled: true; this had separately cut command time from ~21s to ~0.15s before the auto-mode effect was isolated |
| Memory pressure / GC | RSS 276–410MB, majflt ≈ 0, host has 16GB with 5% in use |
| stdout write blocking (Ink re-render) | blocked_write=false in 98/98 [event-loop-stall] records |
| Machine load | load average 0.22 on 20 cores |

Side-by-side measurement (the decisive one)

An independent Python process sampled at 100ms intervals for 10 minutes, writing a heartbeat every
second, while Claude Code ran normally in the same session on the same machine.

The probe:

start T+46:29
end   T+56:29   stalls=0
heartbeats: 600 (T+46:30 - T+56:29), zero gaps
monotonic: 600.04s over a 600s run

6,000 wakeups, not one late.

Claude Code during the exact same window:

T+48:11    12.58s     goes to classifier
T+48:40    14.10s     goes to classifier
T+49:13    14.25s     goes to classifier
T+52:00    14.17s     goes to classifier
T+54:00     0.15s     `ls -1 <dir>` - matches an allow rule, skips classifier
T+54:43    12.44s     goes to classifier
T+56:41    12.83s     goes to classifier

The OS was scheduling everything on time. Only the commands routed through the classifier waited.
Within the same ten minutes, the one command covered by a permission rule returned in 0.15s.

The spread is also telling: 12.44 / 12.58 / 12.83 / 14.10 / 14.17 / 14.25. A machine-level stall would
scatter; this is the signature of a fixed round-trip cost.

Commands that stay fast in auto mode are the ones that skip the classifier

Commands matching a permissions.allow rule return in 0.1–0.35s even in auto mode:

0.10s   grep -n "<pattern>" <file>          # covered by Bash(grep *)
0.35s   grep -rn "<pattern>" <dir>          # covered by Bash(grep *)
0.12s   cat <file>                          # covered by Bash(cat)
0.14s   sed -n 1,60p <file>
0.11s   ls -1 <dir>

Commands that do not match a rule are the slow ones:

111.8s  echo "..." && python3 -c "..."      # compound
 70.2s  curl -sL --max-time 30 https://...  # network
 52.0s  mv -n "<a>" "<b>"                   # file move
 35.8s  python3 - <<'PY' ... PY             # heredoc
 23.3s  cd <dir> && for f in ...; do ...    # loop

This matches the documented behavior that a command approved by a permission rule does not go to the
classifier — and isolates the added latency to the classifier path.

Measurements

The controlled test above is the primary evidence. The observational data below came first and is
included for context, with one caveat stated up front: mode boundaries in it were inferred from
session transcript markers rather than confirmed
, and the command mix was not held constant between
modes, so the aggregate medians here are confounded. The controlled test was run precisely to remove
both problems, and it reproduced the effect on an identical command.

Measured by diffing tool_use and matching tool_result timestamps in the session transcript
(~/.claude/projects/<project>/*.jsonl). Single session, one continuous ~85 minute window.
Times below are relative to the first mode switch (T+00:00).

| Mode | n | Median | Mean | >10s | <1s |
|---|---|---|---|---|---|
| manual | 22 | 0.64s | 6.36s | 4 | 12 |
| auto | 88 | 12.78s | 16.25s | 51 | 13 |

The change is immediate on mode switch:

----- T+00:00  switched to manual -----
  T+00:26     0.16s
  T+00:53     0.19s
  T+01:04     0.12s
  T+01:16     0.15s
----- T+04:22  switched to auto -----
  T+04:40    15.58s
  T+06:10    40.68s
  T+06:56    14.99s
  T+07:25    13.98s
  T+08:12    12.83s
  T+08:31    11.87s
----- T+13:15  switched to manual -----
  T+13:25     1.32s
  T+13:30     0.13s
  T+13:33     0.12s
  T+13:43     0.14s

Not a duplicate of the classifier availability issues

There are many open issues about the auto mode classifier being temporarily unavailable and
blocking Bash entirely (#68437, #49535, #78576, #83773, #63873, #62170, #69950, #82653 and others).

This report is different: the classifier answers successfully every time. Nothing is blocked,
no retry loop appears, and no error is shown. The commands run — they just start 12–14 seconds late,
consistently, in a session where the OS is demonstrably idle.

#74949 is the closest neighbour, since it notes that compound commands are the ones affected during
its outage windows; the same command shape is slow here, which may point at a shared code path.

Additional observation (possibly separate)

While a command is in flight, the input box sometimes stops echoing typed characters for ~0.5–1.5s and
then catches up. [event-loop-stall] records for that duration show 19.3% median CPU (max 62.3%)
and no [likely sleep/wake] label, i.e. synchronous work inside the process — distinct from the
classifier wait, which shows ~5% CPU. I could not attribute this to a specific code path from the logs
alone. Mentioning it in case it is related to the same UI path.

For this observation only, one more environment detail may matter: the Windows host is accessed over
RDP, so terminal output crosses a remote-desktop link. That is irrelevant to the classifier latency
above — the controlled A-B-A test and the zero-stall OS measurement rule it out there — but it could
plausibly interact with terminal rendering, which is what this section is about.

What Should Happen?

The classifier check should not cost more than a human answering the prompt. Some options that would
help:

  • Reuse / cache classifier context across actions in the same session instead of re-sending the full

~140k characters per action

  • Send only the delta since the previous classifier call
  • Run the classifier request concurrently with anything else that can be prepared before execution
  • Surface the wait in the UI (currently there is no indication that a classifier round-trip is in

progress, so the session simply appears frozen)

Error Messages/Logs

**No error is produced.** That is part of what distinguishes this from the existing classifier issues:
nothing is blocked, no retry loop appears, no message is shown. The command simply starts 12-16 seconds
late and then succeeds.

The only relevant log lines come from `--debug`, showing how much context the classifier is sent per
action:


[auto-mode] context comparison: classifierChars=133343 ...
[auto-mode] context comparison: classifierChars=133933 ...
[auto-mode] context comparison: classifierChars=134355 ...
...
[auto-mode] context comparison: classifierChars=144216 ...


12 classifier calls over ~20 minutes, growing by ~10,900 characters.

Raw timings from the controlled A-B-A test (same command throughout, mode switched between phases):


[auto]    12.35s  12.34s  12.30s  12.03s
[manual]   0.15s   0.15s   0.13s   0.19s
[auto]    12.44s  12.40s  12.22s


Independent OS-level probe running during the same session (100ms sampling, 10 minutes):


stalls=0
heartbeats: 600, zero gaps
monotonic: 600.04s over a 600s run

Steps to Reproduce

The split is whether the command would show a Do you want to proceed? prompt in Manual mode.
Anything auto-allowed by the sandbox, or covered by a permissions.allow rule, skips the classifier
and is fast in both modes. Picking the wrong command shape is the easy mistake here — a compound
command is not enough on its own, because a harmless one like echo a && echo b is still auto-allowed.

  1. Start a session in auto mode.
  2. Run a command that is auto-allowed, e.g. grep -c . /etc/hosts. It returns in ~0.1s.
  3. Run a command that Manual mode would prompt for. A python heredoc that writes a file outside the

allow rules works: python3 - <<'PY' … open('<path>','w').write('x') … PY

  1. Compare tool_use → tool_result timestamps in ~/.claude/projects/<project>/*.jsonl.

Verified run. Both shapes, same session, within one minute of each other:

 +0.0s     0.14s   echo repro-A1 && echo done      auto-allowed
 +1.0s     0.12s   echo repro-A2 && echo done      auto-allowed
 +2.0s     0.13s   grep -c . /etc/hostname         matches an allow rule
 +2.0s     0.12s   grep -c . /etc/hosts            matches an allow rule
+59.0s   127.77s   cd <dir> && grep … (multiline)  goes to the classifier
+66.0s   133.63s   python3 - <<'PY' (writes 8 bytes)  goes to the classifier

0.12s and 133.63s in the same minute on the same machine. The body of the slow one writes a single
8-byte file; essentially all of the 133 seconds is wait before execution.

Note: the wait can exceed the tool timeout. In the run above, the 127.77s command hit the 120s Bash tool timeout and was moved to background
execution
. So this is not only a latency annoyance: the classifier wait can consume the entire tool
budget and change how the command is executed.

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.273 (Claude Code)

Platform

Anthropic API

Operating System

Ubuntu/Debian Linux

Terminal/Shell

Windows Terminal

Additional Information

Sandbox configuration

The Bash sandbox is enabled, with the filesystem layer disabled and the network layer active:

"sandbox": {
  "enabled": true,
  "filesystem": { "disabled": true },
  "network": { "strictAllowlist": false, "allowAllUnixSockets": true }
}

This matters because bwrap mount construction was a separate slowdown on this machine earlier
(it cost ~20s per command with the filesystem layer on, traced to the --tmpfs argument per denied
path). That was already resolved by filesystem.disabled: true before any of the measurements in this
report were taken, so it is not a factor here. Command time with the filesystem layer disabled and
auto mode off is ~0.15s.

Filesystem layout

  • Working directory is on /mnt/c (9p / DrvFs)
  • Claude Code config directory (~/.claude) is on ext4

Both were checked as possible causes and ruled out: path resolution for 200 non-existent paths on the
9p mount takes 0.27s, and the measured penalty is identical for commands that touch neither location.

Scope of verification

Reproduced on a single machine. Not yet verified on other platforms, other terminals, or with other
permission rule sets. The A-B-A design rules out ordering and time-of-day effects within that session,
but cross-environment reproduction would strengthen the report.

Method note

All timings are tool_use → matching tool_result timestamp differences read from the session
transcript, not stopwatch measurements. Permission mode at each point was confirmed by the user
switching it deliberately, not inferred.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗