Skip to content

dupe-com/agent-mac-ops

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

22 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

agent-mac-ops

agent-mac-ops

Operate your always-on Mac by talking to an AI agent —
and work on it remotely like you're sitting right in front of it.

FeaturesThe problemRequirementsQuickstartHow it worksWhat this is not


Features

  • 🤖 Drive it with an AI agent. Point Claude or Codex at control/ops/ and say "check on the box" — it SSHes in, reports uptime / disk / load / dev-session health in plain language, and revives a wedged session. No SSH commands typed by you.
  • 🖥️ Native remote terminal sessions. One command opens the remote as native, resizable panes — real Cmd+D / Cmd+T splits connected to the remote, normal keys, auto-colored so you never confuse it with localhost. Works in iTerm2 (tmux -CC) and Ghostty (native splits), auto-detected. (how it's done →)
  • Instant-feeling typing on slow links. box-mosh connects over mosh for predictive local echo, so characters appear immediately even over high latency.
  • 🔐 Log in without Screen Sharing. Remote auth pages open on your Mac, and OAuth localhost callbacks reach the right machine — ports are forwarded automatically and remote browser opens are handed back to your laptop. (details →)
  • 📋 Clipboard bridge (optional). Enable install-clip-watch.sh and screenshots you copy locally auto-mirror to the remote's clipboard — Ctrl+V them straight into a tool running on the remote. Prefer no background watcher? Push on demand with box-clip.
  • 🧑‍💻 code . for the remote. Run code-box in the remote session and your laptop's Cursor (or VS Code) opens in Remote-SSH mode at that folder — so the editor runs locally, on the remote's files. Or box-code from a cold laptop shell, no session needed. Reuses the handoff listener.
  • 📦 Painless file transfer & forwarding. box-push / box-pull move files without typing the host; box-fwd forwards ad-hoc ports (including random OAuth callbacks).
  • 🔪 Reclaim a busy port in one keypress. Port management grew up and moved into its own project: ports-cli — an interactive TUI of every local TCP listener, grouped by category and aware of the ssh forwards this repo creates (your forwarded dev server shows as DEV (SSH), not mystery noise). One keypress kills the holder; it also manages auto-reconnecting kubectl port-forwards. brew install dupe-com/tap/ports-cli. A minimal fzf fallback ships in control/bin/ports.sh — the shell snippet only aliases it when ports-cli isn't installed.
  • 📊 Optional daily health digest to Slack / Discord / any webhook.

The problem

You've got a Mac that never sleeps — a Studio under the desk, an old MacBook on a shelf — and you want to actually use it from your laptop. In practice that means a pile of ssh one-liners, Screen Sharing that feels like molasses, remote shells that don't behave like local ones, and logins that break because the OAuth callback points at the wrong machine. When the dev session wedges, you're the one SSHing in to debug it.

agent-mac-ops turns that always-on Mac into something you operate by talking to an agent and connect to as a native-feeling session — as close to "sitting in front of it" as a remote box gets.

Requirements

  • macOS + iTerm2 or Ghostty on the control machine — for the native-window magic. iTerm2 uses tmux -CC (Terminal.app won't do it, WezTerm only partially); Ghostty (≥ 1.2.0) uses native splits that each auto-ssh in. box auto-detects which you're using. (The agent-ops half — status/logs/revive/digest — is plain SSH + bash and works against any host.)
  • tmux on the remote (brew install tmux).
  • mosh (optional, for box-mosh) on both ends — ./setup.sh remote installs it on the remote; brew install mosh locally. Needs UDP 60000–61000 reachable (Tailscale carries it).
  • SSH reachability to the remote. Tailscale is the recommended way (no public exposure, works from anywhere) but anything your ssh can reach is fine — just put a Host alias in ~/.ssh/config and use its name.
  • python3 and curl on the control machine (both ship with macOS) for the optional webhook digest.

Quickstart

git clone https://github.com/dupe-com/agent-mac-ops && cd agent-mac-ops
./setup.sh            # prompts for host, hostname, dirs, alias, webhook → writes config.env
./setup.sh remote     # pushes the dev-session launcher to the remote

# add to ~/.zshrc, BEFORE your iTerm2 shell-integration line:
source /path/to/agent-mac-ops/control/shell-snippet.sh

# iTerm2: follow SETUP.md for the profile + Automatic Profile Switching (the coloring)
# Ghostty: nothing else to do — see SETUP.md §4b

Now:

  • box (or whatever alias you chose) → native, colored window into the remote (iTerm2 -CC panes, or Ghostty native splits — auto-detected). Ghostty adds box-tmux for a persistent session that survives disconnect.
  • box-mosh (either terminal) → connect over mosh for snappy, predictive typing when the link is laggy. Single session + tmux for persistence; forwards/handoff still ride the SSH master.
  • Point your agent at control/ops/ and say "check on the box."
  • Browser handoff: control/bin/install-open-listener.sh so remote auth pages open on your Mac.
  • Clipboard auto-mirror: control/bin/install-clip-watch.sh so screenshots you copy here land on the remote's clipboard automatically — Ctrl+V them in a tool on the remote, no command in between.
  • Open the remote in your local editor: inside the session, code-box (current dir) opens Cursor/ VS Code on your Mac in Remote-SSH mode; from a local shell, box-code [path]. Needs the handoff listener (install-open-listener.sh) and the host in your ~/.ssh/config.
  • ports → see every local TCP listener and kill the holder in one keypress. Install ports-cli (brew install dupe-com/tap/ports-cli) for the full TUI — it classifies the ssh forwards this repo creates as DEV (SSH) instead of system noise. Without it, the shell snippet falls back to the bundled fzf picker (control/bin/ports.sh).
  • Optional: control/ops/bin/install-launchd.sh for a daily health digest.

How it works

control machine (your laptop)                     always-on Mac (the remote)
─────────────────────────────                     ──────────────────────────
shell-snippet.sh  → `box` ───────── ssh -t ───▶   ~/dev-session.sh
   (iTerm2)                                          └─ tmux -CC attach  ──▶ native iTerm2 windows
   (Ghostty) ghostty-connect.sh ─── ssh -t ───▶      └─ login shell / tmux ─▶ native Ghostty splits
   (mosh)    `box-mosh` ───────── mosh/UDP ────▶      └─ tmux attach ───────▶ predictive-echo session
control/ops/AGENTS.md  ← your agent reads this
control/ops/bin/remote-run.sh ── ssh + stdin ──▶   status.sh / logs.sh / revive.sh (run, then gone)
control/ops/bin/daily-check.sh ── launchd ──▶      webhook digest (Slack/Discord/…)
open-listener.py  ◀── reverse tunnel (-R) ─────    ~/bin/open shim (opens auth URLs on your Mac)
your localhost:3000  ◀── forward (-L) ─────────    remote dev server / OAuth callback
  • Config lives in one file. config.env (gitignored, written by setup.sh) holds the host, hostname, work dir, alias, webhook, etc. Every script sources it; the two *.tmpl files are rendered from it.
  • The remote stays stateless. Only ~/dev-session.sh lives there. The health scripts are shipped over SSH on stdin with config prepended, so there's nothing to install or keep in sync.
  • No secrets in git. The only optional secret is the notify webhook, and it lives in the gitignored config.env. Use a webhook URL, never a bare token.

What this is not

Deliberately small. It does not sync dotfiles, manage packages, or sync editor settings — use chezmoi / yadm / GNU stow for that. This repo is just the above: agent-operable + a native-feeling remote session.

License

MIT — see LICENSE.

About

Operate your always-on Mac with an AI agent + connect as native iTerm2 or Ghostty windows. Includes remote OAuth/localhost forwarding & browser handoff.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors