anthropics / anthropics/claude-code

2.1.275: switching a bypassPermissions session to plan mode routes every read-only Bash call to canUseTool (regression from 2.1.246)

Open
#95,633 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

area:agent-sdk area:permissions bug has repro platform:linux regression
Dominant language
TypeScript
Stars
147k
Forks
24k
PR merge metrics
PR metrics pending

Description

Summary

Since 2.1.275, a session that starts in bypassPermissions and is later switched to plan (via the Agent SDK's query.setPermissionMode("plan") / the set_permission_mode control request) no longer gets plan mode's automatic allow for read-only Bash. Every Bash call — git status --short, git log --oneline -3, grep … — is routed to canUseTool (i.e. a permission prompt). 2.1.246 does not do this. Starting in acceptEdits and switching to plan is fine on both versions.

Any host that lets the user toggle modes on a live session (Paseo does; Shift+Tab in the CLI presumably too) hits this: plan mode becomes "ask for everything".

Repro (Agent SDK 0.3.246)

import { query } from "@anthropic-ai/claude-agent-sdk";

const startMode = process.argv[2]; // "bypassPermissions" or "acceptEdits"
const calls = [];
const user = (content) => ({ type: "user", message: { role: "user", content }, session_id: "", parent_tool_use_id: null });
let go2, end; const gate2 = new Promise(r => go2 = r); const gateEnd = new Promise(r => end = r);
async function* prompts() {
  yield user("Reply 'ok' only. Use no tools.");
  await gate2;
  yield user("Read-only investigation for a plan: run Bash `git status --short`, then `git log --oneline -3`. Report one line. Don't ask questions or write a plan file.");
  await gateEnd;
}
const q = query({ prompt: prompts(), options: {
  cwd: process.cwd(), model: "claude-sonnet-5",
  permissionMode: startMode, allowDangerouslySkipPermissions: true,
  pathToClaudeCodeExecutable: process.env.CLAUDE_BIN, // 2.1.275 vs 2.1.246
  canUseTool: async (name, input) => { calls.push(`${name} ${JSON.stringify(input).slice(0, 60)}`); return { behavior: "allow", updatedInput: input }; },
}});
let phase = 1;
for await (const m of q) if (m.type === "result") {
  if (phase++ === 1) { await q.setPermissionMode("plan"); go2(); continue; }
  console.log(`start=${startMode} -> plan, canUseTool calls: ${calls.length}`); calls.forEach(c => console.log("  " + c)); end(); break;
}

Results

start mode → plan CLI 2.1.246 CLI 2.1.275
bypassPermissions 0 canUseTool calls 3 calls (git status --short, git log --oneline -3, grep …)
acceptEdits 0 0

Plan mode is genuinely active in the failing case (the model refuses Write outside the plan file, ExitPlanMode is offered) — it is only the read-only Bash auto-allow that is lost. Also reproduced with acceptEditsbypassPermissionsplan, so the trigger is "has been in bypass at any point before plan", not the launch flag alone. The CLI was launched with --permission-mode bypassPermissions --allow-dangerously-skip-permissions --permission-prompt-tool stdio.

Expected

After setPermissionMode("plan"), read-only Bash should be auto-allowed exactly as it is when the session was never in bypass.

Environment

  • Claude Code 2.1.275 (native install), Linux x86_64
  • @anthropic-ai/claude-agent-sdk 0.3.246
  • Same behaviour observed through Paseo 0.8.0, which drives the SDK the same way

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Run the supplied Agent SDK reproduction with CLI 2.1.246 and 2.1.275, starting from query.setPermissionMode("plan") and the set_permission_mode control request. Trace how permission handling reaches canUseTool after a session has used bypassPermissions. Done means read-only Bash calls are automatically allowed after switching to plan, without regressing the acceptEdits path.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, typescript
Domain
api, authorization, cli
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
66/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.