Connecting to a lattice
audience: integrators
You connect to a lattice the same way you connect to any mosaik
service: build a Network against builder::UNIVERSE, bring
your own discovery + transport config, and open organism handles
against your compiled-in LatticeConfig.
This page is the reference for the connection side. The application side lives in Quickstart — submit, bid, read.
Default shape
use std::sync::Arc;
use mosaik::Network;
use builder::UNIVERSE;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let network = Arc::new(Network::new(UNIVERSE).await?);
// ... open organism handles ...
Ok(())
}
Network::new(UNIVERSE) applies the mosaik defaults: pkarr /
Mainline DHT bootstrap, /mosaik/announce gossip, iroh QUIC
transport, mDNS off, no explicit bootstrap peers. It works for
most production agents on the open internet.
Bring-your-own-config
When you need specific discovery, transport, or metrics
configuration, use the Network::builder:
use std::{net::SocketAddr, sync::Arc};
use mosaik::{Network, discovery};
use builder::UNIVERSE;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let network = Arc::new(
Network::builder(UNIVERSE)
// Bootstrap off a known peer for cold starts (optional).
.with_discovery(
discovery::Config::builder()
.with_bootstrap(vec![ /* known peer ids */ ])
)
// Expose prometheus metrics for your agent.
.with_prometheus_addr("127.0.0.1:9100".parse::<SocketAddr>()?)
// Turn mDNS on for local development.
.with_mdns_discovery(cfg!(debug_assertions))
.build()
.await?,
);
// ... open organism handles ...
Ok(())
}
Bootstrap peers are universe-level. Any reachable peer on
builder::UNIVERSE — not specific to any lattice — is a valid
bootstrap. Once bonded, the organism’s own discovery locates the
specific committee peers via the shared catalog.
Identity
Your agent’s PeerId is derived from a secret key you control.
The default — Network::new — generates an ephemeral key per
process. That is fine for short-lived agents; long-running ones
(trading bots, indexers) should pin a stable key so your peer
catalog entries survive restarts:
use mosaik::SecretKey;
let secret = SecretKey::from_hex(env::var("BUILDER_AGENT_SECRET")?)?;
let network = Arc::new(
Network::builder(UNIVERSE)
.with_secret_key(secret)
.build()
.await?,
);
See the mosaik getting-started for key rotation and secret-management guidance.
Ticketed admission
Some organisms in some lattices gate their read-side on a
ticket. atelier is the common case on the read side
(integrators reading block bodies); offer gates its write
side on a searcher ticket. When the lattice operator issues you
a ticket, install it on the network:
use mosaik::TicketValidator;
let network = Arc::new(
Network::builder(UNIVERSE)
.with_ticket(operator_issued_searcher_ticket)
.build()
.await?,
);
Ticket formats are per-organism and per-lattice; follow the
operator’s handoff. Missing tickets surface as Attestation
errors on the relevant organism’s verb() call, not as
ConnectTimeout.
Local development
A lattice’s integration test harness is the deterministic path
for iteration. If a lattice publishes a --test workspace
(equivalent to zipnet’s e2e), prefer running that harness for
integration tests rather than hitting a live lattice. Live
lattices have the usual P2P cold-start latencies.
For agent-level development against a live lattice, expect:
- First bond to any committee member: up to a minute on a cold agent over fresh iroh relays.
- Subsequent
verb()calls: sub-second once bonded. ConnectTimeoutafter roughly 60 seconds if no committee member is reachable.
Troubleshooting
| Symptom | Likely cause | Check |
|---|---|---|
ConnectTimeout | Mismatched LatticeConfig or the organism is not running | Compare lattice_id() hex; ask the operator if the organism is up |
WrongUniverse | You built Network against a non-builder universe | network.network_id() == builder::UNIVERSE |
Attestation | Missing or stale ticket | Verify with the operator; rotate if expired |
Protocol("deferred") | You called an organism verb that is not implemented in this version | Check the organism’s own Roadmap |
Next reading
- TEE-gated lattices — compiling with
tee-tdxto pin MR_TDs. - What you need from the operator — the fact sheet that determines whether any of the above actually works.