Expand description
The mesh: how one running Majordomus learns that others exist, and proves which one it is. ADR 0050 is the decision; this module is the whole implementation, and its boundaries are the point:
- Identity is a key, not an address. A node is an Ed25519 keypair kept per user
and machine (
identity); the node id is a digest of the public key. Hostnames, IPs, ports and PIDs are runtime attributes and never identity. - One protocol (
protocol): a compact, versioned, bounded, signed envelope, the same over multicast, broadcast and rendezvous. Parsing never panics; hostile input is a counted refusal. - Providers observe, the manager decides (
provider,manager): a discovery mechanism hands raw bytes up and answers for its own health. The manager owns the one verification path and the oneregistry; adding a mechanism is implementing the provider contract, not editing consumers. - Discovery creates awareness, not authority (
trust): a valid unknown node is observed and trusted for nothing; even a trusted node gains no execution rights — there is no remote execution to gain. The default policy isdeny_unknown, and the mesh itself is off until the repository commits a declaration (config) that says otherwise: the “nothing leaves the machine” posture holds by default. - Every surface is a projection. CLI, HTTP, OpenAPI, MCP and the Cockpit read
MeshRuntimeand the registry; none holds peers of its own.
Nothing here writes to the repository. The identity file lives under the user’s state directory; the registry lives in process memory and dies with it.
The whole lifecycle, in memory:
use majordomus_cli::mesh::{identity::NodeIdentity, protocol};
// a node proves itself: sign, encode, parse, verify — the one path every
// transport's datagrams take
let node = NodeIdentity::ephemeral().unwrap();
let envelope = protocol::advertise(&node, 1, &["127.0.0.1:8741".into()],
&["http".into()], &[], "docs");
let bytes = protocol::encode(&envelope).unwrap();
let heard = protocol::parse(&bytes).expect("a fresh signed envelope verifies");
assert_eq!(heard.adv.node_id(), Some(node.public.node_id.clone()));
// and hostile input is a refusal, never a panic
assert!(protocol::parse(b"garbage").is_err());Re-exports§
pub use config::MeshConfig;pub use config::KIND;pub use doctor::DoctorCheck;pub use doctor::MeshDoctorReport;pub use identity::default_identity_path;pub use identity::InstanceId;pub use identity::NodeId;pub use identity::NodeIdentity;pub use identity::PublicIdentity;pub use manager::MeshRuntime;pub use manager::MeshStatus;pub use manager::Refusals;pub use protocol::Advertisement;pub use protocol::Envelope;pub use provider::MeshProvider;pub use provider::Observation;pub use provider::ProviderContext;pub use provider::ProviderStatus;pub use registry::MeshRegistry;pub use registry::MeshSource;pub use registry::NodeRecord;pub use registry::Presence;pub use registry::Sighting;pub use registry::Tallies;pub use rendezvous::RegisterAnswer;pub use trust::TrustPolicy;pub use trust::TrustState;
Modules§
- address
- Where this runtime can be reached: the
host:portauthorities it advertises and dials back. A server bound to a specific address advertises that address. A server bound to every interface (0.0.0.0) is reachable at each interface’s address and at none called0.0.0.0, so it advertises its up, non-loopback IPv4 interface addresses — physical ones before container bridges, at mostsuper::protocol::MAX_ENDPOINTS. A server bound to loopback advertises loopback, which only this machine can dial; the mesh doctor says so. - broadcast
- The UDP broadcast provider: the controlled fallback for segments where multicast is
filtered. Same protocol, same port, no second serialization — only the destination
differs: the limited broadcast address in
automode, or the directed broadcast addresses the declaration lists inexplicitmode. Neverautoby default, and it does not spray interfaces: one socket, the destinations named above, nothing more. - config
- The mesh declaration: whether this repository’s servers participate in discovery, and
how. One typed object of the
.ai/layer (kindmesh, schemamesh/v1), parsed here and nowhere else. No declaration, orenabled: false, means the mesh is off and not one socket opens — the repository’s default posture (“nothing leaves the machine”) holds until a person commits the object that says otherwise. - cooperation
- Cooperation: the runtime that turns discovered, trusted runtimes of one repository into linked peers and keeps their journal converged. It owns the one peer-link table, the one journal of this runtime, the link handlers the HTTP surface answers, the dialers, the heartbeat and the expiry — and the operations (sessions, claims, handovers, reviews) every surface performs through it.
- doctor
- The mesh self-check: every prerequisite proved on this machine alone, no second node required. Deterministic checks in a fixed order, each with its own verdict, so “why is the mesh not working” has an answer that names the broken link instead of a shrug — and, when a check fails or limits cooperation, what that means and what to do. Read-only toward the repository; the sockets it probes are ephemeral and closed before it answers.
- firewall
- The host firewall, as the mesh needs it: what inbound traffic the declaration implies this machine must admit, which firewall this host runs, the commands that admit it, what the firewall says now, and what the kernel logged it dropping.
- handover
- Handovers across the mesh. A handover is written on one machine by
majordomus handoverinto that checkout’s.ai/local/state/handovers/; this module is the bridge between that record and the journal, in both directions: - identity
- Node identity: who this machine’s Majordomus is, independently of any repository, process, address or port. The identity is an Ed25519 keypair created once per user and machine and kept under the user’s state directory; the node id is a digest of the public key, so claiming an id means holding the key, and a hostname, an IP address or a PID is never identity — those are runtime attributes that change.
- journal
- The cooperation journal: the one replicated record of what the runtimes of a repository
said to each other. Discovery (
super::registry) answers “which runtimes exist”; the journal answers “what are they doing” — sessions, claims, handovers, reviews — as signed events that every linked runtime stores, relays and folds into the same state (super::state). - link
- The link protocol: what two runtimes say to become linked, and what they exchange once
they are. Discovery (
super::protocol) proves that a key exists somewhere; a link proves that the key is answering now, serves the same repository, speaks a compatible protocol, and is trusted — and only then does anything cooperative travel. - manager
- The discovery manager: provider lifecycle, the one verification path, and the one registry. Providers hand raw bytes here; this thread parses, checks bounds and staleness, verifies the signature, evaluates trust, and only then touches the registry — in that order, for every transport alike. A provider cannot skip a step because no provider ever parses.
- multicast
- The UDP multicast provider: the preferred LAN mechanism. One socket, bound to the configured port and joined to the group; a listener thread hands every datagram to the manager, an announcer thread transmits the beacon on the interval with jitter. IPv4 only, TTL from the declaration (1 by default: the local segment and no further).
- page
- What one answer about the mesh carries: a summary a worker can read whole, or the folded state narrowed to what was asked.
- protocol
- The discovery wire protocol: one envelope, every transport. A multicast datagram, a broadcast datagram and a rendezvous candidate all carry the same signed advertisement, so there is one serializer, one parser and one verification path — a second protocol per transport is exactly the five-truths defect ADR 0050 refuses.
- provider
- The provider contract: a discovery mechanism is a source of observations and nothing more. A provider watches one transport (a multicast group, a broadcast port, a rendezvous endpoint set), hands every datagram it hears to the manager as raw bytes, and answers for its own health. It parses nothing, verifies nothing, trusts nothing and holds no peers — the manager owns the one verification path and the one registry, which is what makes adding a provider a registration rather than a rewrite.
- registry
- The one registry of discovered nodes. Every provider’s observation converges here, deduplicated by node id (a digest of the key — never by address), so a node seen over multicast and handed back by a rendezvous is one record with two sources, not two rows with one truth each. Every surface — CLI, HTTP, OpenAPI, MCP, Cockpit — is a projection of this map; nothing else may hold peers.
- rendezvous
- The rendezvous provider: discovery across segments multicast cannot cross. Every
Majordomus server is a rendezvous — the
mesh.registercapability accepts a signed envelope and answers with the envelopes it holds — so a “mothership” is any node the declaration points at, not a different program and not a canonical database. The local registry stays the only truth; a rendezvous is one more source of observations, its failure stretches the retry and stops nothing else, and its answers are signed end-to-end: a poisoned rendezvous can withhold nodes, it cannot invent one. - repository
- Which repository and which runtime a mesh participant is — independently of any path.
- root
- The trust root: which copy of the mesh declaration a runtime obeys (ADR 0050 rule 6, I2135).
- state
- The cooperation state: what the journal’s events mean, folded. Pure: the same set of
events and the same liveness verdicts yield the same state on every runtime, whatever
order the events arrived in and however often — events are applied in
(lamport, stream, seq)order, and a set has no duplicates. That is the whole convergence argument, and a property test holds it. - trust
- Trust: what a verified advertisement is allowed to mean. Verification (the signature proves the key) happens in the protocol; trust (this key is one of ours) is decided here, by policy — and by default the policy is that an unknown key is observed, recorded, visible in every listing, and trusted for nothing.
Enums§
- Mesh
Error - Why a mesh operation did not happen. Each variant names the layer that refused, so a log line places the failure without a backtrace.