Turning a spare Mac into a dedicated Claude Code machine
A new guide provides a detailed walkthrough for converting a spare Mac into an always-on machine that Claude Code can control with full computer use capabilities. The setup enables users to interact with the agent from a phone through the Claude app or from a primary Mac over SSH.
The guide, published on GitHub Pages, was created by a developer who wanted a separate environment for Claude Code to control independently. This allows delegation of tasks that the user prefers not to run on their main machine, such as certain research and development work.
Claude Code, particularly when run with the , dangerously-skip-permissions flag, carries inherent risks on a primary machine. The guide explains that these risks can be eliminated or mitigated by creating a separate environment on a spare Mac with everything the agent needs to access.
An additional benefit is the ability to communicate with Claude Code anytime and anywhere from a phone. The author notes that they often prefer talking to Claude Code over the regular Claude mobile app because Claude Code is frequently more capable.
The guide assumes the user has a main Mac and a spare Mac for setup, but the approach can be adapted to any combination of two machines.
Why not just use a container?
The guide addresses why a container-based approach may not be sufficient. The author built an entire environment for running Claude Code in a container but found several limitations.
First, a container still runs on the main machine, so it is not completely separated. Network requests sent by the container still go through the primary machine.
Second, containers have capability limitations. For example, if the user wants the agent to run Unity for game development, there is no easy way to do that in a container. The same applies to any other app only available on a Mac. This is especially relevant when using computer use features that involve clicking, dragging, and other interactions.
The author prefers having access to the full, latest features of Claude Code and the ability to control it from the Claude app. Running the agent with broad permissions on a machine with nothing to lose is safer, while still providing the benefits of a full Mac instead of a container.
Step 1: Erase the machine (optional but recommended)
The guide recommends giving the agent full access to the machine, so it can reach anything stored on it. If there is existing data the user does not want the agent to access, the machine should be erased first.
After erasing, the user can optionally update to the latest macOS through System Settings, General, Software Update.
The account needs admin rights, or sudo will refuse to run.
Step 2: Enable SSH on the target Mac
On the target Mac, SSH must be turned on so the source Mac can connect. The command is:
sudo systemsetup -setremotelogin on
If the command fails with a message about needing Full Disk Access privileges, the user must give the terminal app Full Disk Access first.
Step 3: Set up passwordless sudo
This step allows the agent and SSH commands to run admin tasks without a password prompt each time. The command runs once on the target and asks for the login password that one time:
echo "<user> ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/<user>-nopasswd > /dev/null
sudo chmod 440 /etc/sudoers.d/<user>-nopasswd
sudo visudo -cf /etc/sudoers.d/<user>-nopasswd
This creates a small rule file telling the Mac that the user can run sudo without a password prompt. After this, sudo runs with no prompt. The user can test with sudo -n true, which succeeds silently if passwordless sudo works.
Step 4: Find the target's address
The target can be reached by either a hostname or an IP address. The guide recommends using the hostname because it stays the same while the IP can change.
To get the hostname, run on the target:
scutil , get LocalHostName
This prints the hostname, such as MacBook-Pro. Adding .local forms the address: <target-host>.local. The hostname can also be read from System Settings, General, Sharing, shown as Local hostname.
The target should have a unique name. Each Mac needs a .local name that is unique on the network. If two machines share a name, the address can point to the wrong Mac. The target's name can be renamed if needed:
sudo scutil , set LocalHostName newmacbook
This results in newmacbook.local.
The IP address can be found with:
ipconfig getifaddr en0
But the IP can change after a reboot or after a certain amount of time.
Throughout the guide, <user> should be replaced with the target account name and <target-host> with the hostname, so the address is <user>@<target-host>.local. An IP can be used in place of <target-host>.local.
Step 5: Set up SSH key authentication
On the source Mac, create an SSH key if one does not already exist:
ssh-keygen -t ed25519
Install the public key on the target. This asks for the target account's login password once:
ssh-copy-id <user>@<target-host>.local
Test the connection. This should print the target username with no password prompt:
ssh <user>@<target-host>.local whoami
Step 6: Keep the target awake
By default, macOS sleeps after about 10 minutes idle, even when plugged in, which takes it off the network. To make it never sleep, run these commands on the target or over SSH from the source:
sudo pmset -c sleep 0
sudo pmset -c disablesleep 1
sudo pmset -c displaysleep 0
These settings prevent system sleep while plugged in, prevent sleep with the lid closed in clamshell mode, and keep the display on.
Verify with:
pmset -g | grep -iE 'sleep'
If the output shows sleep 0, SleepDisabled 1, and displaysleep 0, it worked.
If the machine sometimes runs on battery, 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. To stop the screen saver from ever starting:
defaults -currentHost write com.apple.screensaver idleTime 0
Step 7: Clipboard sync over SSH
macOS ships with pbcopy for writing to the clipboard and pbpaste for reading from it. Piped over SSH, they can move the clipboard between machines in an encrypted, peer-to-peer manner without requiring an Apple ID or third-party service.
A script called clip.sh wraps this into one command with two subcommands and adds image support on top of pbcopy and pbpaste, which are text-only. Install it as a script on the PATH on the source Mac and point it at the target host with IC_BOX:
curl -fsSL https://raw.githubusercontent.com/ykdojo/claude-controls-mac/main/clip.sh -o ~/.local/bin/clip
chmod +x ~/.local/bin/clip
export IC_BOX="<user>@<target-host>.local"
The export line should be added to ~/.zshrc.
Step 8: Install Claude Code on the target
Send the install command over and run it. From the source Mac, the user can push it straight to the target's clipboard or run it remotely. The following command installs a specific version, but the latest or stable version can also be installed:
ssh <user>@<target-host>.local 'curl -fsSL https://claude.ai/install.sh | bash -s , 2.1.201'
The native installer may warn that ~/.local/bin is not on PATH. Fix it on the target by adding it to ~/.zshenv, not ~/.zshrc, because .zshenv is read by every zsh, including non-interactive ones:
ssh <user>@<target-host>.local 'echo '\''export PATH="$HOME/.local/bin:$PATH"'\'' >> ~/.zshenv'
Step 9: Set up an opinionated Claude Code-friendly environment (optional)
This optional step applies a set of opinionated defaults via a script called setup-claude-env.sh. It includes shell aliases, the DX plugin, settings.json tweaks, the GitHub CLI, and opt-in tools like Playwright MCP and yt-dlp. Every item is toggleable.
For interactive setup on the target, the script shows a checklist of every item with core items pre-checked and opt-ins unchecked. Download the script onto the target and run it:
ssh -t <user>@<target-host>.local \
'curl -fsSL https://raw.githubusercontent.com/ykdojo/claude-controls-mac/main/setup-claude-env.sh -o setup-claude-env.sh && bash setup-claude-env.sh'
For non-interactive setup, the script goes into this mode if it detects a non-interactive environment or if at least one flag is supplied. No prompt is shown. It installs core only by default, or the user can pick what they want with flags like , yt-dlp, , playwright, , all, or , core:
Stay ahead of the AI curve
The most important updates, news, and content — delivered weekly.
No spam. Unsubscribe anytime.
ssh <user>@<target-host>.local \
'curl -fsSL https://raw.githubusercontent.com/ykdojo/claude-controls-mac/main/setup-claude-env.sh -o setup-claude-env.sh && bash setup-claude-env.sh , all'
The script is idempotent, so it is safe to re-run.
Step 10: Authenticate Claude Code and GitHub
To authenticate Claude Code, SSH into the target:
ssh <user>@<target-host>.local
Then run claude on the target. It drops into the login for the Anthropic account. The user follows the prompts, which involve a browser or device-code flow that can be completed from a browser on the main Mac.
GitHub authentication is optional but highly recommended so the agent can work with repositories:
gh auth login
If the GitHub CLI was not installed from the previous step, the user should install it first. The guide recommends using a separate GitHub account, not the main one, to avoid messing up the primary account.
Step 11: Enable computer use over SSH
This step allows an interactive Claude session on the target to see screenshots and control its own desktop using mouse and keyboard, driven over SSH.
This does not work out of the box because SSH and macOS's permission model get in the way. macOS gates screen capture and input behind Screen Recording and Accessibility permissions that are tied to the GUI login session, so an SSH process cannot reach the display.
The fix involves a LaunchAgent that 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. The user attaches over SSH.
Run this command:
ssh -t <user>@<target-host>.local \
'curl -fsSL https://raw.githubusercontent.com/ykdojo/claude-controls-mac/main/setup-computer-use.sh -o setup-computer-use.sh && bash setup-computer-use.sh'
This installs the LaunchAgent, which creates a persistent tmux server with an anchor session called cc, and enables the built-in computer-use tool in ~/.claude.json. It requires tmux, which can be installed with brew install tmux, and a Claude Pro or Max plan. The script is re-runnable, and , uninstall removes it.
Step 12: Install ic.sh on the source Mac
The ic.sh script, where "ic" stands for "isolated Claude," is installed on the source Mac:
curl -fsSL https://raw.githubusercontent.com/ykdojo/claude-controls-mac/main/ic.sh -o ~/.local/bin/ic
chmod +x ~/.local/bin/ic
echo 'export IC_BOX="<user>@<target-host>.local"' >> ~/.zshrc
Each ic command spawns its own Claude session on the box, and multiple sessions can run at once. Flags mirror claude, and several additional subcommands are available:
ic: Start a new Claude sessionic -c: Continue the most recent conversationic -r: Resume pickeric , chrome: Start with Claude in Chromeic sh: A plain shell on the box, no Claudeic rc: Remote Control, drive the box from a phoneic history: Show stored conversations with count, location, and recent previewsic ls: List live sessions with state, age, what is running, and conversationic attach <id>: Attach a running sessionic kill <id>: Kill a sessionic kill-all: Kill all sessionsic kill-except <id> <id> ...: Kill all sessions except the listed onesic -h: Help
All ic sessions run with , dangerously-skip-permissions, and ic rc uses , permission-mode bypassPermissions.
For copying text out, sessions run in tmux, and Terminal.app cannot receive the clipboard escape sequences that Claude emits. A quick workaround is to use Cmd-A then Cmd-C to copy the whole visible screen.
Agent-to-agent prompting
Because every ic session lives on the box's tmux server at a fixed socket, a Claude Code session on the source Mac can prompt one directly over SSH. This is useful for delegating work to the box and checking on it.
First, find the session with ic ls. Then send a prompt into it with:
ssh <user>@<target-host>.local "tmux -S /tmp/cc-tmux.sock send-keys -t <session> 'Switch to main and pull; PR #4 is merged.' Enter"
sleep 2
ssh <user>@<target-host>.local "tmux -S /tmp/cc-tmux.sock send-keys -t <session> Enter"
To read the reply, run:
ssh <user>@<target-host>.local "tmux -S /tmp/cc-tmux.sock capture-pane -t <session> -p" | tail -30
One-time grants for computer use
Screen Recording and Accessibility permissions can only be granted in the GUI, and a human must do it at the machine in person or via Screen Sharing. macOS blocks synthetic clicks on these prompts. On first capture, the user will also need to allow a "bypass the window picker" prompt, which recurs about monthly.
The grants go on tmux, not Claude. macOS attributes capture and control to the responsible process in the chain, which here is the tmux server because Claude runs as its child.
To make the entries appear in System Settings in the first place, trigger a computer-use action by running ic and asking Claude to take a screenshot. macOS adds tmux to the list toggled off so the user can switch it on.
Full Disk Access stops the "access data from other apps" prompts. On newer macOS, tmux triggers a separate prompt for each app whose data anything inside it touches. Granting tmux Full Disk Access in the same Privacy and Security pane suppresses these prompts entirely. The user should use the + button and add the tmux binary, then restart the tmux server.
Optional: VPN on the box
The author prefers to run a VPN on the box so its traffic goes out separately from the local IP. They use Proton VPN, which has a free option, but other options are available.
The user can ask the box's Claude to install the VPN by running ic and saying "install Proton VPN." The agent will download and install the app. The parts it cannot do alone include clicking through the installer prompts, granting system extensions, and logging in. This general flow works for most other applications as well.
Remote Control from phone
Remote Control lets the user drive Claude Code from a phone through the Claude app. There are two ways to use it. If the user went through step 11, ic rc starts that server in a way that sessions spawned from the phone have access to computer use.
Claude in Chrome extension
Computer use from step 11 deliberately will not control a browser. Browsers get a restricted tier where Claude can see what is on screen but cannot click or type in it. The Claude in Chrome extension fills that gap with proper browser control, including navigating, clicking, filling forms, and reading console logs and network requests. Unlike Playwright MCP, it drives the regular Chrome profile, so the agent can use any logged-in state set up on the box.
It requires Chrome on the target and a direct Anthropic plan such as Pro, Max, Team, or Enterprise.
The user can ask the box's Claude to install Chrome and open the extension's Chrome Web Store page. The parts it cannot do alone include clicking through the installer prompts and clicking the extension's install button. These must be done at the machine in person or via Screen Sharing.
Then enable it in Claude Code on the target by running /chrome in a session and selecting "Enabled by default" to have the browser tools in every session. Alternatively, use claude , chrome per session or ic , chrome from the source Mac. If the connection does not work, try restarting Chrome once.
To make browser use efficient with element refs from the accessibility tree instead of coordinates and no unrequested screenshots, the environment setup from step 9 adds a "Claude for Chrome" guidance section to ~/.claude/CLAUDE.md on the target. If that step was skipped, re-run the script as it is idempotent.
If the source Mac's Chrome also has the extension signed into the same account, Claude Code can connect to either browser. It prompts the user to pick when both are connected, but its local-machine detection can be wrong. To avoid this, the user can temporarily uninstall the extension from the source Mac's Chrome or just quit Chrome on the source while the box is working.
Sessions spawned from a phone via step 13 do not currently get the browser tools. The workaround is to start the session in the terminal and attach with /rc.
Screen Sharing for visual access
This feature lets the user see the target's screen live from the source Mac and take over its mouse and keyboard using macOS's built-in Screen Sharing.
This must be enabled in the GUI at the machine because since macOS 12.1 it cannot be enabled from the command line.
On the target, go to System Settings, General, Sharing, and turn on Screen Sharing. If Remote Management is on, the Screen Sharing toggle may be hidden, so turn it off first.
From the source Mac, connect with:
open vnc://<user>@<target-host>.local
Log in with the target account's login password and tick "Remember this password in my keychain."
Tailscale for remote access
.local names only resolve on the local network, so everything described so far is local-network only, except phone control which relays through Anthropic. Tailscale fixes this by connecting machines with peer-to-peer, end-to-end encrypted WireGuard tunnels. SSH, ic, clip, and Screen Sharing work from any network with nothing exposed to the public internet. On the home network, it takes a direct LAN path, so local use stays as fast as before. Joining the network only gives a device reachability, and SSH and Screen Sharing still require the key or password on top.
Install Tailscale on the target. The Homebrew formula works headless over SSH:
ssh <user>@<target-host>.local 'brew install tailscale'
ssh <user>@<target-host>.local 'sudo brew services start tailscale'
ssh <user>@<target-host>.local 'sudo tailscale up , operator=<user>'
Sign in at the URL the last command prints. A free account with a social login is fine.
Install on the source, then open the Tailscale app and log in with the same account. Devices only see each other within one account's network:
brew install , cask tailscale-app
With MagicDNS, which is on by default, the target is reachable by bare hostname from anywhere, the same address minus .local. Switch IC_BOX in ~/.zshrc, keeping the original name for reference:
export IC_BOX="<user>@<target-host>"
Screen Sharing works the same way: open vnc://<user>@<target-host>.
The guide recommends enabling device approval in the admin console under Settings, Device management, so a compromised Tailscale login alone cannot add a device to the network. It also recommends disabling key expiry on the target under Machines so the box does not drop off the network when its key expires after about 180 days.
To confirm remote access really works, put the source Mac on a different network, such as a phone hotspot, and run ic ls.

