anthropics / anthropics/claude-code

[BUG] Desktop: Plan mode prompts for every non-read-only Bash command since 2.1.270 (plan+bypass quiet path now requires isInteractive; Desktop sessions get no quiet path)

オープン
#94,274 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る
area:desktop area:permissions bug has repro platform:macos regression
主要言語
Python
スター
145k
フォーク
23.1k
PR マージ指標
PR 指標を取得中

説明

### Preflight Checklist

- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code (2.1.270, as bundled in Claude Desktop 1.52386.6)

### What's Wrong?

In the Claude Desktop **Code tab** (macOS), switching a session to **Plan** mode now raises a permission card for **every Bash command that isn't in the built-in read-only set**. One session produced 35 Bash permission prompts in a single afternoon (desktop `main.log`: `LocalSessions.setPermissionMode … mode=plan` followed by a stream of `Emitted tool permission request … for Bash`). The same Desktop workflow on the previously bundled CLI (2.1.266, and 2.1.260 before it) produced **zero** Bash prompts in plan mode across several days of use.

Desktop launches the CLI as a non-interactive stream: `--output-format stream-json --input-format stream-json --permission-prompt-tool stdio`, plus `--permission-mode bypassPermissions --allow-dangerously-skip-permissions` when the Desktop setting **Allow bypass permissions mode** is on. Auto mode is available on the account and `useAutoModeDuringPlan` is at its default (on).

Comparing the two bundled binaries (`~/Library/Application Support/Claude/claude-code//claude.app/Contents/MacOS/claude`):

- **2.1.266** — the plan-mode "permissive" check at the permission-context resolver is inline:
`n.mode==="plan" && n.isBypassPermissionsModeAvailable===!0`
- **2.1.270** — the same call sites use a new helper:
`function zj(e,n){return e==="plan"&&n===!0&&!Ae()}` where `Ae()` is
`function Ae(){return!n().host.launchOptions.isInteractive()}`.
Desktop sessions are non-interactive, so the "bypass available → plan mode doesn't prompt" path is now switched off for every Desktop (and SDK / stream-json) session.
- The other quiet path — the auto-mode classifier reviewing commands during planning — is gated as
`e.mode==="auto" || e.mode==="plan" && () && !e.isBypassPermissionsModeAvailable`.
With the Desktop bypass toggle on, `isBypassPermissionsModeAvailable` is true for every session, so this path is off as well.

Net effect: in Desktop with the bypass toggle on, **plan mode has no non-prompting path at all**; every non-read-only shell command asks the user. A terminal session with identical settings is unaffected because `isInteractive()` is true there.

The docs (Permission modes → "Skip all checks with bypassPermissions mode") still state: *"In sessions with bypass permissions available, Claude Code also doesn't enforce plan mode's blocks… a file edit or shell command it attempts during planning runs without prompting."* That no longer holds for Desktop/SDK sessions. Nothing in the 2.1.267–2.1.270 CHANGELOG entries mentions plan mode.

### What Should Happen?

One of the two documented quiet paths should apply to Desktop plan mode:

1. plan mode does not enforce its blocks when bypass permissions are available (behavior through 2.1.266, and what the docs describe), **or**
2. if gating that path on interactive sessions is intentional, non-interactive sessions should fall through to the classifier-during-planning path instead of to a prompt (i.e. `!isBypassPermissionsModeAvailable` should not exclude the classifier path when the bypass path itself is unavailable).

If the change is deliberate (e.g. non-interactive sessions must not run commands silently in plan mode), it should be in the changelog and docs, and the Desktop mode selector should not offer a Plan mode that prompts on everything.

### Error Messages/Logs

Desktop `~/Library/Logs/Claude/main.log` (ids elided):

```
2026-09-14 15:46:12 [info] [CCD] LocalSessions.setPermissionMode: sessionId=local_…, mode=plan
2026-09-14 15:46:12 [info] [CCD] Set permission mode for session local_… to plan
2026-09-14 15:58:19 [info] Emitted tool permission request e89ff78f-… for Bash in session local_…
2026-09-14 15:58:23 [info] LocalSessions.respondToToolPermission: requestId=e89ff78f-…, decision=once, hasUpdatedInput=true
2026-09-14 15:58:23 [info] Received permission response for e89ff78f-…: once (tool: Bash)
… 35 Bash permission requests between 15:58 and 16:15 in that one plan-mode session
```

Plan-mode toggles vs Bash permission prompts, same Desktop app and same workflow, counted from the log:

| date | bundled CLI | plan mode entered | Bash permission prompts |
| --- | --- | --- | --- |
| 2026-09-08 | 2.1.260 | 2× via mode selector | 0 |
| 2026-09-09 | 2.1.260 | 3× via mode selector | 0 |
| 2026-09-13 | 2.1.266 | via EnterPlanMode (ExitPlanMode prompt seen) | 0 |
| 2026-09-14 | 2.1.270 | 3× via mode selector (6 mode changes total) | 35 |

### Steps to Reproduce

1. Claude Desktop for macOS 1.52386.6 with bundled Claude Code 2.1.270. Desktop settings: **Allow bypass permissions mode** ON. Auto mode available (Max plan).
2. Code tab → open a session in any folder; mode selector → **Bypass permissions** (or Auto). Confirm shell commands run without prompts.
3. Switch the mode selector to **Plan**.
4. Ask for research that needs non-read-only shell commands (e.g. "inspect X with `ssh`/`gh`/`python3` and write a plan"; long compound commands that the read-only analysis can't classify also qualify).
5. Every such Bash call raises a permission card ("once" / "always" choices). With the previous bundled CLI (2.1.266) the same steps run the commands without prompting.

Code path: `strings` the 2.1.270 binary for `function zj(e,n){return e==="plan"&&n===!0&&!Ae()}` and `function Ae(){return!n().host.launchOptions.isInteractive()}`; in 2.1.266 the corresponding check is `n.mode==="plan"&&n.isBypassPermissionsModeAvailable===!0`.

### Claude Model

claude-fable-5-1 in the affected session (also seen with claude-opus-4-8). Model-independent.

### Is this a regression?

Yes, this worked in a previous version

### Last Working Version

2.1.266 (Claude Code), bundled in the same Desktop app until 2026-09-14. (2.1.267–2.1.269 not tested.)

### Claude Code Version

2.1.270 (Claude Code), bundled in Claude Desktop 1.52386.6

### Platform

Anthropic API (claude.ai Max subscription through the Desktop app)

### Operating System

macOS (26.6.2)

### Terminal/Shell

Other (Claude Desktop app, Code tab — non-interactive stream-json host)

### Additional Information

Workarounds identified (not a fix):

- Add `"Bash(*)"` to `permissions.allow` in `~/.claude/settings.json`. Per the permissions docs, plan mode sends non-read-only commands through the regular permission flow, which honors allow rules, while edits stay blocked. Not yet verified end to end.
- Turn the Desktop **Allow bypass permissions mode** toggle off. Bypass then stops being "available", so the classifier-during-planning path engages. Costs the Bypass mode entirely.

Possibly related but distinct: #10906 (Plan subagent ignores parent permissions), #89403 (plan mode gating after a rejected ExitPlanMode).

コントリビューションガイド

このリポジトリのコントリビューションガイドは索引されていません

調査の方向性

Start at the permission-context resolver and the non-interactive launchOptions.isInteractive() path described in the bundled 2.1.270 binary, then compare it with 2.1.266. Reproduce with Claude Desktop stream-json sessions and the documented Permission modes behavior; done means one documented quiet path works in Plan mode or the intentional behavior is reflected in the changelog, docs, and mode selector.

索引モデルが issue の本文から書いたものです。

評価

技術スタック
python, shell
領域
authorization, cli, developer-experience
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
活発
明瞭さ
おおむね明確
初心者へのやさしさ
48/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。