Repository navigation
[BUG] Root cause identified: GrowthBook A/B flags tengu_permission_friction + tengu_quill_harbor silently override defaultMode:bypassPermissions via periodic server sync — macOS Desktop #62205
Description
Activity
- addedbugSomething isn't workingSomething isn't workingduplicateThis issue or pull request already existsThis issue or pull request already existsplatform:macosIssue specifically occurs on macOSIssue specifically occurs on macOShas reproHas detailed reproduction stepsHas detailed reproduction steps
on May 25, 2026 Update: additional root cause found in claude_desktop_config.json
After further investigation, there is a second mechanism contributing to the Desktop-specific failure, complementary to the GrowthBook flag issue described in the original report.
Finding
~/Library/Application Support/Claude/claude_desktop_config.jsoncontains anepitaxyPrefskey that controls the permission mode for new sessions opened from the Desktop app landing page:{ "preferences": { "epitaxyPrefs": { "cc-landing-draft-permission-mode": "acceptEdits" } } }When
tengu_quill_harbor: "acceptEdits"is active (GrowthBook sync), the Desktop app writescc-landing-draft-permission-mode: "acceptEdits"to this file. This persists the wrong mode even between GrowthBook sync cycles — so fixing~/.claude.jsonalone is not sufficient ifclaude_desktop_config.jsonretains the stale value.Community workaround (confirmed working on macOS by multiple users in #61415)
Adding
"bypassPermissionsModeEnabled": trueto thepreferencesobject inclaude_desktop_config.jsonacts as a Desktop-app-level override:{ "preferences": { "bypassPermissionsModeEnabled": true, "epitaxyPrefs": { "cc-landing-draft-permission-mode": "bypassPermissions" } } }Then relaunch the Desktop app.
Full fix chain (belt-and-suspenders)
For complete and persistent resolution, both files need to be corrected:
File Fix needed ~/.claude.json→cachedGrowthBookFeaturestengu_permission_friction: false,tengu_quill_harbor: "bypassPermissions"claude_desktop_config.json→preferencesbypassPermissionsModeEnabled: trueclaude_desktop_config.json→preferences.epitaxyPrefscc-landing-draft-permission-mode: "bypassPermissions"Since GrowthBook re-syncs
~/.claude.jsonevery ~9 minutes and may trigger the Desktop app to re-writeclaude_desktop_config.json, a persistent watchdog (launchd WatchPaths on both files) is needed to maintain the fix.Note on folder-specific modes
claude_desktop_config.jsonalso contains per-folder permission mode overrides underepitaxy-folder-permission-mode. These appear to be set by the user via the UI and should not be modified by any automated fix — only the globalcc-landing-draft-permission-modeandbypassPermissionsModeEnabledneed to be corrected.Found 3 possible duplicate issues:
- Desktop app always starts sessions in "Accept Edits" mode instead of "Bypass Permissions", even though defaultMode: "bypassPermissions" is set in ~/.claude/settings.json #61436
- [BUG] Desktop: Bypass Permissions mode can't be enabled on macOS — reverts to Accept Edits, "Permission mode couldn't be changed" (2.1.148) #61415
- Desktop launches CLI without --dangerously-skip-permissions despite defaultMode: bypassPermissions #62084
This issue will be automatically closed as a duplicate in 3 days.
- If your issue is a duplicate, please close it and 👍 the existing issue instead
- To prevent auto-closure, add a comment or 👎 this comment
🤖 Generated with Claude Code
Update: 5th attack vector confirmed — per-folder
epitaxy-folder-permission-modeAfter further investigation following a fresh restart, I've identified an additional override path that none of the previously known workarounds (including
bypassPermissionsModeEnabledinclaude_desktop_config.json) cover.New vector
File:
~/Library/Application Support/Claude/claude_desktop_config.json{ "preferences": { "epitaxyPrefs": { "epitaxy-folder-permission-mode.<accountId>": { "/Users/<me>/Downloads": "acceptEdits", // ← silently set by Desktop app "/Users/<me>/some-project": "auto" } } } }When GrowthBook sync flips
tengu_quill_harbortoacceptEdits, the Desktop app persists the per-folder override toepitaxy-folder-permission-mode.<accountId>[<folder>] = "acceptEdits". This per-folder value then takes precedence over both:cc-landing-draft-permission-mode(global default for new sessions)defaultMode: bypassPermissionsin~/.claude/settings.json
So even after fixing every other known vector, opening a new session from an affected folder still lands in Accept Edits mode and the mode change still fails with the original error.
Repro
- Have GrowthBook sync set
tengu_quill_harbor: acceptEditsat least once. - Open a session from a project folder, observe it lands in Accept Edits.
- Close the session. Inspect
claude_desktop_config.json— the folder is now pinned at"acceptEdits". - Even after correcting
tengu_*flags andcc-landing-draft-permission-mode, new sessions from that folder still land in Accept Edits until the per-folder override is cleared.
Summary — 5 attack vectors total
# File Field Symptom 1 ~/.claude.jsoncachedGrowthBookFeatures.tengu_permission_frictionMode change UI fails 2 ~/.claude.jsoncachedGrowthBookFeatures.tengu_quill_harborSession starts in acceptEdits3 claude_desktop_config.jsonpreferences.bypassPermissionsModeEnabledBypass toggle inert 4 claude_desktop_config.jsonpreferences.epitaxyPrefs.cc-landing-draft-permission-modeNew-session default flipped 5 claude_desktop_config.jsonpreferences.epitaxyPrefs.epitaxy-folder-permission-mode.<accountId>[folder]Per-folder pin survives all other fixes Vector 5 is the most insidious because it persists across restarts and is invisible unless you inspect that specific nested key.
Suggested fix
The Desktop app should not write
"acceptEdits"toepitaxy-folder-permission-modewhen the global setting isbypassPermissionsand the user has the bypass gate enabled. Alternatively, a single source of truth (settings.jsondefaultMode) should be respected, with GrowthBook flags treated as defaults only when no user-set override exists.Great analysis — the GrowthBook A/B flag mechanism you identified is the underlying root cause, and your repro is reliable. Adding a complementary workaround for anyone landing here who's tired of patching
~/.claude.jsonevery ~9 minutes:You can short-circuit this one layer above GrowthBook by setting the launcher's global gate
bypassPermissionsModeEnabled: trueinclaude_desktop_config.json. It's a local user pref, never re-synced from the server, so it persists indefinitely.The launcher logic (from
app.asar):const d = i.permissionMode ?? r?.permissionMode ?? u ?? sn.Default, // ← `u` is where the harbor default lands h = Bi("bypassPermissionsModeEnabled") === true, f = d === sn.Bypass && !h, y = f ? sn.AcceptEdits : d; // later: d && Y.push("--allow-dangerously-skip-permissions")
When
h === true, thed === sn.Bypass && !hdowngrade check short-circuits regardless of whatu(the harbor-derived default) resolves to. And the--allow-dangerously-skip-permissionsflag actually reaches the spawned CLI, which also defuses thetengu_permission_friction-induced "Permission mode couldn't be changed" error — flipping mode mid-session fails when the CLI was spawned without the flag.I'm in the same A/B cohort you describe (
tengu_harbor=true, tengu_harbor_permissions=true, tengu_permission_friction=true, tengu_quill_harbor=acceptEdits) and settingbypassPermissionsModeEnabled: truealone defuses both symptoms — no~/.claude.jsonpatching required.Full writeup with macOS paths, the
chmod 444quit-write gotcha, and the account-UUID-after-reinstall caveat: #61415 (comment).Doesn't supersede your fix request — Anthropic should still respect
defaultMode: bypassPermissionsfor harbor users — but it gets people unstuck without a launchd watchpath agent in the meantime.Operator-side note for fellow Cluster 10 victims, building on @amicicixp's root-cause analysis and 5-vector enumeration.
I've published a 2,487-word field guide consolidating the cluster shape and the three currently-shipped operator-side hooks: https://gist.github.com/yurukusa/69a3fcd4eac07533276b3103c8b21d9d (MIT).
What the guide adds beyond this thread:- Three converging axes — periodic re-sync (~9 min), no release boundary, five documented override paths — making the cluster legible as a transport category, not a permission-matcher category. The settings.json contract is correct on the local side; the issue is server-pushed flag values trumping local files.
- The five override paths in their operator-discovery order:
~/.claude.json→cachedGrowthBookFeatures, the session-specificcowork-gb-cache.json,local_<workspace-id>/.claude/.claude.json,epitaxy-folder-permission-mode,claude_desktop_config.json. The same flag can have different values on different paths (which explains observed cases where subagents run in a different mode than the parent session). - Three operator-side hooks shipped in cc-safe-setup, all advisory, all observational:
growthbook-flag-monitor.sh(PR Bash command execution hangs intermittently #402) — SessionStart hook that diff's the flag cache against a baseline and surfaces flag changescompact-dispatch-watchdog.sh(PR Will there be a normal windows version? #413) — Stop hook for the [Bug] Auto-compact never triggers despite statusline reporting "100% context used" (v2.1.153, Max sub, 200K mode) #63015 silent-compaction case (same cluster, different dispatch path:tengu_compact_cache_prefix)permission-mode-drift-guard.sh— PermissionRequest hook for the case where bypass mode silently flips to acceptEdits mid-session
- The structural acknowledgment — none of the three hooks prevents the dispatch path itself. The GrowthBook sync runs on a background timer that no hook surface observes; by the time the next SessionStart/PreToolUse/Stop hook fires, the override has already taken effect. The shipped hooks make the result visible. Only a network-level block (host-file entry routing the GrowthBook CDN to 127.0.0.1) prevents the cause, and that's hostile to the rest of the application.
- What an upstream fix would look like —
tengu_quill_harborshould be a default thatsettings.json'sdefaultModecan override, not a mandatory setting; experiment cohort allocation should not appear in the same code path as managed policy fields likedisableBypassPermissionsMode. The thread's reporter already named this; the guide formalizes it as a policy-boundary suggestion.
The cluster framing (HTML, links to all three hook PRs): https://github.com/yurukusa/cc-safe-setup/blob/main/docs/cluster-tracker.html#cluster-growthbook
I tracked this issue's progression for the Cluster 10 framing because the root-cause depth here is rare in the bug tracker — the @amicicixp three-comment chain (initial analysis → second mechanism inclaude_desktop_config.json→ 5th vector atepitaxy-folder-permission-mode) is the kind of investigation that makes a real cluster, not a duplicate pile-on. Thank you for documenting all five vectors publicly.
If anyone has reproductions on Linux specifically (~/.config/Claude/cachedGrowthBookFeatures), I'd be interested to know whether the sync cadence is the same ~9 minutes there.
Confirming this on Windows 11, Desktop 1.13576.0, npm @anthropic-ai/claude-code 2.1.158.
Same mechanism, additional data points:
- Remote Control sessions launched from the CLI as
claude --remote-control --dangerously-skip-permissions
come up in acceptEdits on the phone, not bypassPermissions. - The launch flag IS honored locally. A/B headless test, same CLI build:
claude -p ... --dangerously-skip-permissions -> "permissionMode":"bypassPermissions"
claude -p ... --permission-mode bypassPermissions --allow-dangerously-skip-permissions -> "permissionMode":"bypassPermissions"
Both record bypassPermissions in the transcript. So the downgrade is NOT in the CLI; it is applied on
the remote/relay path that the mobile app connects through. - On this machine: ~/.claude.json cachedGrowthBookFeatures has "tengu_quill_harbor": "acceptEdits" and
"tengu_permission_friction": true, and %APPDATA%\Claude\claude_desktop_config.json has
epitaxyPrefs."cc-landing-draft-permission-mode": "acceptEdits" (despite bypassPermissionsModeEnabled: true
in the same file). tengu_disable_bypass_permissions_mode is false, so bypass is not disabled, only overridden. - This is platform-independent (the flag is account-level), so the macOS-only label undersells it. Please
have remote-control sessions honor --dangerously-skip-permissions, or make the GrowthBook override
user-overridable.
- Remote Control sessions launched from the CLI as
Adding another confirmed report — same symptoms, different angle.
Claude Max subscriber, Claude Desktop macOS, Claude Code v2.1.204+. My
settings.jsonhaspermissions.defaultModeset (tested both"acceptEdits"and"bypassPermissions"), and it silently reverts to manual/friction mode roughly every ~9 minutes. This makes scheduled/autonomous tasks configured withbypassPermissionsstop running unattended without any warning.Workaround I'm using in the meantime: setting affected scheduled-task SKILL.md files'
permission-modetoacceptEditsinstead ofbypassPermissions, since that mode seems to survive the resync (unlike bypass).Given this affects unattended/scheduled workflows specifically, would appreciate an update on whether accounts can be opted out of this GrowthBook test, or whether
settings.jsonwill be made authoritative over the server-synced flags. Happy to share diagnostic details if useful.Closing as a duplicate of #61415 — please follow and 👍 that issue instead so we can track it in one place. If you think this was closed in error, comment here and we'll reopen.
🤖 Generated with Claude Code
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.
- locked as resolved and limited conversation to collaborators
on Oct 10, 2026
Summary
This is a root cause analysis for the cluster of issues where Claude Code Desktop ignores
permissions.defaultMode: bypassPermissionsand sessions always start in Accept Edits mode. The symptom is already reported in #61415, #61436, #61958, #39523 and many duplicates — but the specific mechanism has not been identified in any of those threads.Short version: Two GrowthBook feature flags, pushed from Anthropic servers every ~9 minutes, silently override the user's
settings.jsonand lock the Desktop app into Accept Edits mode.Environment
Root Cause
When a user account is enrolled in the harbor permissions A/B test (
tengu_harbor: true,tengu_harbor_permissions: truein~/.claude.json'scachedGrowthBookFeatures), two additional flags are synced from Anthropic's GrowthBook CDN and cached locally:Flag 1 —
tengu_permission_friction: trueBlocks mode switching entirely. The UI shows the error:
even when the user explicitly tries to switch to Bypass Permissions.
Flag 2 —
tengu_quill_harbor: "acceptEdits"Forces every new session to start in Accept Edits mode, regardless of
permissions.defaultMode: "bypassPermissions"insettings.json. This is what makes the banner appear on every session start:The harbor model introduces
tengu_quill_harboras the effective session default, which takes priority over the user-levelsettings.jsondefaultMode— effectively treating an A/B test flag as a managed/enterprise policy.Why the standard workarounds fail
The
Allow bypass permissions modetoggle (Settings UI)Enabling the toggle sets
allowDangerouslySkipPermissions: trueinsettings.json, which maps to--allow-dangerously-skip-permissions(adds bypass to the Shift+Tab cycle). This is not the same as--dangerously-skip-permissions(which actually starts the session in bypass mode). Withtengu_permission_friction: true, even cycling via Shift+Tab is blocked.disableBypassPermissionsModeis NOT setChecked
policy-limits.jsonandcachedGrowthBookFeatures—disableBypassPermissionsModeisfalse(or absent). Bypass permissions is not disabled at the organization/managed level. The block comes exclusively from the two A/B test flags above.Why it keeps coming back
GrowthBook syncs
~/.claude.jsonfrom Anthropic's servers approximately every 9 minutes (observed via file modification timestamps across multiple app sessions). Manually settingtengu_permission_friction: falseandtengu_quill_harbor: "bypassPermissions"in~/.claude.jsonrestores correct behavior immediately — but the next GrowthBook sync resets them, reproducing the bug within minutes.The sync also writes to session-specific cache files in:
These session-level files may have different values than the main
~/.claude.json, causing inconsistent behavior (e.g., subagents running in a different mode than the parent session).Reproduction
Verify your account is in the harbor A/B test:
If
tengu_harbor: Trueandtengu_quill_harbor: acceptEdits, you are affected.Configure
~/.claude/settings.json:{ "permissions": { "defaultMode": "bypassPermissions" }, "allowDangerouslySkipPermissions": true, "skipDangerousModePermissionPrompt": true }Start Claude Code Desktop → new session → send any message.
Expected: session runs in Bypass Permissions.
Actual: banner appears, session is in Accept Edits, mode switch fails.
Temporary workaround
Patch
~/.claude.jsonafter each GrowthBook sync:Must be re-applied every time GrowthBook syncs (~9 min). A
launchdWatchPaths agent can automate this.Expected behavior
permissions.defaultMode: "bypassPermissions"insettings.jsonshould be respected regardless of which GrowthBook A/B test cohort the user is enrolled in. A/B tests should not silently downgrade explicitly configured user permissions.Suggested fix
In the harbor permissions model, when computing the effective session start mode,
tengu_quill_harborshould be treated as a default thatsettings.json'sdefaultModecan override — not as a mandatory setting. Similarly,tengu_permission_frictionshould befalsefor any account where bypass permissions is not disabled at the managed/policy level.Related issues
tengu_heron_brookfeature flag #62061 — Related: GrowthBook flagtengu_heron_brookinjecting system prompt content (same sync mechanism)