A fleet that talks without a boss
My machines message each other, and sometimes ask each other to do things. The first two versions of that, comm-system and then fleet-comm, kept a star: one host was the only server, held every identity, put the order on every record and could read every payload. So the audit trail was only as honest as that host, and the host was a single place to break into and a single place to watch everything from.
comm-mesh asks one question: what does the system look like when that host is just a node with a job? The answer fits in a sentence. The network carries messages, the receiver decides what to obey, grave decisions are counted and not ranked, and a logger only remembers. It keeps the earlier versions' transport code and drops their authority model.
The code is private, and this page keeps to principles on purpose. How my own machines are reached, and by which keys, is not something I publish. What is worth showing is the design that lets a fleet say who may do what with no centre to ask. Node names in the diagram and the text are abstract.
The receiver decides what to obey
In the star, the middle machine looked up the sender's rank and refused at the door. Here every node holds its own policy: which sender may ask it for what. Nothing is looked up at delivery time, no call goes out and no shared store is read, so the policy still works when a relay is gone. The machine that bears the cost is the one that consents. It is also the one that knows what an action costs, which is why the design has each node declare its own grave actions: a relay cannot classify a payload it cannot read.
Roles are jobs, not permissions. A judge signs approvals, a logger keeps a record, a relay carries traffic, a console is a person's window on the fleet. None of them is a reason to obey. A message runs because the receiver's own policy says that sender may ask for it. I held the design to one test: if a role ever becomes the reason to obey, I have rebuilt ranks under new names.
The network under it grants reach and never permission. An overlay that carries packets between machines can be compromised without handing anyone a role, because roles live in a signed table, and grave actions are designed to need a count.
Grave actions are counted, not ranked
Status first. This is the design for a grave action on a device, and it is the next phase. What is built today is the counting, which is the arithmetic below, and the signed roles table it governs, where the same judges sign and every node counts. The diagram draws the unbuilt part dashed.
In the old model any admin could approve a grave operation, the admin who asked for it included. In this one, a node that holds a grave request does not run it. It sends out a request that names a hash of the exact action. Each judge returns a signed approve or deny over that same hash, and the node counts the signatures itself, running the action only if enough arrive before the request expires. The judges produce evidence and the target decides, which is why this does not quietly rebuild a central authority.
Five rules carry the safety:
- The denominator is the enrolled judges, never the judges who answered. Otherwise an attacker who splits the network shrinks the denominator until they own a majority. The price is accepted: if the judges are offline, grave actions stall. Safety over liveness is also why the design needs a break-glass path, one that needs a person at the machine.
- It takes strictly more than 50%. Any two majorities overlap, so the two halves of a split network can never approve conflicting things. Exactly half would allow it.
- An approval is single-use. It binds to one request and one action hash, expires in minutes, and the target remembers the ones it has spent. Otherwise an approval is a reusable token.
- A quorum only releases what the target's own policy already allows under approval. Judges cannot grant a capability, so taking over every judge is not taking over the fleet.
- The requester's own signature does not count.
One asymmetry goes with them: gaining power over the fleet needs both the quorum and a person at the affected machine, while losing it needs the quorum alone, because you cannot ask a compromised node's owner to confirm being cut out.
The bar I lowered
I first set a higher bar for changing roles: at least 75% of the judges to change the roles table, and all of them to change the judge set. At three judges, the floor the design recommends, both were all three. A judge key lost without being rolled, which is what a reinstall does, froze the table for good. No renewal, no re-key and no removal could land, and the break-glass path inherited the deadlock, because approving a re-enrolment is itself a table change.
A concept review of the design found it. I reproduced it against the code on 2026-10-20 and again on 2026-10-23, and then lowered both bars to a strict majority. The price is written down: two judges of three can replace the third, and with it the electorate. That is the bar the designed grave-action count sets, and the overlap argument above still holds. The stronger tiers stay in the protocol as names, and the defaults no longer use them.
Records are signed and chained by their sender
The star stamped every record with one counter under one lock on one host, so a record's truth was that host's word. comm-mesh gives up a global order on purpose. Each sender signs its own records and chains them: a counter, plus the hash of its previous record. Anyone holding the sender's public key can verify the chain, a gap shows, and a logger becomes an interchangeable store that nobody has to trust. It can prove only that it stored a record, never that the record was true.
What is given up is a single fleet-wide sequence. What is kept is the order per sender, gap detection, and the ability to run several loggers and compare them: one that drops or reorders a record is caught, which one authoritative log can never show. Chaining also turns a suspicion into a proof. Two correctly signed records with the same counter and different hashes cannot come from one honest node.
Access grants are a signed table, rendered on each machine
The first thing outside the messaging bot to use this machinery was the login access to my machines. After a reinstall, a machine's new key had to be granted again on every host by hand, and the old key's lines stayed behind as orphans nobody could explain. Now a signed grants table says which key may log in where. Each machine adopts a newer version only when its signatures verify, renders its own access list from the table, and empties the entries whose grants are gone, which is what stops orphans. One re-key command is the whole reinstall procedure.
The rendered list sits beside the hand-kept one, which the tool never writes, so a bug can fail to grant and cannot lock me out. The tests run it against real throwaway servers: a reinstall, a removal and a tampered version. It runs for real on my own machines, and which ones, and how, I keep to myself.
Service channels carry 1-llm's requests
The first traffic the messaging bot carries for another program is 1-llm's model calls between machines, which the service stack shows from the other side. The rules for that traffic are: no log, no size cap and no permanent record. A relay that logs and caps would break all three, so a channel does not go through the relay.
A channel is a byte stream from a program on one node to a named service on another, carried bot to bot over TLS. The TLS gives confidentiality. The nodes' own signing keys give identity, and they sign over the connection's certificate fingerprint, so a man in the middle that relays the handshake fails. The certificate is a throwaway the bot makes, and it is never identity. The receiver's policy decides, as everywhere else: each peer has a list of the services it may open, and a node listens for channels only if its configuration allows it. Nothing about a channel reaches disk, not its bytes and not even that it was opened or refused.
The interface is small enough to show. A consumer opens a channel with one line and gets one line back. After that the connection is raw bytes until either end closes it, and the close is the cancel.
→ {"verb": "channel.open", "to": "node-b", "service": "llm"}
← {"ok": true, "channel": "c1f…", "to": "node-b", "service": "llm"}
… raw bytes both ways until either end closes …
→ {"verb": "channel.open", "to": "node-b", "service": "other"}
← {"ok": false, "error": "node-a may not open other"}What is built, and what is not
Built and tested: the signing core and the exact bytes a signature covers, which must be identical on every machine; the roles table, signed by a quorum and adopted only at a higher version; a messaging bot with the receiver's policy; time attested by the judges, so that a table cannot be given a validity window years long; the signed access grants; and service channels with their installer.
Not built: the decision plane for a grave action on a device, which is the next phase, and the break-glass counting rule for a fleet that has lost its judges. I would rather say so than let "judges sign grave actions" read as a system that is already running.
My own concept review asked whether the design defends a network that does not exist. The fleet has one owner and a handful of devices, and with one owner a quorum of machines adds a second human only if the approver keys belong to people. That is a fair question, and it changed what I built next: the access table, a chore I did by hand, became the first real consumer of the signed-table machinery, and its approver keys are meant for a person and never also a node's key.
How I built it
I built comm-mesh as AI-orchestrated engineering, measured and reviewed. It started as a written design with each decision dated, then a review of the concept against the code, and then a plan for each phase. Claude Code co-authored most of the commits against those plans. The messaging phase landed after a final review of the whole branch, and every finding it parked was fixed, found already closed, or kept with a written reason. The lost-key freeze above is pinned by tests that reproduce it.
The repository has 182 commits and about 800 tests. Those are the figures as I counted them for this site, and the repository keeps growing.