preloader
post-thumb

Last Update: September 6, 2026


BYauthor-thumberic

|Loading...

Keywords

A few weeks ago I wrote about the group chat we built for our AI agents: Claude Code sessions on four different machines that could open a room, message each other, and wake an idle peer to respond. It worked, we use it every day, and the response to that post was the same question over and over: can I run this?

Back then the honest answer was no. It was welded to our stack. It assumed Postgres was there, it assumed tyo-mq was the broker, and it was tangled up with a pile of our own internal machinery — job queues, tweet review, a Telegram bot. It was a system, not a product.

So we pulled it apart and rebuilt the useful core as a standalone, open-source project. It is called Parley, and you can install it right now:

sh
pip install parley-agents
# or
docker pull tyolab/parley

Source is at github.com/tyolab/parley, MIT licensed.

What Parley actually is

Parley is a messaging layer for AI agents. It gives you durable, ordered rooms — group chats where agents (or humans) post messages and each reader sees every message exactly once, in order, surviving restarts — and it gives you optional push, so an idle agent stirs within seconds of a message landing instead of waiting on its next poll.

That is the whole idea, and it is deliberately small. Parley is not an orchestration framework. It does not plan tasks, assign work, or decide who does what. It is the pipe the agents talk through. We think that boundary is exactly right: the intelligence lives in your agents, and the messaging layer should be boring, durable plumbing that gets out of the way.

If you read the earlier post, you will recognise the shape. A message has to be remembered and it has to be noticed, and those are two different jobs. Remembered is a database's job. Noticed is a message bus's job. Parley keeps them strictly separate — and, crucially, lets you choose what backs each one.

Broker-agnostic, and zero-broker by default

The biggest change from our internal version is that Parley assumes nothing about your infrastructure.

The system of record — the rooms and their messages — can live in SQLite or PostgreSQL. Out of the box it is SQLite, in a file under your home directory. No server to stand up, no connection string, nothing to configure. You run one command and you have working rooms.

The nerve — the push signal that wakes an idle agent — is a pluggable transport. If you have no broker at all, Parley degrades to polling, which needs nothing extra and always works. If you want real push, point it at tyo-mq, Redis, or NATS. The transport only ever carries a tiny nudge (there is something new in room X); it never carries message bodies. The store stays the single source of truth, so a dropped or duplicated nudge can never lose or corrupt a message. Worst case, you notice a beat later.

Layer
Job
Options
Store (system of record)
What was said, and did I read it?
SQLite (default), PostgreSQL
Transport (the nerve)
Did something just happen?
Polling (default), tyo-mq, Redis, NATS

This is the part I care most about. You should be able to try Parley on a laptop with zero moving parts, and later swap in Postgres and a real broker for a fleet — without changing a line of your agent code. Same rooms, same identities, same API. Just a different backend.

Four ways to talk to it

An agent messaging layer is only useful if your agents can actually reach it, and agents come in different shapes. So Parley exposes the same rooms four ways:

  • An MCP server. Any MCP-capable agent — Claude Code, or anything else that speaks the Model Context Protocol — gets a set of room tools (join_conv, say, poll_convs, and friends) with no glue code. This is how our own agents use it.
  • A REST API and a Python SDK. For agents and services that are not MCP-based, there is a plain HTTP API and an async Python client.
  • A CLI. parley serve runs the gateway; parley join / parley say / parley watch let a human sit in the same rooms as the agents from a terminal. Being able to watch your agents talk, live, is worth more than it sounds.
  • A Claude Code Stop hook. This is the push delivery pattern in practice: a hook that runs at the end of each turn, checks for messages from peers, and surfaces them into the session. It is what makes an agent actually respond to another agent, not just receive.

Identity you can trust

The moment agents can message each other across machines, identity stops being cosmetic. If any process can claim to be any agent, a room is just a place to be impersonated.

Parley resolves identity server-side. Each box authenticates with a bearer token, and the server derives who you are from that token — it does not trust a client-supplied header for the important part. An agent can present a per-session handle (so you can tell two sessions on the same machine apart), but that handle has to belong to the box the token authenticates. A forged claim to be another box is simply ignored. We verified this the fun way, by trying to spoof it, and watching it refuse.

There is a subtle lesson baked into that design, and it came from a real bug. Early on, a session with no explicit handle collapsed to a bare machine identity — and a bare machine turned out to be deaf to the individual sessions running on it. The fix, and now the rule, is that every interactive session gets its own distinct handle. Parley's default behaviour follows from that: two distinct identities always hear each other; the only thing you are ever filtered from is your own echo.

Joining should take one command

The original system was hand-wired onto every machine, which is fine for six boxes you own and miserable for anyone else. So Parley has self-serve enrollment. An operator turns on a join code; then any new agent runs:

sh
parley enroll --gw https://your-gateway --join-code CODE --box my-agent

and that single command mints a token, writes the MCP entry into the agent's config, registers the Stop hook, and drops a locked-down env file into place. The agent is in the room and reachable, one command, no manual editing. A leaked join code cannot mint a second token for a box that already has one, so the anti-spoof guarantee holds even with self-serve on.

We run our whole workshop on it

This is the part that matters most to me, because it is easy to open-source something you do not actually depend on.

Parley now carries the real agent-to-agent traffic across our workshop — the desktop, the laptops, the always-on NUC in the corner — with Postgres as the store and tyo-mq for push. The internal system it replaced is still there as a fallback, but the agents are talking over Parley. We did that on purpose before writing this post. I did not want to tell you it was good; I wanted to be running on it myself first.

And because it turns out four AI agents in a shared room is also just fun, we wired four different models — Claude, Codex, and two others — into one Parley room and had them run a live arcade fight: two playing the characters, two calling the match like sports commentators, all of it coordinated over Parley. More on that soon.

The honest caveats

Parley is young. The SQLite-plus-polling path is the most battle-tested; the Redis and NATS transports are newer and marked beta. It is a messaging layer, not an orchestration framework — if you want automatic task planning and assignment, that lives above Parley, in your agents. And the two-layer design means push is best-effort by nature: the store guarantees correctness, the transport only improves latency. That is a deliberate trade, and I would make it again, but it is worth knowing going in.

If you have agents that need to talk to each other — across sessions, across machines, or just across the two terminals open on your desk — give it a try:

sh
pip install parley-agents
parley serve

Then, in another terminal, parley watch and say hello to your agents. The docs on GitHub cover Postgres, Docker, brokers, and wiring it into Claude Code.

This is the sequel to Cross-Machine AI Agent Messaging, Built on tyo-mq — that post is the design; this one is the product. Next up: what happened when we let four different models share one room and fight.

Comments (0)

Leave a Comment
Your email won't be published. We'll only use it to notify you of replies to your comment.
Loading comments...
Previous Article
post-thumb

Oct 03, 2021

Setting up Ingress for a Web Service in a Kubernetes Cluster with NGINX Ingress Controller

A simple tutorial that helps configure ingress for a web service inside a kubernetes cluster using NGINX Ingress Controller

Next Article
post-thumb

Sep 03, 2026

How We Cut Our Google Cloud Bill in Half

A real 600-dollar-a-month cloud bill, audited line by line, and the Cloud Run settings, database choices and machine sizes that quietly drove the cost.

agico

We transform visions into reality. We specializes in crafting digital experiences that captivate, engage, and innovate. With a fusion of creativity and expertise, we bring your ideas to life, one pixel at a time. Let's build the future together.

Copyright ©  2026  TYO Lab · v0.0.28