remote-mac
Health Uyari
- License — License: MIT
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 7 GitHub stars
Code Basarisiz
- rm -rf — Recursive force deletion command in tests/smoke.sh
Permissions Gecti
- Permissions — No dangerous permissions requested
Bu listing icin henuz AI raporu yok.
Control a remote Mac from Linux/VPS over SSH with two bash scripts: run commands, take screenshots, open/quit apps, scp files, and check channel status as JSON. Built as a remote-Mac layer for AI agents (OpenClaw skill). 从 Linux/VPS 通过 SSH 远程控制 Mac。
remote-mac
remote-mac lets you control a remote Mac from a Linux server or VPS over SSH — run commands, take screenshots, open/quit apps and transfer files — with two plain bash scripts (only ssh, scp and python3 needed locally). Built for AI agents (e.g. OpenClaw) and automation that need hands on a real macOS machine.
从 Linux / VPS 通过 SSH 远程控制 Mac:执行命令、截屏、控制 App、传文件,适合 AI agent 使用。
What it does
| Script | Purpose |
|---|---|
mac_exec.sh |
Run commands, take screenshots, control apps, transfer files |
channel_check.sh |
Check SSH (and an optional bridge URL) availability, output JSON |
Works well paired with OpenClaw as a remote Mac control layer for AI agents.
Requirements
On the machine running the scripts (Linux / VPS):
bash,ssh,scppython3— used bychannel_check.shand for JSON escapingcurl— only if you setMAC_BRIDGE_URL
On the Mac:
- Remote Login enabled (System Settings → General → Sharing → Remote Login).
- SSH key login configured (your public key in
~/.ssh/authorized_keyson the Mac). The scripts useBatchMode=yes, so password login does not work. - For screenshots and app control: the Mac must be logged in to a desktop session with the screen unlocked.
Quick start
# 1. Clone
git clone https://github.com/ythx-101/remote-mac.git
cd remote-mac
# 2. Configure (copy example, fill in your SSH host/user)
cp remote-mac.conf.example ~/.remote-mac.conf
$EDITOR ~/.remote-mac.conf
# 3. Run
bash scripts/mac_exec.sh --run "sw_vers"
Not sure the connection works? Run bash scripts/channel_check.sh first (see Channel status).
Or configure via environment variables (no config file needed):
export MAC_SSH_HOST="your-mac-ip-or-hostname"
export MAC_SSH_USER="your-username"
export MAC_SSH_PORT="22" # default: 22
Usage
bash scripts/mac_exec.sh --help # list all commands
Run a remote command
bash scripts/mac_exec.sh --run "ls -la ~"
bash scripts/mac_exec.sh --run "brew list"
bash scripts/mac_exec.sh --run "some-long-script.sh" 120 # custom timeout (seconds)
Screenshot
bash scripts/mac_exec.sh --screenshot # saves to /tmp/mac_screenshot.png
bash scripts/mac_exec.sh --screenshot /tmp/myscreen.png
Requires an active desktop session. Won't work if the screen is locked.
App control
bash scripts/mac_exec.sh --app "open:Safari"
bash scripts/mac_exec.sh --app "activate:Finder"
bash scripts/mac_exec.sh --app "quit:Safari"
bash scripts/mac_exec.sh --app "kill:AppName" # force kill via pkill -x
File transfer
# Mac → local
bash scripts/mac_exec.sh --file "get:~/Desktop/report.pdf:/tmp/report.pdf"
# local → Mac
bash scripts/mac_exec.sh --file "put:/tmp/script.sh:~/Desktop/"
The argument format is get|put:src:dst. Remote paths are passed to scp as-is (no extra quoting), so ~/... works. For paths containing spaces, escape them with a backslash when downloading (e.g. get:~/My\ Files/a\ b.txt:/tmp/); how scp treats spaces in upload destinations depends on the scp protocol in use (legacy vs SFTP), so prefer space-free destination paths for put.
Channel status (JSON)
bash scripts/channel_check.sh
{
"timestamp": "2026-03-03T07:42:00Z",
"ssh": { "available": true, "latency_ms": 42, "target": "[email protected]:22" },
"ag_bridge": { "available": false, "latency_ms": 0, "status": "" },
"preferred": "ssh"
}
Configuration
All config via ~/.remote-mac.conf or environment variables:
| Variable | Default | Description |
|---|---|---|
MAC_SSH_HOST |
mac.local |
SSH hostname or IP (Tailscale, LAN, etc.) |
MAC_SSH_USER |
current user | SSH username on the Mac |
MAC_SSH_PORT |
22 |
SSH port |
MAC_BRIDGE_URL |
(empty) | Optional: Antigravity bridge health URL |
REMOTE_MAC_CONF |
~/.remote-mac.conf |
Custom config file path |
REMOTE_MAC_CONTROL_DIR |
auto | Override SSH ControlPath directory |
See remote-mac.conf.example for a commented template.
When to use (and when not)
| Option | Good fit | Notes |
|---|---|---|
Plain ssh |
You only need a shell on the Mac | remote-mac builds on ssh/scp and adds one command set for screenshots, app control and file transfer, plus JSON channel status |
| VNC / macOS Screen Sharing | You need to watch the live screen or use the mouse and keyboard | remote-mac does not stream the screen or simulate mouse input; --screenshot takes a single still image |
| OpenClaw Node | You already run an OpenClaw Node on the Mac | Can serve as a second channel next to SSH (see Dual-channel) |
| remote-mac | A Linux server, VPS or AI agent needs to run commands, grab screenshots, open/quit apps or move files on a Mac | Two bash scripts, no extra software on the Mac beyond Remote Login |
FAQ
How do I control a Mac from Linux / a VPS? / 怎么从 Linux 远程控制 Mac?
Enable Remote Login and SSH key login on the Mac, set MAC_SSH_HOST / MAC_SSH_USER, then run bash scripts/mac_exec.sh --run "sw_vers". See Requirements and Quick start.
Why do I get "Mac SSH unreachable" or "permission denied"?
Typical causes: Remote Login is off, your SSH key is not authorized on the Mac, or the host / port is wrong. Run bash scripts/channel_check.sh — if ssh.available is false, fix the SSH connection first (try the same ssh -p <port> user@host by hand).
Why is my screenshot failing or blank?screencapture needs an active desktop session, so it will not work with a locked screen or without a graphical session. It may also be worth checking the Mac's screen-recording permissions for the SSH session.
Can I use it over Tailscale?
Yes — set MAC_SSH_HOST to the Mac's Tailscale IP or name.
Is it safe?
See Security: host keys use accept-new, app names are shell-escaped and passed via argv, and no secrets are hard-coded.
Does it work with password login?
No. The scripts run ssh with BatchMode=yes, which disables password prompts. Use SSH keys.
How do AI agents use it?
As a skill or shell tool: the agent calls scripts/mac_exec.sh with --run, --screenshot, --app or --file, and can parse the JSON from scripts/channel_check.sh to see whether the Mac is reachable. See SKILL.md.
Security
- No hardcoded secrets — all config via env vars or
~/.remote-mac.conf(never committed) StrictHostKeyChecking=accept-new— non-interactive but won't silently accept changed host keys- Shell injection protection — app names are single-quoted via
shell_escape(); AppleScript usesargvpassing - JSON injection protection — all dynamic values in
channel_check.shoutput are encoded viapython3 json.dumps - Portable ControlPath — uses
XDG_RUNTIME_DIR→TMPDIR→~/.cache/remote-mac(works on both Linux and macOS)
Dual-channel architecture
When used with OpenClaw, you can keep two independent control channels to the same Mac — SSH and OpenClaw Node — as mutual fallbacks:
┌─────────────┐
│ VPS │
└──────┬──────┘
│
┌────────────┴────────────┐
│ │
SSH (mac_exec.sh) OpenClaw Node
any shell command persistent WebSocket
via OpenClaw
│ │
└────────────┬────────────┘
│
┌──────▼──────┐
│ Mac │
└─────────────┘
| Channel | How | Best for |
|---|---|---|
| SSH | mac_exec.sh via ssh |
Any shell command, file transfer, screenshots |
| OpenClaw Node | nodes.run tool built into OpenClaw |
AI agent workflows when a Node is installed on the Mac |
channel_check.sh checks the SSH channel and, if MAC_BRIDGE_URL is set, that optional bridge health URL (reported as ag_bridge). It does not check the OpenClaw Node channel — call that yourself from OpenClaw with nodes.run. The preferred field is ssh when SSH is reachable and none otherwise:
bash scripts/channel_check.sh
# → { "ssh": { "available": true }, "ag_bridge": { ... }, "preferred": "ssh" }
If preferred is none, try the Node channel from OpenClaw.
Tips
Keep Mac awake:
bash scripts/mac_exec.sh --run "caffeinate -d &"
SSH multiplexing is enabled by default (ControlMaster=auto, ControlPersist=10m). First connection is slow; subsequent calls reuse the connection.
Tailscale: set MAC_SSH_HOST to your Mac's Tailscale IP to reach it outside your local network.
License
MIT
Yorumlar (0)
Yorum birakmak icin giris yap.
Yorum birakSonuc bulunamadi