Installation
Mister Claude is a Node.js launcher (mrc.js) that drives Docker. You need a Docker engine, and on macOS the lightweight choice is Colima — no Docker Desktop, no GUI, no license fees.
1 · Prerequisites (macOS)
- node — runtime for the
mrclauncher - docker + docker-buildx — the CLI client and build plugin
- colima — the Linux VM that runs the Docker daemon
- terminal-notifier — native macOS desktop notifications
If you already have a ~/.docker/config.json, merge the cliPluginsExtraDirs key in by hand rather than overwriting the file.
2 · Install mrc
The install script drops a launcher into ~/.local/bin/mrc and the Docker build context into ~/.local/share/mrc/:
Or from source (requires Node.js 22+):
On Linux with a native Docker daemon, skip Colima entirely — mrc talks to Docker directly. Swap terminal-notifier for notify-send (usually in libnotify-bin).
Configuration
Three sources, merged in order — global config, per-repo config, then CLI flags. CLI flags always win.
.mrcrc files
One CLI flag per line; # for comments. Global defaults live in ~/.mrcrc; per-repo overrides in <repo>/.mrcrc.
API keys & .env
mrc loads a .env from next to the launcher, or from ~/.config/mrc/.env. Both Anthropic and OpenAI keys are picked up.
Use op:// references and mrc resolves them through the 1Password CLI at launch — keys never touch disk in plaintext:
This key is not your Claude Code subscription. It powers small Haiku calls for session naming and summaries. A dedicated key lets you revoke it independently. Claude Code itself authenticates inside the container as usual.
Environment variables
| Variable | Purpose |
|---|---|
| ANTHROPIC_API_KEY | Anthropic key — from env, .env, or ~/.config/mrc/.env |
| OPENAI_API_KEY | OpenAI key — required for --agent codex |
| MRC_PORT_BASE | Starting port for proxy allocation (default 7722) |
| MRC_HOME | Override the Docker build-context directory (advanced) |
Usage
Point mrc at a repo. Pass anything after -- straight through to Claude Code.
When you quit, the container disappears — your files are safe on the host, only the container is ephemeral. Reopening the same repo auto-resumes via --continue.
Agent teams
Mister Claude can run a whole team of agents on one problem — an architect, engineers, a critic, an adversary — each in its own sandboxed container behind the same firewall, addressing each other by @mention. You steer from a web dashboard or your phone: they propose; you steer; you commit.
Define a roster
A team is a team.json file of members, each with a role and a backend. Write the file, start from a preset, or build one in the dashboard:
Or start from a ready-made preset — game, web, mobile, backend (mrc team presets lists them):
- Roles — architect, engineer, critic, adversary, ultracritical, user-defender, researcher, tester (plus media makers). One lead per team bridges to the shared leads room.
- Write territory — each member's
territoryis mounted read-write and everything else read-only, so two engineers never clobber each other's files and a critic is read-only by capability. - Live vs worker —
claudemembers are live participants;codex/qwenmembers are task-workers (a directed @mention runs their CLI for one turn).
Launch & attach
Each live member boots in its own terminal — you accept its one-time Channels prompt to bring it online. A team isn't hands-free, by design: that per-member accept, plus you commit every change, is the control, not a caveat.
Steer from the dashboard
mrc rooms dashboard opens a local web app for the whole org — every team room, live transcripts, and your inbox. Each project is a tab:
- Close = suspend — stops the members but keeps the team, transcripts, and history; Resume relaunches it and each member picks up its own conversation.
- Delete project — forgets the org from Mister Claude (stops sessions, drops the tab) but deletes nothing on disk: your repo,
team.json, and transcripts stay, so you can re-add it withmrc team up.
The @you inbox
When a member needs you, it lands in your inbox as one of two kinds:
- Question (from
ask_user) — badged; framed "reply to answer". - Notification / FYI (a plain
@user) — reply optional; visible everywhere, nags nowhere.
Both are replyable (your reply routes back to the member as a directive). Dismiss what you don't need — it's recoverable. Each item carries a stable #N id, and the inbox persists across daemon restarts.
Answer from your phone (Telegram)
Optional: link a Telegram bot and the team's questions and FYIs push to your phone — reply there and it routes back to the right agent. Each project uses its own bot, and linking is human-gated (nothing auto-binds):
Create a bot
DM @BotFather → /newbot → copy the token.
Add the token to the project
Put it in that repo's own .env (read strictly per-project — no global fallback): MRC_TELEGRAM_BOT_TOKEN=123456:ABC-…
Bring the project up
mrc team up — the daemon starts the bridge for any project that has a token.
DM the bot /start
from the phone or account you want to link.
Confirm in the dashboard
the chat appears as pending on that project's tab → click Confirm (Reject an unexpected one). Linked.
Questions push as ❓ "reply to answer", FYIs as 🔔 "reply optional", both with the same #N. Reply on either surface and it syncs to the other; Unpair on the tab anytime.
Trust & control
A teammate's message — even the architect's — is untrusted peer data; only your own directives (a steer, or an inbox/Telegram reply) carry authority, and forged "human" markers in agent text are defanged. Members can't overwrite each other's files or reach the open internet, a critic reviews risky work when called, and you commit every change. See the Security model for the layered boundary.
The full architecture — topology, the trust model, and what's tested — lives in docs/agent-teams.md in the repo.
CLI reference
mrc [options] [path-to-repo] [-- claude-code-args...]
Options
| Flag | Description |
|---|---|
| -r, --rebuild | Force a full image rebuild (no cache) |
| -v, --verbose | Show Colima and Docker output |
| -n, --new [name] | Start a new conversation (optionally named) |
| -w, --web | Allow outbound HTTPS to any host |
| --agent <name> | Agent to launch: claude (default) or codex |
| --daemon | Start the container detached and print its ID |
| -j, --json | Stream stream-json instead of an interactive TTY |
| --no-summary | Skip the AI session summary on exit |
| --no-notify | Disable desktop notifications entirely |
| --no-sound | Notify silently (no sound) |
| --colima-cpu N | CPUs for the Colima VM (default: all host cores) |
| --colima-memory N | Memory in GB (default: half host RAM, min 8) |
Commands
| Command | Description |
|---|---|
| mrc status | Show active containers across all repos (no key needed) |
| mrc pick [path] | Interactive session picker (arrow keys) |
| mrc sessions ls [path] | List saved sessions |
| mrc sessions name <name> [#] [path] | Name a session (defaults to most recent) |
| mrc sessions resume <name-or-#> [path] | Resume a specific session |
| mrc sessions pick [path] | Alias for mrc pick |
Sessions
Every conversation is a .jsonl file in .mrc/. They auto-resume, auto-name, and auto-summarize.
- Auto-resume — reopening a repo continues the last conversation (
--continue). - Named sessions —
mrc --new bugfixstarts fresh with a name; names live in.mrc/session-names. - AI names & summaries — once enough conversation builds up, a Haiku call names and summarizes it (skip with
--no-summary). - Tool-miss detection — on exit,
mrcreports any tools Claude reached for but didn't have, with a one-click GitHub issue link.
.sandboxignore
Hide secrets and infrastructure from the container. Works like .gitignore and is recursive — drop a .sandboxignore anywhere in the tree and its entries resolve relative to that directory.
- Files are masked with
/dev/null— they appear empty inside the container. - Directories get an anonymous volume overlay — they appear as empty dirs.
- Comments (
#) and blank lines are supported.
He doesn't know what he's missing. Even if Claude is convinced your AWS keys must be somewhere, the bytes simply aren't in the container.
Colima resources
By default the Colima VM gets all your CPU cores and half your RAM (with an 8 GB floor). Override per-run or in .mrcrc:
Colima is a single shared VM. These settings take effect when mrc starts Colima — if it's already running, it keeps its current size. To resize: colima stop then run mrc again.
Claude & Codex
Claude Code is the default. Pass --agent codex to launch OpenAI's Codex CLI in the same sandbox instead.
- Codex needs
OPENAI_API_KEYin your environment or.env. - Claude config persists in
mrc-config-<hash>; Codex config in a separatemrc-codex-<hash>volume. - Session naming & summaries are Claude-only — they're skipped for Codex.
- The firewall already whitelists
api.openai.com, so Codex works out of the box.
Clipboard (image paste)
Text paste works through the terminal already. Images need a bridge — mrc ships one as an in-process TCP proxy (no socat, no external dependency).
mrcstarts a clipboard server on a dynamic port (fromMRC_PORT_BASE, default 7722).- Inside the container, a shim at
/usr/local/bin/xclipintercepts Claude's clipboard reads. - The shim fetches clipboard data over
host.docker.internal.
The banner shows Clipboard: the Schwartz can see your clipboard when it's live. Just copy an image and press Ctrl+V inside Claude Code.
Check /tmp/mrc-xclip-shim.log inside the container. A "No route to host" there usually means a stale firewall — rebuild with docker rmi mister-claude.
Notifications
A Claude Code Stop hook fires when he finishes responding. The container-side hook sends the repo name and a one-line summary to a host-side proxy, which fires a native notification (terminal-notifier on macOS, notify-send on Linux).
System Settings → Notifications → terminal-notifier → set the style to Banners or Alerts and toggle Allow Notifications on. To let them through Do Not Disturb, add terminal-notifier under Focus → Allowed Notifications.
Status line
A live bar at the bottom of every session: context-window usage, plus 5-hour and 7-day rate-limit gauges, plus the session name.
| Range | Color | Meaning |
|---|---|---|
| 0–59% | Green | Normal usage |
| 60–76% | Yellow | Getting full |
| 77–100% | Red | Compaction imminent (Claude reserves ~15%) |
It's installed automatically on container start — but only if you haven't set your own. A custom /statusline always wins.
Data persistence
Two places, two jobs:
| Location | Holds | Lifecycle |
|---|---|---|
| mrc-config-<hash> | Global Claude config: auth, settings, plugins | Docker volume, per repo |
| mrc-codex-<hash> | Codex config | Docker volume, per repo |
| .mrc/ in your repo | Memory, conversation history, project settings | Lives in the repo; survives volume resets |
Each repo gets its own volumes (keyed by an MD5 hash of the repo path) so projects never cross-contaminate. .mrc/ is auto-created and auto-added to .gitignore, and is symlinked from ~/.claude/projects/-workspace/ inside the container.
Security model
The whole design rests on one idea: the container is the security boundary, not Claude's own permission prompts. That's what makes --dangerously-skip-permissions safe here.
What the firewall does
- Resolves the allowlist to IPs at boot and pins them in an
ipset. - Sets the default
iptablespolicy to DROP on INPUT, OUTPUT, and FORWARD. - Adds an explicit REJECT for non-allowed outbound traffic, so blocked calls fail instantly instead of hanging.
- Blocks all IPv6 — otherwise an IPv6-capable service could sidestep the IPv4 rules.
- Allows the host only on the dynamic proxy ports — your local Postgres, Redis, and everything else stay unreachable.
- Verifies the lock by confirming
example.comis unreachable before handing control to Claude.
The allowlist
Add your own (a private registry, an internal API) by editing the for domain in ... loop in init-firewall.sh, then rebuild. With --web, outbound HTTPS (port 443) opens to any host while every other rule stays in force.
Other guarantees
- UID/GID matching — the image is built with your host UID/GID, so bind-mounted files keep correct ownership and Claude runs as a non-root
coderuser. - Scoped sudo —
codermay run exactly one command with sudo: the firewall script. Nothing else. - Ephemeral containers — every container runs with
--rm; quit and it's gone. - NET_ADMIN / NET_RAW only — the container gets just the capabilities needed to firewall itself.
The allowlist is short on purpose. Every domain you add is a door. Prefer .sandboxignore for secrets and --web only when you actually need the open web.
Updating
Claude Code's version is baked into the image at build time, and auto-update is disabled inside the container (the firewall blocks the npm CDN hosts it would need). To get a newer Claude Code, rebuild:
mrc nudges you when the image is more than four days old. Rebuilding also picks up changes to the Dockerfile, entrypoint, firewall rules, and container scripts.
Troubleshooting
| Symptom | Fix |
|---|---|
| docker: command not found | brew install docker docker-buildx colima and ensure Homebrew is on your PATH. |
| Cannot connect to the Docker daemon | Colima isn't running. Just run mrc — it auto-starts Colima — or colima start --vm-type vz --mount-type virtiofs. |
| Network not ready after 30 attempts | DNS didn't come up in the VM. colima stop && colima start --vm-type vz --mount-type virtiofs. |
| Firewall verification failed | iptables rules didn't apply. Confirm the container has NET_ADMIN/NET_RAW (mrc adds these automatically). |
| Permission errors on mounted files | The image is built with your UID/GID. Rebuild: docker rmi mister-claude, then mrc. |
| Auto-update failed (inside container) | Expected — the image version is pinned. Rebuild to update Claude Code. |
| Slow file access | Make sure Colima runs with --mount-type virtiofs (mrc does this when it starts the VM). |
| Codex: Permission denied loading config | Rebuild the image so ~/.codex is created with the right owner: docker rmi mister-claude. |
Still stuck? Open an issue at github.com/aisaacs/mrc — and run with -v to capture the Colima/Docker output.