Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Agent Setup Backup

This repository is the portable, secret-safe configuration for Isaac's macOS agent workspace: every coding agent on the machine, the rules they all follow, how they hand work to each other, and the tooling that keeps them consistent. It is a refreshed snapshot of the real machine (~/Agent-Backup, GitHub isaachorowitz/multi-agent-setup), not a disk image and not an account export.

If you are new here, read the next two sections. The first is written for anyone; the second is the technical contract. Everything after that is reference material.

This is a personal setup published for reference, not a supported product. It holds no secrets: see SECURITY.md for what is excluded and why, and read install.sh before running it, because it rewrites agent configuration in your home directory.


The setup in plain English

What lives here. Isaac runs several AI coding agents on one Mac: Claude Code (Anthropic), Codex (OpenAI), Cursor, Grok (xAI), OpenCode (open source, running local and OpenRouter models), and Hermes (a scheduler and assistant). He also has a mobile-app testing tool called Argent. Each of these is a separate product with its own settings folder. This repository holds the shared rulebook and the copies of each product's settings, so the whole arrangement can be understood, audited, and rebuilt on another machine.

One rulebook, three layers. Every agent reads the same three files before it does anything:

  1. ~/AGENTS.md, the constitution. The rules that never change per task: never commit or deploy without being asked, never tell Isaac how long something will take, never print a secret, use Isaac's own logged-in Chrome only through the approved route, clean up every process you start.
  2. ~/.agents/AGENTS.md, the runtime overlay. Which model orchestrates, which model does routine work, which one reviews, how to delegate safely.
  3. ~/.agents/agent-graph.yaml, the machine-readable version of the routing. When the prose and the graph disagree, the graph wins.

The rulebook was cut from about 80 KB to 29 KB on 2026-09-04 because both Anthropic and OpenAI publish evidence that shorter, non-repetitive instructions produce better work at lower cost. Each rule now appears exactly once; the mechanics of a tool live in that tool's skill and load only when needed.

Who is the boss. A Claude model (Fable 5.1 or Opus 5) or Codex orchestrates a task: it plans, splits the work, hands pieces out, checks the results, and reports. Routine implementation goes to fast workers (GPT-5.6 Luna first, then Cursor Composer, then Sonnet). Review always crosses vendors: work written by Claude is reviewed by Codex, and work written by Codex is reviewed by Claude, because a reviewer from the same family shares the author's blind spots.

When Isaac names a helper, that is final. If he says "use Grok" or "send this to Codex", the agent uses exactly that provider. It may not quietly substitute one of its own subagents because that was easier. This rule exists because the substitution was silently happening and billing him for tokens he had routed elsewhere.

What is never done without asking. Committing, pushing, opening a pull request, deploying, publishing, running a database migration, posting to social media, writing to his marketing database, or spending money on a large media generation. Plain release language ("push it live", "ship it", "commit and push") is one authorization for the full chain; nothing weaker counts and nothing carries over from an earlier message.

Everything is shared. All agents see the same seven tool servers (Argent, Context7, Tavily, Exa, HotLyne, and two Playwright browser transports), the same library of skills, and the same safety guard on shell commands. A small lint runs at the start of each session and prints a line if any of that has drifted.

Experimental features are on. Isaac's standing preference is that every experimental or under-development feature in every agent is enabled, with a short, named list of exceptions that would remove capability or break a protocol. Codex's own in-app browser and Computer Use are deliberately on; they are Codex's own browser, separate from Isaac's personal Chrome.

How it stays honest. Nothing here contains a password, token, cookie, or account. Every refresh runs two secret scanners and refuses to sync if either finds anything. A daily job refreshes the snapshot at 07:30; committing and pushing remain a human decision.


How the orchestration works (technical)

Runtimes and what they read

Runtime Config root Model(s) Role Reads the shared rulebook via
Claude Code ~/.claude Fable 5.1 or Opus 5 orchestrator; Sonnet 5 fast worker; Haiku dispatchers Primary orchestrator ~/.claude/CLAUDE.md imports ~/AGENTS.md and ~/.agents/AGENTS.md
Codex CLI and ChatGPT app ~/.codex GPT-6 Astra at high (default since 2026-09-05; works by itself, delegates only when told, the only model allowed to work unattended); GPT-5.6 Sol (judgment), Terra (review, exploration), Luna (fast work) on request Orchestrator, implementer, cross-vendor reviewer, autonomous runner (Astra only) ~/.codex/AGENTS.md is a symlink to ~/AGENTS.md
Cursor CLI ~/.cursor Composer 2.5 Bounded isolated-clone implementer, fresh-eyes reviewer Discovers AGENTS.md walking up from the project
Grok CLI ~/.grok grok-4.6 External delegate on request; fresh-eyes reviewer Claude compatibility: loads ~/.claude/settings.json hooks, ~/.claude.json MCPs, ~/.claude/skills, ~/.agents/skills
OpenCode ~/.config/opencode Local Qwen via LM Studio; DeepSeek, Kimi, GLM via OpenRouter Local-model runtime with the same tools instructions array lists the three policy files; scans ~/.agents/skills and ~/.claude/skills
Hermes ~/.hermes Configured per Hermes Scheduler and assistant; delegates code to the CLIs above System prompt tells it to read both policy files and the graph
Argent ~/.argent n/a iOS and Android app testing only Its own vendor rule (claude-code/rules/argent.md)

Hosts that are not policy sources but inherit everything because they launch the CLIs above: Zed, T3 Code Nightly (launches claude, codex, opencode, grok, cursor-agent), Orca IDE (hooks into every agent and drives Claude agent teams), Claude.app (Claude Code inside it uses ~/.claude; its Cowork chat has its own MCP list in ~/Library/Application Support/Claude/claude_desktop_config.json, kept at parity), and ChatGPT.app (its Codex uses CODEX_HOME=~/.codex).

Routing, in the order an orchestrator applies it

  1. Only Astra works unattended, only when asked (autonomous_mode). "Let Astra run on its own" or "run this autonomously" puts GPT-6 Astra (through Codex) into an unattended run; it proceeds without mid-task questions, stops only for gated or destructive actions or a real scope change, and reports outcome first. No other model runs unattended; the gates are unchanged inside the mode. Astra also works by itself: no subagents or delegates unless Isaac names one or asks for fan-out. 0b. "Best" means best (recommendation_standard). "Best solution", "best architecture", "best tech stack", "find me the best" mean: research it against the current month and the previous month, state the period covered, and recommend the best long-term production outcome for the use case, never the fastest or simplest build; coding complexity is not a veto.
  2. Named delegate is binding (delegate_selection in the graph). "Use Grok", "send it to Codex", "have Cursor review it", "give it to Luna" select that exact provider. If the provider cannot do the job (Cursor takes no effort flag; only Luna can build-verify; no external child may touch a live API or network), the agent says so and asks. Silent substitution is a violation.
  3. Delegation intensity depends on the orchestrating model (delegation_by_orchestrator). Anthropic's published guidance is opposite for its two orchestrators: Fable 5.1 should delegate independent work freely and asynchronously and use a separate fresh-context verifier for large work; Opus 5 over-delegates, so it does small work itself, never spawns a subagent to verify, and keeps spawn counts low. Codex delegates only on a direct request or an instruction in AGENTS.md or a skill, capped by [agents] in its config (max_concurrent_threads_per_session = 6, max_depth = 1).
  4. Fast, mechanical work has one preference order (fast_worker_preference): Luna at high (medium for pure boilerplate), then Cursor Composer, then Sonnet as a native Claude subagent when the work needs the parent's conversation, then Sol or Opus only when judgment is genuinely required. Grok is not in the default order but is first-class the moment Isaac names it.
  5. Review is cross-runtime and proportional (review_policy). Large and standard changes only; trivial and small ship without a review pass. Claude-implemented work is reviewed by Codex Terra at high; Codex-implemented work by Claude Opus 5. The orchestrator still verifies delegated work itself before accepting it.
  6. Ceremony scales to blast radius. Trivial: do it and verify. Small: brief plan, self-verify. Standard: plan, implement, reviewer pass before commit. Large: council or deep-reasoner on the design first, then two-stage review-verify. Anything that touches auth, secrets, crypto, SQL, fs/exec, money, or a public API is at least standard.

How a delegate is actually reached

External providers are local CLI child processes, never entries in a model registry:

orchestrator (Claude, Codex, OpenCode, Hermes)
   │
   ├─ Agent tool ──► ~/.claude/agents/{grok,luna,cursor,codex}.md
   │                 thin Haiku dispatchers, Bash+Read only; they shell out and
   │                 return the child's output verbatim, never do the work,
   │                 never apply a patch (OpenCode has the same four)
   │
   └─ Bash ────────► agent-subagent grok|luna|cursor   (or: codex exec)
                       │
                       ├─ copies ONLY the explicit --files allowlist, Git-visible,
                       │  into a fresh task-owned clone; secret filter fails closed
                       ├─ read mode (default): review, second opinion
                       ├─ --mode patch: returns a diff; the PARENT applies hunks
                       └─ Luna only: --verification build runs the parent's exact
                          command in an adapter-owned offline sandbox after Luna
                          exits; the patch is withheld unless it passes

The dispatcher agents exist for one reason: when a person names a delegate, the model looks in the tool that lists agents. Before 2026-09-04 that list contained only Claude-native subagents, so "use Grok" quietly became a Sonnet worker. Now grok, luna, cursor, and codex are visible there.

Codex also has native subagents under ~/.codex/agents/*.toml (fast-worker on Luna, code-reviewer and blind-verifier on Terra at high, the reviewer sandboxed read-only, sol-orchestrator, and the Argent inspector on Terra).

What every agent shares

Layer Canonical source How each runtime gets it
Policy ~/AGENTS.md, ~/.agents/AGENTS.md, ~/.agents/agent-graph.yaml Import, symlink, path, or system prompt (table above)
MCP servers (default profile: argent, context7, tavily, exa, playwright, playwright-isolated, hotlyne) ~/.agents/mcp-registry.yaml Claude ~/.claude/mcp.json and ~/.claude.json; Codex config.toml; Cursor mcp.json; OpenCode opencode.jsonc; Hermes config.yaml; Grok inherits Claude's list; Claude.app has its own file at parity
Skills (one body each) ~/.agents/skills Claude, Codex, Hermes: relative symlinks; Cursor, Grok, OpenCode: scan the directory natively. Rarely useful vendor skills live in ~/.agents/skills-cold and load nowhere
Shell-command guard ~/.claude/guards/git-guard.sh Claude and Codex hooks natively; Hermes config.yaml hooks; Grok via Claude-hook compatibility; Cursor hooks.json preToolUse (same payload shape, exit 2 blocks); OpenCode plugins/git-guard.js shim
Shared launchers ~/.local/bin (agent-subagent, agent-keys, agent-resource-control, agent-status, agent-policy-lint, browser-mcp-server, ...) On PATH for every runtime

Codex's own node_repl bridge and Codex Computer Use are listed under codex_native in the registry: permitted inside Codex and the ChatGPT app as Codex's own browser stack, never a route into Isaac's personal Chrome.

The guard and the gates

The guard sees exactly one command string and never the conversation, so it cannot prove authorization and does not pretend to. Two layers do different jobs. The written rule is what binds the agent: anything irreversible needs an explicit instruction in the current request, and every gated command is recorded to an audit log. The guard itself hard-blocks, with no in-agent override: force, mirror, or delete pushes; destructive branch or worktree mutation; discarding uncommitted work; recursive forced rm on protected targets; blanket node kills; staging or committing secrets; dynamically constructed protected actions; and writes to guard or hook config. git-guard.test.sh exercises every case.

Skill hygiene (audited 2026-09-06 against OpenAI's GPT-6 Astra guidance)

Every skill description is loaded into every session of every runtime, so each one is at most 40 words and says when to use the skill, not everything it can do. The audit cut the description footprint Codex sees from about 3,600 tokens to about 2,150, moved five niche skills to the cold set (~/.agents/skills-cold: wolt-ordering, gloop, standup, hetzner-postgres, fithub-booking, plus the tavily set), and made three constitution changes for Astra: document pointers are contextual, not pre-reads; "Finish the job" defines completion (run, inspect, fix, then return; narrow local checks rerun without asking); skills are advisory and never outrank the constitution or the request. Policy: shared/skills-policy.md.

Writing style and initiative (2026-09-06)

The constitution now sets one house style for every runtime: plain paragraphs with the main point first, lists only for genuinely parallel items, no em dashes, no stock phrases, no listing what the agent will not do. It also states that "can you", "I want to", and "help me" are instructions to act, and that a skill which makes an agent pause or leave work unfinished must be named and quoted so the offending instruction can be found. Both follow OpenAI's GPT-6 Astra guidance on personality and instruction following.

Interactive terminals

Agents use tmux on their own initiative for anything that needs a terminal: logins, installers, REPLs, confirmation prompts, watch loops, and sessions that must outlive a single tool call. They are expected to drive those themselves rather than hand the command back, and to kill the exact session they created when the task ends. A terminal changes who types and never what is permitted, so the hard blocks in the guard and the gated actions in the constitution apply in every shell.

Experimental features

Standing preference: on everywhere. Codex [features] has 98 flags enabled; the seven left off are named in the file with the reason (use_agent_identity was proven live to break every run; shell_zsh_fork was proven live to break the ChatGPT desktop app, whose bundled Codex ships no packaged zsh; rollout_budget is a cap; code_mode_only and skip_host_skill_discovery remove capability; mcp_2026_07_28 forces a not-yet-final protocol; secret_auth_storage can force a re-login). OpenCode has OPENCODE_EXPERIMENTAL=true plus the non-umbrella flags in dotfiles/.zshrc. Grok has its [features] on. Argent has argent-lens, artifacts endpoint, event log, and microinteractions on. Claude Code has agent teams (Orca depends on them), auto mode, auto-dream, voice, remote control, cross-session inbound, and tool search on.

Keeping it from drifting

agent-policy-lint (in shared/bin, installed to ~/.local/bin, run by session-start.sh and by tests/test-policy-lint.sh) checks seven things: every adapter provider appears in the graph; every graph model is named in the constitutions; every Claude and Codex agent file pins a model (an unpinned subagent silently inherits the orchestrator, which is how Fable was once running a mobile inspector with every tool); the default MCP profile is present in every runtime config; no registry-removed server is enabled; no broken skill symlinks. It exits non-zero on any failure and prints only the failing lines into session context.

A launchd agent, com.isaac.agent-backup-refresh, runs regenerate-backup.sh at 07:30 daily. It regenerates only; it never stages, commits, or pushes. (An earlier daily refresh was removed on 2026-07-26; this one was reinstated on 2026-09-04 after policy wiring was lost once when a working directory vanished. Remove it with launchctl bootout gui/$(id -u)/com.isaac.agent-backup-refresh if the earlier decision should stand.)


What this repository promises

It can reproduce the managed configuration and the documented routing rules on another Mac. It cannot reproduce a person's passwords, passkeys, SSO approvals, 2FA, browser cookies, provider accounts, App Store purchases, or project data. Those boundaries are deliberate: the repository can be shared without becoming an account or session dump.

The two important commands are:

# Rebuild the repository snapshot from the live managed configuration.
bash ./refresh.sh

# Restore the repository configuration onto the current machine.
bash ./install.sh

refresh.sh is the actual-machine configuration refresh path. It stages a fresh copy, removes machine-specific paths and secret values, runs the secret gates, and then syncs only the generated categories into the working tree. It does not stage, commit, push, publish, deploy, or load LaunchAgents. The refresh is intentionally manual so an agent or human can review the resulting diff.

install.sh restores the configuration layer. It backs up overwritten files, renders paths for the current home directory, restores shared skill links, and applies the default MCP capability profile. It does not install GUI applications or perform human authentication.

install.sh --resources-only updates only the shared lifecycle policy, resource controller, status command, reaper, graph, and reaper LaunchAgent. It is the narrow path for deploying lifecycle changes without rewriting unrelated agent configuration.

This is not a literal one-command disk clone. Account authentication, GUI apps, App Store purchases, project repositories, provider state, and user data remain outside the repository. SETUP.md states the exact reproducibility contract and the operational workflow; AGENT_INSTALL.md is the detailed restore runbook.

Restore a new machine

The complete operational runbook is AGENT_INSTALL.md. The short version is:

git clone https://github.com/isaachorowitz/multi-agent-setup.git ~/agent-setup
cd ~/Agent-Backup

# Optional: package and CLI inventory, not configuration restoration.
bash machine/install-machine.sh

# Optional: provide local values through Infisical or a gitignored secrets.env.
cp secrets.env.example secrets.env
$EDITOR secrets.env

bash ./install.sh

The clone URL may require the user's normal GitHub SSH or gh authentication. The machine layer installs package-manager items from the captured manifests; GUI and App Store applications remain a deliberate human choice. Install the native Claude Code launcher, Codex CLI, Cursor CLI, and Zed separately when they are not already present. Hermes and Argent are optional unless the work requires them.

After installation, authenticate each service in its own supported client. Do not put credentials into this repository or ask an agent to automate a password, passkey, SSO, 1Password, or 2FA step.

Process ownership and workstation visibility

The setup does not equate a process name, port, or container with ownership. A resource is safe for automatic cleanup only when its creating session registered its exact identity.

Background services, watchers, and workers that outlive one shell tool call use:

agent-resource-control start --name api --kind service \
  --project my-project --cwd "$PWD" -- npm run dev
agent-resource-control status
agent-resource-control stop <resource-id>

The launcher creates a private process group and records the process birth time, owner agent, project, cwd, kind, and an owner-only log. The creating agent remains responsible for normal cleanup. agent-resource-reaper is the launchd-backed safety net that removes completed records and stops exact orphaned process groups after their owner exits. retain explicitly hands a resource off beyond the session; release returns it to automatic cleanup.

Why processes used to pile up, and what stops it now

A cleanup instruction only runs when an agent finishes normally. A session that is killed, crashes, or is closed by its app skips it, and every runtime used to start all eight MCP servers eagerly (both Playwright servers included) whether or not the task touched a browser. So the harness now owns the lifecycle, and the prompt is the second layer:

  • Lazy MCP servers. Heavy servers are registered behind lazy-mcp, a stdio shim that answers the handshake and tool catalog from a cache with no child process, starts the real server on the first tool call, and can stop it again after an idle period. A session that never uses a browser never starts one.
  • Session-end sweep. Every resource started through agent-resource-control is tagged with the session id (CLAUDE_CODE_SESSION_ID, CODEX_THREAD_ID). The shared SessionEnd hook (claude-code/guards/session-end.sh, wired in Claude Code and Codex) runs stop-session for that id and one reap.
  • Retain expires. retain <id> --for 3d (default 24h) keeps a server past its session; when the TTL passes it falls back into normal cleanup.
  • Orphan sweep. agent-orphan-sweep, run by the launchd reaper every two minutes and by the hook, terminates MCP helpers whose parent is gone, orphaned Codex plugin app-servers older than an hour, shuts down iOS simulators idle for four hours, and posts one swap-pressure notification per six hours. Every rule is an exact allowlist; nothing pattern-kills by name.
  • Visibility. agent-status shows memory by agent family, orphaned helpers, and booted simulators, so the build-up is visible before it hurts.

Use agent-status for one local overview of registered resources, tmux, listeners, Docker and Apple containers, plus top CPU and memory consumers. Only the registered resource section grants stop authority. Observed listeners and containers remain user-owned until an exact registration proves otherwise.

For repositories with several cooperating local processes, Process Compose is the preferred project-level supervisor. It provides health checks, dependencies, logs, ports, and a TUI; the shared resource controller remains the cross-project ownership layer. procs is the lightweight on-demand process-tree viewer. Neither runs a permanent monitoring web server.

Browser routing: the exact setup

Operating manual: BROWSER-AUTOMATION.md is the canonical document for authenticated browser control. It carries the architecture, the invariants and why each exists, a top-to-bottom diagnostic funnel, recovery procedures, and an error dictionary. Go there first when anything browser-related misbehaves.

Desktop browser work is routed by the shared browser-mcp skill and the shared/bin/browser-mcp-server launcher. The launcher behavior, rather than a README assertion, is the source of truth.

Before using a browser, an agent should use a CLI, API, SDK, direct HTTP call, or MCP service when that can complete the task. Browser control is for work that genuinely needs interactive browser state.

Default desktop browser pool

MCP server When it is used Isolation and authentication behavior
playwright A task needs the authenticated regular Chrome session Uses @playwright/mcp@0.0.79 --extension through an allowlisted Chrome native-messaging host. The local canary runs each session as a background tab inside a shared pool of normal-type, normal-state, unfocused lane windows (default four lanes, up to 16 sessions each), never activating a lane or creating a window per client.
playwright-isolated Public, logged-out, clean-context work, or the authenticated pool is unavailable and no login is needed Uses pinned @playwright/mcp@0.0.79 --isolated --headless. It never inherits or reports on Isaac's Chrome sessions.
chrome-devtools Console, network, DOM, tracing, or performance debugging Opt-in browser-debug profile. Starts Chrome DevTools MCP with --autoConnect --channel stable --redactNetworkHeaders and uses a lease because debugging domains conflict.
argent Mobile app testing iOS and Android phone/tablet simulators, emulators, and devices only; never desktop browser work.

t3-code collaborative previews (preview_open, preview_snapshot, and all preview_* tools) are isolated and unauthenticated. They are useful for local or public previews, but never for RevenueCat, Google Cloud Console, Play Console, App Store Connect, or any workflow that depends on Isaac's Chrome login. Seeing a login page there is not evidence that Isaac is logged out; the agent must retry with the authenticated playwright MCP server before reporting an authentication problem.

How authenticated browser control works

Agent MCP client
  -> browser-mcp-server playwright
  -> @playwright/mcp@0.0.79 local loopback relay
  -> owner-only Unix socket and native-messaging broker
  -> allowlisted Playwright canary in Isaac's regular Chrome profile
  -> a background session tab inside a shared lane window
  1. The launcher validates the native host, the exact unpacked canary directory, and the owner-only mode-0600 token at ~/.config/playwright-mcp-extension-token. It fails closed rather than opening an isolated, logged-out browser.
  2. The broker accepts only the expected extension ID, private protocol sentinel, and loopback relay URL. It reads the token locally; the token never enters MCP configuration, environment, handshake URL, process arguments, or logs.
  3. Canary 0.4.0 creates the session's task tab silently inside whichever lane (a type: normal, state: normal, focused: false pool window) has spare capacity, and attaches to it. It never activates a lane or creates a window during routine connection, because either would change Chrome's window activation order and route external links into a lane. A per-lane scheduler (the stage) activates only the tab whose session currently has a command in flight, and only within its own already-backgrounded lane. Because this is Isaac's regular profile, every tab inherits its authenticated sessions. The default pool is four lanes of 16 sessions each, 64 concurrent sessions, and scaling within that never creates a window. A connection that arrives when every lane is full waits up to 60 seconds for a slot before failing closed; it never creates a surprise window.
  4. Tabs created by the agent stay inside the lane that created them and inherit the session's ownership. browser_tabs(new) and a plain window.open() both land in that same lane; window.open() with window features still escapes as a separate Chrome window, which the extension removes as a task-owned spill before failing that session closed. Lane windows never create Chrome tab groups.
  5. Page.bringToFront and Target.activateTarget are suppressed. Logical tab selection therefore does not activate Chrome, replace the user's selected tab, or switch the active macOS Space. If Chrome ever routes a foreign tab into a lane anyway (an external link, a bookmark, a restored tab), the extension evicts it straight to Isaac's last-focused normal window and, if Chrome had focused the lane to deliver it, hands focus back there — the one place ordinary extension code focuses a window, because it is only returning one Chrome just took. A background arrival is moved quietly.
  6. Every agent calls browser_close before its final response. That closes only its own session's task-owned tabs; the lane stays, with its anchor and every other session's tabs untouched. If the user focuses, moves, resizes, minimizes, or maximizes a lane, every session in it ends and its tabs are preserved as reclaimed rather than deleted or pooled.

The lane windows are deliberately not minimized or hidden. A minimized Chrome window stops animation frames and trusted CDP mouse/keyboard input, which makes Playwright clicks and typing appear to hang. A normal-state, unfocused window remains input-capable without becoming the frontmost application; depending on macOS window placement it can exist behind other content, but the bridge must not activate it. Never letting a lane be activated after creation, plus the eviction path above, are what keep external links out of it now that lanes are type: normal rather than type: popup — normal type is required so a lane can hold more than one tab. This containment design is a protected invariant enforced by source comments, runtime policy, and regression tests. Chrome also has to start with --disable-backgrounding-occluded-windows; without it, macOS marks a fully covered window hidden and trusted input can stall even though the window remains normal and unfocused. install.sh --browser-only installs Google Chrome (Agent Safe) into the same Dock position as Chrome. For every restart, fully quit with Command-Q and click that Dock item. It opens the same regular Chrome profile and authenticated sessions. While Chrome is running, the invisible launcher temporarily pins the real Chrome bundle in that exact position so the Dock shows one Chrome icon and normal external links route to the authenticated browser. When Chrome quits, it restores the safe launcher for the next start. Chrome Dev, direct Chrome for Testing workflows, and Browser Use Cloud are retired from authenticated browser control. The managed playwright-isolated route remains available only for logged-out clean-context work. The MCP launcher checks the running main process and fails clearly if Chrome was opened another way or the switch disappeared after an update. The browser-only installer also reapplies the current MCP profile, so authenticated and isolated launcher/config changes are installed together. Existing agent clients must be restarted after that catalog changes.

Every lane contains one inert extension-owned anchor tab. Service-worker restarts remove only the owned tabs of dead sessions and re-adopt the surviving lane by its anchor's marker URL, but only while it holds nothing but that anchor. After a full Chrome restart, restored task tabs are ambiguous because Chrome can reuse numeric IDs; such a window is preserved for the user, left out of the pool, and replaced by the preparer. Cleanup never guesses ownership. Explicit browser_close remains mandatory, and there is no fixed inactivity timeout that could terminate a legitimate silent job.

Authenticated Playwright does not use Chrome DevTools Auto Connect and does not require chrome://inspect/#remote-debugging. Auto Connect is reserved for the leased browser-debug profile when console, network, DOM, tracing, or performance inspection is actually needed. It is broader, permissioned per Chrome session, and does not provide this extension's per-client private-window ownership or cleanup.

Install or update only this browser layer with:

bash ./install.sh --browser-only
# Human-only: open chrome://extensions and click Reload on the unpacked canary.
python3 tests/prepare_browser_workspace_pool.py
~/.local/bin/playwright-mcp-native-bridge --status
bash tests/test-playwright-extension-canary.sh
bash tests/test-browser-mcp.sh
python3 tests/test-playwright-native-bridge.py
python3 tests/live_browser_background_acceptance.py

Pool preparation is the only path allowed to create lane windows. Once it reports four lanes, it has also verified that the personal Chrome selection and external-link target did not change. It talks directly to the native broker and does not start a Playwright client, navigate a page, attach a debugger, or create a temporary agent tab group. New lanes are created directly and observed stable as normal-type, normal-state, and unfocused before they are published to the pool. Chrome itself activates when an extension creates a real window on macOS, even with focused: false. Missing lanes are therefore created only while Chrome is already foreground during intentional startup/setup; the preparer then restores the exact normal user window/tab. The acceptance check proves that it does not change the active Space or personal Chrome selection, or redirect external links away from the user's normal window. Routine agent connections never create windows; scaling from a handful of sessions to dozens only creates background tabs inside lanes that already exist. Routine tasks do not require extension reloads, create extra Dock icons, steal focus, switch macOS Spaces, or accumulate task tabs.

Regression guard: do not restore an earlier lifecycle. The August 19 implementation created, grouped, and minimized a window per connection; it appeared stable for navigation but its acceptance test never exercised animation frames or trusted click/type. The August 20 change made those per-task windows normal and added an immediate focus guard, which exposed Chrome's new-window focus race and could also redirect external links. August 21 fixed that with a popup-type pool leased one window per client, live-proven for four concurrent agents but hard-capped at one tab per agent and at eight windows, because Chrome will not let a popup-type window hold a second tab and creating a window activates Chrome on macOS. The September 4 lane design (0.4.0) replaces per-client windows with per-client background tabs inside a small pool of normal-type lanes, using an active eviction path instead of popup type to keep external links out. Any replacement must pass the live covered-window input, desktop focus, macOS Space, external-link, ownership, no-group, and cleanup checks before installation.

One-time cleanup of legacy Playwright groups

Canary versions before 0.3.6 created a named Chrome group for every connection. Chrome automatically saves and syncs those records, and its extension API has no supported saved-group deletion method. In Chrome's Tab groups menu, right-click only entries whose names begin Playwright ·, choose Delete group, and confirm. Do not delete personal groups such as Crypto. This is a one-time cleanup: private agent workspaces in 0.3.6+ never create Chrome groups.

The live acceptance test uses harmless pages to fully cover the agent window and prove visibility, animation frames, trusted click/type delivery, unchanged frontmost app/tab/Space, and complete browser_close cleanup. This is operational tab ownership, not a complete authorization boundary: browser identity is still shared, page content is untrusted, and publishing, money, IAM, deletion, and other consequential actions retain their normal approval gates. The canary is temporary; signed-upstream replacement criteria are in UPSTREAM.md.

Optional browser profiles

The registry in shared/mcp-registry.yaml is the canonical catalog and version pin:

Profile Purpose Activation
default Argent, Context7, Exa, and authenticated regular-Chrome Playwright agent-mcp-profile default
research Default plus Firecrawl extraction fallback agent-mcp-profile research
browser-debug Authenticated Playwright plus Chrome DevTools debugging agent-mcp-profile browser-debug
kitesurf Stateless public-page rendering through Cloudflare Browser Run agent-mcp-profile kitesurf

kitesurf is a remote, unauthenticated, ephemeral public-page renderer. It has no local cookies or login state and requires its narrowly scoped Cloudflare credentials through the local MCP secret environment. firecrawl is an on-demand research/extraction fallback with its key injected at process launch.

Current pinned MCP components are Argent 0.17.0, Context7 3.2.5, Exa 3.2.1, Firecrawl 3.22.4, @playwright/mcp 0.0.79, and chrome-devtools-mcp 1.6.0. The registry requires client/server capability negotiation; it does not force an MCP protocol version through server arguments.

Zed and the agent clients

Zed is the editor host used in the normal workflow. The portable global settings snapshot is editors/zed/settings.json, restored to ~/.config/zed/settings.json by install.sh. It includes the current theme, fonts, autosave/format-on-save behavior, workspace restoration, and Zed agent defaults. The current snapshot uses the write profile and the configured OpenAI-subscribed gpt-5.4 model at medium effort.

Zed is not the source of truth for the CLI clients. Their portable configuration stays in claude-code/, codex/, and cursor/; their accounts, OAuth state, threads, and caches stay with the client. After installing the binaries, run claude, codex, or cursor-agent from a Zed integrated terminal, or use Zed's agent surface where appropriate.

The current observed command set is:

claude --version
codex --version
cursor-agent --version
zed --version                 # if the Zed CLI is installed on PATH
argent --version              # mobile work only
hermes --version              # optional scheduler
agent-mcp-profile current

T3 Code, Orca, Claude.app, and ChatGPT.app are agent hosts, not separate policy sources. Claude, Codex, Cursor, Grok, and OpenCode sessions launched from them use the same global constitution, runtime overlay, model graph, bounded sub-agent adapter, scoped-test rules, and task-owned cleanup contract. Claude imports the two shared policy files from ~/.claude/CLAUDE.md; Codex resolves ~/.codex/AGENTS.md to ~/AGENTS.md; and the current Cursor CLI discovers AGENTS.md while walking up from a project beneath the home directory. T3 starts each provider in that project's directory, so these mechanics remain in force when the UI is T3 Code rather than a provider's own terminal or editor surface.

The adapter selects a validated versioned Cursor Agent launcher rather than trusting a possibly broken cursor-agent alias. T3 Code uses that same stable launcher for its Cursor ACP provider, with background CLI replacement disabled.

Repository map

Agent-Backup/
├── README.md                 this overview and routing contract
├── SETUP.md                  exact rebuild and daily operations guide
├── AGENT_INSTALL.md          operational restore runbook
├── install.sh                idempotent config restore with backups
├── refresh.sh                manual live-machine refresh
├── regenerate-backup.sh      staged capture and secret gate
├── secrets.env.example       names of optional local injection variables
├── STATE.md                  manual refresh log
│
├── shared/                   cross-runtime policy, graph, registry, launchers
├── agents-skills/            shared skill bodies
├── claude-code/              Claude Code instructions, hooks, skills, plugins
├── codex/                    Codex config, hooks, prompts, agents, skills
├── cursor/                   portable Cursor CLI permissions, MCP config, hooks
├── hermes/                   portable Hermes config
├── opencode/                 OpenCode config, dispatcher agents, git-guard plugin shim
├── docs/                     audit reports (docx)
├── editors/zed/              Zed global settings snapshot
├── external-providers/       vendor-owned Argent, Impeccable, OpenAI, Accio content
├── growth-skills/            manually reviewed, curated growth skill library
├── dotfiles/                 shell and Git configuration templates
├── launchd/                  macOS automation plists (backup refresh is loaded; others placed)
├── config/                   small shared application settings
├── machine/                  inventory generator and optional reinstaller (lists are gitignored)
├── dashboard/                secret-safe documentation app
└── tests/                    shell, policy, browser-launcher, and dashboard checks

regenerate-backup.sh owns the generated categories listed in its CATEGORIES array. Root documentation and the hand-maintained curated material are not silently replaced by a refresh. Third-party files are kept under external-providers/ with their authorship and license boundary.

Skills in agents-skills/ are the real shared bodies. Claude Code, Codex, and Hermes receive relative links that resolve back to this shared content; Cursor, Grok, and OpenCode scan ~/.agents/skills natively. The hetzner-postgres runbook is deliberately not captured (it names live infrastructure). Vendor skills may be refreshed by their own installers; the repository snapshot records the known-good local state but does not claim ownership of vendor source.

Generic release work has two shared modes. ship is the regular proportional path: review and focused verification scale with the change, followed by the complete commit/push/migration/deploy/live-smoke chain. ship-fast activates only for an exact Ship Fast request and removes optional release-tail ceremony while retaining mandatory hooks, required release actions, provider status, and direct live smoke. Neither mode silently invokes CE/LFG or turns a release into a PR-babysitting workflow.

zloop is the shared bounded UI-polish loop: invoke /zloop in Cursor or T3 Code, or $zloop in Codex or Claude. It alternates a designer with a blind cross-runtime visual reviewer, stops at the requested score (default 8/10) or cap (default five rounds), and never turns design iteration into an automatic release.

The shared security bundle is split into five focused skills: appsec-review for technical application security, abuse-fraud-review for business-flow and cost abuse, security-operations for estate/IAM/monitoring/incident/recovery controls, agent-host-security for the local Mac and agent toolchain, and security-preflight for bounded change and release checks. All five default to read-only, separate source, committed/CI, deployed, provider, and live evidence, and prohibit blanket security verdicts.

What is deliberately excluded

The capture is an allowlist, not a broad home-directory backup. It excludes:

  • passwords, API values, OAuth tokens, private keys, cookies, browser profiles, authorization headers, and remote-debugging capability values;
  • Claude/Codex/Cursor/Hermes account databases, histories, logs, caches, project trust records, runtime databases, and personal memory stores;
  • Zed account data, extension installations, threads, and workspace databases;
  • Hermes secrets, sessions, memories, runtime databases, and project cron jobs;
  • project repositories, client data, provider dashboards, and application data;
  • GUI/App Store installation state beyond the factual machine inventory;
  • the Codex vendor-managed .system skills and project-owned mobile booking skill;
  • retired skills and any other removed runtime wiring.

The root ~/.claude.json user state is deliberately not replaced by install.sh; the MCP profile manager updates only its supported user-scope MCP entries and keeps a rollback journal. Existing alternate or legacy runtime directories are not silently folded into the canonical snapshot. They must be reviewed explicitly before being added.

Secret handling

secrets.env.example documents the optional values used by this setup: EXA_API_KEY, FIRECRAWL_API_KEY, ZAI_API_KEY, NPM_TOKEN, and optional Git identity values. A real secrets.env is gitignored. On Isaac's machine, Infisical is the preferred broker: inject values per process rather than writing a durable .env file.

Every refresh runs a staged secret gate using Gitleaks and the known-prefix checks. If capture, templating, validation, or either gate fails, the repository is not synced. The installer creates a timestamped local backup before replacing an existing file. Never print a secret to verify that it worked; verify only the presence, mode, names, and behavior of the resulting configuration.

Keeping it current

The snapshot refreshes itself daily at 07:30 (regenerate only). Manual refresh:

cd ~/Agent-Backup
bash ./refresh.sh
git status --short
git diff --check

The refresh reads the live managed roots and launchers, normalizes the portable MCP profile to default, tokenizes paths and secrets, and reports local changes. It is portable when run from a clone: AGENT_SETUP_HOME and AGENT_SETUP_REPO can override the live home and repository paths for a controlled test or another machine.

The machine inventory is a separate deliberate operation:

cd ~/Agent-Backup/machine
bash ./regenerate-machine.sh

It updates package and application manifests. It does not install anything and does not decide which GUI applications belong on a restored machine.

Verification

Run checks proportional to the files changed. For lifecycle-control changes, the focused path is:

bash -n shared/bin/agent-resource-reaper shared/bin/agent-status tests/test-agent-resources.sh
python3 -c 'compile(open("shared/bin/agent-resource-control").read(), "agent-resource-control", "exec")'
bash tests/test-agent-resources.sh
node dashboard/scripts/test-control-plane.mjs

Do not automatically expand an ordinary change into every browser, subagent, dashboard, or repository test. The broader suite is reserved for an explicitly requested full verification or a change that actually crosses those boundaries. Publication still runs the repository's secret gates before commit or deployment.

For a restored machine, also confirm policy and runtime parity:

agent-policy-lint                 # 0 fail expected
bash tests/test-policy-lint.sh    # same lint against this repo's own tree
bash ./install.sh --guard-only
agent-mcp-profile current
test -f "$HOME/.agents/AGENTS.md"
test -f "$HOME/.agents/agent-graph.yaml"
test -f "$HOME/.config/zed/settings.json"
cmp -s shared/bin/browser-mcp-server "$HOME/.local/bin/browser-mcp-server"
cmp -s shared/bin/agent-resource-control "$HOME/.local/bin/agent-resource-control"
agent-resource-reaper --dry-run
agent-status

An active agent client may retain its startup tool catalog. Restart or resume that client after changing an MCP profile. Stop only helpers created for the current task; never terminate another user's browser, simulator, server, or terminal by process-name matching.

License and ownership

The root repository is MIT-licensed. Vendor material under external-providers/ retains its own authorship and license. The setup is intended to be readable and reproducible, but credentials and account state must always be supplied by the person restoring it.

About

One Mac, six coding agents, one rulebook: a portable, secret-free snapshot of a multi-agent coding setup (Claude Code, Codex, Cursor, Grok, OpenCode, Hermes).

Resources

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages