Operations 26 min read

Build a 24/7 Remote AI Agent Hub in 30 Minutes with macOS, Tailscale, hapi and tmux

This guide walks you through setting up a continuously running macOS mini as a remote AI Agent host, connecting it via Tailscale, managing sessions with hapi, synchronizing files with rsync, and keeping terminals alive using tmux, all within half an hour.

Lin is Dream
Lin is Dream
Lin is Dream
Build a 24/7 Remote AI Agent Hub in 30 Minutes with macOS, Tailscale, hapi and tmux

Agent pain points and goals

Three recurring issues when using Claude Code or Codex agents:

Agents pause for manual approval when permissions or unknown decisions arise.

No shared workspace or context across multiple devices.

Inability to trigger work from a phone while away.

The goal is a multi‑device setup where a Mac mini runs the Agent continuously, while a MacBook and iPhone act as remote controllers.

Build the Tailscale network

Tailscale creates a private virtual LAN (100.64.0.0/10) that connects the Mac mini, MacBook, and iPhone without exposing public ports.

Installation steps :

Download the macOS and iOS packages from https://tailscale.com/download and install.

Log in with the same Google, Microsoft, GitHub or Apple account on all devices.

Rename the Mac mini in the Tailscale admin UI (e.g., mini) and verify connectivity with ssh mini.

After registration, check connection type with tailscale status. If a DERP (relay) connection appears, run a self‑hosted relay node.

Network verification commands:

netstat -rn -f inet | grep '^default'   # default route interface
netstat -rn -f inet | grep 100           # Tailscale tailnet routes

Remote access service (SSH)

Enable Remote Login on the Mac mini (System Settings → Sharing → Remote Login) and verify with: sudo systemsetup -getremotelogin Generate an ed25519 key on the MacBook and copy it to the mini:

# Generate an ed25519 key
ssh-keygen -t ed25519 -C "mbp-to-mini"
# Copy the public key to the mini
ssh-copy-id your_user@mini

Add a shortcut to ~/.ssh/config:

Host mini
    HostName mini          # name from Tailscale device list
    User your_user
    IdentityFile ~/.ssh/id_ed25519
    ServerAliveInterval 60

File synchronization with rsync

Use the built‑in rsync tool over the Tailscale‑backed SSH connection for incremental sync.

# Local → remote
rsync -av --progress "local_dir" "mini:remote_dir"
# Remote → local
rsync -av --progress --partial "mini:remote_dir" "local_dir"

Define convenience functions in ~/.zshrc:

rcp() { rsync -av --progress "$1" "mini:$2"; }
lcp() { rsync -av --progress --partial "mini:$1" "$2"; }
source ~/.zshrc

Install and configure hapi

hapi ( https://github.com/tiann/hapi) provides a hub‑runner‑PWA architecture for Claude Code, Codex, Gemini, etc.

Install Node.js and Git, then install hapi globally:

brew install node git
npm install -g @twsxtd/hapi --registry=https://registry.npmjs.org

Run the hub once to generate ~/.hapi/settings.json, then edit the file to listen on all interfaces:

{
  "listenHost": "0.0.0.0",
  "listenPort": 3006
}

Create launchd plist files for the hub and runner (replace your_user and paths with actual values).

<?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.twsxtd.hapi.hub</string>
    <key>ProgramArguments</key>
    <array>
        <string>/opt/homebrew/bin/hapi</string>
        <string>hub</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
    <key>StandardOutPath</key>
    <string>/Users/your_user/.hapi/logs/hub.out.log</string>
    <key>StandardErrorPath</key>
    <string>/Users/your_user/.hapi/logs/hub.err.log</string>
</dict>
</plist>

Runner plist (example):

<?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.twsxtd.hapi.runner</string>
    <key>ProgramArguments</key>
    <array>
        <string>/opt/homebrew/bin/hapi</string>
        <string>runner</string>
        <string>start-sync</string>
        <string>--workspace-root</string>
        <string>/Users/your_user/Projects</string>
        <string>--workspace-root</string>
        <string>/Users/your_user/agentcode</string>
    </array>
    <key>EnvironmentVariables</key>
    <dict>
        <key>PATH</key>
        <string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
        <key>HAPI_CLAUDE_PATH</key>
        <string>/Users/your_user/.local/bin/claude</string>
    </dict>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
    <key>StandardOutPath</key>
    <string>/Users/your_user/.hapi/logs/runner.out.log</string>
    <key>StandardErrorPath</key>
    <string>/Users/your_user/.hapi/logs/runner.err.log</string>
</dict>
</plist>

Load the services:

mkdir -p ~/.hapi/logs
launchctl load ~/Library/LaunchAgents/com.twsxtd.hapi.hub.plist
launchctl load ~/Library/LaunchAgents/com.twsxtd.hapi.runner.plist
launchctl list | grep hapi   # should show hub and runner entries

Using hapi from a phone (PWA)

Open the hub URL in a mobile browser, e.g., http://mac-mini-m4:3006/. Log in with the access token from ~/.hapi/settings.json. The PWA lists Agent sessions; clicking a session opens a chat window for prompts, output, and permission management.

hapi wraps Claude Code commands (e.g., hapi codex, hapi cursor) so that the launched process registers with the hub and becomes visible in the PWA.

Session persistence with tmux

Install tmux on both MacBook and Mac mini: brew install tmux Create a long‑living session named work: tmux new -s work Re‑attach later with: tmux a -t work Enable mouse support and increase history limit:

echo -e "set -g mouse on
set -g history-limit 50000" >> ~/.tmux.conf
tmux source-file ~/.tmux.conf

Define a shortcut function in ~/.zshrc for quick re‑attach:

echo 'function ww() { tmux new -A -s work; }' >> ~/.zshrc && source ~/.zshrc

Remote desktop

Apple devices can use the built‑in Screen Sharing (Finder → Go → Connect to Server, vnc://mac-mini-m4). Windows users may use third‑party VNC tools.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

AI AgentmacOSSSHhapitmuxRemote AccessTailscale
Lin is Dream
Written by

Lin is Dream

Sharing Java developer knowledge, practical articles, and continuous insights into computer engineering.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.