ACP: `approvalMode: auto-review` classifier and `autoRun` instructions are ignored; auto-review degrades to plain allowlist and `.cursor/permissions.json` is never read

Summary:
In ACP mode, approvalMode: "auto-review" does not apply its auto-review behavior. The AI classifier that auto-runs safe/trusted calls does not run, the autoRun.allow_instructions / block_instructions are never consulted, and .cursor/permissions.json (which holds autoRun, terminalAllowlist, mcpAllowlist) is not read at all. Only the static permissions.allow tokens in cli.json/cli-config.json take effect — so auto-review behaves identically to allowlist under ACP.

Environment:

  • cursor-agent version 2026.07.09-a3815c0
  • macOS (Darwin), cursor-agent acp, approvalMode: "auto-review"
  • ACP session mode agent, model grok-4.5

Repro:

  1. Global ~/.cursor/cli-config.json with approvalMode: "auto-review".
  2. Drive cursor-agent acp (client below) and prompt it to run read-only commands: pwd, cat package.json, date.
  3. Result: all three trigger session/request_permission — even though auto-review’s classifier should auto-run non-mutating inspections.
  4. Add a project .cursor/permissions.json with terminalAllowlist: ["pwd","cat","date"] and autoRun.allow_instructions: ["Allow read-only commands …"]. Re-run.
  5. Result: still prompts for all three — no change.
  6. Discriminating test: put a bogus key in .cursor/permissions.json → ACP server starts with no error (file not validated/read). Put a bogus key in .cursor/cli.json → ACP server rejects it with a schema validation error at startup (this file is read).

Captured IDs (live runs, one session per command, all prompted under auto-review):

[pwd]
  sessionId:   6c34e8fe-06ce-4a16-b74e-41ca80c57ad3
  request id:  0
  toolCallId:  call-8cb3b224-920f-4fa0-bff5-33f3f36e8e56-0
               fc_c31a79fd-d95d-9c4e-a2de-9cdb3e66964f_0
  kind/title:  execute / `pwd`

[cat package.json]
  sessionId:   a1eca519-9be3-4fe2-9b54-46834a381fcd
  request id:  0
  toolCallId:  call-c32e79a0-d05a-4076-8ab7-45dda8733556-0
               fc_04de762f-36cc-9a9a-8de4-f61684c40133_0
  kind/title:  execute / `cat package.json`

[date]
  sessionId:   3925867d-4d53-41ae-9983-beb85ca6fb81
  request id:  0
  toolCallId:  call-924e354d-03d0-411e-ac51-d956eff9da28-0
               fc_9357da0c-d646-983a-98be-0f80c75949d7_0
  kind/title:  execute / `date`

Expected: Under auto-review, the classifier and autoRun instructions should apply in ACP (read-only commands auto-run; autoRun/terminalAllowlist from permissions.json honored).

Actual: Auto-review’s distinctive behavior is entirely absent in ACP; .cursor/permissions.json is ignored; only permissions.allow static tokens in cli.json/cli-config.json and approvalMode: unrestricted have any effect.

Impact: Users who configure auto-review + autoRun rules (the documented recommended setup) get a full manual-approval experience through any ACP client, with no indication their config is being ignored.

Suggested fix: Honor approvalMode: auto-review (classifier + autoRun) in ACP mode, and read .cursor/permissions.json in ACP — or, at minimum, document that ACP only consults cli.json/cli-config.json permissions.allow + approvalMode, and surface a warning when a permissions.json is present but ignored.


Attachment — minimal ACP repro client (acp-repro.mjs)

Run with node acp-repro.mjs <cwd> "<prompt>". It auto-approves any permission request (so the run completes) and logs the sessionId + every session/request_permission with its ids. For this ticket, run with prompts such as "Run exactly this shell command and nothing else: pwd".

import { spawn } from "node:child_process";

const cwd = process.argv[2] ?? process.cwd();
const text = process.argv[3] ?? "Run exactly this shell command and nothing else: pwd";

const child = spawn("cursor-agent", ["acp"], { cwd, stdio: ["pipe", "pipe", "pipe"] });
let buf = "";
let id = 0;
const pending = new Map();

const send = (method, params) => {
  const msg = { jsonrpc: "2.0", id: ++id, method, params };
  child.stdin.write(JSON.stringify(msg) + "\n");
  return new Promise((r) => pending.set(msg.id, r));
};
const respond = (rid, result) =>
  child.stdin.write(JSON.stringify({ jsonrpc: "2.0", id: rid, result }) + "\n");

child.stdout.on("data", (d) => {
  buf += d.toString();
  let i;
  while ((i = buf.indexOf("\n")) >= 0) {
    const line = buf.slice(0, i);
    buf = buf.slice(i + 1);
    if (!line.trim()) continue;
    let m;
    try { m = JSON.parse(line); } catch { continue; }
    if (m.method === "session/request_permission") {
      const tc = m.params.toolCall ?? {};
      console.log(
        `PERMISSION_REQUEST jsonrpc.id=${m.id} toolCallId=${tc.toolCallId} ` +
        `kind=${tc.kind} title=${JSON.stringify(tc.title)}`,
      );
      // auto-approve so the turn completes
      respond(m.id, { outcome: { outcome: "selected", optionId: m.params.options?.[0]?.optionId } });
    } else if (m.id && pending.has(m.id)) {
      pending.get(m.id)(m);
      pending.delete(m.id);
    }
  }
});
child.stderr.on("data", (d) => process.stderr.write("[stderr] " + d));

await send("initialize", {
  protocolVersion: 1,
  clientCapabilities: { fs: { readTextFile: true, writeTextFile: true } },
});
const sess = await send("session/new", { cwd, mcpServers: [] });
console.log(
  `sessionId=${sess.result.sessionId} currentMode=${sess.result.modes?.currentModeId} ` +
  `model=${sess.result.models?.currentModelId}`,
);
await send("session/prompt", { sessionId: sess.result.sessionId, prompt: [{ type: "text", text }] });
child.kill();
process.exit(0);

Hi there!

We detected that this may be a bug report, so we’ve moved your post to the Bug Reports category.

To help us investigate and fix this faster, could you edit your original post to include the details from the template below?

Bug Report Template - Click to expand

Where does the bug appear (feature/product)?

  • Editor, Tab & Chat (autocomplete, Composer, in-editor agent)
  • Terminal & commands
  • Models, pricing & API keys (availability, Auto/Max, BYOK/Bedrock)
  • MCP & tools
  • Cloud Agents & Automations (cursor.com/agents, scheduled/event)
  • BugBot & Code Review
  • Cursor CLI
  • Cursor Mobile
  • Remote (SSH / Dev Containers / WSL)
  • Account, billing & login
  • Something else…

Describe the Bug
A clear and concise description of what the bug is.


Steps to Reproduce
How can you reproduce this bug? We have a much better chance at fixing issues if we can reproduce them!


Expected Behavior
What is meant to happen here that isn’t working correctly?


Screenshots / Screen Recordings
If applicable, attach images or videos (.jpg, .png, .gif, .mp4, .mov)


Operating System

  • Windows 10/11
  • MacOS
  • Linux

Version Information

  • For Cursor IDE: Menu → About Cursor → Copy
  • For Cursor CLI: Run agent about in your terminal
IDE:
Version: 2.xx.x
VSCode Version: 1.105.1
Commit: ......

CLI:
CLI Version 2026.01.17-d239e66

For AI issues: which model did you use?
Model name (e.g., Sonnet 4, Tab…)


For AI issues: add Request ID with privacy disabled
Request ID: f9a7046a-279b-47e5-ab48-6e8dc12daba1
For Background Agent issues, also post the ID: bc-…


Additional Information
Add any other context about the problem here.


Does this stop you from using Cursor?

  • Yes - Cursor is unusable
  • Sometimes - I can sometimes use Cursor
  • No - Cursor works, but with this issue

The more details you provide, the easier it is for us to reproduce and fix the issue. Thanks!