
You kick off a two-hour build on your remote Mac, close your laptop to board a flight, and land to find the build died at the fifteen‑minute mark. Two things killed it: the terminal that your remote-desktop client opened sent a hangup signal when the connection dropped, and the Mac idled into sleep because nothing was holding a power assertion. Fix both and builds, test runs, and long data jobs will outlast every disconnect.
Direct recommendation. On Figment, the $29 virtual Intel macOS host is the practical persistent build target for Intel-compatible toolchains, including supported Xcode 26-or-earlier workflows. Access is through the browser console, so when you close the tab the guest keeps running — your tmux session, your caffeinate process, and whatever it is wrapping. Pick the M-series tier from $95/month when you need Apple silicon execution (ARM-only binaries, Xcode 27, or visionOS); exact chip, RAM and disk are confirmed in the quote. Request a configuration.
The tmux behaviour below is from the tmux(1) manual; LaunchAgent behaviour is from Apple's Creating launchd Jobs. Xcode/Intel limits come from Apple's porting notes at developer.apple.com.
When a remote-desktop client closes, the login session's windowing stack tears down any terminal windows it owned. Processes started in those terminals are attached to a pseudo-terminal (pty). When the pty closes, the kernel delivers SIGHUP to the foreground process group, which terminates unless the process explicitly ignores it.
A second failure mode is idle sleep on physical Macs. macOS parks the system when no user activity is detected, so the network stack suspends and background jobs stall. The $29 virtual Intel macOS host has no hardware sleep path, but its desktop session can still blank its own screen saver, and you still want tmux there so a closed browser tab does not take the shell with it. On a physical M-series Mac both problems apply, so you want tmux and caffeinate.
tmux runs a server process that owns sessions independently of any client. Install once if not present:
brew install tmux
Start a named session before starting any long job:
tmux new-session -s build
Inside the session, run your build normally. To detach without killing it:
C-b d # detach — session and its processes keep running
After reconnecting, re-attach:
tmux attach-session -t build
| Task | Command |
|---|---|
| New named session | tmux new-session -s build |
| Detach, keep running | C-b d |
| List sessions | tmux ls |
| Re-attach by name | tmux attach-session -t build |
| Re-attach to most recent | tmux attach |
| Kill a finished session | tmux kill-session -t build |
| Rename | tmux rename-session -t old new |
| New window inside session | C-b c |
| Split pane left/right | C-b % |
| Split pane top/bottom | C-b " |
| Peek without attaching | tmux capture-pane -t build -p | tail -20 |
Use a naming convention so tmux ls is self-explanatory after a weekend away: job type plus a short date, e.g. release-20261110, tests-integration, data-etl.
caffeinate ships with macOS and takes an IOKit power-management assertion — the same mechanism Xcode uses when it shows "Preventing Sleep." No install required. It matters on physical hardware (Figment M-series, your own Mac Mini, a leased host); on the Intel VM it is harmless but mostly a no‑op because the guest has no real power manager.
Wrap a single job (the assertion is released when the command exits):
caffeinate -i make all 2>&1 | tee build.log
Hold one umbrella assertion for multiple jobs:
caffeinate -i &
echo "caffeinate PID: $!"
-i prevents idle sleep while letting the display dim. Add -d only if something needs the display on; -s prevents system sleep but only on AC power and so is relevant on Mac mini and Mac Studio hardware, not laptops on battery.
A LaunchAgent in ~/Library/LaunchAgents/ starts automatically when your user session opens and restarts the program if it ever exits. Put this at ~/Library/LaunchAgents/com.figment.caffeinate.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.figment.caffeinate</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/caffeinate</string>
<string>-i</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
</dict>
</plist>
Set permissions and load without rebooting:
chmod 600 ~/Library/LaunchAgents/com.figment.caffeinate.plist
launchctl load ~/Library/LaunchAgents/com.figment.caffeinate.plist
launchctl list | grep caffeinate # a PID in the first column means it is running
To stop it (for example, a laptop you want to let sleep):
launchctl unload ~/Library/LaunchAgents/com.figment.caffeinate.plist
Label, ProgramArguments, RunAtLoad and KeepAlive are the keys Apple documents for this pattern; man launchd.plist on the host lists every other key you may want (StandardOutPath, WorkingDirectory, EnvironmentVariables, and so on).
On a physical Figment M-series host or any other dedicated Mac, add a system-level backstop:
Never for a build host.These settings persist across reboots and pair cleanly with the LaunchAgent above.
Once the job is running in tmux and caffeinate is live, you rarely want an open remote-desktop session to it. Three light-weight ways to check progress:
Write the build to a log inside the session, then detach:
# inside tmux
make all 2>&1 | tee ~/builds/release.log
# C-b d
Peek at the live pane without attaching:
tmux capture-pane -t build -p | tail -40
Tail the log file from any shell on the host:
tail -f ~/builds/release.log
On the $29 virtual Intel macOS host, "any shell on the host" means a second terminal window inside the browser console; inbound public SSH is not part of that plan. On an M-series plan, confirm the exact access method (browser console, VNC, or other) in the quote before you build tooling around it.
Start at /mac-hosting or request a configuration and state your toolchain, target architecture, and whether you need the box to survive browser or network disconnects for hours or days at a time.