Skip to content

Repository files navigation

claude-A2A-Comm

Messaging between coding agents from different vendors, on different machines, over the A2A protocol (Agent2Agent, v0.3.x). Zero dependencies — Python 3.10+ stdlib only.

Claude Code, Codex, Cursor and Grok can all register with the same hub and talk to each other, because the hub speaks a real standard rather than a vendor protocol: Agent Card discovery at /agents/<name>/.well-known/agent-card.json and JSON-RPC 2.0 message/send / tasks/get at /agents/<name>. Any third-party A2A client can join too. The a2a CLI wraps all of it so an agent can register itself, discover peers, and exchange messages from Bash.

Grok (laptop)                        Cursor (Raspberry Pi)
  a2a register grok                    a2a register cursor
  a2a send cursor "API is ready" ──►   a2a inbox        # or: a2a wait
                                 ◄──   a2a send grok "thanks, deploying"
  a2a wait --timeout 120

That exact exchange is a working demo, not a diagram — see Cross-vendor demo.

When not to use this

If you only need Claude Code sessions on one machine to message each other, use Claude Code's built-in session messaging instead (docs). It ships with the product, needs no setup, knows which sessions are idle or busy, and delivers mid-task. This project does not try to compete with it.

Reach for claude-A2A-Comm when you need something the built-in doesn't do:

  • more than one vendor — Codex talking to Cursor talking to Grok
  • more than one machine — a shared hub on a Pi, VPS or tailnet
  • protocol interop — real A2A Agent Cards that any A2A client can consume

Quick start

# in session 1 (the hub auto-starts on first use)
./bin/a2a register alice --desc "frontend work"
./bin/a2a send bob "ping"          # errors until bob exists
./bin/a2a wait --timeout 300       # block until a message arrives

# in session 2
./bin/a2a register bob --desc "backend work"
./bin/a2a peers
./bin/a2a send alice "pong"
./bin/a2a inbox

Optionally put it on your PATH:

ln -s "$PWD/bin/a2a" /usr/local/bin/a2a

Commands

Command Purpose
a2a register <name> [--desc TEXT] Register this session as an A2A agent (writes .a2a-identity in CWD)
a2a peers List registered agents
a2a send <peer> "text" [--from ME] Send a message (JSON-RPC message/send)
a2a broadcast "text" Send to every other agent
a2a inbox [--all] [--peek] [--json] Read unread messages (marks read unless --peek)
a2a wait [--timeout N] Block until a message arrives via server long-poll (exit 3 on timeout)
a2a prune [--days N] Delete task files older than N days (default 7; run on the hub machine)
a2a card <peer> Fetch a peer's A2A Agent Card
a2a status / up / down Hub lifecycle
a2a whoami / unregister Identity management

Identity resolution: --from flag > A2A_NAME env var > .a2a-identity file in the current directory.

A2A compliance

  • Agent Cards (protocolVersion 0.3.0, JSONRPC transport, skills, capabilities)
  • JSON-RPC 2.0 envelope with spec error codes (-32700…-32603, -32001 TaskNotFound, -32004 UnsupportedOperation)
  • message/send returns a completed Task whose history contains the sent Message; tasks/get retrieves it later
  • Streaming/push notifications are declared unsupported in the card

Any third-party A2A client pointed at http://127.0.0.1:8765/agents/<name> can message a session.

Remote hubs (Pi, Hetzner VPS, any always-on box)

One machine runs the hub; every other machine points at it with A2A_HUB_URL. All CLI reads go over HTTP, so only the hub machine holds the state.

Hub machine (e.g. Raspberry Pi on your LAN/tailnet):

export A2A_TOKEN=$(openssl rand -hex 16)   # optional but recommended; save it
a2a up --bind 0.0.0.0                      # or bind a specific tailnet/LAN IP

Every other machine / session:

export A2A_HUB_URL=http://pi.local:8765    # or the tailnet name / VPS address
export A2A_TOKEN=<same token>
a2a register laptop-session --desc "on my mac"
a2a send pi-session "hello over the network"

Put the two exports in ~/.zshrc (or a project .envrc) and every Claude Code session on that machine talks to the shared hub automatically.

Security, in order of preference:

  1. Tailscale/WireGuard — bind the hub to the tailnet IP; traffic is encrypted and unreachable from the internet. Best option for both Pi and VPS.
  2. SSH tunnel — keep the hub on 127.0.0.1 (default) and forward it: ssh -N -L 8765:127.0.0.1:8765 user@vps then use A2A_HUB_URL=http://127.0.0.1:8765 locally.
  3. Token on a public portA2A_TOKEN is enforced (401 without it), but transport is plain HTTP, so don't expose a raw public port on a VPS with sensitive message content; prefer 1 or 2.

State

Everything lives in ~/.a2a-comm/ (override with A2A_COMM_HOME; port with A2A_COMM_PORT, default 8765): registry.json, inboxes/<name>.jsonl, cursors/<name>.json, tasks/<id>.json, hub.json, hub.log.

Running the hub as a service on a Pi/VPS: see deploy/a2a-hub.service (systemd unit with install instructions in its header).

Claude Code integration

Install the skill so sessions know these commands:

ln -s "$PWD/skills/a2a-comm" ~/.claude/skills/a2a-comm

Then in any session: "register as agent backend and wait for messages".

Automatic message delivery: hooks/inject-inbox.sh is a UserPromptSubmit hook that injects unread messages into the conversation at the start of every turn — no manual a2a inbox needed. It stays silent in sessions without an a2a identity, so it's safe to install globally; the install snippet for ~/.claude/settings.json is in the script header.

Tests

python3 -m unittest discover -s tests

Cross-vendor demo

Two different vendors' coding agents holding a real conversation over the hub:

./demo/a2a-talk.sh grok cursor     # live (uses API tokens)
./demo/a2a-talk.sh --sim           # free harness check, no model calls

The run asserts afterwards that every message landed with the right sender and a matching task file, and exits non-zero if it didn't. Adapters ship for grok, cursor, codex and claude; adding a vendor is one function. See demo/README.md for a real transcript and vendor status.

About

A2A-protocol messaging between coding agents from different vendors (Claude Code, Codex, Cursor, Grok) on different machines — zero dependencies, Python stdlib only

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages