macOS TCC permissions are bound to versions/<version> instead of the signed bundle, so Screen Recording and Accessibility must be re-granted after every update
Summary
On macOS, Claude Code's Screen Recording and Accessibility (Apple Events) grants are attributed to the per-version executable at ~/.local/share/claude/versions/<version> rather than to the signed app bundle. Two consequences:
- The permission dialog is unidentifiable. It names the process
2.1.224, so the user sees a bare version number with no indication it is Claude Code. I denied it initially for exactly this reason — I had no idea what was asking. - The grant does not survive an update. Because the path contains the version, each release is a different executable to TCC, so every update silently loses the permission. Claude Code updates frequently; I have four versions on disk (
2.1.221–2.1.224) from a short window.
The net effect is that any workflow depending on screen capture or UI scripting breaks after each update, with no error that points at the cause — the tools just start failing.
Why this looks like an attribution bug rather than expected behaviour
The bundle is present and properly signed with a stable identity:
$ codesign -dv ~/.local/share/claude/ClaudeCode.app
Identifier=com.anthropic.claude-code
TeamIdentifier=Q6L2SF6YDW
So a stable TCC subject already exists. The process that actually triggers the prompt is a child of the bundle's main executable:
/bin/zsh
└─ ~/.local/share/claude/versions/2.1.224 ← TCC attributes here
└─ ~/.local/share/claude/ClaudeCode.app/Contents/MacOS/claude
└─ ~/.local/bin/claude
TCC keys on the responsible process. Because the versioned binary is the responsible process rather than the bundle, the grant is recorded against a path that changes on every release, instead of against com.anthropic.claude-code, which does not.
Reproduction
- On macOS, run a Claude Code session that calls
screencapture, orosascript -e 'tell application "System Events" ...'. - Observe the permission prompt names a bare version number (e.g.
2.1.224), not Claude Code. - Grant it. Restart Claude Code. The tool now works.
- Let Claude Code update to a new version.
- The same call fails again:
screencapture -x out.png→could not create image from displayosascript→execution error: Not authorized to send Apple events to System Events. (-1743)
- System Settings → Privacy & Security shows the previously granted entry still listed under the old version number, now inert.
Suggested fix
Make the bundle the responsible process for TCC, so grants key on com.anthropic.claude-code and persist across updates. Options that would each address it:
- Launch the versioned binary as a bundled helper (inside
ClaudeCode.app/Contents/) with the bundle as its responsible process, rather than from a siblingversions/directory. - Set the responsible process explicitly for the spawned child so TCC attributes to the parent bundle.
- Failing either, keep a stable path (e.g.
versions/currentas a symlink target that is itself the executed path) so the TCC subject does not change per release.
A secondary improvement regardless of the above: the prompt should present a recognisable name. Even when attribution is correct, a dialog reading 2.1.224 gives the user nothing to decide on, and the safe default is to deny.
Environment
- Claude Code 2.1.224
- macOS 26.6 (build 25G72), Apple silicon
- Install path:
~/.local/share/claude/, launcher~/.local/bin/claude - Affected APIs: Screen Recording (
screencapture), Accessibility / Apple Events (osascript→ System Events)
Related
- #63037 — docs omit the macOS Privacy & Security identity for background agents. Adjacent, but that is a documentation gap; this is that the identity itself is unstable.
- #74631 — Computer Use per-app
request_access. Different mechanism.