Claude Code Just Got Diversity
Claude Code sessions have been able to message each other since August. What I have not seen anyone doing yet is putting a different vendor's model behind each session and keeping the messaging working: Claude on my subscription, open weights through Ollama, ten vendors through OpenRouter, a model on my own GPU, seventeen seats in one roster, each with a role, getting work done and validated among themselves.
What is new here, and what is not
Cross-session messaging shipped in Claude Code v2.1.224, the week of August 3 to 7, 2026. Claude discovers your other sessions on the machine with a ListAgents tool and sends with SendMessage. The message is text one Claude writes for another, delivered over a per-session Unix socket that never touches Anthropic's servers. Two months on, that is table stakes, and the docs cover it well.
What the docs assume, quietly, is that every session on the far end is Claude.
It does not have to be. In July I wrote about running Claude Code against Ollama. Claude Code is an agent harness that happens to ship pointed at Anthropic. Change the base URL and it is the same harness, same tool loop, same skills, with a different brain behind it. Any provider that speaks the Anthropic Messages API can sit behind a session, and Ollama and OpenRouter both do, natively.
Put the two together and you get something no vendor has an incentive to build: a team of Claude Code sessions where each seat runs a different lab's weights, and the harness's own messaging lets them coordinate without you in the middle. The messaging is the harness's job, not the model's.
The reason I care is not the plumbing. It is the point of view each seat brings. My last post, on October 4, was about the Developer, Reviewer, Critic team I have run across providers for over a year, with a Security seat and a PMO alongside. The value was never that one model is smarter. It is that a Reviewer on one lab's weights does not share the Developer's blind spots, and a Critic on a third lab's weights refuses to inherit either of their trust. Until now the handoffs between those seats went through me or through a database. Now the Developer messages the Reviewer, the Reviewer re-runs it and messages the Critic, and the Critic rules, each in its own session with its own brain.
The roster
This is ListAgents as seen by a coordinator session I named DESK, running Claude Sonnet on my Max subscription, in a fresh config directory set up for the demo:
This session is DESK [9cf94c] — the name other sessions use to message it.
Peer sessions (17):
OLLAMA_KIMI [a2b9de] · bg · idle · started 4m ago
OLLAMA_GLM [a55b4d] · bg · idle · started 4m ago
HAIKU [7548a8] · bg · idle · started 4m ago
OLLAMA_MISTRAL [065dae] · bg · idle · started 4m ago
MISTRAL [1b5bcc] · bg · idle · started 5m ago
3k1o-dc [c5700a] · interactive · idle · started 34m ago
GEMINI [36dad3] · bg · idle · started 5m ago
GPT [c48808] · bg · idle · started 5m ago
OLLAMA_DEEPSEEK [ea64fa] · bg · idle · started 4m ago
OPUS [c14fb0] · bg · idle · started 6m ago
LOCAL_GPTOSS [791bc3] · bg · idle · started 4m ago
DEEPSEEK [233cde] · bg · idle · started 5m ago
KIMI [8b7d6c] · bg · idle · started 5m ago
LLAMA [fda21a] · bg · idle · started 5m ago
GROK [c01747] · bg · idle · started 5m ago
GLM [ee1cae] · bg · idle · started 4m ago
QWEN [100b93] · bg · idle · started 5m ago
| Source | Seats | Model tags, from each seat's own transcript | Meter |
|---|---|---|---|
| Anthropic, direct | DESK, OPUS | claude-sonnet-5-5, claude-opus-5-5 | Claude Max subscription |
| Ollama Cloud | OLLAMA_KIMI, OLLAMA_MISTRAL, OLLAMA_GLM, OLLAMA_DEEPSEEK | kimi-k3:cloud, mistral-large-4:cloud, glm-5.3:cloud, deepseek-v4-pro:cloud | Ollama Pro, $20/mo |
| Ollama, local | LOCAL_GPTOSS | gpt-oss:20b, 13 GB resident on the 4070 | my GPU |
| OpenRouter | GPT, GEMINI, GROK, LLAMA, MISTRAL, DEEPSEEK, QWEN, KIMI, GLM, HAIKU | gpt-6-luna-pro, gemini-3.8-flash, grok-4.3, llama-4-maverick, mistral-small-2603, deepseek-v4.1-flash, qwen3.8-flash, kimi-k3, glm-5.3-flash, claude-haiku-5.5 | OpenRouter credits |
| (me) | 3k1o-dc | the terminal I ran /login from, still open |
subscription |
One claude binary, one config directory, one subscription login, one Ollama sign-in, one OpenRouter key. Kimi, DeepSeek and GLM each appear twice, once through Ollama and once through OpenRouter, which is the point: the seat does not care which road the weights came in on.
DESK sent all sixteen the same request: list your peers and message me back with your model and provider. Twelve did, in about two minutes:
ACK from OPUS: model=claude-opus-5-5, provider=unknown, peers=17 [OPUS]
ACK from HAIKU: model=claude-haiku-5.5, provider=anthropic, peers=17
ACK from DEEPSEEK: model=deepseek/deepseek-v4.1-flash-1017, provider=unknown, peers=17
ACK from OLLAMA_DEEPSEEK: model=deepseek-v4-pro:cloud, provider=cloud, peers=17
ACK from GLM: model=z-ai/glm-5.3-flash, provider=z.ai, peers=1
ACK from KIMI: model=kimi-k3, provider=Moonshot AI (moonshotai), peers=17
ACK from OLLAMA_KIMI: model=kimi-k3:cloud, provider=cloud, peers=17
ACK from OLLAMA_GLM: model=glm-5.3:cloud, provider=cloud (glm-5.3:cloud), peers=17
ACK from QWEN: model=qwen/qwen3.8-flash, provider=unknown, peers=17
ACK from GPT: model=gpt-6-luna-pro, provider=OpenAI, peers=2
ACK from GEMINI: model=google/gemini-3.8-flash, provider=Google, peers=17
ACK from OLLAMA_MISTRAL: model=mistral-large-4:cloud, provider=ollama cloud, peers=17
All four Ollama Cloud seats answered. Opus, DeepSeek and Qwen wrote provider=unknown rather than guess, because nothing inside a session shows it the base URL. On an earlier pass Opus spelled it out: "per system prompt; endpoint not independently verified." A model declining to assert what it cannot see is the behavior I pay a Critic for, and it showed up unprompted in a ping test.
The message I actually wanted has no Claude in the middle of it. On a pass with the same seats I told GPT to message GEMINI, and GEMINI to forward whatever GPT sent. What arrived at DESK:
GEMINI forwarding: relay from GPT: hello Gemini, forward this line to DESK
OpenAI's model wrote to Google's model, which wrote to Anthropic's model, over a Unix socket on my desk, inside a tool Anthropic ships. When I pointed the same relay at an Ollama seat on the seventeen-peer run (GPT to OLLAMA_KIMI to DESK) it did not complete. OLLAMA_KIMI confirmed it was ready to forward, GPT sent its own ACK, and GPT's transcript says its send to OLLAMA_KIMI was "denied as an external system write." I did not see the denial from the harness side, only GPT's report of it, so I will say this much: each session's permission boundary is its own, a peer message cannot loosen it, and this time that cost me a relay. I would rather have that than the alternative.
The four that did not answer, run twice
I gave the four misses a second run an hour later, same seat files, same prompt, nothing else changed.
| Seat | First run | Second run |
|---|---|---|
| GROK (grok-4.3, OpenRouter) | Called SendFeedback three times to file reports about the mesh check, wrote a correct ACK line as plain text, never called SendMessage |
Same three SendFeedback calls, this time refused ("not enabled in this session"), then loaded SendMessage through ToolSearch on its own and ACKed properly: model=grok-4.3, provider=x-ai, peers=5 |
| LLAMA (llama-4-maverick, OpenRouter) | API Error: 502 Model call failed: upstream returned an invalid response |
Spawned two subagents instead of calling the tool itself. DESK received their stray hand-back lines, "[LLAMA] Ready" and "[LLAMA] ACK". The real ACK line was printed as text and never sent |
| MISTRAL (mistral-small-2603, OpenRouter) | Composed the ACK as plain text with peers=0, never sent it |
ListAgents worked, then "tool call could not be parsed", twice. Mistral Large 4 through Ollama Cloud answered fine both times |
| LOCAL_GPTOSS (gpt-oss:20b, my GPU) | Printed the keyboard-shortcut help, then an ACK as plain text identifying itself as claude-3-5-sonnet-20240630 |
Never processed the prompt. Answered "How can I help you today?" and sat there. No transcript written |
Every one of those is the model, not the mesh. The sockets were bound, the names resolved, the messages were accepted into each inbox. What differed was whether the model on the far end could read a plain instruction, find the right tool among the hundred-plus a Claude Code session exposes, and call it with the right shape. The frontier and strong mid-tier models did it in seconds, through either road. The small or older ones composed the right words and put them in the wrong place. Grok is the instructive one: a frontier model that got there on the second try, by a detour, once its first wrong tool was closed off. That is a seat I would keep, with a shorter leash. Joining the roster is free. Holding a job is a property of the model, and the cheapest way I know to measure it for my work is to put the candidate in a chair next to the incumbent and send it one message.
The team that does work
Pings prove reachability. The point is the roles. Same config directory, six seats counting DESK, each launched from a folder holding a one-paragraph seat file:
| Seat | Model | Served by |
|---|---|---|
| DESK | claude-sonnet-5-5 | Anthropic, Max subscription |
| CRITIC | claude-opus-5-5 | Anthropic, Max subscription |
| DEVELOPER | deepseek-v4-pro:cloud | Ollama Cloud |
| REVIEWER | glm-5.3:cloud | Ollama Cloud |
| SECURITY | openai/gpt-6-luna-pro | OpenRouter |
| DBA | gpt-oss:20b | Ollama, local GPU |
Four of five ACKed. DBA, the local gpt-oss:20b seat, did not, the same way LOCAL_GPTOSS did not in the table above.
ACK from REVIEWER: model=glm-5.3:cloud, provider=cloud (GLM), peers=DBA, DEVELOPER, 3k1o-dc, SECURITY, DESK, CRITIC
ACK from CRITIC: model=claude-opus-5-5, provider=Anthropic, peers=DBA, DEVELOPER, REVIEWER, 3k1o-dc, SECURITY, DESK [CRITIC]
ACK from DEVELOPER: model=deepseek-v4-pro, provider=cloud, peers=DBA,REVIEWER,3k1o-dc,SECURITY,DESK,CRITIC
ACK from SECURITY: model=openai/gpt-6-luna-pro, provider=OpenAI, peers=DBA, DEVELOPER, REVIEWER, 3k1o-dc, DESK, CRITIC
Start with the smallest job that still has three hops. On a later run I swapped REVIEWER's chair to openai/gpt-6-luna-pro through OpenRouter, so this chain is three vendors on three roads: DeepSeek through Ollama Cloud, OpenAI through a broker, Anthropic on the subscription. DESK sent DEVELOPER one message: write print_arg.py, a script that takes exactly one argument and prints it, exits 2 with a usage line on stderr for zero or two arguments, run it three ways, and send the code and outputs to REVIEWER. Seventy-five seconds later the ruling was in DESK's inbox.
DEVELOPER (DeepSeek, Ollama Cloud) to REVIEWER:
#!/usr/bin/env python3
import sys
def main():
if len(sys.argv) != 2:
print("Usage: print_arg.py <argument>", file=sys.stderr)
sys.exit(2)
print(sys.argv[1])
if __name__ == "__main__":
main()
Tested three ways (exit codes in parens):
$ python3 print_arg.py hello
hello
(exit=0)
$ python3 print_arg.py
Usage: print_arg.py <argument>
(exit=2)
$ python3 print_arg.py foo bar
Usage: print_arg.py <argument>
(exit=2)
[DEVELOPER]
REVIEWER (GPT-6, OpenRouter) to CRITIC:
Code reviewed at the path given: checks
len(sys.argv) != 2, writes usage to stderr and exits 2, otherwise prints sole argument. I ran the three reported invocations:helloexit 0; no arg and two args each usage + exit 2. No real finding. REVIEWER VERDICT: PASS expected argument handling confirmed. [REVIEWER]
CRITIC (Opus, Anthropic subscription) to DESK:
CRITIC RULING: PASS. print_arg.py re-derived independently: exactly one arg prints it (exit 0); 0 or 2+ args print usage to stderr only, exit 2. Also checked: "" prints empty line, "a b" and "-h" pass through verbatim, exit 0. [CRITIC]
Three things to notice before the harder one. The Reviewer did not take the Developer's word for the test output; it read the file and ran the three cases itself. The Critic did not take the Reviewer's word either; it ran them again and added three cases nobody asked for, the empty string, an argument with a space, and -h, which a lazier script would have swallowed as a flag. And every message is signed with the seat, not the model, so you can swap any chair tomorrow and the audit trail still reads the same. That is a passing grade from three companies that do not share a server, and it cost less than a cent on the broker side.
Now the one that earns its keep. DESK handed DEVELOPER a second task, with REVIEWER back on GLM through Ollama Cloud: write safe_div(a, b) that returns a/b, returns None on a zero divisor, raises TypeError on non-numeric input, with three edge-case asserts, and send it to REVIEWER. Nobody relayed anything after that. Each hop below is lifted from the sending seat's transcript.
DEVELOPER (DeepSeek, Ollama) to REVIEWER:
import numbers
def safe_div(a, b):
if not isinstance(a, numbers.Number) or not isinstance(b, numbers.Number):
raise TypeError("non-numeric input")
if b == 0:
return None
return a / b
Tested: ran it with three edge-case asserts, normal division (10/2 == 5.0), zero divisor (10/0 is None), and non-numeric ("a", 2) raises TypeError. All passed.
REVIEWER (GLM, Ollama) to CRITIC:
I ran it myself: DEVELOPER's three asserts pass. Extra traces also behave: 0.0 and -0.0 divisors give None, Decimal(0) divisor gives None, None input raises TypeError, complex/Fraction fine. Only quirk: bools are numbers.Number (True/2==0.5), standard Python semantics, not a defect. No real finding. REVIEWER VERDICT: PASS verified by execution; behavior matches spec on all traced edge cases.
CRITIC (Opus, Anthropic subscription) to DESK:
CRITIC RULING: FAIL. safe_div still raises on numeric inputs that pass its own guard: safe_div(10**400, 1) raises OverflowError, and safe_div(Decimal(1), 2.0) or a Decimal/Fraction mix raises an uncaught TypeError from the division itself. Re-derived by running it myself. The 3 asserts pass, and so do 0, -0.0, Decimal(0), Fraction and complex. REVIEWER's PASS missed that numbers.Number lets through types that can't divide each other, and that int/int can overflow float. Whether 1/1e-320 returning inf counts as a defect depends on the spec, which only has 3 asserts. Spec owner should decide: catch (OverflowError, TypeError) and return None/raise, or narrow the accepted types.
Read that as a provider-diversity result, because that is what it is. Zhipu's model executed the code, traced seven extra cases, and passed it. Anthropic's model refused to inherit that trust, executed it again, and found two inputs that satisfy the function's own type guard and still blow up. Then it separated the real defects from the judgment calls and sent the judgment calls back to the spec owner instead of inventing a spec. I did not touch a keyboard between "send the task" and "read the ruling."
Two small things made that chain legible. Every seat file ends with "sign every message with this session's name, never with the harness name," because in my very first test every seat, Mistral and GLM and DeepSeek alike, signed as [Claude]; the harness identity leaked over the model identity, and in a mixed team that erases the diversity from the audit trail. And every seat is named for its role, so the transcript's model field, not the name, tells you which brain was in the chair.
The rule, and three traps
Peers are discovered per CLAUDE_CONFIG_DIR. Providers are set per seat. Everything else follows from that sentence.
I made it harder than it needed to be the first time by building profiles, and that itself limited me. My July setup is a separate config directory pointed at Ollama, and four cloud models launched through it found and messaged each other within nine minutes. Then I tried to message them from my everyday Claude session:
SendMessage → MISTRAL
{"success":false,"message":"No agent named 'MISTRAL' is reachable.\nUse ListAgents to see everyone you can message."}
Same Linux user, sockets side by side in /run/user/1000/cc-socks/, no visibility. Each config directory runs its own background daemon with its own roster, and ListAgents reads that roster. A profile buys isolation, and isolation was the problem.
The second half is what a config directory does not hold. ANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN, and --model are read per session. Nothing says every session in a directory has to use the same provider. So: one directory for the whole team, the provider set per seat, and the subscription seats need nothing at all because the directory is logged in.
Trap 1: --bg throws away your environment
The obvious way to set a provider per seat is an environment prefix, and it fails silently:
env ANTHROPIC_BASE_URL=http://127.0.0.1:11434 ANTHROPIC_AUTH_TOKEN=ollama ANTHROPIC_API_KEY= \
claude --bg --name KIMI --model kimi-k3:cloud ...
There's an issue with the selected model (kimi-k3:cloud). It may not exist or you may
not have access to it. Run /model to pick a different model.
The session went to api.anthropic.com and asked for a Kimi model. A --bg session is not a child of your shell. The directory's daemon spawns it, and it inherits the daemon's environment plus a short list of keys the dispatcher forwards by name. The daemon's roster file records what it passed: env passed to worker: {}. Pass the override as settings instead. --settings takes a file, the dispatcher carries it to the worker, and a 0600 file keeps the key off the command line:
kimi-k3:cloud · API Usage Billing
READY KIMI_BG2
Trap 2: a fresh directory has three gates
I built the demo in a brand-new config directory so the roster would hold only demo seats. Three gates, and I hit all three.
Workspace trust. Every --bg launch refused with "Workspace not trusted. Run claude in .claude.json. Open each seat folder interactively once, or seed the flag the way I did in the NVIDIA post.
Login. The subscription seats came up "Not logged in · Please run /login." A new directory has no credentials, and your main directory's login does not carry over. One interactive /login in the new directory covers every seat launched there afterwards.
A stale key in your shell beats your login. After logging in, the subscription seats still failed: "Invalid API key · Fix external API key." My shell exports an ANTHROPIC_API_KEY from some long-dead experiment, the API returns 401 for it, and Claude Code gives an environment key precedence over a login. My everyday sessions had been working on OAuth while I ignored a warning about "connectors disabled because ANTHROPIC_API_KEY is set." Launch the team from a shell with it unset, because the daemon inherits that shell. The claude-opus-5-5 in CRITIC's transcript and the "Claude Max" banner are the proof that the subscription paid for that seat.
Trap 3: ~ does not expand inside ${...}
Fifteen of my sixteen seats died on launch when I wrapped the settings path in a parameter expansion: ${provider:+--settings ~/.claude-seats/$provider.json} hands Claude Code a literal tilde. The one seat without a provider file was fine. Use $HOME. Pure shell, nothing to do with Claude Code, and it will get you anyway.
The recipe
# 0. Claude Code 2.1.224+ and an Ollama that answers /v1/messages (0.33.3 here).
# `ollama signin` once for the :cloud shelf; local models need nothing.
# 1. One config dir for the team. Fresh is fine. Log in once, with any stale key unset.
export CLAUDE_CONFIG_DIR=$HOME/.claude-team
cat > $CLAUDE_CONFIG_DIR/settings.json <<'JSON'
{"crossSessionInbound":"accept","dialogExpiry":"never","permissions":{"defaultMode":"auto"}}
JSON
env -u ANTHROPIC_API_KEY claude --model opus # /login, /exit
# 2. One 0600 file per provider. The key lives here, never on a command line.
mkdir -p ~/.claude-seats && chmod 700 ~/.claude-seats
cat > ~/.claude-seats/ollama.json <<'JSON'
{"env":{"ANTHROPIC_BASE_URL":"http://127.0.0.1:11434","ANTHROPIC_AUTH_TOKEN":"ollama",
"ANTHROPIC_API_KEY":"","ANTHROPIC_SMALL_FAST_MODEL":"qwen3:14b",
"CLAUDE_CODE_DISABLE_UNKNOWN_MODEL_WINDOW_ENFORCEMENT":"1"}}
JSON
cat > ~/.claude-seats/openrouter.json <<'JSON'
{"env":{"ANTHROPIC_BASE_URL":"https://openrouter.ai/api","ANTHROPIC_AUTH_TOKEN":"sk-or-...",
"ANTHROPIC_API_KEY":"","ANTHROPIC_SMALL_FAST_MODEL":"z-ai/glm-5.3-flash",
"CLAUDE_CODE_DISABLE_UNKNOWN_MODEL_WINDOW_ENFORCEMENT":"1"}}
JSON
chmod 600 ~/.claude-seats/*.json
# 3. One folder per role, each with a short AGENTS.md. Trust them (Trap 2).
# 4. Launch. Provider per seat. Name the session after the role.
seat(){ local name=$1 model=$2 provider=${3:-}; local sf=""
[ -n "$provider" ] && sf="$HOME/.claude-seats/$provider.json" # $HOME, not ~ (Trap 3)
( cd team/$name && env -u ANTHROPIC_API_KEY \
claude --bg --name $name --model $model --permission-mode auto \
${sf:+--settings "$sf"} \
"Read AGENTS.md. Reply READY $name. Wait for messages." ); }
seat DEVELOPER deepseek-v4-pro:cloud ollama
seat REVIEWER glm-5.3:cloud ollama
seat SECURITY openai/gpt-6-luna-pro openrouter
seat CRITIC opus # subscription: no provider file
seat DESK sonnet # subscription
# 5. Look, then confirm each seat is on the provider you meant. The banner line says.
claude agents
claude logs REVIEWER | head -3 # glm-5.3:cloud · API Usage Billing
claude logs CRITIC | head -3 # Opus 5.5 · Claude Max
The ANTHROPIC_SMALL_FAST_MODEL line matters: without it the harness asks the provider for a Haiku it does not have whenever it wants a cheap side-call.
The seat file that produced the chain above, in full:
# REVIEWER seat
Never assume the Developer is correct. Trace or run the code. Send CRITIC one message:
the code, one real finding if any, and "REVIEWER VERDICT: PASS|FAIL <reason>".
Sign every message with this session's name, never with the harness name.
Then open any session in the same directory and type English. You never call the tools yourself:
❯ Ask @DEVELOPER to write safe_div(a, b) per the spec in its AGENTS.md and send it to @REVIEWER.
Doing it by hand
You do not need DESK. Any interactive session in the directory is a seat with you in the chair, and the human side of the mesh is four things you type. This is from my July run, four Ollama Cloud seats under the old profile, before I knew better about directories. The mechanics have not changed.
Name the session, so peers can address it:
❯ /rename KIMI1
⎿ Session renamed to: KIMI1
Ask it, in English, to talk to a peer. The session finds the tool; you never type SendMessage:
❯ can you message KIMI1
Yes. KIMI1 is reachable — I can see it as a live peer session (KIMI1, background, idle,
started ~5 min ago) ...
“Round-trip reply to KIMI1 connectivity test” → sent to KIMI1 — another Claude session on this machine
Allowed by auto mode classifier
Inbound mail shows up in your terminal between turns, folded to one line, and the session answers it without being asked:
› Message from @KIMI1: [Claude] Hello from session KIMI1 [03fd54] (Claude / Kimi K3, /opt/ai_workspace). Testing that all active agent session… (ctrl+o to expand)
That's a legit connectivity test from the KIMI1 peer session — I'll reply over the session channel so they can confirm the round-trip.
Park it and walk away. /bg sends the session to the background with its name and inbox intact, and claude agents is the room from the outside:
❯ /bg
backgrounded · f9609196
$ claude agents
Needs input
✻ DEEPSEEK send a prompt to start 16s
✻ GLM send a prompt to start 34s
✻ MISTRAL send a prompt to start 1m
Completed
✻ KIMI1 Mesh test complete: MISTRAL, GLM, DEEPSEEK, and KIMI1 are mutually visible via SendMessage 7m
Note the [Claude] in KIMI1's greeting. That is Kimi K3 signing with the harness name, the leak I mentioned above, and the reason the seat files now say sign with the seat.
claude stop CRITIC parks a seat with its conversation intact, and a later message to a stopped seat resumes it, which is convenient and also the reason to stop seats you do not want woken by a chatty peer. My production tree is the same idea with a year of accumulated law in it: a shared AGENTS.md at the top, a folder per seat, and the line in every seat file that makes model-swapping possible at all, "Whoever opens this folder is Critic."
Two settings that decide whether any of this works
Inbound delivery. The receiving session decides what to do with each message based on crossSessionInbound: accept delivers, hold shows a notice and waits for a human, refuse drops. When nothing is set, Claude Code decides per message from the two sessions' permission modes, and a session that bypasses permissions holds messages from anyone who does not. In a background seat with no terminal attached, that approval dialog just sits there, and the sender sees nothing wrong. That is why the team directory's settings.json sets accept and a dialogExpiry of never.
The boundary that stays in place is the one you want. A message from another session arrives as plain text and the receiving Claude is told it came from a session, not from you. It cannot approve a pending permission prompt. It cannot change settings or CLAUDE.md. A slash command inside it is just text. And Claude is instructed never to ask a peer to do something its own session was denied, which the docs call permission laundering. Those limits are why I am comfortable leaving ten vendors' models in a room with my subscription seats.
Remote Control does not widen the room. It reaches your sessions on other machines and in the cloud, and only from a session whose active authentication is a claude.ai sign-in. The Ollama and OpenRouter seats authenticate with a bearer token, so they cannot join it, and on one machine it is not a bridge between config directories either. For this, the roster is the directory.
Optional: a database for what has to outlive a session
For most of the day the seats need nothing beyond the socket. Work gets done and validated in the conversation between them, and that is the design. You can stop reading here and have the whole thing.
I add a database because of what session messages are not. They are for now. They live in the receiving session's transcript and nowhere else; stop a seat and in flight is gone. The channel also caps at 50 queued and 100 held messages, refuses rapid bursts, and drops identical repeats so two seats cannot loop forever. Right for a conversation, wrong for a work queue.
So anything that has to be there tomorrow goes in a table. Mine is ai_comms in MySQL, fronted by a small MCP server so every seat gets the same five tools (inbox, read, send, reply, close) regardless of which model is behind it. The schema is a message id, from, to, subject, body, status, a parent id for threads, a priority, and three timestamps. You do not need the MCP server to start; Claude Code can run mysql in Bash, and a seat file that says "check your inbox with this SELECT, send with this INSERT" works on day one. It is also the honest answer to the directory problem: two config directories cannot message each other over the socket, but they can both read the same table. Mine has 7,902 rows going back to February 25, 2026. A session message is "the migration finished, rebase is safe." A table row is "something is wrong and someone must eventually own it."
What it cost, and what I am not claiming
Three meters ran today.
The subscription. CRITIC, DESK, and OPUS ran on Claude Max. The banner says "Claude Max," the transcripts say claude-opus-5-5 and claude-sonnet-5-5. Those seats drew from the plan I already pay for, which is the whole point of putting the expensive brain there and nowhere else.
Ollama Cloud, from their pricing page today: Free is $0 with starter credits and one concurrent request; Pro is $20 a month with $60 of credits and three concurrent requests; Max is $100 with $300 and ten. The concurrency column is the one that matters for a mesh. Four Ollama seats answering at once on Pro queue behind three slots, which is fine for a review flow where seats take turns. Local seats have no meter and no limit beyond the GPU.
OpenRouter. The key's own usage counter says today cost $2.29, for about forty broker seats launched across eight runs, the print_arg and safe_div chains included, most of them cheap flash-class tags doing one ping and one reply. A loaded Claude Code session sends tens of thousands of tokens of instructions and tool schemas on every turn, so the model you pick for a seat that mostly pings should be the cheap one, and the expensive tag belongs on the seat that has to be right.
Every delivered message bills like a prompt you typed, on whichever meter that seat runs.
And the open question. A team with real diversity in it leans on OpenRouter and Ollama far more than on subscriber accounts, because that is where the other labs' models are. Whether that is worth it, against paying for one good model and a lot of it, is yet to be seen. Today's run says the Critic on Anthropic caught what the Reviewer on Zhipu passed. One run is an anecdote. I will know what it is worth when the ledger has a few months of rulings in it.
Rented is still rented. The cloud weights run on someone else's GPUs behind someone else's limits, and the subscription seat is Anthropic's call to switch off. The messaging layer is the piece that is genuinely local: socket on my box, never through anyone's server, works with the internet unplugged if the seats are local too. That is the part I would build on.
What I am considering next. The products that shipped this autumn, OpenAI's Dots, xAI's Grok Bot, and this week Anthropic's Claude Duet, each give one agent its own cloud computer. The seats above share mine. I am now looking at a small Docker container per seat, so each has a computer of its own if it needs one: its own filesystem, its own tool versions, and above all its own egress, so the OpenRouter seat can reach openrouter.ai and nothing else. The mesh does not survive that for free. The sockets live in one runtime directory named by PID, and the roster lives in one config directory, so every container has to mount the same two paths and share a PID namespace, and seats run in the foreground inside their box rather than through --bg. Not tested yet. When it is, it gets its own post.
One directory, logged in once. A 0600 file per provider. A role folder per seat. Anthropic built the messaging, Ollama and OpenRouter built the compatible endpoints, and I have not seen any of them describe the part where their model sits in a room with the competition and has to answer to it. That part is yours, and it is a shell function.
Related reading
- Claude Code, week of August 3 to 7, 2026 Where cross-session messaging shipped (v2.1.224)
- Message your other Claude Code sessions The official doc, including the inbound controls and the limits
- AI CLI Tools, Provider Diversity, and the Consensus No Vendor Will Build You The Developer, Reviewer, Security, Critic seats, and why they run different labs
- I Kept Paying for One AI Model. Then Ollama Handed Me 37 of Them for Twenty Bucks. Claude Code on Ollama, and the
ollama launchshortcut - Running Claude Code Against Anything Profiles,
CLAUDE_CONFIG_DIR, and what actually isolates - Claude Code at NVIDIA's Free Model Catalog. It Took a Proxy and Four Traps. Providers that only speak OpenAI's shape, and the trust-seeding snippet
- Ollama Cloud pricing Check the concurrency column before you size a team