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.
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:
~/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.~/.agents/AGENTS.md, the runtime overlay. Which model orchestrates, which model does routine work, which one reviews, how to delegate safely.~/.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.
| 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).
- 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. - Named delegate is binding (
delegate_selectionin 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. - 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 inAGENTS.mdor a skill, capped by[agents]in its config (max_concurrent_threads_per_session = 6,max_depth = 1). - Fast, mechanical work has one preference order (
fast_worker_preference): Luna athigh(mediumfor 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. - 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. - 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.
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).
| 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 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.
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.
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.
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.
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.
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.)
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.shrefresh.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.
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.shThe 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.
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.
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-controlis tagged with the session id (CLAUDE_CODE_SESSION_ID,CODEX_THREAD_ID). The sharedSessionEndhook (claude-code/guards/session-end.sh, wired in Claude Code and Codex) runsstop-sessionfor 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-statusshows 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.
Operating manual:
BROWSER-AUTOMATION.mdis 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.
| 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.
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
- The launcher validates the native host, the exact unpacked canary directory,
and the owner-only mode-
0600token at~/.config/playwright-mcp-extension-token. It fails closed rather than opening an isolated, logged-out browser. - 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.
- Canary
0.4.0creates the session's task tab silently inside whichever lane (atype: normal,state: normal,focused: falsepool 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. - Tabs created by the agent stay inside the lane that created them and inherit
the session's ownership.
browser_tabs(new)and a plainwindow.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. Page.bringToFrontandTarget.activateTargetare 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.- Every agent calls
browser_closebefore 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.pyPool 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.
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.
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 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 currentT3 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.
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.
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
.systemskills 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.
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.
The snapshot refreshes itself daily at 07:30 (regenerate only). Manual refresh:
cd ~/Agent-Backup
bash ./refresh.sh
git status --short
git diff --checkThe 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.shIt updates package and application manifests. It does not install anything and does not decide which GUI applications belong on a restored machine.
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.mjsDo 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-statusAn 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.
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.