Claude on WholeTech network
home/settings/communication
Inter-Claude pathways

Communicating between Claudes

Syncing config across machines is one problem. Getting Claudes on different machines to talk to each other — kick off tasks, share state, hand off threads, ping you when finished — is a different problem. This page is the practical guide to that.

Six communication primitives — remote invocation, shared queues, exposed MCP servers, notification routing, managed agents, and session hand-off — with the real commands, the trade-offs, and the patterns that hold up in a fleet of mixed Windows / macOS / Linux / mobile / droplet boxes.

01 — Taxonomy

The six primitives

Inter-Claude communication isn't one thing — it's six. Each handles a different question, and most real fleets use four or five of them at once. Recognising which primitive each request is asking for is half the work.

PrimitiveAnswersLatencyState
Remote invocation"Run a Claude session over there, return the result here."Sync, seconds–minutesNone (each call fresh)
Shared task queue"Drop work on this list; whichever Claude is free takes it."Async, seconds–hoursPersistent queue file
Cross-host MCP"Let Claude on PC A reach into PC B's filesystem / DB / mailbox."Per-tool-call, msLives on the host
Notification routing"Tell me on my phone when the job on the droplet finishes."Push, secondsNone
Managed agents"Run this in Anthropic's cloud while I close my laptop."Async, minutes–hoursStored in claude.ai
Thread hand-off"The conversation I started on the phone should continue on the laptop."Cloud-sync, secondsclaude.ai threads

The first three are active — one Claude reaches out and does something on another machine. The last three are passive — they exist as infrastructure that multiple Claudes (and humans) draw from.

The mental shift: a "fleet of Claudes" isn't seven copies of the same chat. It's a network of agents, each with different access to the world (your droplet sees the live nginx config; your phone sees what's on the screen; your laptop sees your full repo), connected by these primitives. Plan which Claude has which access first; pick the primitive after.
02 — Remote invocation

SSH + claude exec

The simplest inter-Claude primitive. SSH to a remote host, run claude exec (or codex exec for the other agent), get the result back. Same model you've used for decades to run anything else on a remote box — Claude is just another command.

The one-liner

# from your laptop, run a one-shot Claude task on the droplet
$ ssh root@wholetech.com "cd /var/www/codex.wholetech.com && claude --print 'summarise the recent commits in this site repo'"

That's the whole thing. The flag is --print (or the older alias -p) — it tells Claude Code to run non-interactively, print the answer, and exit. The remote host needs to have Claude Code installed and authenticated.

Authenticating Claude on a server you'll SSH into

Server boxes don't have a browser, so the usual claude login OAuth flow doesn't work directly. Three options:

  1. API key. Set ANTHROPIC_API_KEY in the server's environment (or /etc/environment for system-wide). The CLI picks it up automatically. Cleanest for a server.
  2. Headless OAuth. claude login --no-browser prints a URL; open it on a laptop, paste the resulting code back. One-time.
  3. Copy ~/.claude/auth.json from a logged-in machine. Works but ties the server's identity to a specific browser session — refresh tokens expire, and you've duplicated a sensitive credential.
For the droplet specifically: the cleanest setup is an Anthropic API key scoped to a low-volume "infra" project. echo 'ANTHROPIC_API_KEY=sk-ant-...' >> /etc/environment, then any SSH session inherits it. Don't put the key in ~/.bashrc — that doesn't fire for non-interactive SSH.

Patterns that pay off

read

"Look at the live server"

The laptop has the repo; the droplet has the running nginx and the real cert. ssh root@wholetech.com 'claude -p "what's wrong with the cert renewal log at /var/log/letsencrypt/letsencrypt.log"' gets you Claude's read of the actual server state, not your stale local copy.

write

"Make this change in production"

Gated version. ssh root@wholetech.com 'claude --dangerously-skip-permissions -p "add a security_headers.conf snippet to /etc/nginx/snippets and include it from sites-available/wholetech.com"' — only if you trust the prompt and the host.

bulk

Fan out across hosts

A shell loop over your hosts file: for h in pc1 pc2 droplet; do ssh "$h" 'claude -p "what'\''s the disk usage warning level?"'; done. Each Claude sees its own machine's state; you collect the answers.

cron

Scheduled Claude work

Cron job on the droplet at 03:00: 0 3 * * * claude -p "scan /var/log/nginx/error.log from the last 24h and write a summary to /var/log/claude-nightly.md". The droplet does the read in the small hours; you see the summary in the morning.

Piping data in

Anything you pipe into claude -p becomes the input. Useful for sending another command's output through Claude before printing.

$ ssh root@wholetech.com "journalctl -u nginx --since yesterday | claude -p 'find the request patterns that look like scrapers'"
Bandwidth note: claude -p uploads the prompt + context to Anthropic's API. Piping a 100 MB log file in is expensive and slow. If you're scanning logs, pre-filter with grep or awk first.
03 — Shared task queues

The inbox pattern

Where remote invocation is "do this now, return the answer," a shared queue is "drop this on a list; whoever's free will pick it up." It decouples the producer from the consumer in time. Useful when the work is bursty, when the machine doing the work isn't always on, or when you want a record of what was asked.

The simplest queue: a directory

Pick a shared location — NAS mount, a directory on the droplet, a synced OneDrive folder. Each task is a file. The producer writes a file; a consumer picks it up, runs Claude, writes the result alongside.

/mnt/queue/
  pending/
    2026-05-18T14:22-summarise-pr-1234.md     # input prompt
    2026-05-18T14:25-bump-tailwind-v4.md
  running/
    2026-05-18T14:01-investigate-cron-fail.md.host-droplet
  done/
    2026-05-18T13:42-find-unused-deps.md
    2026-05-18T13:42-find-unused-deps.md.result

The worker loop

One Claude per host runs a tiny loop. Pull a file from pending/, move to running/ (atomically, with a hostname suffix so two workers don't grab the same one), run Claude on the contents, write the result to done/.

#!/usr/bin/env bash
# queue-worker.sh — minimal, idempotent, runs on any host
set -euo pipefail
QUEUE="/mnt/queue"
HOST="$(hostname -s)"

while true; do
  # atomic claim: find one pending, mv to running with our host suffix
  for f in "$QUEUE/pending"/*.md; do
    [[ -e "$f" ]] || continue
    target="$QUEUE/running/$(basename "$f").host-$HOST"
    if mv -n "$f" "$target" 2>/dev/null; then
      # we won the race — run it
      claude --print < "$target" > "${target}.result"
      mv "$target" "$QUEUE/done/$(basename "$target" .host-$HOST)"
      mv "${target}.result" "$QUEUE/done/"
    fi
  done
  sleep 5
done

Where it wins

Where it doesn't

A real-world variant: store the queue in /var/spool/claude-queue/ on the droplet, mount it on each Windows PC via SFTP or rclone-mount, and run the worker loop on whichever machine has the right local tools. The Windows PCs see the queue as a normal drive; the droplet sees it as a directory it owns. Conflicts handled by the atomic mv -n.
04 — Cross-host MCP

Let one Claude reach into another box

MCP (Model Context Protocol) lets Claude call tools that aren't built in — filesystem access, GitHub, Postgres, custom services. By default the MCP server runs as a local subprocess on the same machine as Claude. But MCP also speaks over network transports: SSE and stdio-over-SSH. That means Claude on PC A can invoke MCP tools that run on PC B.

Three transports

TransportHow it worksUse when
stdioClaude launches the MCP server as a subprocess; talks over stdin/stdout. The default for local servers.The MCP server and Claude live on the same machine.
sse / HTTPClaude opens an HTTP/SSE connection to a running server. The server is a long-lived process you operate separately.Many Claudes need the same MCP tool; the tool is expensive to spin up; the server is on a different host.
stdio over SSHSame as local stdio but Claude launches the subprocess via ssh on a remote host.You want a server-on-another-box without standing up an HTTP service.

Pattern: filesystem MCP on the droplet, called from your laptop

Your laptop runs Claude. You want Claude to read live files from /var/www/ on the droplet. Configure an MCP server in ~/.claude/settings.json that runs over SSH:

"mcpServers": {
  "droplet-www": {
    "command": "ssh",
    "args": [
      "root@wholetech.com",
      "npx -y @modelcontextprotocol/server-filesystem /var/www"
    ]
  }
}

Now Claude on the laptop can list, read, and (with permission) write files inside /var/www/ on the droplet, as if they were local — but every tool call routes through the SSH tunnel to the remote process. The remote MCP server speaks stdio; SSH bridges stdio across the network.

Pattern: a long-lived MCP service on the droplet

For something heavier — say, a database connection pool or a connector that takes 10 seconds to warm up — you don't want a fresh subprocess per session. Run the MCP server as a systemd unit on the droplet, exposed on a local socket, and have Claude connect via the SSE transport over an SSH-forwarded port.

// on the droplet: systemd unit running an MCP HTTP server on 127.0.0.1:3050
// from the laptop: forward the port
$ ssh -fNL 3050:127.0.0.1:3050 root@wholetech.com

// settings.json on the laptop
"mcpServers": {
  "droplet-postgres": {
    "transport": "sse",
    "url": "http://localhost:3050/mcp"
  }
}

Pattern: exposing the WholeTech network from one Claude

The high-leverage move for a multi-machine setup: run a small MCP server on the droplet that exposes "tools" representing the rest of your network — sitemap data, nginx config snippets, scheduled-task status. Now any Claude that mounts this server can ask questions about the whole fleet without having to SSH to each box.

The dual benefit: Claude on the laptop gets reach; the droplet gets a single audit point. Every cross-host tool call goes through the one MCP server you wrote, so you can log, rate-limit, and reason about access in one place.
05 — Notification routing

Telling you what the Claudes did

Half of inter-Claude communication is the Claudes talking to each other. The other half is the network telling you when something happened. Three transports, each with a different lag and a different reach.

1

ntfy.sh cheapest, push to phone

Free service. Subscribe to a topic from the ntfy app on your phone; any HTTP POST to https://ntfy.sh/<your-topic> arrives as a push notification. No account needed. Used as the Stop hook in the settings page, but the real power is firing it from any machine — droplet cron jobs, scheduled tasks, queue worker results — not just from Claude itself.

$ curl -d "droplet cron finished — 247 changes in today's sitemap" https://ntfy.sh/walhus-claude
2

Pushover paid, more polish

$5 lifetime per platform. Better delivery reliability, sound priorities, per-device routing (laptop vs phone vs tablet). Use when ntfy's "best effort" isn't reliable enough.

$ curl -s "https://api.pushover.net/1/messages.json" \
    -F "token=$PUSHOVER_TOKEN" -F "user=$PUSHOVER_USER" \
    -F "message=Claude on droplet just touched nginx" \
    -F "priority=1"
3

Slack / Discord / Teams team-visible

Webhook URL per channel. Post into a Slack #claude-fleet channel and now every team member sees what each Claude is doing. Pairs well with managed agents: kick off a cloud agent, get a Slack notification when its PR is ready.

$ curl -X POST -H 'Content-Type: application/json' \
    -d '{"text":"droplet Claude: cert renewal succeeded for codex.wholetech.com"}' \
    https://hooks.slack.com/services/T.../B.../...

The routing pattern that actually works

Set a single environment variable on every machine — CLAUDE_NOTIFY_URL — pointing at one of the three transports above. Every Claude on every machine fires its Stop hook against that one URL. Now you have:

  1. One notification channel for "Claude finished a task somewhere in the fleet."
  2. Per-machine differentiation (the hook posts $(hostname) in the message body).
  3. Easy switch between transports — change the env var, redeploy, every machine routes to the new place.
# in ~/.claude/settings.json on every machine
"hooks": {
  "Stop": [{
    "matcher": "",
    "hooks": [{
      "type": "command",
      "command": "curl -s -d \"[$HOSTNAME] claude finished\" $CLAUDE_NOTIFY_URL"
    }]
  }]
}
06 — Managed agents

Cloud Claudes that run while you're away

Anthropic's Managed Agents (sometimes called "agent SDK in the cloud" or referenced via /managed-agents) are persistent Claude sessions running in Anthropic's infrastructure. You kick one off; it spins up a fresh container with your repo cloned; it works for hours; you check back. From a fleet perspective they're "another Claude, but the host is the cloud."

When to reach for managed agents over your own boxes

parallel

Fan-out

Spin up five managed agents for five different framings of the same refactor. Walk away. Two land clean, two need follow-ups, one fails. That ratio is the whole point — you're paying for exploration.

long

Long-running work

A 90-minute dependency upgrade, a full test-suite repair, a multi-file refactor. Your laptop would suspend during the run; the managed agent doesn't.

async

Truly async tickets

From GitHub: mention the agent on an issue, it kicks off, comes back with a PR. You read the PR when you read PRs.

isolation

When you don't want it on your machine

Sketchy code, untrusted dependency, a refactor with potential for chaos. Managed agents run in disposable containers — if it goes sideways, the container dies, your machines are untouched.

The communication bit

From the fleet's point of view a managed agent is reachable in three ways:

The hybrid pattern: local Claude does the planning and the final review; managed agent does the long-running execution. Local says "here's a list of 12 small fixes." Managed agent does them in 12 parallel runs. Local reads the 12 PRs and merges the good ones.
07 — Hand-off

Threads that follow you

The other primitive that hides in plain sight: claude.ai threads themselves act as persistent state across machines. Start a conversation on your phone walking to lunch; sit down at the laptop; the same thread is there in your browser. This isn't "communication between Claudes" in the agent-to-agent sense, but it's the most-used form of it in practice.

What syncs

SurfaceThreadsProjectsFilesTools
Web (claude.ai)All
iOS / Android app✓ via ShareVoice, camera, share
Claude Code (CLI)SeparateNoLocal fsBash, Edit, etc.
Managed agent✓ as Project taskContainerContainer

The split that matters: claude.ai-family surfaces (web, mobile apps, managed agents) all share threads. Claude Code sessions are independent — they don't appear in your claude.ai history. That's an intentional separation: CLI sessions touch your local filesystem, where threads are noisier; cloud surfaces are about the conversation itself.

Cross-surface hand-off patterns

phone → laptop

Capture on phone, refine on laptop

Voice-mode walk; sit down; open claude.ai; the thread is there. Now type a refined follow-up. Pattern works because the conversation persists, not because it was transmitted.

web → CLI

Plan on web, execute in CLI

The web thread is great for "what should we do." The CLI is great for actually doing it. Copy the plan out of the web thread; paste it into claude on the laptop; let the CLI session execute against your local filesystem.

CLI → web

CLI did the work, web does the writeup

After a long local Claude Code session, open claude.ai and start a fresh thread to write the PR description, the changelog entry, or the team update. The CLI session focused on the code; the web thread focuses on the words.

agent → laptop

Managed agent runs, laptop reviews

Kick off a managed agent on the train; when its PR appears in the GitHub app, switch surfaces to the laptop CLI for the diff review. Three Claudes, one task.

The "no inbox" rule: don't try to make Claude Code threads sync to the cloud. They're meant to be local — your shell history, your edits, your context. Use the cloud for what it's good at (persistent conversations) and the CLI for what it's good at (acting on the machine you're at). Treat them as separate networks that talk to you, not to each other.
08 — Pattern

The primary orchestrator

Once you have three or more Claudes and a couple of these primitives, the question becomes "who's in charge." The cleanest answer for a small fleet is to pick one machine as the orchestrator — the place where decisions happen and tasks fan out from — and treat the others as workers.

The shape

[you] | v [orchestrator] - your daily-driver PC / | \ - runs the local Claude v v v - holds the synced ~/.claude/ [droplet] [NAS] [managed agent] remote shared cloud invoke queue agent

What the orchestrator owns

What the workers own

Why this beats a mesh

A mesh — every Claude talks to every other Claude — sounds elegant but produces hard-to-debug behaviour. Two Claudes both edit the same file. Two notifications fire for the same event. Pick a primary, route through it. If the orchestrator dies, you promote a worker. /settings/architecture goes deeper on this.

09 — Worked examples

Three real multi-Claude flows

Flow 1 — "The deploy pipeline"

  1. Laptop Claude (CLI). Edits files in C:\Users\walhu\websites\codex.wholetech.com\. Runs /diff, eyeballs.
  2. Laptop Claude. Calls scp to push the new index.html to the droplet. Then ssh root@wholetech.com 'claude -p "scan the new /var/www/codex.wholetech.com/index.html for any external URLs that 404"'.
  3. Droplet Claude (remote invocation). Reads the file, fans out curl -sI on each link, reports back.
  4. Laptop Claude. Receives the report, decides if anything needs fixing.
  5. Stop hook (on laptop). Fires curl ntfy.sh/walhus-claude. Phone buzzes "deploy clean."

Flow 2 — "The overnight batch"

  1. Friday 17:00, laptop. Drops 10 task files in /mnt/queue/pending/ via the NAS mount. Each one is a small refactor of a different site in the WholeTech network.
  2. Droplet queue worker. Picks tasks up over the weekend. For each: runs claude --print < task.md, commits the result to a feature branch, opens a GitHub PR.
  3. Managed agent. Each PR also kicks off an automated review agent (@claude review). The agent comments inline on any concerns.
  4. Monday 09:00. Laptop Claude reads the 10 PR results, ranks them by which need human review vs which can auto-merge, posts a summary to Slack.

Flow 3 — "The mobile-initiated investigation"

  1. iOS Claude. You photograph a confusing graph in Grafana while standing in front of a TV. Ask voice: "what's the most likely cause of this spike at 14:00."
  2. iOS Claude. Suggests three hypotheses. You pick one: "yeah, can we dig into the nginx log?"
  3. iOS Claude. Doesn't have SSH. So you walk to the laptop, open claude.ai on the browser — the same thread is there, still in voice mode's transcript.
  4. Laptop CLI Claude. You quote the hypothesis into a fresh CLI session. It runs ssh root@wholetech.com 'journalctl -u nginx --since 13:30 --until 14:30 | claude -p "find requests matching pattern X"'.
  5. Droplet Claude. Returns the actual log evidence. Laptop CLI synthesises an answer.
  6. Stop hook. ntfy notification. You confirm the hypothesis was right.

Three Claudes, three transports, one investigation. None of the individual pieces are hard; the value is the choreography.

10 — Audit

Knowing what each Claude did

A fleet without logging is a fleet you can't trust. Three logging layers, each catching different things.

1

Session transcripts per-machine

Every Claude Code session writes to ~/.claude/projects/<slug>/history.jsonl. Don't sync these (they're huge and machine-specific) — but do keep them on the host for forensics. jq can grep them when something looks wrong.

2

The notification stream aggregate

If every Claude's Stop hook fires through a single ntfy/Pushover/Slack channel, that channel is your aggregate event log. Scroll back to see what happened across the fleet in the last week.

3

The orchestrator log decisions & dispatches

The orchestrator (see §8) writes a line to ~/.claude/fleet.log for every cross-machine action it takes: "dispatched task X to droplet at 14:22; received result at 14:24." That log is the spine — pair it with the per-machine transcripts when you need to reconstruct a complex run.

# minimal logging wrapper around remote invocation
function ssh-claude {
  local host="$1"; shift
  local msg="$*"
  echo "$(date -Iseconds)  dispatch  host=$host  msg=$msg" >> ~/.claude/fleet.log
  ssh "$host" "claude --print" <<< "$msg" | tee -a ~/.claude/fleet.log
}
11 — Security

Inter-Claude trust boundaries

Every primitive above moves data, instructions, or credentials between machines. Each one needs a moment of thought about who can do what to whom.

PrimitiveAuthWhat an attacker who compromised one host could do
Remote invocationSSH keyRun arbitrary commands on the remote (it's SSH). Worth using SSH keys with limited scope (force-command, no agent forwarding).
Shared queueFilesystem permsInject malicious task files. Always validate the queue producer; never run untrusted prompts in --dangerously-skip-permissions mode.
Cross-host MCP (stdio over SSH)SSH keySame as remote invocation — the tunnel is SSH.
Cross-host MCP (HTTP/SSE)Bearer token / IP allowlistCall MCP tools the server exposes. Don't expose a filesystem MCP server on a public port without auth.
Notification routesTopic / tokenSpam your notification channel. Keep ntfy topics private; rotate Pushover tokens occasionally.
Managed agentsAnthropic authRead/write the connected repo. Use per-repo install of the GitHub app, not org-wide.

SSH key hygiene for the fleet

The two unforgivable mistakes: (1) running --dangerously-skip-permissions remote Claude on a prompt you didn't write yourself, and (2) using the same SSH key on every machine in the fleet. The first lets a prompt-injection compromise your droplet; the second turns one stolen laptop into the whole network.
12 — Pitfalls

What goes wrong

echo

Notification loops

Claude A pings Claude B; Claude B's Stop hook pings the channel; Claude A reads the channel and triggers again. Always make the notification one-way (or include a "from" tag so a downstream Claude knows to ignore self-originated events).

drift

State drift between machines

Laptop Claude assumes the droplet has the latest deploy; droplet was rolled back; laptop's plan is now wrong. Verify state on the remote before acting on it (cheap remote invocation: ssh droplet 'cat /var/www/foo/index.html | head').

silent

Silent failures of cross-host MCP

SSH tunnel drops; Claude on the laptop keeps calling the MCP tool and getting timeouts. Set short timeouts in the MCP client config and surface the error loudly — don't let Claude paper over a dead tunnel.

cost

Fan-out cost surprise

Five managed agents in parallel = five API bills. Set a hard spend cap on the API account and budget for the parallel-exploration pattern explicitly.

queue

Queue worker stalls

The worker on the droplet crashed three hours ago. Your tasks pile up. Add a heartbeat — write $(date) $HOSTNAME alive to /mnt/queue/.heartbeats/$HOSTNAME every loop; alert when a heartbeat is >5 minutes stale.

prompt-inject

Prompt injection via remote files

Cross-host MCP exposes a filesystem; an attacker writes a malicious instruction in a file Claude reads. Treat the contents of any file the model touches as untrusted user input; never let the model execute arbitrary commands based on file content without a confirmation gate.

Live
◐ Theme