Auto mode circuit breaker is cached, poisoning subsequent sessions into Manual
Summary
A transient tengu_auto_mode_config.enabled === "disabled" verdict is persisted to cachedGrowthBookFeatures in ~/.claude.json. The startup path reads that cache synchronously, so sessions started in the seconds after one bad fetch silently ignore "defaultMode": "auto" and start in Manual — even though their own async gate confirms, ~500ms later, that auto mode is available.
The demotion is one-way. kickOutOfAutoIfNeeded drops a session out of auto, but nothing restores the resolved defaultMode when verifyAutoModeGateAccess subsequently returns canEnterAuto=true. The session stays in Manual for its entire life.
Environment
- Claude Code 2.1.205 (native install), macOS 15 / Darwin 25.5.0
- Provider: firstParty. Model: claude-opus-4-8. Fast mode off.
~/.claude/settings.jsonsetspermissions.defaultMode: "auto"(user settings — a trusted source)- No managed-settings file, no
--permission-modeflag, no shell alias, nodisableAutoMode
Evidence
Two sessions started four seconds apart. The first fetched disabled and wrote it to the cache:
06:03:09.764 [WARN] auto mode disabled: tengu_auto_mode_config.enabled === "disabled" (circuit breaker)
06:03:09.764 [DEBUG] [auto-mode] kickOutOfAutoIfNeeded applying: ctx.mode=default ctx.prePlanMode=undefined reason=circuit-breaker
The second read the poisoned cache at startup, then its own fetch immediately disagreed:
06:03:14.004 [WARN] auto mode circuit breaker active (cached) — falling back to default
06:03:14.573 [DEBUG] [auto-mode] verifyAutoModeGateAccess: enabledState=enabled disabledBySettings=false
model=claude-opus-4-8 modelSupported=true disableFastModeBreakerFires=false
carouselAvailable=true canEnterAuto=true
569ms after falling back to Manual, the CLI established canEnterAuto=true and did nothing with it. There are no further mode transitions in the remaining 376 lines of that debug log, and the session transcript records a single permission-mode: default. By the time a user inspects ~/.claude.json, the cache has self-repaired to enabled, so the cause leaves no trace.
Impact
Startup permission mode, grouped by CLI version, from 190 local session transcripts with defaultMode: "auto" set throughout:
| Versions | auto | default | % auto |
|---|---|---|---|
| 2.1.150 – 2.1.197 | 146 | 0 | 100% |
| 2.1.202 – 2.1.205 | 23 | 16 | 59% |
(5 further default sessions predate 2.1.150, on 2.1.143–2.1.145.) The regression landed somewhere in 2.1.198–2.1.202; there are no local sessions on those four versions to narrow it further. 2.1.200 changed the default mode's display name to "Manual", which is coincidental but makes the symptom read as new.
These counts understate the frequency. A transcript's first permission-mode record is written when the transcript is first flushed — at the user's first prompt — not at startup. Sessions opened and never prompted leave no record at all, and any session that somehow self-corrected before the first prompt would be recorded as auto.
Sessions that started in auto and in default appear within the same minute of each other, so this is not a per-model, per-launch or per-terminal condition, and it does not cluster into windows. A Wald–Wolfowitz runs test over the 2.1.202+ sessions gives 19 runs against 18.8 expected under randomness — consistent with a sub-second race rather than any sustained state.
It is triggered most by starting several sessions in quick succession.
Suggested fixes
Either would resolve it:
- Don't persist a
disabledcircuit-breaker verdict intocachedGrowthBookFeatures. A breaker is transient by nature; caching it converts one bad fetch into a multi-session outage. - Re-apply the resolved
defaultModewhenverifyAutoModeGateAccessreturnscanEnterAuto=trueon a session that fell back at startup. Today the transition is one-way.
The second is the more robust of the two, since it also covers a genuinely-disabled session recovering when the breaker clears.
Related issues
Neither of these is a duplicate, but both may share a cause:
- #74949 — "Auto mode classifier 'temporarily unavailable' in bursts — fail-closed blocks Bash". Same server-side breaker family, different symptom: that report is about the classifier failing closed mid-session, this one is about the breaker's verdict being cached and demoting the permission mode of later sessions. If the bursts in #74949 line up with the flaps here, they are two faces of the same flapping backend.
- #75235 — "permissions.defaultMode=bypassPermissions stopped being honored". Adjacent but distinct: Windows, Claude Desktop,
bypassPermissionsrather thanauto. That mode has its own gate (the interactive disclaimer must have been accepted), and no circuit breaker is involved.
Reproduction
Hard to force, since it depends on catching a flap. To observe it, set DEBUG_SDK=1 in the env block of settings.json — this enables the same file logging as --debug without the flag, and unlike DEBUG it is read nowhere else in the CLI. Then grep the newest file in ~/.claude/debug/ for auto mode after a session comes up in Manual.