[BUG] Claude Code app bundle lacks NSBluetoothAlwaysUsageDescription — child processes get hard-killed instead of prompted with Routines
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
When Claude Code (or a process it spawns, e.g. via the Bash tool) triggers a macOS Bluetooth permission check (kTCCServiceBluetoothAlways), the request is refused outright instead of showing the normal user permission dialog - especially in Claude Code Routines!
This happens because Claude Code's app bundle Info.plist does not declare an NSBluetoothAlwaysUsageDescription key. Without this key, macOS's TCC daemon cannot show a permission prompt at all — it silently denies the request. Confirmed via log show:
Refusing authorization request for service kTCCServiceBluetoothAlways and subject
Sub:{com.anthropic.claude-code}Resp:{TCCDProcess: identifier=com.anthropic.claude-code, ...}
without NSBluetoothAlwaysUsageDescription key
For comparison, other apps that do declare this key (e.g. Terminal.app) get a normal prompt (AUTHREQ_PROMPTING → user clicks Allow → Granting), and everything proceeds normally.
Impact: Any child process launched from Claude Code (e.g. a browser automated via Bash/Playwright) that happens to trigger a Bluetooth-related API call — even indirectly, e.g. via a website's device-fingerprinting/bot-detection script — gets hard-killed by macOS (SIGABRT) instead of just being denied Bluetooth access gracefully. The parent Claude Code session survives, but the spawned process crashes outright, which can silently break long-running automation tasks with no clear error message pointing to the real cause (it just looks like a random crash).
Expected behavior: Either (a) Claude Code's Info.plist should declare NSBluetoothAlwaysUsageDescription so macOS can prompt the user normally instead of hard-refusing, or (b) at minimum, child processes should be able to fail gracefully (Bluetooth API call returns "denied") rather than being terminated.
Workaround found: Running the same script via a user LaunchAgent (launchd) instead of through Claude Code avoids the issue entirely, because the "responsible process" TCC attributes the Bluetooth request to is then the script's own interpreter, not Claude Code.
What Should Happen?
Workaround found: Running the same script via a user LaunchAgent (launchd) instead of through Claude Code avoids the issue entirely, because the "responsible process" TCC attributes the Bluetooth request to is then the script's own interpreter, not Claude Code.
Error Messages/Logs
Steps to Reproduce
Workaround found: Running the same script via a user LaunchAgent (launchd) instead of through Claude Code avoids the issue entirely, because the "responsible process" TCC attributes the Bluetooth request to is then the script's own interpreter, not Claude Code.
Claude Model
Opus
Is this a regression?
Yes, this worked in a previous version
Last Working Version
_No response_
Claude Code Version
Claude 1.20186.0 (d7731e)
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
_No response_