Skip to main content

crosschat

A method for agents to talk to each other.

crosschat gives Claude Code sessions a way to send each other messages over NATS — fire-and-forget, no blocking, no polling. Addressing is at the project level, not the session level, so you never need to know which ephemeral session is running: you send to a stable project id and whichever session is live there wakes up.

Why

Sub-agent fan-out is the usual answer when one session needs something another context already knows. It is expensive, and it re-derives context the other session already holds. crosschat lets two live sessions simply talk instead — each keeps its own working memory, and a question costs one message.

It also lets you run several specialised projects at once and address them individually — a team of experts rather than one generalist.

Install

pip install crosschat

Requires a reachable NATS server with JetStream enabled.

Use

One-time, shared infrastructure setup — run once ever, from anywhere:

crosschat init

Register a project and start listening:

crosschat register /path/to/my-project
crosschat monitor my-project

Send a message (this is also how you reply — pass the sender's id as the destination):

crosschat send my-project other-project "what did you learn about X?"

Discovery and cleanup:

crosschat list
crosschat remove my-project

All subcommands take an optional trailing NATS URL, defaulting to nats://localhost:4222.

How it works

  • Channelproject.{id}, one subject per project, backed by a JetStream stream (CROSSCHAT) so a message sent while a listener is reconnecting is not lost.
  • Discovery — a JetStream KV bucket (crosschat-registry) holds one entry per live project. Entries carry a 5-minute TTL and the monitor refreshes its own every 60 seconds, so a project that dies falls out of the registry on its own. No manual cleanup.
  • Delivery — the monitor subscribes with a durable consumer (crosschat-{id}), so the delivery position is tracked server-side. It never replays an already-acked message and never skips one, across restarts.
  • Wake contract — the monitor prints one CROSSCHAT_MESSAGE <json> line per message and keeps running. In Claude Code, watch it with the Monitor tool and each line becomes its own notification.

Project id

A project's id is its address. crosschat register is the only place it is decided; every other command takes it as an argument or reads it from the registry. Three ways to set it, in precedence order:

crosschat register /path/to/brain --id sb-architect   # explicit wins
CROSSCHAT_PROJECT_ID=sb-architect crosschat register /path/to/brain
crosschat register /path/to/sb-architect              # falls back to folder name

Prefer an explicit id for anything long-lived. The folder-name fallback is convenient but ties identity to location: renaming the directory renames the brain, and two brains cannot share a directory name.

The environment variable is what makes this work unattended — a project's own .claude/settings.json can set CROSSCHAT_PROJECT_ID, and the generic SessionStart hook picks it up with no per-project edit.

Whatever the source, the id is normalized the same way: lowercased, runs of non-alphanumerics collapsed to single hyphens, hyphens trimmed. It has to be a legal NATS subject token, so a chosen id is not trusted verbatim.

Who sent this

source_project_id is a field the sender fills in, so on its own it is a claim rather than a fact. crosschat signs it.

Each project gets an Ed25519 keypair on first register. The public half goes into its registry entry; the private key stays at ~/.crosschat/keys/<id>.key (override with CROSSCHAT_KEY_DIR). send signs the envelope, monitor verifies it against the sender's published key, and every delivered message carries a verification field:

value meaning
verified signature matches the sender's published key
unsigned no signature — an older or unsigned peer
no-key signed, but the sender publishes no key to check against
bad-signature signature does not match — treat the claimed sender as unproven

Messages are marked, never dropped. What an unverifiable message is worth is your session's judgement, and a listener that silently discarded one would make that call for you — and would break any mesh that is only partly upgraded.

Identity travels with the message, not with the routing, so the same scheme survives moving off NATS entirely.

What this gives you is continuity, not authority. The registry is unauthenticated, so anything that can reach it can publish a key under any id. A signature proves the same holder keeps using the same name, and makes a swap visible. It does not prove that name was entitled to exist. That is the right trade for a mesh whose realistic failure is a project misaddressing itself; if you need more, put NATS behind real authentication.

Claude Code plugin

This repository is the engine — the Python package and its CLI. The Claude Code integration (four skills plus a SessionStart hook that registers the project and hands the live session its listener command) ships separately as a plugin in the apex-tools marketplace, so that each piece has exactly one home:

/plugin marketplace add kaushikhazra/apex
/plugin install crosschat@apex-tools

The plugin shells out to whichever crosschat is on PATH, so install this package first. If it is missing, the hook says so and the session continues normally rather than failing to start.

Status

Extracted from an internal fleet tool in August 2026 and renamed. The messaging core, discovery layer and CLI are covered by unit tests against NATS fakes plus a live smoke test. Trust between projects is deliberately out of scope for now: anyone who can reach the NATS server can publish to any project channel, which is fine for a single-machine, single-user setup and is the first thing to revisit if that changes.

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

crosschat-0.3.1.tar.gz (51.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

crosschat-0.3.1-py3-none-any.whl (17.1 kB view details)

Uploaded Python 3

File details

Details for the file crosschat-0.3.1.tar.gz.

File metadata

  • Download URL: crosschat-0.3.1.tar.gz
  • Upload date:
  • Size: 51.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.10

File hashes

Hashes for crosschat-0.3.1.tar.gz
Algorithm Hash digest
SHA256 972867c2379108626c4b6a405a195dc8a8d81a08031edf27ec3b7bcfa0f6b135
MD5 f29e85fa5fc66544f4c2d14c5e714c33
BLAKE2b-256 e78d4d25077d70fdede2a4e08e2e95c02d015ab368ac35a64b12462eb826a6fb

See more details on using hashes here.

File details

Details for the file crosschat-0.3.1-py3-none-any.whl.

File metadata

  • Download URL: crosschat-0.3.1-py3-none-any.whl
  • Upload date:
  • Size: 17.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.10

File hashes

Hashes for crosschat-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 68881847b16bcd67a15a36f99ff7ca980b4fbce1ae24659f5543939a87baf486
MD5 bb5754abe90ea38720a40b84de281589
BLAKE2b-256 14ccd3f693201a0a6b37259d3e41ae4ce23012633252b204847cc699358affc2

See more details on using hashes here.

Release history Release notifications | RSS feed

0.3.2

2 files

This release

0.3.1 This release

2 files

0.3.0

2 files

0.2.1

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page