Parley is a chat network built to resemble email while acting like IRC, with no central server whatsoever. Each individual operates their own small instance for their own domain, and these instances locate each other through DNS and identity documents, trading signed messages over HTTPS. The outcome is a federated chat system that standard IRC clients such as irssi, WeeChat or Textual can link to directly, without needing any plugins, using identities formatted like email addresses.
A recent repair corrected an issue where a note sent to one individual might stir up several people sharing the same handle across separate servers. The correction alters how Parley processes a handle within a message, so a plain handle now points to the recipient on the sender’s own server instead of broadcasting to all who carry that handle.
How Names Were Broken
Prior to the correction, a message such as bob: lunch? coming from one server would trigger a notification for anyone carrying the handle bob, no matter which server they were attached to. The same held true for a specific handle like bob:bar.com: if bob was present on both foo.com and bar.com within the same chat, a message directed at bob:bar.com alerted both of them, rather than only the one on bar.com.
A fault was detected during testing. The test TestOnlyTheBobThatWasMeantIsPushed connects two cases, each bearing a bob, and verifies that each of the five lines pushes only to the bob it identifies. Running on main, it fails on the opening line: “a notification was pushed to /bar.com/bob and should not have been.”
Fixing Names By Reading Them As Shown
How the fix reads a name depends on how the sender showed it:
- A qualified nickname such as
bob:bar.comorbob@bar.comis treated as bob on bar.com, no matter who wrote it. - A bare nickname like
bobis treated as the bob on the sender’s own instance, so it names an account here only when the sender is local. barinsidealice:bar.comoralice@bar.comnames nobody.
The update was recorded as R189. It alters how the pushConsidered function operates, switching to reading s.peers from within it, since the callers of that function already hold s.mu. The integration test ran 10 times in succession without issue, even when run with -race. Running bte check parley.bt shows the same 0 errors and the identical 7 warnings that appear on main, while bte fmt makes no changes to the file at all.
What Parley Actually Does
The Parley setup uses the client you already own. There are two servers: foo.com and bar.com, each running its own stock irssi session. Alice logs into her server; Bob logs into his. When Bob wants to reach Alice, he opens a query with /msg alice@foo.com hi, and the two servers link together right away. Alice then sees Bob as bob on bar.com; Bob sees Alice as alice on foo.com.
lobby is a global channel that copies itself across their instances, and it has no owner, no topic and no operators. The local channels, which carry a tilde (~) rather than a hash, remain within their own instance and stay hidden from other users — that is where the topic can actually be found.
IRCv3 features such as message-tags and echo-message are part of the system. When a message carries tags, those tags remain attached to it. This means that a +reply stays a reply even after it comes back out of history, and draft/multiline keeps a pasted paragraph together as one message instead of splitting it into eight. The scrollback follows the user personally, showing what they have not yet seen, and relies on draft/read-marker to track where they have already read up to.
The accounts themselves sit inside the instance’s data directory rather than in a config file. New ones can be created using parleyctl, the admin page, the HTTP API, or through single sign-on with any OpenID Connect provider, or identity headers from a reverse proxy. Users generate IRC tokens for their clients via their settings page; bots are accounts carrying the bot role.
Why This Matters
Parley remains a proof of concept rather than a finished product. It shows the design from start to finish and runs a genuine instance, though it has not been hardened yet. The correction is neat. Instead of altering the notification logic directly, Parley changed how it reads names, which stops the issue at the input stage. The test failure on main made the bug plain to see, and the correction reads names as the sender displayed them, covering every nickname a client could have been shown.
The architecture relies on DNS plus WKID, with _parley._tcp.<domain> SRV records directing traffic toward the server and https://<host>/.well-known/parley/instance.json exposing the ed25519 public key alongside the inbox. A user’s existence is confirmed through .well-known/parley/<user>.json. Each event gets delivered as a signed JSON document POSTed to the recipient’s inbox, with an ed25519 signature in headers verified against the key found by the receiver.
When an instance joins a new domain, it can be told to automatically connect with another instance there, and the two will join up by themselves. Once linked, the joined instances share the peers they already know, which causes a network to form without needing any setup at all.
Source material: “Parley: Federated, decentralised chat that speaks plain IRC,” mills.io.
Get the Notebook.
The day's best stories and every fresh verdict, in plain English, in your inbox by seven. One email a day, no more.

