Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

69 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Agent Stack

A macOS bootstrap that turns one Mac into a always-reachable host for running named AI agent sessions with GitHub Copilot CLI, Claude Code CLI, or Codex CLI. Choose a backend explicitly (agent-stack copilot alpha, agent-stack claude alpha, or agent-stack codex alpha) and reach it from any device (phone, tablet, another laptop) over Tailscale SSH and tmux, with Termius as the terminal client.

The end state: tap a host in Termius on your phone, land in the same agent CLI conversation your laptop left mid-thought.

This README is the full setup walkthrough — fresh Mac to phone to desktop. If you already have parts of this stack working, jump to the section you need from the table of contents.


Contents

  1. What you get
  2. How many agents?
  3. Prerequisites
  4. Part 1 — Server Mac setup
  5. Part 2 — iPhone (Termius iOS)
  6. Part 3 — Mac desktop (Termius)
  7. Daily use
  8. Configuration
  9. Uninstall
  10. Status & roadmap

What you get

  • A single multi-call wrapper (bin/agent) installed as agent-stack plus the descriptive aliases copilot-agent, claude-agent, and codex-agent. It launches or reattaches to a named agent session. Keychain unlock, tmux session management, and best-effort resumption of the previous CLI session for that name (Copilot: stable UUID via --session-id; Claude: --continue; Codex: resume --last when the workspace has history) are all handled.

    Each backend has its own workspace root and its own tmux session namespace, so the three never collide:

    • agent-stack copilot alpha$COPILOT_WORKSPACE_BASE/agent-alpha, tmux alpha
    • agent-stack claude alpha$CLAUDE_WORKSPACE_BASE/agent-alpha, tmux claude-alpha
    • agent-stack codex alpha$CODEX_WORKSPACE_BASE/agent-alpha, tmux codex-alpha

    Copilot keeps its established unprefixed tmux names. Claude and Codex use backend prefixes, so the three namespaces do not collide. Matching pre-release copilot-<name> sessions remain attachable but are not created.

  • A one-shot installer for OS-level prerequisites: Homebrew, tmux, Tailscale (CLI build), and the MagicDNS resolver fix that Homebrew's Tailscale formula leaves out.

  • An optional request_help MCP tool for Copilot CLI, Claude Code, and Codex CLI. A blocked agent can send one bounded iMessage identified by its NATO-alphabet tmux session. The tool opens temporary Screen Sharing and includes a clickable screens:// link using the Mac's actual Tailscale name.

  • Optional installation of dfrysinger/dreaming as a headless Copilot learning and skill-curation service, isolated from normal interactive agent context.

  • A symmetric uninstaller.

Command reference

Task Command
Launch or reattach Copilot agent-stack copilot <name> or copilot-agent <name>
Launch or reattach Claude agent-stack claude <name> or claude-agent <name>
Launch or reattach Codex agent-stack codex <name> or codex-agent <name>
Enable bounded Screen Sharing agent-screen on [1-8]
Disable Screen Sharing agent-screen off
Inspect Screen Sharing agent-screen status

How many agents?

Pick whatever count fits your workflow. The author runs about a dozen in practice — named after the NATO phonetic alphabet (alpha, bravo, charlie, delta, echo, foxtrot, golf, hotel, india, juliet, kilo, lima). The wrapper accepts any non-option name without / and prepends agent- to derive a workspace directory, so agent-stack copilot coordinator or claude-agent planner Just Work.

Names are case-sensitive end-to-end (tmux session, workspace directory, Copilot CLI session name all match exactly what you type). Pick a casing convention and stick with it. Lowercase is what we use.

Prerequisites

  • A Mac (Apple silicon, macOS Tahoe or newer; older versions probably work but aren't tested).
  • A Tailscale account (the free tier covers everything here).
  • Termius on every device you want to drive agents from. Termius Pro is recommended for the snippet features used in Part 2, but the whole stack also works on Termius Free if you're willing to type agent-stack copilot alpha after each connect.
  • The direct-download Termius build on macOS — not the Mac App Store version, which is sandboxed and has no local-terminal feature. Download from https://termius.com/download.

Part 1 — Server Mac setup

This is the Mac that will host the agent sessions. Everything in this part runs once, on the Mac itself.

Auth model heads-up: this stack uses Tailscale SSH, which authenticates by tailnet identity — server-side, the SSH server uses auth method none and trusts the tailnet for identity. The username field on the host has to match a real macOS user that the ACL allows (autogroup:nonroot in the rule below means "any non-root user"). The password field can be left blank; if you do save a value, it's sent on the wire but ignored by the Tailscale SSH server.

1.1 — Tailscale account

If you already have a tailnet, skip ahead. Otherwise: sign up at https://login.tailscale.com/start (free personal plan is enough), then confirm MagicDNS is on at https://login.tailscale.com/admin/dns (it's on by default for new tailnets — just verify). The full Tailscale walkthrough is docs/tailscale.md.

1.2 — Keep the Mac awake

Amphetamine (free, Mac App Store) keeps the Mac from sleeping while still letting the display sleep, the screensaver lock the screen per MDM policy, etc.

Recommended config (Amphetamine menu → Quick Settings):

  • Allow display sleep — ON
  • Allow system sleep when display is closed — OFF (keeps the Mac awake even with the lid down on a clamshell setup)
  • Allow screen saver after 45m of inactivity — ON (so MDM lock policy still fires)
  • Start session at app launch — ON, set to Indefinitely
  • Launch Amphetamine at login — ON (System Settings → General → Login Items)

The result: rebooting the Mac auto-resumes an indefinite caffeine session, the display still sleeps and locks, but the system never suspends — so the tailnet stays online and tmux sessions stay alive.

Amphetamine Quick Settings showing Allow display sleep ON, Allow system sleep when display is closed OFF, Allow screen saver after 45m of inactivity ON, with "New session at app launch" set to Indefinitely.

1.3 — Clone and run the installer

git clone https://github.com/dfrysinger/agent-stack \
  ~/code/agent-stack
cd ~/code/agent-stack
./install.sh

The installer is idempotent — safe to re-run. It:

  • Installs Homebrew (if missing), tmux, and the Tailscale CLI build.
  • Writes /etc/resolver/ts.net (the MagicDNS resolver fix).
  • Detects Copilot CLI, Claude Code, and Codex CLI, then asks which should receive the optional request_help tool.
  • Installs a root-owned Screen Sharing helper whose passwordless commands are limited to on for one through eight hours and off. A launchd watchdog enforces the deadline after logout, sleep, or reboot.
  • Symlinks agent-stack, copilot-agent, claude-agent, and codex-agent into /usr/local/bin, all pointing at the same multi-call wrapper (bin/agent). During upgrade it removes ca, cc, co, and transitional remote-agent links only when they are owned by this checkout; foreign commands are preserved.
  • Symlinks agent-screen for bounded Screen Sharing. During upgrade it removes owned ss and transitional remote-screen links; foreign commands are preserved.
  • Optionally installs dfrysinger/skills for any selected backend and dfrysinger/dreaming as a dedicated headless Copilot service.
  • Stamps a managed block into ~/.tmux.conf that hides tmux's status bar (the agents are full-screen TUIs and your Termius tabs already label each session). Toggle it back per-session with prefix + b. Any hand-written ~/.tmux.conf you already have is preserved.
  • Prints a checklist of the GUI / interactive steps it can't do for you — Full Disk Access grants (next step), tailscale up --ssh, first Copilot CLI auth prompt.

Upgrading from the old short commands: the installer intentionally retires owned ca, cc, co, and ss links. Update saved Termius startup snippets to agent-stack <backend> <name>. For an existing Mac Termius workspace, run the new command once in every pane and save the workspace again so autocomplete replays the replacement command. Use agent-screen instead of ss. Any foreign command using those names is left untouched.

If you're driving the install over VNC / Screens / Termius — anywhere the sudo prompt could be hard to see — use the GUI launcher instead, which opens a fresh Terminal.app window where the password prompt is obvious:

open ~/code/agent-stack/install-gui.command

(Or double-click install-gui.command in Finder.)

1.4 — Full Disk Access

tmux and tailscaled both need Full Disk Access on macOS Ventura+. Grant FDA before running tailscale up --sshtailscaled without FDA can flap offline and DNS goes intermittent.

The installer printed the exact Cellar paths to add. See docs/fda-grants.md for the why and the step-by-step. (After every brew upgrade tmux or brew upgrade tailscale, the version-numbered Cellar path changes and you'll need to re-add — annoying but unavoidable.)

1.5 — Authenticate Tailscale and turn on Tailscale SSH

sudo tailscale up --ssh

Open the auth URL it prints, sign into your Tailscale account, and the Mac joins the tailnet. The --ssh flag tells tailscaled to bind a Tailscale SSH server on :22 (replacing macOS's built-in Remote Login, which on a managed Mac MDM keeps disabling anyway).

Gotcha — sandboxed GUI Tailscale.app: if you already have /Applications/Tailscale.app running its own tailscaled (both the Mac App Store build and, since ~1.98, the standalone download from tailscale.com are sandboxed), tailscale up --ssh refuses with:

The Tailscale SSH server does not run in sandboxed Tailscale GUI builds.

The installer detects this and prints the switchover steps. In short: quit the GUI (osascript -e 'quit app "Tailscale"'), uninstall its system daemon (sudo /usr/local/bin/tailscaled uninstall-system-daemon), start Homebrew's version (sudo brew services start tailscale), then re-run sudo tailscale up --ssh --accept-routes (re-auth once because brew's tailscaled has its own state dir).

1.6 — Add an SSH ACL rule

Tailscale SSH only binds :22 if your tailnet ACL contains at least one SSH rule that could apply to the node. Out of the box, new tailnets have zero SSH rules — :22 will refuse connections even though tailscale debug prefs shows RunSSH: true. Edit your ACL at https://login.tailscale.com/admin/acls/file and add:

{
  "ssh": [
    {
      "action": "accept",
      "src":    ["autogroup:member"],
      "dst":    ["autogroup:self"],
      "users":  ["autogroup:nonroot"]
    }
  ]
}

tailscaled picks this up within seconds. Verify:

sudo tailscale debug netmap | python3 -c \
  'import json,sys; d=json.load(sys.stdin); p=d.get("SSHPolicy") or {}; \
   print("rules:", len(p.get("Rules",[])))'

rules: 1 (or higher) means you're good. If it's still 0, you saved to the wrong tailnet or the ACL has a syntax error — see docs/tailscale.md.

1.7 — First backend CLI launch

Install whichever backend CLI(s) you plan to use:

  • Copilot CLI — per its own instructions (brew install copilot-cli works once it's published; otherwise follow the README there). The first launch asks:

    System vault not available — store token in plain text config file?

    Answer Yes. The macOS keychain prompts the GUI for unlock, which there's nobody to dismiss when you're SSH'd in from a phone — the keychain stays locked and Copilot CLI stalls. The plaintext fallback lives at ~/.copilot/config.json with mode 0600, inside the FileVault-encrypted home volume. The risk delta over the keychain is small; the operational benefit (Copilot CLI just works over SSH) is large.

  • Claude Code CLI — per the Claude Code quickstart. The first launch opens an in-terminal login flow — follow the prompts to authenticate; the token lands under ~/.claude/.

  • Codex CLI — install and authenticate Codex normally. The wrapper resumes the most recent session for the selected workspace when matching history exists.

Install any combination. The wrapper checks for a backend binary only when that backend is launched.

The help-tool selection can also be supplied noninteractively:

AGENT_HELP_RECIPIENT='you@example.com' ./install.sh \
  --agent-help-clis copilot,claude,codex \
  --skills-clis copilot,claude,codex \
  --dreaming \
  --screen-sharing-port 15900 \
  --screen-sharing-hours 1

The recipient is stored only in ~/.config/remote-agent-stack/agent-help/config.json with mode 0600. Prefer the hidden interactive prompt or the temporary AGENT_HELP_RECIPIENT environment variable over a command-line flag so the value does not enter shell history.

The installer also offers to install dfrysinger/skills through each CLI's native user-scoped plugin manager. Supply the complete desired set noninteractively with:

./install.sh --skills-clis copilot,claude,codex

Use --skills-clis none or a smaller list to remove only plugins and marketplaces created by this installer. Pre-existing installations are preserved. Ownership state lives under ${XDG_STATE_HOME:-~/.local/state}/remote-agent-stack/, outside the purgeable recipient and wrapper configuration.

The installer can also install dfrysinger/dreaming as a Copilot-only, headless learning and skill-curation service:

./install.sh --dreaming

Dreaming is independent of --skills-clis. Its dedicated runtime checkout defaults to ~/.local/share/remote-agent-stack/dreaming, so a separate development checkout can remain on another branch or contain local edits. Installation delegates to Dreaming's own install, self-test, and enable lifecycle. The stack sets DREAMING_SKIP_PLUGIN_SYNC=1, so Dreaming's five private orchestration skills do not appear in normal interactive CLI context. --no-dreaming removes only a runtime adopted by this installer and preserves the checkout and recovery state.

1.8 — Workspace locations

Each backend has its own root directory; inside each, agents are agent-<name>/ subdirs (e.g., agent-alpha/, agent-bravo/). The installer asks for all roots and auto-picks smart defaults:

  • With Dropbox installed (recommended — workspaces sync across Macs):
    • Copilot: ~/Library/CloudStorage/Dropbox/copilot-workspace
    • Claude: ~/Library/CloudStorage/Dropbox/claude-workspace
    • Codex: ~/Library/CloudStorage/Dropbox/codex-workspace
  • Without Dropbox:
    • Copilot: ~/copilot-workspace
    • Claude: ~/claude-workspace
    • Codex: ~/codex-workspace

Press Enter to accept a default, or type any path (~, $HOME, and shell expansions all work). Re-running install.sh later keeps existing choices and skips the prompts.

To pick paths non-interactively (or from a script):

./install.sh \
  --copilot-workspace-base ~/code/copilot-workspace \
  --claude-workspace-base  ~/code/claude-workspace \
  --codex-workspace-base   ~/code/codex-workspace

This writes COPILOT_WORKSPACE_BASE, CLAUDE_WORKSPACE_BASE, and CODEX_WORKSPACE_BASE into ~/.config/remote-agent-stack/config. Edit that file directly any time to move a workspace base later (you'll have to move existing <name>/ directories under it by hand).

1.9 — Test the wrapper locally

Copilot backend:

agent-stack copilot alpha

Claude Code backend:

agent-stack claude alpha

Codex backend:

agent-stack codex alpha

You should land inside the matching tmux session with the backend CLI running. Detach with Ctrl-b d (you're back at the Mac shell). Reattach with the same command again — should be instant. Now the Mac side is done.

1.10 — Optional: install Open Markdown

Copilot CLI sessions write a lot of Markdown to disk — ~/.copilot/session-state/<uuid>/plan.md, per-session checkpoints, files in files/. Open Markdown is a free native macOS viewer that renders GitHub-flavored Markdown with live reload, Mermaid diagrams, syntax highlighting, and inline editing. It's the nicest way to skim what an agent has been writing without leaving the Mac.

Install from https://ptheofan.github.io/open-markdown/, then in Finder right-click any .md file → Open WithOpen MarkdownAlways Open With to make it the default.


Part 2 — iPhone (Termius iOS)

The phone is your "land in any agent in one tap from anywhere" client.

2.1 — Tailscale on iOS

Install Tailscale from the App Store, sign in with the same account as the Mac, and toggle it on. That's it — no config.

2.2 — Install Termius

Termius from the App Store. Sign in with the same account you'll use on the Mac desktop client (this enables Termius Sync, optional but convenient).

2.3 — Copy your Mac's tailnet FQDN

In the iOS Tailscale app, tap your Mac in the device list. Its MagicDNS name appears at the top of the detail screen with a copy button next to it — tap it. You now have something like macbook-air.tail-xxxx.ts.net on your clipboard, ready to paste into Termius next.

2.4 — Create a "Mac" host group

A host group lets every Agent host inherit shared SSH credentials (username, optional password) so you only have one place to fix things. Per Termius's docs on groups, groups inherit credentials, snippets, protocols, environment, and themes — but not the address, which is always set per host.

  1. Termius → Hosts+New Group.
  2. Name it Mac.
  3. Toggle SSH on at the group level so the credential fields appear, then set:
    • Username: your macOS username (whatever whoami prints on the Mac). This must be a real user — Tailscale SSH checks it against the ACL, and a wrong/blank username is what causes the "connection failed" prompt loop.
    • Password: Tailscale SSH doesn't use this for auth. Two reasonable choices:
      • Save your macOS login password. Termius will autofill it at sudo prompts on iOS, which is the only reason to bother. The value is sent on the wire (encrypted under SSH + WireGuard) and discarded by the Tailscale SSH server.
      • Leave it blank. You'll type your password by hand whenever sudo asks.
  4. Save.

2.5 — Create one host per agent

For each agent name (alpha, bravo, charlie, …):

  1. Termius → Hosts+New Host.

  2. Address: the FQDN from 2.3 (macbook-air.tail-xxxx.ts.net). This is per-host on iOS — the group can't set it for you.

  3. Parent Group: Mac. The host will show "Inherited from group" under the credential fields; leave those blank to use the group's username and password.

  4. Label: Agent alpha (or whatever you want to see in the host list).

  5. Startup snippet: tap Startup Snippet, then Add new snippet. Enter:

    agent-stack copilot alpha
    

    Name the snippet Agent alpha (or whatever you want), save, and it'll be selected as the host's startup snippet. Termius docs on snippets: https://docs.termius.com/termius-handbook/snippets.

  6. Save the host.

Repeat for each agent. The host list now has Agent alpha, Agent bravo, etc., all inheriting credentials from the Mac group, each with the same address and a different one-line startup snippet.

2.6 — Tap and go

Tap Agent alpha. Termius connects over Tailscale SSH (the iPhone's tailnet identity is what authenticates server-side — no password or key needed), lands in the Mac shell, runs agent-stack copilot alpha, and you're in the agent's tmux session. Detach with Ctrl-b d, kill the Termius tab, and reattach later from the same host (or from a different device entirely) — the tmux session keeps running on the Mac.


Part 3 — Mac desktop (Termius)

On the Mac itself, Termius's local-shell + workspaces feature is more ergonomic than snippets — you get a saved grid of named local terminals that auto-reconnect to their tmux sessions when you reopen the workspace. This is the trickiest part of the whole stack to set up because the Termius UI for it isn't obvious.

3.1 — Install the direct-download build

Mac App Store Termius is sandboxed and has no local terminal at all. Download the unsandboxed build from https://termius.com/download.

3.2 — Enable autocomplete and verify it replays commands

Termius → Settings → enable Autocomplete. This is what makes a saved local shell replay its last-entered command on reopen — the mechanism we'll use to auto-reconnect to tmux. Verify it works before you invest in building the full workspace:

  1. Open one local terminal (⌘L).
  2. Run echo replay-test.
  3. Close the tab.
  4. Reopen a local terminal in the same window.
  5. Termius should suggest echo replay-test (or replay it automatically depending on your version) — confirming autocomplete is on.

If nothing replays, recheck the setting before continuing. The whole auto-reconnect flow in 3.5 depends on it.

3.3 — Build the workspace

Termius doesn't have a "create workspace" button. You build one by dragging a tab into the body of another tab's window:

  1. Open the first local terminal: click Vaults → Terminal, or press ⌘L. A local shell tab opens.

  2. Open a second local terminal in a new tab in the same window: ⌘L again.

    Termius desktop with two local-terminal tabs in the same window — "Local Terminal" (active) and "Local Terminal (1)" — the pre-workspace state.

  3. Drag-drop to form the workspace: select one of the tabs, then drag the unselected tab into the body of the window. A drop-zone box appears; release. You now have a tiled workspace with two panes.

    Termius desktop mid-drag: a floating "Local Terminal (1)" tab is being dragged over the body of the existing terminal, with a tinted drop-zone overlay showing where the new pane will land.

  4. Save the workspace: tap the small dot in the workspace tab's header. Right-click the tab to rename it (e.g., Agents).

    Termius desktop after the drop: a single "Workspace" tab now contains two stacked panes ("Local Terminal (1)" on top, "Local Terminal" on the bottom). The small unfilled dot next to the "Workspace" tab title is the unsaved-changes indicator — click it to save.

  5. Add more panes: open another ⌘L tab, drag-drop into the workspace body to add a third pane. Repeat until you have one pane per agent (the author runs ~12).

3.4 — Name each pane

By default the panes have generic names. To rename:

  1. Click the focus mode button in the top-right of any terminal card (next to the X). This expands the card and reveals a left panel listing every named local-shell session in the workspace.

    Termius desktop in focus mode: the left "Terminals · 2" side panel lists "Local Terminal (1)" and "Local Terminal" entries; the active terminal fills the right side. Right-click a session name in this side panel to rename it.

  2. Right-click a session name in the side panelRename → give it the agent name (alpha, bravo, …).

  3. Click the split-view button at the top-right of the side panel to return to the grid view of all panes.

  4. Save again (the tiny dot on the workspace tab).

3.5 — Run agent-stack <backend> <name> once in each pane

In each pane, run the matching command:

agent-stack copilot alpha   # in the pane named "alpha"
agent-stack copilot bravo   # in the pane named "bravo"
#

This serves two purposes:

  1. Bootstraps the actual tmux/Copilot CLI session for that agent.
  2. Becomes the last entered command in that pane, which is what Termius's autocomplete replays on reopen.

3.6 — Save, close, reopen

Save the workspace one more time (tiny dot). Close the workspace window. Reopen it from the Workspaces sidebar.

Each pane reopens, replays agent-stack copilot <name>, and reconnects to the already-running tmux session on the Mac — you're back in the same grid of agent conversations you left.

3.7 — Whenever you change the layout, save again

Save the workspace every time you change anything — adding a pane, renaming a session, resizing splits. The tiny dot is easy to miss. If you close the window without saving, the change is lost.


Daily use

Once everything is set up:

  • From the phone: tap an Agent host in Termius. You're in.
  • From the Mac desktop: open the saved Termius workspace. Every pane reconnects.
  • Detach (leave session running, drop back to shell): Ctrl-b d inside tmux.
  • Kill an agent session entirely: exit Copilot CLI, then exit the shell tmux gave you. Or from outside any device: tmux kill-session -t alpha.
  • Reattach from anywhere: agent-stack copilot alpha on the Mac, or tap Agent alpha in iOS Termius. Same session.
  • GUI access (graphical desktop, not just the terminal): agent-screen on enables Screen Sharing for an hour and forwards it over the tailnet. It no longer asks for a password because the installer grants only the exact bounded helper commands. Connect using the printed screens://<tailscale-name>:<port> link. See docs/screen-sharing.md.
  • Agent needs you: the selected CLIs expose request_help. Its tool description tells agents to call it once when blocked on your login, permission, or decision. The request opens Screen Sharing for SCREEN_SHARING_HOURS and identifies the originating NATO-alphabet tmux session.

tmux sessions live in memory — they don't survive a Mac reboot. The wrapper relaunches Copilot CLI with the same --session-id=<uuid> on next launch, so the Copilot CLI conversation comes back; only the tmux scrollback is lost.

Configuration

Defaults live in ~/.config/remote-agent-stack/config, which the installer writes for you (see §1.8). The file looks roughly like:

COPILOT_WORKSPACE_BASE="/Users/you/.../Dropbox/copilot-workspace"  # set during install
CLAUDE_WORKSPACE_BASE="/Users/you/.../Dropbox/claude-workspace"    # set during install
CODEX_WORKSPACE_BASE="/Users/you/.../Dropbox/codex-workspace"      # set during install
MAILBOX_INTEGRATION="false"                                        # off by default
ALLOW_ALL="false"                                                  # off by default
AGENT_HELP_CLIS="copilot,claude,codex"                             # complete desired set
SCREEN_SHARING_PORT="15900"                                        # Tailscale TCP forward
DESK_DISPLAY_COUNT="3"                                             # legacy compatibility setting
SCREEN_SHARING_HOURS="1"                                           # automatic bounded lease
# COPILOT_BIN="copilot"
# CLAUDE_BIN="claude"
# CODEX_BIN="codex"
# AGENT_DIR_PREFIX="agent-"
# SESSION_WARN_MB="300"

The three *_WORKSPACE_BASE values are whatever you picked at install time (Dropbox defaults if Dropbox is installed, otherwise backend-specific directories directly under $HOME). Inside each root, agents live in agent-<name>/ subdirs (change the prefix with AGENT_DIR_PREFIX if you want a different convention). Re-run ./install.sh with the matching --<backend>-workspace-base PATH option or edit the file directly to move a root.

MAILBOX_INTEGRATION enables the cross-session mailbox skill — the wrapper pokes the recipient's pane on attach + cold-start when pending mail exists. Off unless you have the skill installed.

ALLOW_ALL makes the wrapper skip permission prompts on new-session launch — Copilot: --allow-all (auto-approves tools, paths, URLs); Claude Code: --dangerously-skip-permissions; Codex: --dangerously-bypass-approvals-and-sandbox. Personal-machine convenience; do not enable in shared environments.

SESSION_WARN_MB (Copilot only) is the size at which the wrapper offers to retire an agent's session and start a fresh one. Copilot replays a session's whole event log on resume, so a session carried for weeks grows into the gigabytes and becomes slow to start. Accept the offer and the wrapper records the old session as retired, launches a new one, and seeds it with a prompt that rebuilds context from the old session's plan.md, checkpoints, todo database, and conversation tail. Nothing is deleted — the retired session stays on disk, resumable and minable. Set to 0 to disable the prompt.

The first carry-over asks Copilot to approve reading ~/.copilot/session-state, which sits outside the agent workspace. Choose "add these directories to the allowed list" and later rotations run without prompting.

COPILOT_BIN, CLAUDE_BIN, and CODEX_BIN let you point the wrapper at a specific backend binary (e.g., /opt/homebrew/bin/copilot or a nightly build).

AGENT_HELP_CLIS is the complete managed set. Re-run the installer with --agent-help-clis none or a smaller list to remove only this repository's MCP entries and instruction blocks from deselected CLIs. Existing unrelated CLI configuration and instruction text are preserved.

SKILLS_CLIS is the independently managed set for the dfrysinger-skills plugin. Reruns update installations created by this installer. Deselecting a CLI removes only owned plugin and marketplace registrations; same-named user-managed installations are left untouched.

DREAMING_ENABLED independently controls the headless Dreaming service. DREAMING_REPO_ROOT records its source checkout. Reruns fast-forward only an exact, clean dfrysinger/dreaming checkout on main; a dirty checkout, different branch, or foreign origin fails closed. The lifecycle journal lives under ${XDG_STATE_HOME:-~/.local/state}/remote-agent-stack/.

The help guidance lives in the request_help tool description, which is in context for any CLI where the tool is registered. The installer no longer adds a managed instruction block, and removes any block it previously wrote from:

  • Copilot CLI: ~/.copilot/copilot-instructions.md
  • Claude Code: ~/.claude/CLAUDE.md
  • Codex CLI: ~/.codex/AGENTS.md

Active CLI sessions must be restarted after changing MCP selection.

tmux keychain bootstrap LaunchAgent

The installer offers to install a tiny LaunchAgent (~/Library/LaunchAgents/com.dfrysinger.tmux-keychain-bootstrap.plist) that pre-warms the tmux server in your GUI (Aqua) login session at every login and re-fires automatically whenever the tmux socket disappears.

Without it, the first agent-stack <backend> <name> call after a Mac reboot bootstraps the tmux server from your SSH login shell. macOS gives that shell a restricted keychain search list (System keychain only, no login keychain), and every subsequent shell inside that tmux server inherits the restriction — including the ones the wrapper opens later when you re-attach. The visible symptom is that gh, the osxkeychain git credential helper, and anything else that reaches into the login keychain silently fail inside agent shells, even though they work in Terminal.app on the same Mac.

The LaunchAgent fixes that by starting the tmux server itself under the GUI session, so the security context is correct from the first session onward. It runs once at login, starts a hidden anchor session called _keychain-anchor (so the server stays alive), and exits. Subsequent wrapper calls just attach to or create sessions on that already-running, properly-contextualized server.

It also installs a PathState watchdog on the tmux socket. If you ever run tmux kill-server — intentionally or by accident — launchd notices the socket disappear within a few seconds and re-fires the bootstrap script, which spawns a fresh GUI-context server. So recovery is hands-off: kill the server, wait a moment, run the same agent-stack <backend> <name> command again, you're back.

If you skip it: keep using gh-auth-macos from the dfrysinger/skills plugin as a per-shell fallback that reads the keychain via the security CLI and exports GH_TOKEN. That works but is per-shell setup, not a one-time fix.

To install later, re-run ./install.sh and answer Y at the prompt. To uninstall:

launchctl bootout "gui/$(id -u)/com.dfrysinger.tmux-keychain-bootstrap"
rm ~/Library/LaunchAgents/com.dfrysinger.tmux-keychain-bootstrap.plist

Uninstall

~/code/agent-stack/uninstall.sh           # wrappers, MCP entries, instructions, remote access
~/code/agent-stack/uninstall.sh --purge   # also drops private recipient/state config
~/code/agent-stack/uninstall.sh --commands-only  # only owned agent command links

Homebrew packages, FDA grants, and Tailscale network state are left in place — see the uninstaller output for the manual cleanup commands.

Status & roadmap

Single-machine, single-user, macOS arm64. Tested on macOS Tahoe. Copilot CLI, Claude Code CLI, and Codex CLI are first-class named-session backends. Linux support remains an open issue.

Other docs

  • docs/tailscale.md — Tailscale account → MagicDNS → ACL → CLI install → resolver fix.
  • docs/fda-grants.md — exactly which binaries need Full Disk Access and why.
  • docs/troubleshooting.md — every macOS / Tailscale / Copilot CLI / Termius gotcha we hit.
  • docs/screen-sharing.md — GUI access over Tailscale: the agent-screen / vncfix scripts, black-screen recovery, the IPv4-blackhole workaround, and going dark without locking.

About

macOS bootstrap for remote-accessible named AI agent sessions over Tailscale SSH + tmux

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages