该方案通过 SSH 从主 Mac 连接,并可通过手机上的 Claude 应用控制,从而在主机器上隔离风险。 指南建议在备用 Mac 上创建不含个人数据的新本地账户,并配置无密码 sudo 权限。
这里有一个完整的逐步指南,教你如何将闲置的 Mac 变成一台 Claude Code 可以完全控制的全天候运行机器,并且可以启用计算机使用功能。你可以通过 Claude 应用从手机与它对话,或者通过 SSH 从你的主 Mac 与它连接。
如果你是在 GitHub Pages 上阅读本文,这里是仓库版本:https://github.com/ykdojo/claude-controls-mac。
我想创建一个 Claude Code 可以独立控制的独立环境,这样我就可以委派一些我不一定想在自己机器上运行的任务——某些类型的研究任务和开发任务。
Claude Code,尤其是在启用了 --dangerously-skip-permissions 标志时,在你的主机上运行具有固有风险。你可以通过在备用 Mac 上创建一个包含所需全部访问权限的独立环境来消除或降低这些风险。
它还有一个额外的好处,就是可以随时随地通过手机与 Claude Code 对话。我个人发现这非常有用,因为我经常更喜欢与 Claude Code 对话,而不是在移动应用上使用普通 Claude——Claude Code 通常更强大。
以下指南假设你有你的主 Mac 以及可以用于设置的备用 Mac,但你应该能够从中获得灵感,并将其应用到任意两台机器的组合中。
首先,让我们快速回答你可能有的一些问题。
我非常支持在容器中运行它——我甚至构建了一个方便运行的完整环境:https://github.com/ykdojo/safeclaw。不过,我发现它有一些限制。首先,它仍然在主机上运行,所以并不是完全隔离的。例如,它发送的网络请求仍然通过你的主机。
其次,容器的功能是有限的。例如,我希望我的代理能够运行 Unity 进行游戏开发,而在容器中没有简单的方法做到这一点。对于任何仅适用于 Mac 的应用程序也是同样的情况——你将无法访问它。尤其是如果你希望 Claude Code 通过计算机使用来控制这些应用程序——点击、拖动等等,这一点尤其相关。
我个人喜欢能够使用 Claude Code 的完整最新功能。我也喜欢能够通过 Claude 应用程序来控制它——我发现这非常方便。而且,如果你恰好有 Claude 订阅,还可以使用你的订阅额度,这是一个额外的好处。
归根结底,在一台没有资产风险的机器上运行具有广泛权限的代理更安全——但你也可以享受到使用完整 Mac 而不是容器的好处。这里的方法:
你将给予代理对这台机器的完全访问权限,因此它可以访问存储在其中的任何内容。如果有不希望其访问的现有数据,先清空机器:
可选择随后更新到最新 macOS(系统设置 -> 通用 -> 软件更新)。
账户需要管理员权限,否则 sudo 会拒绝运行。
在目标设备上开启 SSH,以便源 Mac 可以连接:
如果命令失败并显示“开启或关闭远程登录需要完全磁盘访问权限”,先给予你的终端应用完全磁盘访问权限:
这是为了让代理(以及你的 SSH 命令)能够运行管理员任务,而不必每次都提示输入密码。在目标上运行一次即可。它只会请求一次登录密码:
这会创建一个小的规则文件,告诉 Mac 可以在运行 sudo 时不提示密码:
之后,sudo 将无需提示即可运行——通过 sudo -n true 测试,如果免密码 sudo 生效,将默默成功。
你可以通过主机名或 IP 地址访问目标。我推荐使用主机名:它保持不变,而 IP 地址可能会改变。
主机名(推荐)。在目标设备上运行:
添加 .local 来形成地址:.local。你也可以在系统设置 -> 通用 -> 共享中查看,本地显示为 Local hostname。
给目标设备一个唯一名称。每台 Mac 需要在网络上拥有唯一的 .local 名称。如果两台设备名称相同,地址可能指向错误的 Mac。确保目标名称唯一——如有需要请重命名:
IP 地址(不推荐)。在目标设备上运行:
请注意,IP 地址在重启后或经过一段时间后可能会改变。
在本指南的其余部分,用目标账户名和上面提到的主机名替换,这样地址就是 @ .local。你也可以用 IP 代替 .local。
在源 Mac 上创建一个 SSH 密钥(如果你已经有了可以跳过):
在目标上安装你的公钥。这会要求输入一次目标账户的登录密码:
进行测试 —— 这应该会显示目标用户名而不提示输入密码:
默认情况下,macOS 在闲置约 10 分钟后会进入睡眠,即使插着电源,这会使其脱离网络。要让它永不睡眠,在目标上(或者通过源上的 SSH)运行此命令:
sleep 0、SleepDisabled 1 和 displaysleep 0 的输出显示成功。
如果机器有时用电池供电,使用 -a 替代 -c,以应用到所有电源来源(代价是电池消耗较大)。
屏幕保护程序启动时屏幕仍可能锁定。阻止屏幕保护程序启动,这样它就不会自动锁定:
macOS 自带 pbcopy(写入剪贴板)和 pbpaste(读取剪贴板)。通过 SSH 管道,它们可以在机器之间移动剪贴板内容 —— 加密、点对点,无需 Apple ID 或第三方服务。
clip.sh:/claude-controls-mac/clip.sh 将此命令封装为一个带两个子命令的命令,并在 pbcopy / pbpaste(仅限文本)基础上增加了图像支持。在源 Mac 上将其安装为 PATH 中的脚本,并用 IC_BOX 指向目标主机(“ic”代表“isolated claude”):
发送安装命令并运行。从源 Mac 你可以直接推送到目标的剪贴板,或者远程运行。以下命令安装特定版本,但你也可以选择安装最新或稳定版本:
本机安装程序可能会警告 ~/.local/bin 不在 PATH 中。在目标上通过将其添加到 ~/.zshenv (不是 ~/.zshrc)来修复 —— .zshenv 会被每个 zsh 读取,包括非交互式的:
此可选步骤通过 setup-claude-env.sh:/claude-controls-mac/setup-claude-env.sh 应用一组推荐的默认设置:包括 shell 别名、DX 插件、settings.json 调整、GitHub CLI,以及(可选择的)Playwright MCP 和 yt-dlp。每个项目都可以开启或关闭;完整列表见 claude-env-components.md:/claude-controls-mac/claude-env-components.html。
目标界面交互式——显示每个物品的清单(核心已预勾,未勾选的选择),方便你选择任意组合。将脚本下载到目标上并运行:
非交互式——如果脚本检测到非交互环境或你提供至少一个标志,就会进入此模式。没有提示;默认只安装 Core,或者用 flags ( --yt-dlp, --playwright, --all, --core ) 来选择你想要的:
这个脚本是幂零的(可以重播)。
两个登录都是交互式的,所以 SSH 在:
然后在目标上运行 Claude——它会直接进入你的 Anthropic 账户登录。按照提示操作(你可以在主Mac上的浏览器完成的浏览器/设备代码流程)。
GitHub——可选,但强烈推荐,这样代理能处理仓库:
如果你还没安装上一步的 GitHub CLI:#9-setup-up-opinionated-claude-code-friendly-environment-optional,务必先安装。
我个人建议用一个独立的 GitHub 账号,而不是主账号,这样就不会影响主账号。
这使得目标节点上的交互式 claude 会话能够看到(截图)并控制(鼠标/键盘)自己的桌面,通过 SSH 驱动。
这开箱即用是不行的——SSH和macOS的权限模型会阻碍,所以下面设置就是为了绕过这些问题而设。
为什么需要变通:macOS 将屏幕录制和输入设置在与 GUI 登录会话绑定的屏幕录制和无障碍权限后面,因此 SSH 进程无法访问该显示器。修复方法:LaunchAgent 在固定套接字的 GUI 会话中保持 tmux 服务器存活;每个在那里创建的 Claude 会话都会落在该服务器并继承 GUI 会话,因此可以访问显示界面。你通过SSH连接。
在目标上运行 setup-computer-use.sh:/claude-controls-mac/setup-computer-use.sh:
这会安装 LaunchAgent(带有锚点会话 cc 的持久 tmux 服务器),并启用 ~/.claude.json 中的内置计算机使用工具。需要 tmux(brew 安装 tmux)和 Claude Pro 或 Max 套餐。可重播;——卸载以移除。
在源 Mac 上安装 ic.sh:/claude-controls-mac/ic.sh ( ic = “isolated claude”):
每个 ic 都会在服务器上生成自己的 Claude 会话(可以同时运行多个)并附加。标志与 Claude 相同,并且增加了几个子命令:
所有 ic 会话都使用 --dangerously-skip-permissions(并且 ic rc 使用 --permission-mode bypassPermissions)。
复制文本:会话运行在 tmux 中,而 Terminal.app 无法接收 Claude 发出的剪贴板转义序列(OSC52),因此用鼠标选择文本片段不会可靠地复制到 Mac 剪贴板。快速解决方法:Cmd-A 然后 Cmd-C 可以复制整个可见屏幕。
因为每个 ic 会话都驻留在服务器的 tmux 服务器上的固定套接字中,你的源 Mac 上的 Claude Code 会话可以通过 SSH 直接提示它——这对于将工作委托给服务器并进行检查很有用,代理对代理:
屏幕录制和辅助功能只能在 GUI 中授予,必须由人亲自在机器上执行(现场或通过屏幕共享)——macOS 会阻止对这些提示进行模拟点击。在第一次捕获时,你还需要允许一个“绕过窗口选择器”的提示(大约每月重复一次)。
权限授予的是 tmux,而不是 Claude。macOS 将捕获/控制归因于链中负责的进程,这里是 tmux 服务器(Claude 作为其子进程运行)。所以:
为了让条目首次出现在系统设置中,触发一个电脑使用操作(ic,然后让 Claude “截屏”)——macOS 会将 tmux 添加到列表中(默认关闭),这样你就可以打开它。
我个人喜欢在服务器上运行 VPN,这样它的流量就会与我的本地 IP 分开。我使用 Proton VPN——它有免费选项,我已经使用很长时间了——当然,也有其他选项。
Here’s a full step-by-step guide on how to turn your spare Mac into an always-on machine Claude Code can fully control, with computer use enabled. You’ll be able to talk to it from your phone through the Claude app, or from your main Mac over SSH.
In case you’re reading this on GitHub Pages, here’s the repo version:https://github.com/ykdojo/claude-controls-mac.
I wanted to create a separate environment Claude Code can control on its own, so I can delegate tasks I don’t necessarily want to run on my own machine - certain types of research tasks, and development tasks.
Claude Code, especially with the --dangerously-skip-permissions flag on, carries inherent risk when run on your main machine. You can eliminate / mitigate these risks by creating a separate environment on your spare Mac with everything it needs to have access to.
It has an added bonus of being able to talk to Claude Code anytime, anywhere from your phone. I’ve personally found it really useful because I often prefer to talk to Claude Code instead of regular Claude on the mobile app - Claude Code is often more capable.
The following guide assumes you have your main Mac as well as a spare Mac you can set up for this, but you should be able to take inspiration from it and apply it to any combination of two machines.
First, let’s quickly address a few questions you might have.
I’m a big proponent of running it in a container - I even built an entire environment for doing so conveniently:https://github.com/ykdojo/safeclaw. However, I’ve found it has a few limitations. First, it still runs on your main machine, so it’s not completely separated. For example, network requests it sends still go through your main machine.
Second, there are limitations to the container’s capabilities. For example, I wanted my agent to be able to run Unity for game development, and there’s no easy way to do that in a container. The same goes for any other app that’s only available on a Mac - you won’t have access to it. That’s especially relevant if you want Claude Code to control these apps through computer use - clicking, dragging, and so on.
I personally like having access to the full, latest features of Claude Code. I also like being able to control it from the Claude app - I’ve found it really convenient. And you get to use your Claude subscription usage if you happen to have one, which is an added bonus.
At the end of the day, running an agent with broad permissions is safer on a machine that has nothing to lose - but you get the benefit of being able to use a full Mac instead of a container. The approach here:
You’ll be giving the agent full access to this machine, so it can reach anything stored on it. If there’s existing data you don’t want it to have access to, erase the machine first:
Optionally update to the latest macOS afterward (System Settings -> General -> Software Update).
The account needs admin rights or sudo will refuse to run.
On the target , turn on SSH so the source Mac can connect:
If the command fails with Turning Remote Login on or off requires Full Disk Access privileges , give your terminal app Full Disk Access first:
This is so the agent (and your SSH commands) can run admin tasks without a password prompt each time. Run this once on the target. It asks for the login password this one time:
This creates a small rule file telling the Mac that can run sudo without a password prompt:
After this, sudo runs with no prompt - test with sudo -n true , which succeeds silently if passwordless sudo works.
You can reach the target by either a hostname or an IP. I recommend using the hostname: it stays the same, while the IP can change.
Hostname (recommended). Run on the target:
Add .local to form the address: .local . You can also read it from System Settings -> General -> Sharing, shown as Local hostname .
Give the target a unique name. Each Mac needs a .local name that’s unique on your network. If two machines share a name, the address can point to the wrong Mac. Make sure the target’s name is unique - rename it if needed:
IP address (not recommended). Run on the target:
Note that the IP can change after a reboot or after a certain amount of time.
Throughout the rest of this guide, replace with the target account name and with the hostname from above, so the address is @ .local . You could also instead use an IP in place of .local .
On the source Mac, create an SSH key (skip if you already have one):
Install your public key on the target. This asks for the target account’s login password once:
Test it - this should print the target username with no password prompt:
By default macOS sleeps after ~10 minutes idle, even when plugged in, which takes it off the network. To make it never sleep, run this on the target (or over SSH from the source):
sleep 0 , SleepDisabled 1 , and displaysleep 0 in the output confirm it worked.
If the machine runs on battery sometimes, use -a instead of -c to apply to all power sources (at the cost of battery drain).
The screen can still lock when the screen saver kicks in. Stop the screen saver from ever starting so it never locks on its own:
macOS ships pbcopy (write clipboard) and pbpaste (read clipboard). Piped over SSH, they can move the clipboard between machines - encrypted, peer-to-peer, no Apple ID or third-party service.
clip.sh :/claude-controls-mac/clip.sh wraps this into one command with two subcommands, and adds image support on top of pbcopy / pbpaste (which are text-only). Install it as a script on your PATH on the source Mac, and point it at the target host with IC_BOX (“ic” standing for “isolated claude”):
Send the install command over and run it. From the source Mac you can push it straight to the target’s clipboard, or run it remotely. The following command installs a specific version, but you can also install latest or stable if you’d like:
The native installer may warn that ~/.local/bin is not on PATH. Fix it on the target by adding it to ~/.zshenv (not ~/.zshrc ) - .zshenv is read by every zsh, including non-interactive ones:
This optional step applies a set of opinionated defaults via setup-claude-env.sh :/claude-controls-mac/setup-claude-env.sh - shell aliases, the DX plugin, settings.json tweaks, the GitHub CLI, and (opt-in) Playwright MCP and yt-dlp. Every item is toggleable; see the full list in claude-env-components.md :/claude-controls-mac/claude-env-components.html.
Interactively on the target - shows a checklist of every item (core pre-checked, opt-ins unchecked) so you can pick any combination. Download the script onto the target and run it:
Non-interactively - the script goes into this mode if it detects a non-interactive environment or you supply at least one flag. No prompt; installs core only by default, or pick what you want with flags ( --yt-dlp , --playwright , --all , --core ):
The script is idempotent (OK to re-run).
Both logins are interactive, so SSH in:
Then run claude on the target - it drops into the login for your Anthropic account. Follow the prompts (a browser/device-code flow you can finish from a browser on your main Mac).
GitHub - optional, but highly recommended so the agent can work with repos:
If you haven’t installed the GitHub CLI from the previous step:#9-set-up-an-opinionated-claude-code-friendly-environment-optional, make sure to do so first.
I personally recommend using a separate GitHub account, not your main one, so it doesn’t mess up your main account.
This lets an interactive claude session on the target see (screenshots) and control (mouse/keyboard) its own desktop, driven over SSH.
This doesn’t work out of the box - SSH and macOS’s permission model get in the way, so the setup below exists to route around that.
Why it needs a workaround: macOS gates screen capture and input behind Screen Recording and Accessibility permissions that are tied to the GUI login session, so an SSH process can’t reach the display. Fix: a LaunchAgent keeps a tmux server alive inside the GUI session on a fixed socket; every claude session created there lands on that server and inherits the GUI session, so it can reach the display. You attach over SSH.
Run setup-computer-use.sh :/claude-controls-mac/setup-computer-use.sh on the target:
This installs the LaunchAgent (persistent tmux server with anchor session cc ) and enables the built-in computer-use tool in ~/.claude.json . Requires tmux ( brew install tmux ) and a Claude Pro or Max plan. Re-runnable; --uninstall to remove.
Install ic.sh :/claude-controls-mac/ic.sh ( ic = “isolated claude”) on the source Mac:
Each ic spawns its own claude session on the box (run several at once) and attaches. Flags mirror claude , and it adds several more subcommands:
All ic sessions run with --dangerously-skip-permissions (and ic rc uses --permission-mode bypassPermissions ).
Copying text out: sessions run in tmux, and Terminal.app can’t receive the clipboard escape sequences (OSC52) that claude emits, so mouse-selecting a snippet won’t reliably reach your Mac clipboard. Quick workaround: Cmd-A then Cmd-C copies the whole visible screen.
Because every ic session lives on the box’s tmux server at a fixed socket, a Claude Code session on your source Mac can prompt one directly over SSH - useful for delegating work to the box and checking on it, agent to agent:
Screen Recording and Accessibility can only be granted in the GUI, and a human has to do it at the machine (in person or via Screen Sharing) - macOS blocks synthetic clicks on these prompts. On first capture you’ll also Allow a “bypass the window picker” prompt (recurs ~monthly).
The grants go on tmux , not claude . macOS attributes capture/control to the responsible process in the chain, which here is the tmux server (claude runs as its child). So:
To make the entries appear in System Settings in the first place, trigger a computer-use action ( ic , then ask Claude to “take a screenshot”) - macOS adds tmux to the list (toggled off) so you can switch it on.
I personally like to run a VPN on the box so its traffic goes out separately from my local IP. I use Proton VPN - it has a free option and I’ve been using them for a long time - but of course there are other options.