Skip to main content

Module mesh

Module mesh 

Source
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 one registry; 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 is deny_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 MeshRuntime and 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:port authorities 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 called 0.0.0.0, so it advertises its up, non-loopback IPv4 interface addresses — physical ones before container bridges, at most super::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 auto mode, or the directed broadcast addresses the declaration lists in explicit mode. Never auto by 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 (kind mesh, schema mesh/v1), parsed here and nowhere else. No declaration, or enabled: 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 handover into 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.register capability 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§

MeshError
Why a mesh operation did not happen. Each variant names the layer that refused, so a log line places the failure without a backtrace.