Repository navigation
feat(desktop): run the macOS Host under its own identity - #6587
Conversation
Native Computer Use on macOS needs Accessibility and Screen Recording, which macOS grants to the application that started the Host. Without them the first AX call failed with an opaque -25211 deep inside a tool. Check both grants before native work, ask macOS to show its request the first time one is missing, and fail with a single permission_required: line naming the application to allow. The check is a real call (an AX query to this user's Dock, a ScreenCaptureKit listing), because AXIsProcessTrusted and CGPreflightScreenCaptureAccess keep their first answer in a Host without a run loop; a grant the user turns on is seen by the next call without restarting the Host. A confirmed grant is remembered, and failures that a missing grant explains (AX -25211, a refused ScreenCaptureKit listing) check again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
macOS grants privacy permissions such as Accessibility and Screen Recording to the application responsible for a process. The Host belonged to whichever application started it first: Maka, or the terminal a CLI ran in. Users had to find and allow that application, and a grant could follow the wrong one. Maka.app now carries Helpers/Maka Host.app. Its executable starts itself again with responsibility disclaimed and runs the Host, passing stdio through, forwarding termination signals and returning the Host's status. Interactive, activation and launchd starts run the Host through it, so its grants belong to "Maka Host". macOS ties a grant to the bytes of the helper's executable, and each package lives in a directory of its own. The helper is therefore copied once into the account data directory and replaced only when a package carries a higher bundle version. Without a helper, the Host runs directly as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rmissions-20261103
Generated-by: Codex
Generated-by: Codex
M4n5ter
left a comment
There was a problem hiding this comment.
English
The cleanup is pushed in d1744d200. This branch now includes the #6582 fix and the latest rust-preview, with no merge conflicts.
The separate Host helper has a concrete purpose: keeping the macOS permission identity stable across launch paths. I kept that design and the packaging checks for its identity, executable contents and executable permissions. I removed the assertions that pinned both helper version fields to 1; those assertions only repeated the current constant and would need changing during a legitimate helper upgrade.
Validation: the related packaging/build/launcher tests passed 9/9 locally. The actual macOS helper launch and TCC attribution were not exercised on this WSL machine. The new GitHub CI run is currently queued.
简体中文
已在 d1744d200 完成精简。该分支已包含 #6582 的修复和最新 rust-preview,没有合并冲突。
独立 Host helper 有明确用途:让不同启动路径使用稳定的 macOS 授权身份。因此保留了这套设计,以及对 helper 身份、可执行文件内容和执行权限的打包验证。删除了将两个 helper 版本字段写死为 1 的断言;它们只是在复述当前常量,正常升级 helper 时也会要求改测试。
验证:相关打包、构建和启动器测试本地 9/9 通过。WSL 下未实测 macOS helper 启动和 TCC 授权归属。新的 GitHub CI 目前仍在排队。
Stacked on #6582.
macOS grants privacy permissions such as Accessibility and Screen Recording to the application responsible for a process. The Host belonged to whichever application started it first: Maka, or the terminal a CLI ran in. So users had to find and allow that application, and a grant could follow the wrong one. Allowing a terminal also gives the permissions to everything else that terminal runs.
Maka.appnow carriesContents/Helpers/Maka Host.app. Its executable starts itself again with responsibility disclaimed (responsibility_spawnattrs_setdisclaim), then runs the Host. It passes stdio through, forwards SIGTERM/SIGINT/SIGHUP and exits with the Host's status. Interactive, activation and launchd starts run the Host through it, so the request dialog and System Settings name "Maka Host". Without a helper, the Host runs directly as before.Choices the diff does not explain on its own:
~/Library/Application Support/Maka/Maka Host.appand replaced, atomically withRENAME_SWAP, only when a package carries a higherCFBundleVersion. A new build of the same version keeps the copy and its grants; moving a byte-identical bundle keeps them too (measured on macOS 26.6). BumpinghostApp.versioninscripts/rust/build-cli.mjsmakes every user grant again. A launchd service installs the helper only when it starts, not when it is observed, stopped or removed.makawithhost candidateorhost service-run, so it is not a general way to borrow its grants. A process of the same account can still replace thatmaka, so the grants protect no more than the account does; Developer ID signing would not change that.DISCLAIMERin fix(release): ship the standard disclaimer in Rust distributions #6500, so an older CLI rejects a package that carries it.Review follow-up
The branch includes the updated permission-probe implementation and latest
rust-preview. Packaging tests still validate the helper identity, executable and permissions, without pinning its bundle version to the current value.AI use
Tool(s) and scope: Claude Code wrote the change and this description, and ran the macOS permission experiments; the commit carries
Co-Authored-By: Claude Opus 5.5. Codex implemented the review follow-up fixes.