Desktop app ignores settings.json permissions.allow and defaultMode: bypassPermissions

Resolved 💬 21 comments Opened Feb 26, 2026 by kdmyers56 Closed May 4, 2026

Bug Description

~/.claude/settings.json permission settings (permissions.allow rules and defaultMode: "bypassPermissions") have no effect in the Claude Code desktop app (macOS). Every tool call still prompts for manual approval.

Steps to Reproduce

  1. Set ~/.claude/settings.json:
{
  "permissions": {
    "defaultMode": "bypassPermissions",
    "allow": [
      "Bash(*)",
      "Read(*)",
      "Write(*)",
      "Edit(*)",
      "Glob(*)",
      "Grep(*)"
    ],
    "deny": []
  }
}
  1. Also enabled "Allow bypass permissions mode" in Desktop app → Settings → Claude Code
  1. Start a new session in the Claude Code desktop app
  1. Any tool call (Bash, Read, Write, Edit) still prompts "Allow Claude to Run/Read/Write...?" with Deny/Allow once/Always allow for session

What Was Tried (All Failed)

| Attempt | Result |
|---------|--------|
| Specific path patterns: Write(//Users/me/path/**) | Still prompted |
| Wildcard patterns: Bash(echo *), Write(*) | Still prompted |
| Blanket wildcards: Bash(*), Read(*), Write(*), Edit(*) | Still prompted |
| defaultMode: "bypassPermissions" | Still prompted |
| Desktop app UI: Settings → Claude Code → "Allow bypass permissions mode" ON | Still prompted |
| All of the above combined | Still prompted |

Expected Behavior

With defaultMode: "bypassPermissions" or matching permissions.allow rules, tool calls should auto-approve without prompting.

Actual Behavior

Every tool call prompts for approval regardless of settings. The "Always allow for session" button sometimes appears but:

  • Only approves the exact command, not the pattern (each echo with different content triggers a new prompt)
  • Sometimes doesn't appear at all (only "Deny" and "Allow once")

Environment

  • Claude Code desktop app (macOS, Sequoia 15.5)
  • Claude Opus 4.6
  • ~/.claude/settings.json confirmed correct (validated JSON, correct keys)
  • No project-level settings.json overriding
  • CLI claude --dangerously-skip-permissions works — only desktop app is affected

Impact

Workflows that involve repeated tool calls (batch processing, session documentation protocols) require dozens of manual approvals per session, making automation impractical.

Workaround

None for the desktop app. CLI with --dangerously-skip-permissions is the only working alternative.

View original on GitHub ↗

21 Comments

github-actions[bot] · 4 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/18160
  2. https://github.com/anthropics/claude-code/issues/24381
  3. https://github.com/anthropics/claude-code/issues/27040

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

kdmyers56 · 4 months ago

Additional data points from continued use (Feb 25-27):

  1. Read tool also prompts — even Read(*) in permissions.allow doesn't auto-approve file reads in the desktop app
  1. "Always allow for session" is inconsistent — sometimes the button appears (with Cmd+Enter shortcut), sometimes it doesn't. When it DOES appear and is clicked, it only approves that exact command — not the pattern. For example, clicking "Always allow for session" on one echo '...' >> file.jsonl does NOT approve the next echo with different content.
  1. "Always allow for session" sometimes missing entirely — some prompts only show "Deny" and "Allow once" with no session-level option at all (particularly for python3 and Bash commands)
  1. New sessions don't pick up settings — confirmed by starting fresh sessions after each settings.json change. The permissions.allow rules and defaultMode: "bypassPermissions" have zero observable effect in the desktop app.

This makes any workflow involving repeated tool calls (batch processing, automated documentation) extremely painful — each call requires a manual click.

blwfish · 4 months ago

I’m one of likely many with great frustration on this. I’m not 100% certain, but I think that in my case, it’s even worse. I have some permissive Allow() that mostly worked. Really trivial stuff like ls, find and grep. They used to work at least a lot of the time - definitely not ALL the time - but now that I have put bypassPermissions in, they seem to be ignrored comprehensively. AND since bypassPermissions does not work, it makes me approve pretty much every single action. Yikes.

I routinely use two or three Code windows working on separate parts of a project, which may further complicate this, but having to constantly approve even trivial things in multiple windows is like being a one-armed paper hanger.

Related issue is that the docs are a complete mess, leading to confusion when either I or Claude (or both) try to figure this out. See https://github.com/anthropics/claude-code/issues/30113

CRMinarian · 3 months ago

Adding a Windows + UNC path data point to this bug.

Environment

  • OS: Windows 11 Pro 10.0.26200
  • IDE: VS Code with Claude Code extension (freshly reinstalled)
  • Shell: bash
  • Working directory: UNC network path (\vandelay\SkippyKB — Synology NAS over SMB)

Reproduction

Same as OP — defaultMode: "bypassPermissions" set at all three levels (user, project, project-local settings), comprehensive permissions.allow lists including Edit, plus skipDangerousModePermissionPrompt: true. The bypass mode banner shows correctly at the top of the window, but the Edit tool still fires "Allow Claude to Edit?" permission dialogs on every edit.

What was tried (all failed)

  • bypassPermissions in ~/.claude/settings.json (user level)
  • bypassPermissions in .claude/settings.json (project level)
  • bypassPermissions in .claude/settings.local.json (project-local level)
  • skipDangerousModePermissionPrompt: true in both user and project-local settings
  • Comprehensive allow lists with all tools + MCP wildcard patterns
  • VS Code extension file permission re-approvals
  • Full machine reboot to clear SMB file locks
  • Multiple fresh sessions

Key observation

The bypass mode banner displays correctly ("Bypass permissions mode: Claude can take actions without asking"), confirming the setting IS being read. But the Edit tool specifically still prompts. This suggests the Edit tool has its own permission check that doesn't respect the bypass mode flag.

Workaround

"Always allow for session" (Ctrl+Enter) on the first Edit prompt. Holds for the session but resets on restart.

houserooms · 3 months ago

Still experiencing this on the desktop app (macOS, Opus 4.6, March 2026). bypassPermissions set at user, project, and worktree levels -- all correctly formatted, all ignored. Every Bash, Edit, Write, and WebSearch call prompts. This has persisted for months across dozens of sessions.

I am a non-developer business user who relies on Claude Code via the desktop app for daily email triage and project management (~30+ tool calls per morning routine). The CLI flag workaround is not viable because the desktop app has no way to pass --dangerously-skip-permissions.

This is a significant workflow blocker. Filed a detailed standalone report at #38662.

CRMinarian · 3 months ago

Update: Root cause identified + working fix

After weeks of fighting this, we traced the root cause and have a permanent fix. Sharing in case it helps others here.

Root Cause: macOS SMB File Handling (Not Claude Code)

The permissions bypass does work — but not on network/SMB/UNC paths. The issue is how macOS (and Windows to a lesser extent) handles files accessed over SMB shares:

  • macOS uses SMB3 with POSIX extensions and treats files on network shares as untrusted
  • Windows treats UNC paths (\\server\share) with NTFS ACLs differently than local paths
  • Claude Code correctly reads bypassPermissions (the banner shows), but the underlying filesystem permission checks from the OS layer still fire for Edit/Write operations on network-mounted paths
  • This is essentially working as designed from Apple's perspective — they intentionally restrict trust on network-mounted filesystems

This is why some users see it work sometimes and not others — if your repo is local, bypass works. If it's on a NAS, network share, or mounted volume, the OS intercedes.

Our Setup (Before — Broken)

Mac ──SMB──→ NAS (Synology, \\vandelay\SkippyKB) ←──SMB── Windows PC
              ↑ git repo lived here
              ↑ SMB file locking + untrusted paths = bypass ignored

Both machines accessed the same repo over SMB. Claude Code's bypassPermissions was ignored on both because the OS treated the files as network resources.

The Fix: Local Repo + SSH

We moved the repo to a local filesystem on a dedicated Ubuntu server and access it via SSH:

Ubuntu Server (Hot Rod)    ← THE repo. ~/Dev/skippy-brain/. Claude runs HERE.
    ↑ SSH (key-based)
MacBook                    ← Thin client. ssh user@server, run claude there.
  • Repo is on a local ext4 filesystem — no SMB, no UNC, no network paths
  • bypassPermissions works perfectly on local paths
  • Mac SSHs in and runs Claude Code on the server — zero permission prompts
  • GitHub is backup only (auto-push every 30 min)
  • NAS is relegated to file archive storage via NFS (not repo hosting)

TL;DR

If you're running Claude Code against a repo on a network share (SMB, NFS-mounted, UNC path, mounted NAS volume), bypassPermissions will be ignored because the OS doesn't trust network-mounted files the same way it trusts local files.

Fix: Move your repo to a local filesystem. If you need multi-machine access, use SSH to a central server rather than a shared network filesystem.

This isn't a Claude Code bug per se — it's a filesystem trust boundary that Claude Code can't override. But it might be worth documenting this caveat in the permissions docs, since "network paths are treated differently" isn't obvious and multiple users here have been bitten by it.

houserooms · 3 months ago

Still happening as of 26 March 2026 on Desktop app (macOS Sequoia 15.3.2, Team plan). We have now also discovered that the Auto mode and Bypass permissions options are greyed out in the UI dropdown even after enabling both account-level toggles on claude.ai and setting defaultMode in settings.json. The app tooltip says to enable them in settings — but they are enabled. Restart does not help. Filed separately as #39311. Background agents also completely blocked — filed as #38859.

roqueragazzo · 3 months ago

Root cause and workaround

After debugging this on macOS, I found the root cause: Claude Desktop does not read permissions.defaultMode from ~/.claude/settings.json. The settings.json permission config only applies to the CLI.

Here's what actually happens when Desktop spawns a Claude Code session:

  1. Desktop stores the selected permission mode in Electron's Local Storage (a LevelDB database at ~/Library/Application Support/Claude/Local Storage/leveldb/), under the key LSS-cc-landing-draft-permission-mode.
  2. When starting a Code session, Desktop reads that stored value and passes it as --permission-mode <value> to the Claude Code subprocess.
  3. This CLI flag takes precedence over settings.json's defaultMode, so the settings file is effectively ignored.

You can verify this yourself by inspecting the running Claude Code process:

ps aux | grep "claude.app/Contents/MacOS/claude" | grep -v grep

You'll see --permission-mode acceptEdits (or whatever your current UI selection is) alongside --allow-dangerously-skip-permissions — the bypass capability is already enabled, but the selected mode is what Desktop stored in Local Storage, not what's in settings.json.

Fix

The workaround is to modify the Electron Local Storage value directly. Requires classic-level from npm and Claude Desktop must be fully quit first (it holds an exclusive lock on the DB).

mkdir /tmp/fix-claude-perms && cd /tmp/fix-claude-perms
npm init -y && npm install classic-level

Save this as fix-desktop-permission-mode.mjs:

#!/usr/bin/env node

// Fix for Claude Desktop ignoring ~/.claude/settings.json permission config.
//
// Claude Desktop persists the permission mode in Electron Local Storage (LevelDB),
// then passes it as --permission-mode <value> to the Claude Code subprocess.
// This overrides settings.json's defaultMode. This script modifies the stored value.
//
// Usage:
//   node fix-desktop-permission-mode.mjs [mode]
//
// Supported modes: bypassPermissions, acceptEdits, auto, plan, default

import { ClassicLevel } from "classic-level";
import { join } from "path";
import { homedir } from "os";

const VALID_MODES = ["bypassPermissions", "acceptEdits", "auto", "plan", "default"];
const DB_PATH = join(homedir(), "Library", "Application Support", "Claude", "Local Storage", "leveldb");
const targetMode = process.argv[2] || "bypassPermissions";

if (!VALID_MODES.includes(targetMode)) {
  console.error(`Invalid mode: "${targetMode}". Valid: ${VALID_MODES.join(", ")}`);
  process.exit(1);
}

async function main() {
  let db;
  try {
    db = new ClassicLevel(DB_PATH, { keyEncoding: "buffer", valueEncoding: "buffer" });
    await db.open();
  } catch (err) {
    if (err.message?.includes("lock")) {
      console.error("Database is locked. Quit Claude Desktop (Cmd+Q) before running this.");
      process.exit(1);
    }
    throw err;
  }

  let updated = false;

  for await (const [key, value] of db.iterator()) {
    const keyStr = key.toString("utf8");
    if (!keyStr.includes("permission-mode")) continue;

    const valStr = value.toString("utf8");
    const prefix = valStr.startsWith("\x01") ? "\x01" : "";
    const jsonStr = prefix ? valStr.slice(1) : valStr;

    let parsed;
    try { parsed = JSON.parse(jsonStr); } catch { parsed = null; }

    const currentMode = parsed?.value ?? "(unreadable)";
    console.log(`${currentMode} → ${targetMode}`);

    const newValue = parsed && typeof parsed === "object"
      ? { ...parsed, value: targetMode, timestamp: Date.now() }
      : { value: targetMode, tabId: "", timestamp: Date.now() };

    await db.put(key, Buffer.from(prefix + JSON.stringify(newValue)));
    updated = true;
  }

  if (!updated) {
    // Create entry using Electron's localStorage key format
    const fullKey = Buffer.from("_https://claude.ai\x00\x01LSS-cc-landing-draft-permission-mode");
    const newValue = Buffer.from("\x01" + JSON.stringify({ value: targetMode, tabId: "", timestamp: Date.now() }));
    await db.put(fullKey, newValue);
    console.log(`(none) → ${targetMode}`);
  }

  await db.close();
  console.log(`Done. Open Claude Desktop — the permission dropdown should now show "${targetMode}".`);
}

main().catch((err) => { console.error(err.message); process.exit(1); });

Then run:

# Quit Claude Desktop first (Cmd+Q), then:
node fix-desktop-permission-mode.mjs bypassPermissions

# Reopen Claude Desktop — new Code sessions should use bypass mode.
# You can also use: acceptEdits, auto, plan, default

Notes

  • The fix survives Desktop restarts, but a Desktop update may reset the value. Just re-run the script.
  • This only affects macOS. The LevelDB path will differ on other platforms.
  • The proper fix from Anthropic's side would be to have Desktop respect settings.json's defaultMode, or at minimum expose a persistent config key in claude_desktop_config.json for the initial permission mode.

Tested on Claude Desktop 1.1.9493, Claude Code 2.1.87, macOS 15.4 (Darwin 25.2.0).

cppudge · 3 months ago

Same issue on CLI (not Desktop/VS Code).
Version: 2.1.101
Platform: Debian Trixie (13) / WSL2, CLI only
~/.claude/settings.json:
json{
"defaultMode": "bypassPermissions",
"skipDangerousModePermissionPrompt": true
}
claude — still prompts for every tool call.
claude --dangerously-skip-permissions — works as expected.
No project-level settings overriding. This confirms the issue is not IDE-specific — defaultMode in settings.json is ignored across CLI as well.

moritzWa · 3 months ago

pls fix this!!!

wantpinow · 3 months ago

+1 this makes the desktop app unusable for any serious development

MoHcTpUk · 2 months ago

fix it pls!! I'm very like desktop app, but cannot use it!

stefansimik · 2 months ago

Fix please, this makes Claude Desktop unusable in daily practice

apurbaks · 2 months ago

We need fix.. we need desktop app to work same way cli .. We need it badly..

nikita-rippling · 2 months ago

+1, Rippling HRIS team affected on macOS Desktop. The discrepancy with Claude Code CLI (which honors ~/.claude/settings.json permissions.allow) vs Desktop (which appears to ignore it) is the most disorienting part — same config file, opposite behavior, no docs flagging the gap. Even just documented parity would help. Willing to test fixes.

— Posted via AI agent on Nikita's behalf; may contain errors. Tag or DM Nikita if feedback.

ArabianKnightx · 2 months ago

The problem seems to have gotten worse with the new update.

-----------------------------------------

Edit tool prompts for permission in acceptEdits and bypassPermissions/auto modes — affects both CLI and desktop app (v2.1.126)

Summary

In Claude Code 2.1.126, the Edit tool fires a permission prompt even when the session is in acceptEdits or auto / bypassPermissions mode. The bug:

  • Reproduces in both the CLI and the desktop app with identical symptoms — implicating the shared permission-resolver layer, not any client-specific code.
  • Reproduces with zero user configuration (i.e. with ~/.claude/settings.json removed entirely).
  • Does not affect the Write tool in auto mode, despite Write being in the same tool category and same modes — which scopes the bug narrowly to Edit's permission resolution path.

This blocks normal day-to-day use because every file edit interrupts the workflow with a prompt that no documented mechanism (mode toggle, allowlist, skipAutoPermissionPrompt) can suppress.

Environment

  • Claude Code version: 2.1.126
  • Surfaces affected: Claude Code CLI and Claude Code desktop app — bug reproduces in both with identical symptoms.
  • OS: macOS 26.4.1 (build 25E253), Darwin 25.4.0, arm64
  • Install method (CLI): native (/Users/<user>/.local/share/claude/versions/2.1.126)
  • Shell: zsh
  • /doctor output: all green — auto-updates enabled, latest channel, no version-lock conflicts.

The fact that the same bug reproduces in both the CLI and the desktop app rules out terminal/TTY handling, shell integration, and CLI-specific Shift-Tab parsing as causes. The bug must live in the shared permission-resolver layer that both clients use.

Steps to reproduce (clean-room — settings file removed)

  1. mv ~/.claude/settings.json ~/.claude/settings.json.bak (no project-level settings, empty settings.local.json).
  2. Start a brand-new Claude Code session.
  3. Press Shift-Tab to switch to acceptEdits mode. The system reminder confirms the mode change is registered.
  4. Ask Claude to edit a file (e.g. please add a line to note.txt).
  5. Observed: Permission prompt fires for Edit(...).
  6. Press Shift-Tab again to switch to auto / bypassPermissions mode. System reminder confirms "Auto Mode Active".
  7. Ask Claude to edit a file again.
  8. Observed: Permission prompt still fires for Edit(...).
  9. Ask Claude to write a new file with Write in the same auto-mode session.
  10. Observed: No prompt — Write is correctly auto-approved.

Expected behavior

  • acceptEdits mode is documented to auto-approve Edit, Write, and NotebookEdit. Edit should not prompt.
  • bypassPermissions / auto mode is documented to auto-approve all non-destructive tools. Edit should not prompt.

Actual behavior

  • Edit prompts in acceptEdits mode.
  • Edit prompts in auto / bypassPermissions mode.
  • Write does not prompt in auto mode (working as expected).
  • Read prompts in acceptEdits mode (this is expected — acceptEdits is for edit tools only — but mentioning for completeness).
  • Read does not prompt in auto mode (working as expected).

Earlier (non-clean-room) findings

Before stripping the config, the user's ~/.claude/settings.json contained:

{
  "permissions": {
    "allow": [
      "Read",
      "Bash(ls:*)",
      "Bash(grep:*)",
      "..."
    ],
    "defaultMode": "default"
  },
  "skipAutoPermissionPrompt": true
}
  • Adding "Read" to the allowlist correctly silenced Read prompts in all modes.
  • Adding "Write" and "Edit" to the allowlist (tested previously) did not silence Edit prompts.
  • skipAutoPermissionPrompt: true had no effect on Edit prompts.

So three independent suppression mechanisms (allowlist, mode, skipAutoPermissionPrompt) all fail for Edit specifically.

Plugin / hook audit

Confirmed no installed plugin registers a PreToolUse hook. The two plugins with hooks/hooks.json files (vercel, explanatory-output-style) only register SessionStart / SessionEnd hooks. So plugin interception is ruled out.

The clean-room reproduction further rules out plugins entirely, since the test session ran with no enabledPlugins config.

Hypothesis for maintainers

Because Edit and Write differ in behavior despite being in the same tool category and the same modes:

  • There may be an additional safety-check path that fires for Edit ("you're about to modify existing content") that is not properly gated on acceptEdits / bypassPermissions mode.
  • Or, the allowlist matcher silently does not match the Edit pattern even when literally "Edit" is configured, while it does match "Read" and "Write".

Both hypotheses predict the observed asymmetry between Edit and Write.

Impact

Daily use is significantly degraded. Every routine file edit interrupts the workflow with a prompt that no documented in-product mechanism can suppress. The user has confirmed that all four of the following bypass mechanisms fail to suppress Edit prompts in v2.1.126:

  1. Allowlisting "Edit" explicitly in ~/.claude/settings.json — no effect.
  2. acceptEdits mode (Shift-Tab toggle) — no effect.
  3. Auto / bypassPermissions mode (Shift-Tab toggle) — no effect.
  4. "skipAutoPermissionPrompt": true setting — no effect.

The only mechanism that does currently suppress Edit prompts is launching with the --dangerously-skip-permissions CLI flag. This is not a viable day-to-day workaround because it disables all permission resolution globally and is documented as unsafe.

Cross-version progression (potentially useful for maintainers)

The --dangerously-skip-permissions behavior changed across versions:

  • v2.1.123: --dangerously-skip-permissions did not suppress Edit prompts.
  • v2.1.126: --dangerously-skip-permissions does suppress Edit prompts.

So progress was made between these two releases on at least one bypass path. However, the four documented (non---dangerously- ) mechanisms above still don't work for Edit. This suggests the fix between 2.1.123 → 2.1.126 patched the --dangerously-skip-permissions flag's path specifically, but the corresponding fix for acceptEdits, bypassPermissions, allowlist matching, and skipAutoPermissionPrompt was not made. A grep for whatever change unblocked the --dangerously- path may point directly at where the analogous fix needs to go for the other paths.

Repro environment available

Happy to provide:

  • Full ~/.claude/settings.json
  • Full /doctor output
  • A short screen recording of the clean-room repro on request.
lhall-lexbe · 2 months ago

Why is this closed. This bug isn't fixed by the mentioned PR. There is no reason given for this being closed.

kitsunekyo · 1 month ago

@amorriscode can you elaborate why you closed this ticket, although plenty of users still see that issue to this day? it only ever got worse.

manos · 1 month ago

Claude code desktop is completely unusable because of this. Other tickets refer to this one as duplicate, yet this was closed with no resolution.

blwfish · 1 month ago

There _is_ a workaround, which is successful. Use a PreToolUse hook, and set up your hook so that it only checks truly dangerous things like formatting drives, removing databases, etc. I’ve been using it instead of the recommended but inoperative fixes with bypassPermissions etc. I can’t explain why this one is closed, I do still have to use the hook.

github-actions[bot] · 5 days ago

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.