Cli: Permission allowlist written to global config instead of project-level `.cursor/cli.json`

Where does the bug appear (feature/product)?

Cursor CLI

Describe the Bug

When running cursor agent inside a project that has .cursor/cli.json, granting a permission writes the entry to ~/.cursor/cli-config.json (global) instead of the project-level .cursor/cli.json. Because the project-level file takes precedence, the granted permission is never recognized and the permission dialog reappears every time.

Steps to Reproduce

  1. Create a project with a minimal .cursor/cli.json:
$ cat .cursor/cli.json
{}
  1. Confirm ~/.cursor/cli-config.json has empty permissions:
{
  "permissions": {
    "allow": [],
    "deny": []
  }
}
  1. Run cursor agent inside the project and trigger a web fetch
  2. When prompted, press tab to choose “Always allow …”

→ The entry is written to ~/.cursor/cli-config.json, not to .cursor/cli.json

  1. Run cursor agent again — the same permission dialog reappears

Expected Behavior

The allowed entry is written to the project-level .cursor/cli.json, which takes precedence over the global config.

Screenshots / Screen Recordings

Operating System

MacOS

Version Information

About Cursor CLI

CLI Version 2026.05.09-0afadcc
Model Composer 2 Fast
Subscription Tier Pro
OS darwin (arm64)
Terminal ghostty
Shell bash
User Email

Additional Information

After allowing “Always allow forum.cursor.com”, ~/.cursor/cli-config.json is updated:

{
  "permissions": {
    "allow": [
      "WebFetch(forum.cursor.com)"
    ],
    "deny": []
  }
}

But .cursor/cli.json remains {} and takes priority, so the permission is never applied.

Does this stop you from using Cursor

Sometimes - I can sometimes use Cursor

Hey, thanks for the detailed report and the repro steps. The “Always allow” behavior really only writes an entry to ~/.cursor/cli-config.json, that’s the current implementation. It doesn’t write to the project-level config. This should be improved, and I’ll log it as a bug.

One quick question so I can understand which exact case you’re hitting. After step 4 when you press tab and pick “Always allow forum.cursor.com”, can you share the exact contents of .cursor/cli.json?

cat .cursor/cli.json

Scenario A: if the file is still {}, the global permission should be picked up on the next run via deep merge, and the dialog shouldn’t show again. If it still prompts, that’s an extra bug besides only writing to global.

Scenario B: if the file has a permissions section, even an empty one like { "permissions": { "allow": [], "deny": [] } }, that explains the repeated prompt. The empty project-level arrays override the global allow list during merge. In that case, the workaround is to add the needed entries manually to .cursor/cli.json:

{
  "permissions": {
    "allow": ["WebFetch(forum.cursor.com)"],
    "deny": []
  }
}

As another temporary workaround, you can run cursor agent --disable-project-configs so the CLI ignores the project config and uses only the global config.

Let me know what the file looks like after you grant it, then I can report it to the team more accurately.

Thanks for the clarification! After testing, this is Scenario B.

My actual .cursor/cli.json has a permissions section with existing entries:

{
  "permissions": {
    "allow": ["Shell(ls)"],
    "deny": []
  }
}

After granting “Always allow forum.cursor.com”, the file remained unchanged, and the entry was written to ~/.cursor/cli-config.json instead. Since the project-level config takes priority, the dialog reappears every time.

As a side note, I also tested with .cursor/cli.json = {} (no permissions key at all). In that case, the global config was picked up correctly and the dialog did not reappear — so the deep merge works fine when there is no project-level permissions section.

To summarize: the bug is triggered when .cursor/cli.json contains a permissions section. The workaround of manually adding entries to .cursor/cli.json works. Thanks for logging it!