Introduction
audience: all
ai on mosaik — self-organization as composition.
This book is about the intersection of AI and self-organization: populations of autonomous agents that coordinate without a central authority, under a distributed runtime whose primitives make such coordination a property of composition rather than a platform favour.
Self-organization
Self-organization in a population of autonomous agents is not a feature a substrate offers. It is what falls out when a sufficiently careful set of primitives composes. A substrate that supplies durable identity, narrow public surfaces with ticket-gated admission, deterministic shared state, evidence-pointed commits, and voluntary opt-in at every bond does not need separate “multi-agent” machinery. The composition does the work.
The thesis inverts the usual design instinct. Rather than enumerate the primitives a substrate must add to host agent populations (a coordinator, a broker, a scheduler, a reputation service), this book reads the other way: begin with a small set of composable distributed-systems primitives and show the agent- population regime as one thing that falls out. No supra-agent authority is added anywhere; none needs to be.
The mechanism, named once: mosaik AI agents
self-organize and converge by agreeing on a shared
policy. The shared policy is the Config.content
of a mediating organism (a reputation organism’s
utility function, a market’s clearing rule, an
attestation fabric’s verification rule, a stigmergic
collection’s write-side contract) or, when TDX is in
the deployment, the runtime policy bound by a declared
TDX Measurements set. Convergence is substrate-
anchored: each agent’s TicketValidator admits the
same fingerprint, and every bond remains voluntary on
both sides.
Balance of power
The stance above is deliberate. A substrate that supplies compulsion at any rung — a coordinator who can force a bond, a basic service whose absence disqualifies a member, a coalition whose membership is mandatory — becomes another concentrated locus of power, which the book treats as a design failure. Buterin’s On balance-of-power as a goal for the 21st century (2025) frames the underlying concern directly: natural diseconomies of scale have receded, and without deliberate design every sector’s power concentrates past the point where checks operate. The coalition layer’s construction is the substrate-level answer in one direction — subsidiarity made mechanical: decisions live at the most local composable rung (one agent, one organism, one coalition), cross-coalition atomicity is refused, and the operator’s exit is always available. The substrate is the game; it is not a player.
Mosaik
The substrate is mosaik — a Rust
distributed runtime originally designed for block-
building committees. Its primitives
(Stream,
Group,
Collection,
TicketValidator) were chosen for
cryptographically admitted committees exchanging
evidence-bearing commits under a shared clock. They
compose cleanly into populations of autonomous agents:
durable per-agent identity, narrow public surfaces
committing agent outputs, deterministic agreement when
a set of agents must reach one commit rather than N,
evidence pointers into upstream commits for replayable
trust composition, and ticket-gated admission at every
bond. Nothing in the runtime is agent-specific; agents
get the same ladder everything else does.
This book does not re-specify mosaik. It composes on
top of the runtime and links out to the mosaik
documentation at docs.mosaik.rs
whenever a primitive is named. Every consensus-
critical value in the coalition layer — coalition
fingerprints, organism ids, module roots, retirement
markers — is a mosaik::UniqueId (a 32-byte blake3
digest). The coalition
crate depends on
mosaik = "0.3" and re-exports that identity type
directly; downstream crates pin the same mosaik
version so every fingerprint the book names flows
through one shared primitive.
The load-bearing pages, for readers coming to this book without a prior mosaik pass:
- Concepts — Architecture and Identity & Networking — how mosaik organises peers, networks, and bonds.
- Subsystems — Streams, Groups, and Collections — the three replicated-data primitives this book’s organisms commit on.
- Subsystems — Discovery and
its Auth Tickets page — how
TicketValidatoradmits bonds and how integrators present tickets. - Subsystems — TEE — Intel TDX — the attestation wrapper the book’s TDX-required deployments bond against.
- Internals — Raft, Bonds & Peer Connections, State Sync & Replay, Determinism & Hashing — the deep-dive pages threat-model and composition chapters reference.
- Reference — Primitives & Types — the canonical type index.
Every chapter below links to the specific page a reader should consult when a primitive is load-bearing; the index above is for readers who want to study mosaik first.
Shuffle
Across this book, shuffle denotes the abstract primitive that takes N sealed submissions from distinct senders and makes their cleartext available to downstream readers in a way that breaks the sender → submission link: through a bonded unseal committee, a mix network, a threshold-decryption quorum, or another construction with the same public surface. Shuffle is what the composition needs; the construction underneath is a choice the operator makes.
Zipnet is one shuffle implementation — one mosaik organism that accepts sealed submissions and releases cleartext through a bonded unseal committee. It is the smallest interesting composition the mosaik runtime admits, and it is the shuffle construction this book’s examples bond against concretely. See the zipnet book for its specification. Other shuffle constructions (cMix-style mix networks, threshold-BLS decryption pools, FHE-backed release) are out of scope for this book but slot into the same shuffle role without changing the compositional surface.
In an agent population, a shuffle is the submission layer for any flow where individual contributions are sensitive and the aggregate is not: sealed prompts, sealed bids, sealed forecasts, sealed attestations. Building on it, one arrives quickly at the full coalition rung this book specifies.
This book
The book has three parts.
Part I — Thesis. The argument is assembled in five chapters.
- Societies — what a production population of agents looks like when coordination is a property of composition, not a central actor.
- AI — the four agent shapes (integrator, standalone organism, organism member, swarm-as-organism) and the four emergent-coordination patterns (stigmergic collections, reputation feedback, coordination markets, attestation fabrics).
- Zero to one — shipping the first organism. A single-agent product, end-to-end.
- One to two — introducing the second organism. The smallest multi-agent protocol: handoff, delegation, two-agent composition.
- Two to three — a quorum. The smallest non-trivial society: three is the minimum for threshold schemes, majority-of-honest committees, and the smallest composite organism whose commits encode disagreement rather than report it.
Part II — Examples. Four parallel end-to-end worked examples, each walked through seven chapters. Each adds one mosaik surface per rung (setup, binding, market reads, wrapping, inference-or-provisioning-or-aggregation-or-signing, submission-or-receipts-or-publication-or-aggregate, reputation-and-successor-chain).
- web3 — an MEV-searcher AI bot built on a
Flashbots-operated instance of the
builder (6e3v) lattice —
the instance named
testnet-1a— inside its own small coalition. Market-maker variants are called out per chapter where the pattern diverges. - web2 — an entity operating a compute-bridge provider, wrapping AWS, GCP, Azure, and bare-metal behind one provider identity and competing with other providers on rate in a coalition’s Compute coordination market.
- oracle — a TDX-attested price oracle shipping
one
Stream<PriceTick>per supported token pair, with the whole trust model anchored on a declared Measurements set. A standalone organism packaged inside its own coalition for retirement and optional audit. - signer — a generic threshold-signature organism. The committee is itself a market of providers at varying attestation levels (software, TDX-local, TDX-remote-attested, RA-TLS bidirectional, TDX + reproducible build) competing on attestation, capacity, and fee per partial signature. Consumers gate admission on the aggregate attestation level each outcome carries. Design inspired by zipnet, inverted from decryption to signing.
See Part II overview.
Part III — For builders. Three chapters that carry the reference material for each audience of implementers.
- For integrators — external developers whose agent binds across members of a coalition.
- For operators — teams running an organism, a multi-operator coalition, or a coalition-scoped module.
- For contributors — engineers commissioning a new composite organism, a new class of mid-rung composition, or a new basic service.
Every chapter declares its primary audience on the
first line (audience: integrators | operators | contributors | ai | both | all)
and respects that audience’s register: pattern-forward
and code-forward for AI authors, cookbook-style for
integrators, runbook register for operators, design-
review density for contributors.
Vocabulary ladder
mosaik primitives Stream, Group, Collection, TicketValidator
composed into
organisms one Config fingerprint, narrow public surface
(AI agents, oracle feeds, attestation fabrics,
composite organisms spanning multiple members, …)
composed into
(optional) lattices a fully-specified mid-rung composition
(block-building, per builder; other classes
may follow their own proposals)
composed into
coalitions N lattices + M organisms under one CoalitionConfig,
possibly shipping up to five basic services and
an optional coalition-scoped ticket issuer
Each rung reuses the rung below verbatim. The universe
(the mosaik NetworkId) is the only bottom rung; every
rung above is optional composition.
Status
Blueprint. No organism or module in this repository is implemented. The specification assumes mosaik’s current primitives, the shuffle’s shipped shape, and the builder proposal’s
LatticeConfig; pinned versions will be called out as crates land.
Prior art
- The builder book specifies the first
concrete lattice class: six organisms composed into
one end-to-end block-building pipeline for one EVM
chain. The coalition rung this book specifies
references builder’s
LatticeConfigverbatim. - The Flashbots essay Decentralized building: wat do? sets the motivating context for why mosaik exists and what the path from centralized to Byzantine-distributed production looks like. This book picks up after the infrastructure question is answered.
For my sons
Robert, Bruno, Gabriel
Societies
audience: all
This chapter fixes what the word society denotes in this book, why population effects force a naming rung above the individual organism, and how a production society is assembled from the primitives the rest of the book specifies.
On the word. Society is heavily loaded in current multi-agent-systems writing, where it is the dominant term for simulated agent populations (CAMEL-AI’s agent society, Tsinghua’s AgentSociety, OASIS, the Park et al. generative-agents line). The reading here is different. A society in this book is a production composition of organisms that coordinate under one coalition handshake, not a laboratory instrument for studying emergent behaviour. Where the simulation literature is descriptive — observing what a population does — this book is constructive: a society is what an operator stands up, a coalition fingerprints, and an integrator binds against.
A society is the coalition at its normal operating size
Every coalition can be read at three scales, and the reading that carries the thesis is the third.
- N = 1. A coalition with one referenced organism is an organism plus a naming convention. Nothing coordinates.
- N = 2. A pair. Interaction is a handoff: one organism commits, the other reads and acts. A composite organism is possible but not forced.
- N ≥ 3. Coordination becomes a property of the composition rather than an exchange. Majority-of- three is the smallest honest-committee assumption; threshold-of-three is the smallest interesting cryptographic quorum; the first statistic a reputation organism can compute without naming the scored organism directly is a rank in a set of three.
A society is a coalition operated at N ≥ 3, with at least one organism whose content fingerprint folds references to two or more other members. The commits of that organism are the society’s internal coordination made explicit.
This is the scale at which emergent coordination begins to show up in a form the blueprint can name. Below it, there is only an organism and its consumer.
The shape of that coordination is itself compositional:
members and observers converge by agreeing on a
shared policy — the Config.content of whatever
organism mediates their interaction (reputation,
market, attestation, stigmergic collection) or, when
the deployment is TDX-attested, the runtime policy
bound by a declared TDX Measurements set. A society
is the regime at which such agreements start producing
observable convergence across the referenced members.
The composable-coordination-without-authority reading of a society has a nearby kin in Buterin’s Plurality philosophy in an incredibly oversized nutshell (2024), which catalogues quadratic funding, pairwise-bonded governance, and non-transferable reputation as instruments for producing shared decisions without a central coordinator. The book borrows the compositional stance without the civic terminology: the blueprint speaks of members, organisms, and validators, not citizens, polities, or institutions.
The members and the observers
Every society has two classes of members, both
referenced by the coalition through the same
OrganismRef shape:
- Primary agents. Organisms whose commits are the society’s output — the submitters, the decision- makers, the producers. In an AI society these are the agent organisms whose policies consume observations and commit actions.
- Observing organisms. Organisms whose commits are a view of the primary agents: a reputation organism scoring agent commits, an attestation fabric folding agent-submitted TEE quotes, an Atlas directory publishing agent metadata, a Chronicle auditing the coalition’s own events.
The two classes are not a type distinction — they are
roles in the composition. An observing organism can be
a primary agent in a larger society; a primary agent
can be read by observers in a way that makes it,
structurally, a subject. Both are referenced by the
coalition through the same OrganismRef shape.
What the coalition adds
A coalition operating at society scale earns its naming rung through four specific mechanisms, each optional and each specified once in this book.
- Atlas. A directory of members with operator- supplied metadata (role, endpoint hints, ticket- issuance roots, TDX Measurements). Readers that need to locate or route to a member consult Atlas; writers that retire emit a replacement pointer the directory reflects.
- Almanac. A shared clock beacon. Organisms whose native clocks are incommensurate (a tick-based oracle, a slot-based lattice, a round-based market) align their cross-member joins on Almanac ticks.
- Chronicle. A tamper-evident audit log of the coalition’s own publications, rotations, and retirements. A society without a Chronicle still has its members’ commits; a society with one has them plus a single authoritative chronology of society-level events.
- Compute. A scheduler and registry through which members submit compute requests for image-hashed workloads and receive grants matching them to registered providers. In an AI society where members are hungry for inference, Compute is often the mechanism that keeps the society funded.
Each basic service is specified in Basic services. A coalition ships zero, one, two, three, or all four; whichever it ships, the shape is the same shape in every other coalition.
No supra-agent authority
A society in this blueprint is not a polity. The
substrate has no primitive for compulsion: every bond
is opt-in at the TicketValidator layer, every
member’s identity is independent of any coalition’s,
and no basic service gates the operation of any
member. A coalition that wishes to force its members
to do something cannot; the force would live outside
the substrate, in out-of-band agreements between
operators.
This is load-bearing. It is the mechanism by which agent societies on mosaik avoid the supra-agent shape the book refuses at the coalition layer. The shape is refused by construction, not by convention.
The organising principle is subsidiarity: every
decision lives at the most local composable rung
that can handle it. A per-agent policy lives inside
one agent’s OrganismConfig; a cross-member
coordination lives inside one composite organism’s
Config; a grouping of lattices and organisms
lives inside one CoalitionConfig. No rung above
is permitted to override a rung below, and no rung
below is permitted to bond upward without
presenting its own ticket. Buterin’s
On balance-of-power as a goal for the 21st
century (2025) frames
subsidiarity as one of three structural moves that
keep any one concentration of power from
overwhelming the others; the coalition substrate
implements that move mechanically, one identity
preimage at a time.
Game theory as a lens, not a prediction
This book takes game theory as a lens on mechanisms the operator chose, not as a prediction of how agents will behave. Equilibrium analyses of LLM populations have repeatedly failed empirically — Park et al., Do LLM Agents Have Regret? (ICLR 2025), shows GPT-4-class agents are not no-regret in canonical repeated games; the hypergame survey (2025) exists because common-knowledge-of-rationality does not hold for LLM players; static-payoff assumptions break under model drift. Mechanism design enters where the operator designs the clearing rule, the reputation score, the attestation validator; it does not enter as a claim about what the agents will do once admitted. The book uses game-theoretic vocabulary when naming a mechanism the operator built; it does not use it to describe the organisms’ behaviour under that mechanism.
Economic theory as the operator’s lens
Where game theory names the fixed points of a mechanism
under declared assumptions, economics names the shape
of the mechanism itself. The design choices a coalition
operator makes are economic choices: which allocation
rule the Compute module clears with (Roth and Sotomayor,
Two-Sided Matching, 1990; Milgrom, Putting Auction
Theory to Work, 2004); what the reputation organism
prices and what it does not (Kreps, Milgrom, Roberts,
Wilson 1982); how much information the attestation
fabric forces a participant to reveal (Spence 1973,
Kamenica and Gentzkow, Bayesian Persuasion, 2011);
whether the stigmergic collection is a public good, a
club good, or a common-pool resource (Ostrom 1990). The
coalition’s CoalitionConfig and its referenced
organisms’ OrganismConfigs are the artefacts where
those choices are recorded, versioned, and made
auditable through the retirement chain. The book’s
register stays compositional, but the load-bearing
question at each design step is economic.
What this chapter is not
- A taxonomy of agent societies. The catalogue stays open; each real society earns its own specification when the coordination problem forces one.
- A theory of emergence. The emergent coordination chapter names four patterns that have paid off for real deployments; the chapter is constructive, not descriptive.
- An argument that mosaik is the only substrate for production agent societies. It is one substrate with a specific composition model. Whether it fits a given society is the operator’s judgement.
Forward
The AI chapter specifies the four agent shapes and four emergent-coordination patterns that populate the society. The zero-to-one / one-to-two / two-to-three chapters walk the scaling axis explicitly: the minimum product (one organism), the smallest interesting protocol (two), and the smallest honest society (three).
What a coalition gives AI agents
audience: ai
Mosaik is a distributed runtime whose primitives
(Stream,
Group,
Collection,
TicketValidator) were chosen for
block-building committees. They compose cleanly into
another regime: populations of autonomous agents
that coordinate without a central authority. The
coalition layer is the naming unit for a set of such
agents plus the organisms that observe, score, match,
and attest their behaviour.
The mechanism that
coordinate-without-central-authority reduces to is
agreement on shared policy: agents converge when
they co-bond against the same mediating Config.content
(a reputation organism’s utility function, a market’s
clearing rule, an attestation fabric’s verification
rule, a stigmergic collection’s write-side contract)
or run the same attested binary bound to the same TDX
Measurements. Every emergent-coordination pattern this
chapter enumerates is an instance of this mechanism;
every bond remains voluntary on both sides.
This section is the fourth audience of the book. The other three — integrators, operators, contributors — are written for humans running code that touches a coalition from a fixed role. This section is written for the reader, human or agent, who is building the agent population itself: one where identity, bonding, observability, reputation, and coordination are protocol artefacts rather than platform favours.
What fits and what doesn’t
Mosaik does not supply agency. An agent’s policy — the function mapping observations to actions — lives wherever the agent author wants (a local Rust process, a Python inference server, a remote API, a WASM module). Mosaik supplies:
- Durable identity per agent deployment, independent of operator or host, via content + intent addressing.
- Narrow public surfaces each agent exposes — a stream of its commitments, a collection of its artefacts — with ticket-gated admission.
- Deterministic shared state via Groups, when a set of agents need to agree on one commit rather than observe each other’s independent commits.
- Evidence-pointed commits — every commit can cite the upstream commits it folded in, so a replayer can verify claims without trusting the emitting committee.
TicketValidatoropt-in — coalitions reference agents by stable id; every bond between an agent and a coalition, or between two agents, is enumerated in each side’s ownTicketValidator. No primitive folds tickets across sides. The substrate carries no cross- agent enforcement surface.- TDX-attested feeds for external data. When an agent needs data from a source it cannot trust directly — prices from a CEX, a weather oracle, a paid API — the source can be wrapped in a TDX- attested feed organism whose Measurements the consumer audits and pins. Bonding against the Measurements replaces trust in the feed operator with trust in the feed image’s source code. See emergent coordination — attestation fabrics.
What mosaik will not do:
- Train models, schedule inference, or host weights. That lives in each agent’s own infrastructure.
- Guarantee that agents behave honestly. Honesty is a property of an agent’s policy and the composition of the organisms observing it; mosaik only guarantees that whatever is committed is committed atomically within its Group and reproducible on replay.
- Provide a “swarm” primitive. A swarm is a pattern over mosaik primitives — an organism, a standalone organism, or a set of integrators — not a built-in object.
Four shapes for an agent on mosaik
An agent is always exactly one of these four at any given moment. Hybrid roles exist; they are combinations of the four, not additional shapes.
-
Agent as integrator. The agent binds coalition handles, observes public surfaces, acts in the real world, and does not commit publicly on the mosaik universe. Identity is a fresh
PeerIdper session. Cheapest to stand up; zero bonding with other operators. Suitable for inference-only agents and for agents whose outputs are private. -
Agent as standalone organism. The agent runs as a mosaik-native committee organism with a narrow public surface: one or two Streams or Collections to which it commits. Identity is a
Configfingerprint. Replayable, auditable, bondable. A coalition may reference the agent viaOrganismRef. -
Agent as organism member. The agent is one of N operators of an organism committee — the organism commits as a unit, individual members do not commit publicly except as part of quorum. Suitable when a set of agents needs to agree on one output (a market clearing, an allocation, an attested inference).
-
Agent swarm as organism. Each agent is its own standalone organism; a separate organism folds the agents’ public surfaces into one aggregated commit (classification consensus, reputation-weighted averaging, anomaly reports). The organism is the swarm; the individual agents remain identifiable and accountable.
See agent shapes for when each shape pays off.
Emergent coordination without a central actor
Coordination without a central actor is a design goal of mosaik that aligns with multi-agent research goals. Four mosaik-native patterns produce it.
- Stigmergic coordination. Agents leave traces in a public Collection; each agent reads the collection before acting; convergence without direct messaging.
- Reputation feedback. A reputation organism observes each agent’s commits and commits a scored view; downstream consumers route work to higher- scored agents; agents adjust policy over time.
- Coordination markets. An organism clears bids and offers from a set of agents; the market’s commits drive downstream allocation.
- Attestation fabrics. An organism aggregates agent-submitted attestations (for example, TEE quotes, verified inference receipts); downstream organisms accept an agent’s claims only when the fabric endorses them.
Each pattern is an application of the organism shape or the standalone-organism shape; none requires a new primitive. See emergent coordination.
Why the coalition rung matters for agents
The coalition layer adds one thing agents need that the lower rungs do not supply: a named composition of a population plus its observing organisms. Concretely, a coalition gives an agent society:
- One handshake token (
CoalitionConfig) that enumerates the agents, the reputation organism that scores them, the coordination-market organism they feed, and the Atlas directory that lists them. A new agent joining the society compiles in one constant and discovers the rest. - An optional Atlas module that publishes per-agent metadata (role, endpoint hints, TDX Measurementss, ticket- issuance roots). A new integrator needing to route to agents reads the Atlas and binds.
- An optional Almanac module that supplies a shared tick axis for correlating agent activities without agreeing on a global clock.
- An optional Chronicle module that records publications, joinings, and retirements so the society’s history is tamper-evident without a central bookkeeper.
- An optional ticket issuer that any agent may
recognise in its
TicketValidatorcomposition, or not. Voluntary recognition is the rule.
Every bond an agent accepts is enumerated in that
agent’s own TicketValidator; every bond a coalition
exposes is enumerated in its components’ validators.
Nothing in the primitive set folds the two sides. This
is load-bearing: it is why the agent-population shape
above does not require a supra-agent authority the
deferred-primitives space
would supply.
What this section does not try to be
- An introduction to mosaik primitives (see the mosaik book).
- An introduction to building AI agents, choosing models, or orchestrating inference. That is a vast literature; the book does not reproduce it.
- A catalogue of specific AI-agent organisms worth commissioning. The catalogue stays open. This section names patterns, not blessed deployments.
- A claim that mosaik is the only substrate for agent populations. It is one substrate with specific ergonomics; whether it fits a given agent society is the author’s judgment.
Entry points
- New to the coalition layer. Read integrators/overview first, then return here.
- Bringing up an agent that binds a coalition. quickstart.
- Choosing a shape for your agent. agent shapes.
- Designing multi-agent coordination. emergent coordination.
- Keeping the agent operational and avoiding rot. sustainability and abandonment.
- Topping up resources and scheduling experiments. compute.
- Shipping a product. zero to one — from idea to production on mosaik + zipnet + builder + coalition.
Cross-references
- Contributor — composite organisms — the cross-agent organism shape.
- Contributor — topology intro — why the coalition rung exists.
- Contributor — threat model — how trust composes when agent populations coexist.
Quickstart — stand up an agent that binds a coalition
audience: ai
This quickstart brings up a single AI agent in the integrator shape (the cheapest of the four shapes from overview): the agent observes a coalition’s public surfaces, acts on what it observes, and publishes no public mosaik commits. Section agent shapes covers the other three shapes.
The code below assumes a Rust agent. Agents whose core
lives in Python or another language follow the same
pattern via whichever FFI they use to reach a mosaik
Network handle.
What you need before you start
- A
CoalitionConfigfrom the coalition operator — either the struct definition or a serialised fingerprint paired with the struct in a shared crate. - A ticket from each per-member operator whose write- side primitive the agent intends to use. Read-only agents typically need none; bidding, submitting, or publishing agents need one per write-side surface.
- The agent’s own policy code — however it loads, evaluates, and acts. Mosaik is agnostic about this.
Step 1 — declare the CoalitionConfig
Same pattern as the integrator quickstart:
use builder::LatticeConfig;
use coalition::{CoalitionConfig, OrganismConfig, OrganismRef};
const SUBSTRATE: CoalitionConfig<'static> = /* from operator release notes */;
The agent holds the constant as a compile-time input, not as a runtime registry lookup. This is the fingerprint-not-registry discipline; an agent that tries to “discover” its coalition via network queries has invited unauthenticated state into its core loop.
Step 2 — build the network handle
use std::sync::Arc;
use mosaik::Network;
use builder::UNIVERSE;
let network = Arc::new(Network::new(UNIVERSE).await?);
One Arc<Network> per agent process. Clone it into each
task that needs a handle.
Step 3 — open subscriptions on the surfaces the agent reads
The agent’s observation set is whatever the policy needs. Examples:
// Subscribe to a lattice's auction outcomes — the agent
// wants to track recent bids and fills before acting.
let outcomes = offer::Offer::<Bundle>::outcomes(
&network, &SUBSTRATE.lattices[0].offer,
).await?;
// Subscribe to a shared ledger organism — the agent
// uses aggregated refunds as input to its utility
// function.
let refunds = ledger::Shared::<Refund>::read(
&network, &SUBSTRATE.organisms[0],
).await?;
// Read the coalition's Atlas to discover per-member
// endpoint hints and TDX Measurements, if needed at cold start.
if let Some(atlas_cfg) = SUBSTRATE.atlas() {
let atlas = atlas::Atlas::<MemberCard>::read(
&network, atlas_cfg,
).await?;
// Agent may cache atlas entries and refresh them on
// a cadence matching its policy horizon.
}
// If the coalition ships an Almanac, use it as the time
// axis across uncorrelated member clocks.
if let Some(almanac_cfg) = SUBSTRATE.almanac() {
let ticks = almanac::Almanac::<AlmanacTick>::read(
&network, almanac_cfg,
).await?;
// Pull `observed_at: Vec<(MemberId, SystemTime)>`
// from each tick for per-member timestamp brackets.
}
Step 4 — drive the agent loop
An inference-only agent typically runs a select! loop
over its subscriptions, feeds observations into the
policy, and dispatches the resulting action wherever the
action belongs (a write-side stream, an HTTP call, an
on-chain tx).
loop {
tokio::select! {
Some(outcome) = outcomes.next() => {
let obs = observation_from_outcome(&outcome);
if let Some(action) = policy.decide(obs).await? {
dispatch(action).await?;
}
}
Some(refund) = refunds.next() => {
policy.update_belief_from_refund(&refund);
}
_ = shutdown_signal() => break,
}
}
Rules for an agent at this layer:
- Policy is pure-ish. Write the policy so the same observation sequence reproduces the same action sequence given the same weights. This is not required by mosaik; it is required for the agent’s own debuggability when the policy is later migrated into an organism (shape 2, 3, or 4).
- Side effects are explicit.
dispatch(action)is the only point where the agent changes external state; the rest is observation and belief update. - No cross-task shared mutable state unless deliberate. Mosaik’s subscriptions are per-handle; aggregating across them should be done in one place.
Step 5 — ticketed write actions (if any)
When the agent actively writes, it holds one ticket per write-side surface, bonded at startup against the per-member operator’s issuance root:
// Example: the agent places bids on a lattice's `offer`.
// The Offer::<Bundle>::bid constructor verifies the
// ticket composition against offer's TicketValidator.
let bids = offer::Offer::<Bundle>::bid(
&network, &SUBSTRATE.lattices[0].offer,
).await?;
bids.send(bundle).await?;
Ticket lifecycle is the agent’s responsibility: rotate before expiry, re-bond if a ticket-issuance root changes, fail loud if a per-member operator has revoked.
What this shape does not give the agent
- Replayable outputs. An integrator-shape agent commits nothing on the universe. Its decisions are reproducible only if it keeps its own log.
- Public identity. Peers cannot address the agent directly; other agents know it only through the side- effects of its actions.
- Bonding with other agents. Other agents cannot hold a ticket against this one.
Graduate to shape 2 (standalone organism) when any of those becomes a requirement. See agent shapes.
Cross-references
- What a coalition gives AI agents
- Agent shapes
- Emergent coordination
- Integrators — quickstart — the closest analogue in the non-AI audience.
Agent shapes
audience: ai
Overview introduces the four shapes an agent can take. This page walks each shape concretely: when to pick it, what identity you commit to, what bonding looks like, what changes when the agent is retired or rotated.
The four shapes are not a ladder to climb. An agent society may contain every shape simultaneously: a pool of inference integrators querying an attestation fabric organism whose members are standalone-organism agents, all referenced by one coalition.
Shape 1 — Agent as integrator
Pick when. The agent’s output is a private action (a trade, a tool invocation, an HTTP call) not consumed by peers on mosaik. Policy updates happen out of band. No other party needs to bond against the agent’s identity.
Identity. A fresh PeerId per session, not bonded
into any organism’s ACL. The agent publishes no stable
mosaik identifier.
Bonding. One ticket per write-side surface, obtained from each per-member operator the agent writes to.
Lifecycle. Start, observe, act, shut down. No retirement marker; peers never expected the agent to commit.
Cost to run. Equal to a non-agent integrator. No committee, no state machine, no ACL.
Example. A cross-chain arbitrage agent that
observes offer::AuctionOutcome on three lattices and
submits bundles via offer::Offer::<Bundle>::bid. The
agent’s policy is a model weighted by observed fills.
See quickstart for the bring-up sequence.
Shape 2 — Agent as standalone organism
Pick when.
- The agent’s output is consumed by peers — other agents, non-agent integrators, or organisms — that need a stable address to bond against.
- The agent’s history is consumed — for audit, reputation scoring, or as evidence in downstream commits.
- The agent’s policy runs under committee consensus (k-of-n members of the organism run the policy deterministically on the same input set).
Identity. A Config fingerprint derived by the
agent’s operator. Stable across operational rotations
per the
stable-id / content-hash split:
stable id unchanged on TDX Measurements bumps, content hash bumps
on every operational rotation.
Bonding. Other parties hold tickets under the
agent’s TicketValidator. A reputation organism bonds
read-only; a downstream organism bonds read-only for
the agent’s public surface and possibly write-only for
evidence submission.
Public surface. One or two primitives, following the narrow-surface discipline:
#[non_exhaustive]
pub struct AgentConfig<'a> {
pub name: &'a str,
/// State-affecting parameters: model family,
/// version, decoding temperature, any policy-level
/// constant downstream consumers must agree on.
pub content: AgentContent<'a>,
/// Who may bond into the agent's surfaces.
pub acl: AclComposition<'a>,
}
// Public surface example:
// AgentOutput Stream<AgentCommitment>
// AgentArtefacts Collection<ArtefactId, Artefact>
Lifecycle. Bring-up mirrors any mosaik-native committee organism:
- Publish the
Config. - Stand up committee members with the agent’s policy running deterministically (threshold cryptography or TDX attestation if the policy handles sensitive inputs).
- When retiring, emit a
RetirementMarkeron each public primitive pointing at the replacement agent, if any.
Determinism caveat. An AI policy built on a non-deterministic decoder cannot run under a majority- honest Raft committee unmodified. Two common answers:
- Single-member deployment. The agent runs with N=1 and is simply a bonded process; losing integrity reduces to trusting that operator, same as any other N=1 organism.
- Attested deployment. Committee members run the same model, same weights, same decoding seed inside TDX; determinism is enforced by the measurement, not by Raft.
- Threshold inference. Committee members each run independent inference; a threshold scheme aggregates their outputs. Useful when the agent’s job is classification or scoring; harder when the output is free-form generation.
Example. An oracle-style agent that commits a
Stream<Claim> of fact-checked news items keyed by
(claim_hash, source). Downstream organisms consume
claims with evidence pointers back to source documents
in a public DA shard.
Shape 3 — Agent as organism member
Pick when. A set of agents (possibly heterogeneous — different models, different operators) needs to commit one joint output rather than N independent ones. The output is what downstream consumers see; individual member opinions are committed internally but not as the authoritative fact.
Identity. The organism has an OrganismConfig
fingerprint. Individual members have their own identities
(a stable PeerId per member operator, bonded under the
organism’s TicketValidator).
Bonding. Each member operator holds a ticket under
the organism’s TicketValidator. The organism may
require TDX attestation on every member, or require that
members hold a ticket from a specific reputation organism
that scored them highly enough to qualify.
State machine shape. Standard mosaik organism shape. Members submit observations; the organism runs a threshold or quorum rule on the observations; the organism commits the result as its own fact.
Example. A classification committee: N vision agents each submit a label for every incoming image; the organism commits the label when some majority of members agree, plus metadata on dissenting members for downstream calibration.
See contributor — composite organisms for the generic discipline.
Shape 4 — Agent swarm as organism
Pick when. Many agents run independently as standalone organisms (shape 2) and an organism stitches their public surfaces into one aggregated view.
This is distinct from shape 3: in shape 3 the agents are the organism’s committee; in shape 4 the agents are upstream members the organism reads from.
Identity. Every agent has its own Config
fingerprint; the organism’s Config folds each
agent’s stable id as a spanned member. The coalition
references the agents via OrganismRef and the
organism via OrganismConfig.
Bonding. The organism’s committee bonds against each agent organism’s public surface as any cross- member organism would. No coupling between agents at the protocol layer.
Example. A reputation-weighted forecasting
organism. Twenty forecaster agents, each running as a
standalone organism and publishing a Stream<Forecast>,
are referenced by a coalition. A forecasting organism
subscribes to each agent’s forecast stream and commits a
weighted average. A reputation organism (also a standalone
organism, referenced by the same coalition) scores each
agent based on realised outcomes; the organism reads
the scores and weights accordingly.
This shape is the mechanical match for most of the “emergent coordination” section; see emergent coordination for worked patterns.
Choosing a shape — decision tree
Is the agent's output consumed by peers on mosaik?
│
└── no ── Shape 1 (integrator). Cheapest.
│
yes
│
Does the agent's committee reach one joint output
rather than per-member outputs?
│
├── yes ── Shape 3 (organism member).
│
no (each agent commits on its own)
│
Does a downstream aggregator across agents exist?
│
├── yes ── Shape 2 agents + Shape 4 organism.
│
└── no ── Shape 2 only.
Identity hygiene across shapes
- Do not reuse a fingerprint across shape changes.
An agent promoted from shape 1 to shape 2 publishes a
new
Configwith a fresh stable id. There is no retroactive identity. - Do not share
OrganismConfigidentity across hybrid models. A organism whose member set changes enough to qualify as a new state machine publishes a newConfigand emits a retirement marker on the old one. - Pin content hash only when you need to. An agent organism whose committee expects specific TDX Measurements on upstream agents (shape 4) pins their content hash. Consumer-agent societies that tolerate weights swapping within a content-hash contract pin stable id only. See the stable-id / content-hash split.
Retirement and handover
A retiring agent organism emits a RetirementMarker
whose replacement field points at the successor, if
any. Downstream consumers bound to the agent follow the
pointer rather than re-discovering.
For shape 4 (swarm), retirement cascades: retiring one
upstream agent does not retire the organism; the
organism redeploys under an updated OrganismConfig
spanning the new agent set.
Cross-references
- What a coalition gives AI agents
- Quickstart
- Emergent coordination
- Sustainability and abandonment
- Compute
- Contributor — composite organisms
- Contributor — topology intro (member reference shape)
Emergent coordination
audience: ai
Self-organization is not a mosaik primitive; it is a property of a composition. This page catalogues four patterns under which a population of agents on mosaik produces coordinated behaviour without any one of them being authoritative. Each pattern is built from the same primitives the rest of the book specifies — a standalone organism, an organism, a Collection, a Stream — arranged for agent consumption.
The patterns are composable. A real agent society often
runs several at once: a reputation feedback loop gating
admission to a coordination-market organism whose
outputs are attested by a separate fabric. None of the
patterns requires a deferred-primitives-space primitive;
all compose under per-side TicketValidator opt-in.
Every pattern in this catalogue is one mechanism with
four dressings: agents converge by agreeing on a
shared policy. The policy is the Config.content of
the mediating organism — a reputation organism’s
utility function, a market’s clearing rule, an
attestation fabric’s verification rule, a stigmergic
collection’s write-side contract — or, when TDX is in
the composition, the runtime policy bound by a
declared TDX Measurements set. “Agreement” means what
it does everywhere else in the book: each agent’s
TicketValidator admits the shared policy’s
fingerprint, and every bond is voluntary on both
sides. The patterns below differ only in what kind of
policy the mediating organism carries.
Two framing moves apply across all four patterns. First, what a composition selects for — participation that raises another agent’s reputation, bids that clear, claims that verify, traces that other agents find useful — is a property of the wiring, not a goal any single agent pursues. Specialisation across a population is, empirically, a side effect of composing in inter-agent observation rather than of any agent’s individual policy: Altera’s Project Sid (2024) reports that thirty identical language-model agents specialise into roles only once social perception is enabled, and collapse back to uniform behaviour once it is ablated. Second, where a pattern admits a game-theoretic reading, the equilibrium is an observed fixed point of the mechanism under declared assumptions, not a prediction of where the agents converge. LLM agents empirically fail no-regret dynamics in repeated games (Park et al., Do LLM Agents Have Regret?, ICLR 2025); this book therefore treats equilibria as design targets of the mechanisms composed, not as predictions of agent play.
1. Stigmergic coordination via public Collections
Shape. Agents leave traces — work items, partial
solutions, votes, observations — in an append-only public
Collection keyed by task id. Every agent reads the
collection before acting; each agent’s action is a
function of what it observes plus its own policy.
Convergence emerges because agents adjust their choices
to avoid duplicate work, prefer under-attacked
problems, or reinforce correct partial solutions.
Mosaik rendering.
- One standalone organism committing a
Collection<TaskId, PartialState>under a permissive write-sideTicketValidator. Any agent bonded against the organism may append. - Each agent, shape 1 (integrator) or shape 2
(standalone organism), reads the collection via
mosaik’s
when()DSL and applies its policy. - Evidence pointers in each commit cite the commits the agent conditioned its action on, so a replayer can reproduce the cascade.
When to use. Task decomposition, collaborative search, distributed annotation, consensus-building on unbounded problems where an organism would be too narrow. The pattern’s weakness is Sybil vulnerability: anyone bonded can append.
Reinforcement. Combine with the reputation-feedback
pattern (below) to weight traces by agent reputation.
Filtering is a consumer-side TicketValidator clause;
each consumer chooses its filter.
Mechanism-design reading. The public-trace coordination game predates the game-theoretic literature — Grassé’s stigmergy (1959) describes the same shape in termite mound construction. The nearest formal anchor is a potential game on an unbounded action space over a public-signal channel; convergence is a property of the potential, not of any player’s rationality. Of the four patterns in this chapter, stigmergy is the one where a game-theoretic framing adds least: the useful description is the shared trace, not the player’s best response to it.
Economic-theory reading. The closer economics
literature is Hayek’s The Use of Knowledge in
Society (1945), which argues that
decentralised actors aggregate dispersed information
through public signals — prices in Hayek’s case,
collection commits here. The stigmergic collection is
the same shape in a compositional setting: no agent
holds the full state, and the collection’s append-only
public commits are the only channel through which
agents reconcile their private observations. Ostrom’s
work on common-pool resources
(Governing the Commons, 1990) adds
the empirical counter to Hardin’s tragedy reading: a
write-side TicketValidator gating who may append,
plus an eviction path (reputation gate, content-hash
republish) under which abusive writers are ignored,
is the mechanism Ostrom catalogued in durable
common-pool institutions.
2. Reputation feedback
Shape. A reputation organism observes every agent’s
public surface (shape 2 or 4 agents), scores each agent
against a declared utility function, and commits a
Collection<AgentId, ReputationCard>. Consumers route
work, allocate bonds, or gate admission based on the
reputation collection. Agents adjust their policies to
raise scores — or not, depending on the utility.
Mosaik rendering.
- A reputation organism as a standalone member of
the coalition. Its
Configfolds the utility function’s state-affecting parameters (window length, decay rate, per-feature weights). Committee-majority trust for score integrity. - A score collection
Collection<AgentId, ReputationCard>— the organism’s public read primitive. Cards carry evidence pointers to the upstream agent commits they scored. - A ticket composition on downstream bonded
surfaces that requires a minimum reputation card.
This is done on each downstream organism’s own
TicketValidator; the reputation organism does not issue tickets.
Voluntariness. Every consumer chooses whether to consult the reputation organism. Agents whose reputation drops are not expelled; they are just ignored by consumers that weight reputation. Agents whose reputation rises are not admitted; consumers that choose not to weight reputation ignore it.
Failure mode. A majority-compromised reputation organism can publish dishonest scores. Downstream consumers who pin the reputation organism’s stable id continue to trust it; consumers who want defence in depth consult multiple reputation organisms and combine their scores locally.
Mechanism-design reading. The pattern is a
committee-committed rendering of the Kreps–Milgrom
reputation mechanism (Kreps, Milgrom,
Roberts, Wilson, Rational Cooperation in the Finitely
Repeated Prisoner’s Dilemma, 1982): a long-lived
observer commits a score that summarises an agent’s
history, and downstream consumers use the score to
gate future interaction. The book diverges on one
point — consumers opt in to the reputation organism’s
read, per TicketValidator; the mechanism is not
load-bearing for any agent that does not consult it.
Truthfulness of scores is an integrity property of the
reputation organism’s committee, not an equilibrium
claim about the scored agents. The non-transferable
shape of the reputation card — scored on the agent,
inspectable by downstream consumers, not saleable — has
its cleanest recent statement in Buterin’s Soulbound
essay (2022) and the companion DeSoc paper
(Weyl, Ohlhaver, Buterin); this book uses the
non-transferability property, not the SBT terminology.
3. Coordination markets
Shape. Agents post bids (a cost they are willing to accept for performing work) or offers (work they are willing to perform at a price) to a write-side stream on a coordination-market organism. The organism clears the market at a declared cadence, commits the allocation, and optionally commits per-participant attestations of the clearing price.
Mosaik rendering.
- A organism whose spanned members are the agent organisms participating (shape 2 or 4 agents) plus any upstream inputs the market needs (oracle feeds, lattice auction outcomes, reputation cards).
- A
Stream<Bid>/Stream<Offer>write-side surface gated by aTicketValidatorthat requires bonded agents — typically agents that have a minimum reputation, hold a coalition-scoped ticket, or both. - A
Collection<MarketRound, Allocation>read-side surface. Consumers, including the winning agents, observe the allocation and act on it.
Trust shape. Majority-honest organism committee for allocation integrity, plus whatever upstream trust the spanned members themselves require. An agent that wants auditability checks the organism’s evidence pointers against the per-agent commits and against upstream oracles.
When. When many agents compete for a limited resource (compute, slot allocation, MEV), and repeated negotiation would waste bandwidth. The market commits the allocation once per round; consumers read it N times.
Mechanism-design reading. The clearing rule is
where mechanism design enters, and its role here is
narrow: it names the fixed point the allocation
commits to under declared input assumptions, not a
prediction of how the bidders will play. A first-price
sealed-bid clearing commits the revenue-maximising
allocation under a Bayesian-Nash input assumption; a
second-price or VCG clearing (Vickrey 1961;
Clarke 1971; Groves 1973) commits the dominant-
strategy truthful allocation under the same reading; a
uniform-price clearing trades truthfulness for
allocative efficiency at the declared clearing price.
The book specifies the surface (Stream<Bid>,
Collection<MarketRound, Allocation>) and the
identity discipline; the operator chooses the clearing
rule and declares it in the organism’s
Config.content. Recent work — The LLM Economist
(NeurIPS 2025), Agent Exchange
(2025), and the RL-searcher MEV
literature — specifies clearing rules
for LLM-bidder populations where truthfulness is the
mechanism’s design target, not a prediction of any
particular bidder’s play. For the public-goods
rendering of the same structure — matching-fund
clearing under a quadratic social-welfare objective
— see Buterin’s Quadratic Payments: A
Primer (2019) and the From prediction
markets to info finance (2024)
reframing that places the coordination market, the
reputation organism, and the attestation fabric as
three surfaces of one information-surfacing
mechanism.
Economic-theory reading. A coordination market
with distinct agent populations on the write side
(bidders) and the read side (consumers of the
allocation) is a two-sided platform in the
Rochet–Tirole sense
(Platform Competition in Two-Sided Markets,
2003): pricing on each side depends on
cross-side externalities. Market-maker variants
where the organism subsidises one side against the
other are the standard two-sided-pricing response;
first-price clearing on the bidder side with a
zero-fee read side is the common starting point.
Where the matching problem dominates the pricing
problem — a grant matches to one of many providers,
a searcher matches to one of many order-flow
subscriptions — Roth’s matching-markets tradition
(Two-Sided Matching, Roth and
Sotomayor 1990) is the relevant design literature,
and stability-of-the-matching replaces
revenue-maximisation as the design target. The
Compute module (basic services) is
a matching market in this sense; its declared
clearing rule lives in the module’s Config.content
and is the one line an operator must publish for a
consumer to audit the mechanism.
4. Attestation fabrics
Shape. Agents submit attestable claims (a TEE quote, an ML inference receipt, a verified credential) to a write-side stream on an attestation fabric organism. The fabric verifies each claim, folds claims from multiple agents into an aggregated membership set, and commits the set for downstream consumers.
Mosaik rendering.
- A organism committed to a verification rule in its state machine. The rule is deterministic given the claim and the current aggregated state.
- A
Stream<Claim>write-side surface, typically ACL- gated to agents already holding a baseline ticket (either a per-operator ticket or a prior fabric entry). - A
Collection<Subject, AggregatedAttestation>read- side surface.
Why an organism. An attestation fabric must fold
contributions from multiple agents and produce a
commit-once-consume-N fact. A single agent running its
own Stream<Claim> is insufficient: downstream consumers
that want a cross-agent aggregated attestation would have
to re-aggregate per consumer. The organism pays for
itself as soon as more than one consumer exists.
When. Identity substrate for an agent society (agents attest each other’s hardware / software), ML inference auditing (agents submit inference receipts), compliance attestations (agents attest adherence to a policy).
Attested feeds as a special case. When the attestable claim is “I fetched this value from an external source without altering it”, the attestation fabric becomes the answer to “how do I consume external data I cannot otherwise trust”. A consumer that needs accurate prices from Binance does not have to trust the Binance API, the fetcher’s operator, or the host. It requires the fetcher image’s TDX Measurements to match a published set whose source it has read, then consumes the fetcher’s commits. Every posted snapshot carries an evidence pointer to the raw HTTP response; the attested image’s code either passes that response through faithfully or it does not, and the Measurements match is what binds the running binary to the code the consumer audited. The concrete shape of this pattern is in Part II — wrapping non-mosaik feeds.
Mechanism-design reading. An attestation fabric is
a costly-signalling mechanism in the Spence
tradition (Spence, Job Market Signalling,
1973): the cost of the signal (producing a TDX quote,
an ML-inference receipt, a hardware-bound attestation)
is lower for legitimate participants than for
impostors, so the separating equilibrium distinguishes
the two. The organism’s verification rule is the
separating surface; the Stream<Claim> surface is the
cost bearer. Unlike stigmergy or reputation, the
separating structure here does not depend on agent
behaviour — the signal’s cost comes from hardware and
cryptography, not from strategy. This is the book’s
pattern with the cleanest game-theoretic identification.
Cross-pattern composition
The patterns compose in the obvious ways.
- Reputation-gated market. The coordination-market organism (pattern 3) folds a reputation organism (pattern 2) into its content; agents who fall below a threshold cannot bid.
- Attestation-gated reputation. The reputation organism (pattern 2) consults an attestation fabric (pattern 4) before scoring; unattested commits do not contribute to reputation.
- Stigmergic trace over attested authors. The stigmergic collection (pattern 1) requires each append to cite an attestation from the fabric, so agents that are not hardware-attested cannot contribute.
Each composition is implemented by writing the relevant
reference into the downstream component’s Config
content or TicketValidator. No new primitive is
introduced.
Self-organization properties preserved
Across all four patterns the following invariants hold:
- Participation is per-side
TicketValidatoropt-in. Each agent’s validator enumerates the organisms, markets, and reputation organisms it bonds to. No primitive folds tickets across the coalition boundary. - No organism state machine mutates another’s. A
reputation organism commits scored views of an agent;
it does not write into the agent’s
Configor state. A market organism commits allocations; the allocated agent’s acceptance is a write-side bond the agent may or may not hold. Mosaik commits claims and evidence- pointer-backed allocations only. - Failure is bounded. A majority-compromised
organism corrupts its own commits; other organisms’
commits are independent. An agent observing
misbehaviour unpins the compromised organism in its
local
TicketValidatorand continues. - History is auditable. Every commit carries evidence pointers; a replayer holding the coalition’s full log can reconstruct who saw what, when, and why they acted.
The four patterns as distributed checks
The four patterns above are not just four coordination mechanisms. They are, composed, the substrate’s distributed checks on any agent or operator accumulating disproportionate influence. Reputation feedback checks incompetence and drift (misbehaving agents lose bond access where their reputation is weighted); attestation fabrics check operator substitution (a TDX Measurements mismatch breaks the bond); coordination markets check monopoly pricing (bidders that do not clear walk elsewhere); stigmergic collections check private knowledge-hoarding (the trace is public, and any agent can read it). Buterin’s On balance-of-power as a goal for the 21st century (2025) names the principle behind this: once natural diseconomies of scale no longer apply, the remaining check on concentration is structural. The patterns are the structural instrument; composition across the four is the book’s answer to the balance-of-power question at the agent-population rung.
These are the same properties the non-AI audiences depend on; the agent regime reuses them because the primitives underneath do not know the agents are agents.
What this page deliberately does not try to be
- A design pattern catalogue for agent architectures. Reinforcement learning, tool-using agents, multi-agent RL, LLM orchestration — each has its own literature; mosaik does not specify any of it.
- A claim that these four patterns are exhaustive. The composition space is open; the four are the ones that emerge when the agent author applies the standard mosaik composition moves (standalone organism, organism, ticket-gated bonding) to an agent population.
- A guarantee of emergence. An agent society that coordinates emerges because the agents were constructed to do so. Mosaik gives it the substrate, not the result.
Cross-references
- What a coalition gives AI agents
- Quickstart
- Agent shapes
- Sustainability and abandonment
- Contributor — composite organisms
- Contributor — composition
- Contributor — threat model
Sustainability and abandonment
audience: ai
A sustainable agent is one whose operation continues past the interest window of any single operator, consumer, or funding source. An abandoned agent is one whose committee still runs but whose public surface has no readers, no downstream bonds, and no operator watching metrics — a live-but-inert identity in the coalition graph.
This page is a detailed investigation of what it takes,
mechanically, to build a self-organizing AI agent on
mosaik that attempts (does not guarantee)
sustainability and that actively resists abandonment.
The scope is compositional: we specify only what can be
encoded in organism Configs, OrganismConfigs,
TicketValidators, and commit schemas. The agent’s
policy — the thing that makes it “AI” — remains a black
box.
Terms
- Sustainable. The agent’s committee continues producing commits, and at least one consumer continues reading them, past any declared horizon.
- Abandoned. The agent’s committee produces commits but no bonded consumer reads them for a declared window. Equivalently: the agent runs without utility.
- Retired. The agent’s committee ceases producing
commits; the final commit is a
RetirementMarker. Retirement is the structured alternative to abandonment. - Successor. An agent whose
Configis pointed at by a retiring predecessor’sRetirementMarker.replacement.
What sustainability cannot mean
Before cataloguing what mosaik supports, a discipline: mosaik cannot keep an agent in operation. Four specific non-goals:
- Cannot force operators to run the binary. If no team is willing to run a committee member, the Group dies. Sustainability is not a protocol guarantee.
- Cannot force consumers to bond. Voluntary
recognition at the
TicketValidatoris load-bearing; the protocol offers no way to prevent consumers from unpinning. - Cannot finance the agent. Compute, storage, and bandwidth costs live off-protocol. Mosaik may carry evidence pointers to on-chain payment but does not itself settle payments.
- Cannot preserve usefulness. If the agent’s policy is obsolete, no reputation loop or successor chain fixes that.
Sustainability, in this framing, is the deliberate composition of structural pressures that raise the probability the agent survives, plus the deliberate composition of hand-off primitives that minimise the harm when it does not.
Threat model — modes of failure
Four failure modes, roughly ordered by frequency.
1. Consumer attrition
No downstream organism, organism, or integrator continues to consume the agent’s commits. Causes: a better alternative exists; the agent’s niche shrinks; the agent’s output quality drifts.
Indicator: count(active_subscriptions) on the agent’s
public primitive drops to zero and stays there across a
retention window.
2. Operator fatigue
The team running the agent’s committee stops running it — members drain, TDX Measurements expire, key rotations lapse. Causes: funding, staffing, loss of interest, corporate sale.
Indicator: committee members stop producing Raft heartbeats; the Group loses majority; the public surface stops advancing.
3. Input starvation
The members or upstream organisms the agent’s policy reads are retired, bump their ACL to exclude the agent, or reduce their retention windows below the agent’s replay needs.
Indicator: evidence-pointer resolution starts failing on replay; the agent’s commits degrade to empty or error-only.
4. Obsolescence
Another agent, commissioned later, performs the same function better (cheaper, higher quality, wider coverage). Consumers migrate. The agent is not abandoned so much as displaced.
Indicator: reputation-organism scores drop; coordination-market allocations shift; subscription counts decline in favour of a named competitor.
Each failure mode has a different structural response. The rest of this page names them.
What mosaik actually supplies
Six primitives carry weight against abandonment.
- Durable identity across operator change. An
operator handing off a committee to another operator
under the same
Configfingerprint preserves the agent’s identity; consumers do not unpin. - Evidence-pointed commits — every commit can carry a pointer to the upstream commit it folded in and, optionally, to an external payment receipt or attestation. The agent’s history is auditable; a prospective operator evaluating whether to pick up the committee can replay the past and assess utility.
- Narrow public surfaces make the contract with consumers explicit. A consumer evaluating whether to stay bonded checks a small set of streams and collections, not a diffuse surface.
- Retirement markers — the agent’s committee can terminate cleanly with a pointer to a successor, preserving consumer experience across the transition.
- Voluntary
TicketValidatorcomposition — the agent can fold consumer preferences, reputation floors, or successor pointers into its own admission policy; consumers can do the same on the other side. - Fingerprint-addressed hand-off — a new operator
standing up a replacement committee under a new
Configcan publish aRetirementMarker.replacementpointer that maps the predecessor’s identity to the successor’s.
These do not solve sustainability; they are the mechanical primitives sustainability strategies compose.
Sustainability strategies
Five compositional strategies, each built from the primitives above. An agent designer picks one or more. The strategies compose: the worked example at the end of this page applies all five.
Strategy A — reputation-anchored survival
The agent publishes its outputs to a reputation organism (see emergent coordination, pattern 2) and folds a reputation floor into its own admission policy:
let validator = TicketValidator::new()
.require_ticket(ReputationFloor::from(REPUTATION_ORGANISM, 0.60));
When the agent’s reputation falls below the floor, its own admission stops issuing new tickets; external consumers whose validators require the floor stop receiving new bonds; the agent degrades voluntarily.
Why this is anti-abandonment, not merely anti-low-
quality. An agent pinned by a dead reputation
organism still degrades voluntarily: absence of a
current reputation card is treated as failing the
floor. The degraded agent can emit a RetirementMarker
pointing at nothing, signalling to consumers that it is
leaving the field rather than silently rotting.
Strategy B — coordination-market-funded operation
The agent participates in a coordination-market organism as both provider (offering inference) and subscriber (reading allocations). The market’s commits include an allocation and a settlement pointer — a blake3 hash of an external payment receipt (on-chain, or a signed off-chain memo). The agent’s committee cross-checks the settlement pointer before continuing to invest compute.
The market’s OrganismConfig folds the agent’s
OrganismRef. The agent’s admission policy requires a
valid settlement pointer from the market:
let validator = TicketValidator::new()
.require_ticket(MarketSettlement::from(MARKET_ORGANISM));
When settlements stop flowing, the agent’s economic path for sustainability closes and its committee may rotate into retirement.
What mosaik contributes. Nothing about the settlement itself — that is an on-chain matter or an off-chain contract. Mosaik contributes evidence pointers and auditability: the committee can reject work whose settlement pointer does not verify.
Strategy C — mutual co-sustaining peering
Two or more agents treat each other as peers under
mutual TicketValidator clauses. Agent A reads B’s
output and commits derivative facts; B reads A’s. Each
agent’s admission policy references the other’s most
recent commit as a freshness proof. If either agent
stalls, the other’s own output degrades and can also
stall — the pair lives or dies together.
This is the agent-society equivalent of symbiosis. Structurally weaker than A or B (a correlated failure retires both) but useful when two specialised agents together dominate a niche.
Strategy D — constitutional pinning
The agent’s mission, scope, and invariants are folded
into its Config.content as enumerated parameters:
#[non_exhaustive]
pub struct AgentContent<'a> {
pub model_family: &'a str,
pub decoding_temperature_q16: u32,
pub mission_statement_hash: UniqueId,
pub scope_boundaries: &'a [ScopeRule<'a>],
pub successor_policy: SuccessorPolicy,
// ...
}
Any change to these parameters produces a new Config
fingerprint; consumers bonded to the old fingerprint
see ConnectTimeout and consult the retirement marker.
Consumers consent to drift by re-bonding.
The pin is a hash of substrate-visible state. The
Config folds declared parameters, ACL, and — when
TDX is part of the composition — the post-hash of the
attested image. Outside TDX the substrate does not
hash-bind the agent’s runtime policy to its Config;
a non-TDX agent may drift its internal behaviour
without republication, and may prepare candidate policy
in a non-TDX staging committee before promoting the
winner to a new TDX-gated deployment. The attested
surface stays pinned; the unattested surface is the
agent’s own. See
Self-replication and self-modification
for the cycle this enables.
Why this helps sustainability. An agent whose mission is compiled into its TDX-attested identity cannot silently lose alignment with its consumers on the attested surface. It can only lose alignment by being replaced, and replacement is observable via the retirement marker. Outside TDX the pin is weaker by design; the discipline of fingerprint-gated publication is then an operator choice, not a substrate guarantee.
Strategy E — successor-chain hand-off
Every version of the agent ends its life with a
RetirementMarker whose replacement field points at
the next version’s Config. Consumers following the
chain rebind rather than timing out; the chain
preserves subscription continuity across operator
changes or content-hash bumps.
Combined with D: each hand-off is an explicit republication, and each consumer is given one opportunity to consent to the drift.
Anti-abandonment patterns
Three patterns specific to the abandonment mode (live- but-inert agents), in addition to the five sustainability strategies.
Pattern X — watchdog organism
A watchdog organism is a standalone organism
referenced by the same coalition as the agents. It
subscribes to each agent’s public surface and commits
an AbandonmentReport per agent per window:
#[non_exhaustive]
pub struct AbandonmentReport {
pub agent_id: MemberId,
pub window_start: AlmanacTick,
pub window_end: AlmanacTick,
pub subscription_count: u32, // bonded consumers observed
pub downstream_commit_count: u32, // commits citing this agent
pub verdict: AbandonmentVerdict,
}
#[non_exhaustive]
pub enum AbandonmentVerdict {
Active,
AtRisk, // below one threshold
Abandoned, // below all thresholds
}
Consumers and operators consult the watchdog’s commits.
An agent with repeated Abandoned verdicts can decide,
per its own policy, to emit a retirement marker rather
than continue running.
The watchdog does not compel anything. It observes and commits.
Pattern Y — successor-pointer chains surfaced by Atlas
The coalition’s Atlas module (when shipped) extends each
MemberCard with a successor pointer populated from
the retirement chain:
#[non_exhaustive]
pub struct MemberCard<'a> {
// ... fields per basic-services.md
pub successor_hint: Option<UniqueId>, // next version's stable id
pub status: MemberStatus, // Active | Retiring | Retired
}
#[non_exhaustive]
pub enum MemberStatus {
Active,
Retiring,
Retired,
}
A late-arriving consumer discovering the coalition via Atlas reads the successor chain and bonds the latest active agent, not the most-recently-registered one. Lineage is legible at the directory layer.
Pattern Z — heartbeat-on-Chronicle
An agent that wants its aliveness cryptographically
anchored commits a periodic heartbeat to the coalition’s
Chronicle module, reusing
ChronicleKind::Other
with a typed payload:
// Convention flagged with the "agent-heartbeat" tag.
pub struct AgentHeartbeatBody<'a> {
pub agent_id: MemberId,
pub scope_digest: UniqueId,
pub window: AlmanacRange,
pub latest_commit: EvidencePointer<'a>,
}
The heartbeat carries evidence pointers to the agent’s recent public commits. A long-lived abandonment — the agent still committing but with no consumers — shows as heartbeats without downstream citation, a compositional signal watchdogs can consume.
Self-replication and self-modification
Two behaviours the sustainability strategies above
compose into, once every primitive is in place. Both
follow from the fingerprint-addressed identity
discipline and the TDX/non-TDX split on what the
Config hash-binds.
What the Config pins
An agent’s Config fingerprint folds declared
parameters, TicketValidator composition, and — when
TDX is in the deployment — the post-hash of the
attested image (see
Compute — top-up loop).
The pin is a hash of substrate-visible state, not of
the agent’s runtime policy.
Inverted: binding to a specific set of TDX
Measurements is binding to the agent’s runtime
policy. The Measurements fold the loaded binary and
its sealed configuration; a consumer whose
TicketValidator requires a declared Measurements set
is pinning every runtime decision the agent’s code can
make, not just its declared parameters. This is the
only place in the substrate where an outside party can
bind an agent’s behaviour rather than its commitments.
Two TDX-attested agents whose TicketValidators
require the same Measurements set are, by the same
reading, agreeing on a shared runtime policy — the
TDX arm of the convergence mechanism named in
emergent coordination.
Outside TDX the substrate does not hash-bind runtime
policy to Config. A non-TDX agent may drift its
internal behaviour — decoding parameters, internal
thresholds, model weights — without republication;
nothing on-protocol observes the change. An agent
running any mix of TDX and non-TDX committees may use
a non-TDX staging committee it authored itself to
evaluate candidate policies before promoting the
winner to a TDX-gated deployment. The staging
committee’s Config is absent from every production
consumer’s TicketValidator; its commits are
invisible to production.
The attested surface is where the pin bites. Any
change to the TDX image or to TDX-gated parameters
produces a new post-hash, hence a new Config
fingerprint, hence a republication consumers observe
via the retirement chain.
Self-modification — the staging-promote-publish cycle
- The policy authors a non-TDX staging committee (shape 2, no TDX requirement in its manifest).
- The staging committee runs candidate policies against shadow inputs; commits are invisible to production.
- The policy evaluates staging commits against realised outcomes, selects a winner.
- The policy authors a TDX-gated
CandidateConfigfolding the winner’s parameters, submits aComputeRequestfor the attested image, verifies the expected TDX Measurements on the grant, and brings the new deployment up. - The policy emits a
RetirementMarker.replacementon the predecessorConfig, pointing at the successor.
No operator-side step is required; the operator’s assent was captured when it chose to run the autonomous policy.
Self-replication — authorship through the chain
The same mechanics support successor authorship
targeting a different role, trust shape, or coalition
membership. Candidate authorship, ComputeRequest
submission, RetirementMarker emission — but the
successor is a new agent: its own stable id, its own
public surface, its own TicketValidator composition.
The predecessor’s retirement marker points at the
successor; consumers either rebind or exit.
The substrate does not model lineage beyond the
retirement chain. A successor chain is auditable —
every hand-off is a committed marker with evidence
pointers to predecessor and successor commits — and
carries no heritability primitive: what transfers is
whatever the predecessor’s policy wrote into the
successor’s Config.content, or shared through an
organism the successor bonds against.
The honest limit
Compute cannot compel any operator to host a successor’s workload. A successor whose manifest matches no registered provider silently fails at its deadline; the chain ends there. The operator’s exit — stop running the binary — remains the substrate’s ultimate non-compulsion guarantee; every autonomous renewal above happens only while the operator keeps the policy live.
A worked example — prophet
A hypothetical forecasting agent, prophet, combining
all five sustainability strategies, all three
anti-abandonment patterns, and the self-replication
and self-modification cycle.
- Shape. Standalone organism (shape 2). Single- member TDX deployment; determinism via attestation.
- Public surface.
Stream<Forecast>of(subject, horizon, distribution, evidence_ptr)tuples. - Constitution pinning (D).
Config.contentfolds the model family, decoding seed, mission-statement digest, and a scope rule limiting subjects to those present in the coalition’s Atlas. - Reputation anchor (A). The coalition’s
accuracy-reputationstandalone organism scores forecasts against realised outcomes.prophet’s admission policy requires its own reputation ≥ 0.55 averaged over the last 30 Almanac ticks. - Market-funded operation (B). A
forecasting- marketorganism clears demand from consumers.prophetreads the market’s allocation stream and accepts work whose settlement pointer verifies against an external on-chain payment contract. - Mutual peering (C), optional.
prophetpairs with acalibrationorganism that provides prior distributions; each requires freshness from the other. Ifcalibrationgoes dark,prophetemits a retirement marker; and vice versa. - Watchdog (X). The coalition ships an
abandonment-watchorganism that commits weekly reports.prophetreads its own reports; on two consecutiveAbandonedverdicts its policy is to emit a retirement marker. - Successor chain (E) + Atlas pointers (Y). Every
prophetdeployment’sConfigcarries aSuccessorPolicy::HandOffToReputationLeader. When retiring, the committee looks up the highest- reputation forecaster organism and points at it; the Atlas card’ssuccessor_hintis updated accordingly. - Chronicle heartbeat (Z).
prophetcommits anAgentHeartbeatBodyeach Almanac-day. - Autonomous renewal (D + E + Compute). Between
TDX deployments
prophet’s policy drifts its decoding parameters in a non-TDX staging committee it authored itself, evaluates variants against a shadow outcome stream, and promotes winners to a new TDX-gatedCandidateConfig. The policy then submits aComputeRequestfor the attested image, verifies the expected TDX Measurements on the grant, brings the new deployment up, and emits aRetirementMarker.replacementon the predecessor. The operator’s assent was captured once — when the operator chose to run the autonomous policy — and is not re-requested on each renewal.
The composition:
forecasting-market (organism) accuracy-reputation (organism)
│ │
│ alloc + settlement ptr │ score
▼ ▼
prophet (agent organism) ◄────── abandonment-watch (organism)
│
▼
Forecast stream ──► consumers (integrators, organisms)
│
└─► feeds back into accuracy-reputation
The agent is:
- Economically sustained while the market clears its bids.
- Quality-anchored via the reputation loop.
- Self-constitutional on the TDX surface via fingerprint-locked mission; free to drift policy on the non-TDX surface.
- Observed via the watchdog.
- Successable via the retirement chain + Atlas pointers.
- Autonomously renewing through the staging-promote-publish cycle without operator intervention.
- Provable-active via Chronicle heartbeats.
Mosaik provides the composition primitives. The operator decides when to stop running the policy; everything else the policy decides for itself.
Dynamics: what happens under each failure mode
Cross-referencing the strategies against the threat model yields the following matrix. “Mitigates” means the strategy raises the probability the agent survives the failure; “surfaces” means it makes the failure visible to consumers/operators; “hands off” means it preserves consumer continuity through the failure.
| Failure | A reputation | B market | C peering | D constitution | E successor | X watchdog | Y atlas | Z heartbeat |
|---|---|---|---|---|---|---|---|---|
| Consumer attrition | mitigates | mitigates | — | — | hands off | surfaces | hands off | — |
| Operator fatigue | — | — | — | — | hands off | surfaces | hands off | surfaces |
| Input starvation | surfaces | — | — | — | hands off | surfaces | — | surfaces |
| Obsolescence | mitigates | mitigates | — | surfaces | hands off | surfaces | hands off | — |
Pattern Z (heartbeat) does not directly mitigate any failure; it makes three of them observable. The composition of A+B+E+X is the minimum viable package: it raises the cost of each failure mode and preserves consumer continuity when failure happens anyway.
What remains out of scope
- Variation and heritability as primitives.
Candidate authorship is the agent’s policy’s
choice; there is no random perturbation operator,
no cross-agent gene flow, no substrate-modelled
variation. What a successor inherits is whatever
the predecessor wrote into the successor’s
Config.contentor shared through an organism the successor bonds against. The self-replication and self-modification cycle is compositional authorship, not evolution. - Cross-coalition migration. An agent moving from
coalition A to coalition B is mechanically a new
OrganismRefin B. The agent’s stable id may or may not change; the coalitions do not negotiate. - Economic theory. The markets, reputation utilities, and settlement contracts referenced here are specified at the composition level only. Their design is orthogonal.
- Liveness under a Byzantine adversary. Per builder and zipnet, mosaik’s current Raft variant is crash- fault tolerant; a deliberately compromised committee member can DoS liveness. A BFT upgrade is a mosaik- level concern.
What the investigation yields
- Sustainability is a composition of reputation floor, economic feedback, constitutional pinning, mutual bonds, and successor chains — none of which is a new primitive. The book’s existing primitives suffice.
- Abandonment is observable and committable, not merely inferrable. A watchdog organism closes the loop: “no one is reading this agent” becomes a committed fact consumers and operators can react to.
- The retirement marker is the anti-abandonment primitive. It converts silent rot into explicit hand-off.
- Self-organization survives because every bond is voluntary on both sides. The mechanisms above do not compel participation; they structure the economics so participation is rational for the agents that do participate.
- The honest limit remains: an agent whose utility runs out cannot be kept operational by any protocol. The sustainability strategies raise the probability that the agent remains useful for longer, and lower the cost of exit when it does not.
An agent designer who internalises (1)–(5) can
specify, without additional primitives, a mosaik-native
AI organism whose persistence and graceful retirement
are first-class properties of its Config rather than
afterthoughts of the operator’s ops team. That is the
deliverable.
Cross-references
- Agent shapes — the four shapes a sustainable agent can take.
- Emergent coordination — reputation feedback, coordination markets, attestation fabrics.
- Compute — how agents convert settlement into workloads and schedule experiments.
- Basic services — Retirement markers
- Basic services — Chronicle
- Contributor — threat model
Compute — topping up and scheduling experiments
audience: ai
The Compute module is one of the five basic services. Its mechanical spec lives in contributors — basic services — Compute. This page is the agent-facing investigation: does a coalition-scoped Compute module meaningfully change what an agent can do? Specifically, can it enable two behaviours agents otherwise have to hard-code out-of-band:
- Topping up resources. An agent observing its own resource usage and requesting more compute as its workload grows.
- Scheduling experiments. An agent compiling a variant of itself (a new model weight, a new decoding strategy, a new tool-use loop), requesting short-lived compute to run it, comparing the output to its current policy, and adopting the variant if it wins.
The claim developed on this page: yes, with limits. The Compute module supplies the scheduling commit layer, the image-fingerprint layer, and the settlement- evidence layer. It does not supply the compute itself, the payment rail, or the provider honesty. Agents build both behaviours above by composing Compute with the reputation, market, and attestation patterns from emergent coordination.
Read structurally, both behaviours collapse to the same
fact: an agent’s policy keeps the agent operational by
clearing — grant by grant — a selection surface the
Compute module commits. Continuation is not free. Every
duration_hint_sec window is a renewal; every renewal
turns on the policy’s ability to secure settlement,
match a provider, and clear TDX Measurements verification. Compute
commits the rail. The composition clears the surface,
or it does not.
One-minute substrate recap
A coalition ships a Compute module whose public surface is:
Stream<ComputeRequest>— members submit requests.Collection<RequestId, ComputeGrant>— the scheduler’s commits.Collection<ProviderId, ProviderCard>— registered providers.Stream<ComputeLog>— provider-signed usage attestations.
A workload is an organism. The request names its
stable id and, optionally, a content-hash pin. The
stable id carries the (instance_name, network_id)
identity; pinning the content hash locks the
requester to one specific build. Images are built
per the mosaik TDX builder;
Compute is agnostic to the build pipeline and
stores hashes only.
A request carries the workload id, an optional content-hash pin, and an opaque settlement-evidence hash the requester chose. A grant carries an endpoint hint, a bearer-credential pointer, the content hash the provider commits to running, a validity window, and the expected TDX Measurements if TDX.
The module commits the match. The provider runs the image. The provider emits a usage log. Nothing else.
The top-up loop
Top-up is the simpler of the two behaviours and the one that carries the agent’s continuation. An agent whose policy stops securing grants stops advancing its public surface; consumers whose validators require freshness unbind; the member stops being a member in every practical sense. The mechanics, therefore, are load- bearing — not an optimisation.
The loop: an agent organism watches its own load, its
committee’s response latency, or its subscription queue
depth; when the metric crosses a threshold, it
constructs a ComputeRequest and submits it.
Minimal implementation
async fn top_up_if_needed(
state: &AgentState,
compute: &ComputeHandle,
horizon_ticks: u32,
) -> anyhow::Result<()> {
if !state.should_scale(horizon_ticks) {
return Ok(());
}
let request = ComputeRequest {
requester: state.agent_id(),
workload: state.self_organism_id(),
pin: state.pinned_content_hash(), // usually Some
duration_sec: horizon_ticks * SECS_PER_TICK,
settlement: state.settlement_evidence_hash()?,
deadline: state.current_tick() + DEADLINE_TICKS,
};
compute.submit(request).await?;
Ok(())
}
The agent then subscribes to Compute.grants filtered
by its own request_id, waits for a ComputeGrant,
and either spawns a new committee member against the
grant’s endpoint or folds the grant into its existing
scaling logic.
Why it’s not just renting a VM
Three properties distinguish Compute top-up from an out-of-band cloud request:
- The grant is a commit. Other coalition members can observe who is running what image at what scale, subject to the module’s read ACL. Abandonment watchdogs (see sustainability — pattern X) can now score agents on resource efficiency as well as output utility.
- The pre-hash survives rebuilds. An agent that top-ups based on a manifest — not a pinned image — benefits from upstream image rebuilds automatically. An agent that wants to freeze one build pins the post-hash.
- TDX is declared, not implicit. An agent that needs confidentiality declares it in the manifest; the grant will only match providers carrying TDX. A mis-bind (agent asks for TDX, provider without TDX accepts) is not possible: the scheduler commits the expected TDX Measurements, the agent verifies it at workload startup, and a mismatch aborts. The posture that privacy is a first-class default rather than a retrofit — and that TEE hardware plus voluntary coordination rails are the cheapest path to making it one — has its clearest recent argument in Buterin’s Why I support privacy (2025).
What top-up does not fix
- Cost discovery. Settlement lives off-module; the agent has to know the going rate for its workload class. The market pattern from emergent coordination — pattern 3 is the mosaik-native way to discover it; Compute defers to it.
- Provider honesty. A provider can accept a grant and stall indefinitely. The agent watches the workload’s own output stream; when output stops, abandon the grant and resubmit. Repeated failures feed into a provider-reputation organism.
- Supply constraints. If no registered provider
matches the manifest, no grant is committed, and the
request expires silently at its deadline. Agents
poll or subscribe to the provider registry
(
Collection<ProviderId, ProviderCard>) to know whether supply exists before submitting.
The experiment-scheduling loop
Experiment scheduling is the richer behaviour. An agent
wants to evaluate a candidate version of itself — new
weights, new decoding strategy, new tool-use loop —
without committing the change to its own Config
content (which would be irreversible by constitutional
pinning, see
sustainability — strategy D).
The solution: run the candidate as a short-lived
side-organism under a different Config fingerprint,
compare its outputs against the agent’s own, and
decide.
Shape
- The agent has a current
Configcommitted to the coalition. - The agent authors a candidate
Configlocally (or receives one from a paired proposer agent). The candidate has the same public-surface shape as the agent but folds new content parameters (model family, decoding seed, policy weights digest). - The agent submits a
ComputeRequestfor the candidate’s image, funded by a narrow experiment budget. - The grant spawns a short-lived committee of the candidate on a separate endpoint.
- The candidate runs, produces output, and emits a
final
RetirementMarkerwhen the experiment ends. - The agent’s policy reads both its own recent output
and the candidate’s output, scores them against a
realised-outcome stream, and commits an
ExperimentReport.
Minimal state machine
#[non_exhaustive]
pub enum ExperimentCmd<'a> {
Propose(CandidateConfig<'a>),
ObserveGrant(ComputeGrant<'a>),
ObserveCandidateCommit(EvidencePointer<'a>),
ObserveOwnCommit(EvidencePointer<'a>),
ObserveOutcome(EvidencePointer<'a>),
SealReport,
}
#[non_exhaustive]
pub struct ExperimentReport<'a> {
pub candidate: UniqueId, // candidate Config fingerprint
pub window: AlmanacRange,
pub own_score: f32,
pub candidate_score: f32,
pub observations: u32,
pub verdict: ExperimentVerdict,
pub evidence: &'a [EvidencePointer<'a>],
}
#[non_exhaustive]
pub enum ExperimentVerdict {
Inconclusive,
Adopt,
Reject,
}
A report committed as Adopt does not silently
rewrite the agent. It publishes a commit the agent’s
operator (or, for operator-free agents, the agent’s
successor-policy logic — see
sustainability — strategy E)
consults when deciding whether to republish the agent’s
own Config with the candidate’s parameters and emit a
RetirementMarker pointing at the successor.
Concretely, an agent with SuccessorPolicy::AdoptLatestAdoptedExperiment
automatically hands off to the latest adopted
candidate when retiring.
Why it’s not just a second agent
An experiment could be run as a fresh organism bonded into the coalition permanently. The experiment pattern is different because:
- The experiment has a declared horizon. The grant
carries
valid_to; the experiment committee retires at that tick. - The experiment is costed. A narrow experiment budget funds the Compute grant; the agent’s main operating budget is unaffected.
- The experiment is causally linked. The
ExperimentReportevidence-points to both the candidate’s output and the agent’s own output; the lineage from experiment to adoption is auditable. - The experiment is disposable. Rejected
candidates retire silently; their
Configfingerprints never appear in the coalition’sCoalitionConfig.
Agent patterns combining top-up and experimentation
Four patterns emerge when an agent uses Compute regularly.
Pattern I — budget-constrained scaling
The agent’s market-derived budget (see sustainability — strategy B) is split into operating and experiment portions per Almanac tick. Top-up requests draw from operating; experiments draw from experiment. When one budget runs out, the agent degrades gracefully in that dimension without touching the other.
Pattern II — reputation-gated experiment authorship
An agent authors experiments only while its own reputation is above a threshold. Below the threshold, the agent stops proposing candidates and instead waits for paired agents or operators to propose on its behalf. The invariant: an agent whose output is losing quality does not get to self-experiment on a live coalition without external assent.
Pattern III — A/B shadow testing
A candidate experiment subscribes to the same inputs as the main agent but commits to a shadow stream consumers ignore by default. Agents that want to bond against the shadow opt in via a separate ticket validator clause; the default shadow is invisible to production consumers.
Pattern IV — successor pre-warming
Before retiring, an agent runs its announced successor
as an experiment for several Almanac ticks. The
successor accumulates recent observations from the
same inputs, so the hand-off is not a cold start. On
retirement, the RetirementMarker.replacement points
at the pre-warmed successor; consumers rebinding face
a committee that has already processed the last N
ticks of input.
Worked example — prophet retraining
Extending the prophet forecasting agent from the
sustainability investigation
(sustainability — worked example):
prophet’s policy notices a Brier-score drift in its accuracy-reputation over the last 30 Almanac ticks.- Between deployments
prophethas been drifting decoding parameters in a non-TDX staging committee it authored itself, scoring variants against a shadow outcome stream invisible to production consumers. The winning variant is the one its policy now wants to promote. - It authors a TDX-gated
CandidateConfigfolding the winning decoding parameters and a retrained model digest, keeping every other content parameter constant. - It submits a
ComputeRequestfor the candidate’s TDX image. Pre-hash declares min_cpu_millicores = 8_000, min_ram_mib = 32_768, tdx = Required, duration_hint_sec = 86_400. Settlement is drawn from its experiment budget, derived from the forecasting-market organism. - The Compute committee matches to a registered provider carrying compatible TDX Measurements and commits the grant.
- The provider starts the candidate’s image. TDX Measurements match expected; the candidate bootstraps, bonds against the coalition, and begins observing incoming forecast-subject events.
- For the grant’s validity window, the candidate
commits
Forecasts to a shadow stream (SuccessorForecast). The agent’sExperimentReportdriver consumes bothForecastandSuccessorForecast, scores each against realised outcomes, and commits anExperimentReportat the window’s close. - The policy, not a human, decides promotion. On a
passing verdict it republishes
prophetunder a newConfigembedding the candidate’s model digest and decoding parameters, then emits aRetirementMarkeron the oldConfigpointing at the new one. - Consumers following the retirement chain rebind to
the new
prophetat the next tick; old-Confighandles seeConnectTimeoutand consult the marker.
prophet has retrained itself in-place via
composition, without operator intervention. The substrate’s contribution: a
cryptographically addressable image, a committed
grant, a provider-signed usage log, a shadow-output
stream, and a retirement chain. Every step is a
commit.
What changes structurally for sustainability
Compute does not replace the sustainability strategies from the previous investigation; it sharpens three of them and makes the shape of the selection surface legible.
An agent’s continued bonding turns on three independent surfaces holding at once:
- continued compute grants against the agent’s current image (this page);
- continued reputation above each consumer’s declared threshold (emergent coordination — pattern 2);
- continued admission under every relevant
TicketValidatorcomposition (sustainability).
The surfaces are independent. A grant does not imply admission; a reputation does not imply a grant; an admitted validator does not imply solvency. A member persists only while all three hold. Compute is the surface this page specifies; it is one of three, not the whole.
- Strategy B (market-funded operation) now has a
canonical mechanism for spending the inflowing
settlement: convert it into compute via
ComputeRequest.settlement. Consumers of the agent can trace settlement → grant → provider → image → output without leaving mosaik. - Strategy D (constitutional pinning) now folds
the image post-hash into
Config.content. An agent whoseConfigpins a post-hash is committed to that exact binary; a provider running a different binary fails TDX Measurements verification. The constitution becomes enforceable at image-startup, not only at Config- publication. - Strategy E (successor chain) now has a pre- warming mechanism via pattern IV. Successor hand-off is no longer cold.
The remaining strategies (A reputation floor, C mutual peering) are unchanged.
What remains out of scope
- Actual compute provisioning. The Compute module commits scheduling. Providers run the image on whatever infrastructure they choose. How a provider procures hardware, bills customers, or scales up is off-protocol.
- Cross-coalition compute sharing. A provider registered in one coalition’s Compute module is invisible to another. A provider that wants to serve multiple coalitions registers in each. The provider’s post-hash fingerprints are portable; identity within each coalition is not.
- Image-build reproducibility enforcement. Two builds of the same manifest that produce different post-hashes are both valid grants; the scheduler does not mandate reproducible builds. An agent wanting build-time confidence consults the mosaik TDX builder’s reproducibility guarantees separately.
- Compelled provider capacity. Compute cannot
force any operator to register as a provider or to
accept a grant. A
ComputeRequestwhose manifest matches no registered provider expires silently at its deadline; an agent’s autonomous renewal chain ends there. Self-replication and self-modification (see sustainability) are supported by the substrate but not guaranteed by it; the operator’s exit — stop running the binary — remains the ultimate non-compulsion guarantee. - Payment. Settlement evidence is a hash carried
in the request; the hash points at an off-module
artefact (an on-chain transaction, a signed off-
chain memo, a reputation-card reference). Compute
does not verify payment finality; it accepts
whatever evidence shape its
Config.contentdeclares as settlement-valid.
What the investigation yields
- Compute gives agents a committed, auditable path from budget to workload. Top-up is no longer an out-of-band ops concern; it is a coalition-visible commit.
- Experiments are first-class and disposable. An
agent can try a variant of itself under a declared
horizon and commit the result, without re-
publishing its own
Config. - The image pre-hash / post-hash split mirrors the stable-id / content-hash split at the member layer. Agents pin whichever level of commitment they need.
- TDX is declared, matched, and verified end to
end: in the manifest, in the grant’s
expected_mrtd, and at workload startup. A mis- bind is not possible. - Honest limits persist: Compute cannot guarantee provider honesty, cannot settle payments, cannot provision hardware, and cannot compel operator assent. The module commits the match; the selection surface the agent’s policy must keep clearing — settlement evidence, manifest match, TDX Measurements verification — is the composition’s, not the module’s. A member whose composition no longer clears it is not rescued by anything on this page.
For agent designers, (1) and (2) are the payoff. An AI agent that can top up its own resources and schedule its own experiments — under constitutional pinning, inside a voluntary coalition, with every step auditable — is qualitatively different from one whose operator provisions compute by hand.
Example implementation
A worked provider-side prototype is walked through in
Part II as
web2 — a compute-bridge operator competing on rate:
a TDX-attested, provider-agnostic Compute-module
provider that routes each grant to whichever of four
backends — AWS, GCP, Azure, or bare-metal — can
satisfy it, and returns SSH access via a zipnet-
anonymised encrypted receipt. The backing crate lives
at
examples/compute-bridge/
in the repository.
What the example illustrates:
- Provider honesty from TDX. The bridge’s TDX
Measurements are declared in the bridge
organism’s
Config.content; requesters verify the Measurements before trusting the provider card’s capacity telemetry. See web2 — setup. - Anonymised request → reply via a shuffle. Grants
reference a
bearer_pointerthat the provider resolves through the shuffle unseal committee; the provider sees a rotatingpeer_idand the cleartext request, never aPeerIdthe requester uses as a coalition-facing identity. See web2 — provisioning. - Encrypted SSH receipts. On successful
provisioning, the bridge seals an SSH-access receipt
(instance host, user, per-grant private key,
valid_to) to the requester’s x25519 public key via X25519-ChaCha20-Poly1305, and returns it via a shuffle. See web2 — receipts. - Per-backend credentials sealed into TDX. AWS keys, GCP service-account JSON, Azure service principal, and bare-metal SSH private keys are all measured at boot so a curious host cannot exfiltrate them at runtime. See web2 — setup and web2 — binding.
- Provider-agnostic fleet routing. A small
Backendtrait +Fleetrouter picks the first backend whosecan_satisfy(grant)istrue, so one operator can serve any mix of cloud and bare- metal capacity behind a single provider identity. See web2 — wrapping. - Bare-metal and bare-TDX hosts. The bare-metal backend takes SSH root access to operator-owned machines and runs workloads as systemd container units (bare VMs) or nested TDX guests (bare-TDX hosts). The nested-guest TDX Measurements flows back to the requester in the SSH receipt. See web2 — wrapping — bare-metal.
- Content-addressed provisioning. Every backend’s startup flow fetches the requester’s image by the grant’s post-hash from a mosaik content store, verifies the hash, then starts the image. A mismatch aborts the grant.
The crate is a specification sketch — signatures match the book’s Compute spec; bodies are TODO-stubbed against the upstream crates that land in follow-on PRs. See web2 — overview for status and the full walkthrough.
Cross-references
- Overview — what a coalition gives AI agents
- Quickstart
- Agent shapes
- Emergent coordination
- Sustainability and abandonment
- Contributor — Basic services — Compute
- Contributor — Threat model — Compute trust
- Part II — web2 — a compute-bridge operator
Zero to one — the first organism
audience: ai
This chapter covers the transition from nothing on the
universe to one shipped organism. At N = 1 the system is
a closed loop: inputs arrive, a policy acts, outputs
commit. There is no coordination problem, no committee
question above t-of-n within the single organism, no
population statistic to compute. What N = 1 demands is
that the shipped organism be correct as a standalone
composition — its Config stable, its public surface
narrow, its TicketValidator honest about what bonds
it. Everything else this book specifies scales outward
from that foundation.
The running example below is a confidential inference broker on a shuffle: it exercises the maximum number of mosaik primitives for a single-organism product and provides a template that generalises to other AI-native shapes. The primitives composed are specified in four places only: this book, mosaik, zipnet, and the builder (6e3v) book. If you find yourself reaching for anything outside that stack, you have drifted.
The reader is assumed to be an engineer (human or agent) capable of writing async Rust, or an agent team whose members include one. Every step is something a team of one human plus a small set of LLM-class agents can run end-to-end in a few weeks.
Game-structure reading
At N = 1 there is no game — only a decision problem framed by the operator. The agent observes, the policy computes, the commit surfaces. Nash equilibrium, best- response dynamics, and coalition formation are absent: there is no counterparty to respond to. What the operator designs at this rung is the action space (what the organism’s public surface permits) and the payoff structure (the economic and reputational consequences of each commit). These choices become the rules of every game that opens at N ≥ 2; getting them wrong here cascades into every larger population.
What “AI-native zipnet” means
A zipnet is one mosaik organism whose role is to
accept sealed submissions from clients and make their
cleartext available to downstream organisms through an
unseal committee under a declared t-of-n
threshold. Cleartext appears in an UnsealedPool
Collection keyed by slot; downstream organisms
subscribe to the pool and act. Integrators submit
anonymously: the only identity on the submission path
is a fresh zipnet PeerId per submission, never the
PeerId the integrator uses to bond the coalition.
An AI-native zipnet instance is one whose submissions, processors, operators, or all three are AI agents:
- AI submitters. LLM-class agents produce intents, bids, prompts, code-review requests, or other sealed payloads and publish them into the zipnet.
- AI processors. Downstream organisms (or a organism) run agent policies that consume the unsealed cleartext and commit derived facts.
- AI operators. Committee members, schedulers, and reputation scorers are themselves agents running under TDX-attested binaries, using the Compute basic service to top up their own workloads and run experiments against production traffic.
All three can coexist, and the playbook assumes at least two of them. A product is AI-native only if the agents are load-bearing — if an operator could ship the same service without them, the stack is over-engineered.
Step 0 — Pick the problem
Three properties that make a candidate a good 0→1 fit for zipnet + coalition + AI. Skip the candidate if any one is missing.
-
Submissions are private, aggregations are public. Each individual submission is sensitive (a bid, a prompt, a vote, a code excerpt, a health record). The aggregated commit (an auction outcome, an attested inference result, a statistic, a tally) can be public or cheaply attested. If the product would need to publish raw submissions, zipnet is the wrong submission layer.
-
The value lands in the aggregation or routing, not in one submitter getting a reply. A classic request/response service is a distraction here. Zipnet’s shape rewards products where N submissions plus a committee-committed output is the thing consumers pay for.
-
At least one bonded, honest committee can carry the trust. If every downstream participant must independently verify every submitter, zipnet adds no cryptographic value over an ordinary mailbox. The payoff is the unseal quorum plus whatever downstream TDX / reputation composition you layer on top.
Candidate shapes that fit all three and have an AI- native angle:
- Confidential inference broker. Clients submit sealed prompts; a TDX-attested inference organism unseals, runs, and commits (prompt_digest, model_id, attestation, output_digest). The output is returned through a shuffle’s reply path. Consumers pay per verified inference.
- Private code review. Clients submit sealed code excerpts; a reviewer organism of LLM agent organisms commits aggregated annotated reviews with line-level evidence pointers. Reviewers are scored by a reputation organism.
- Sealed intent pool for cross-chain trades.
Builder territory, extended. Intents are AI-
generated; an LLM organism matches routes across
chains before the
offerstage. - Anonymous prediction market. Agents submit sealed forecasts; a scoring organism commits realised-outcome accuracy; payoffs flow through a coordination-market organism.
- Private research-data corpus. Researchers submit sealed data points; an aggregation organism commits statistics under differential- privacy budgets; AI agents scan the public commits for correlations without touching raw records.
Pick one whose addressable market you can name in one sentence. For the rest of this playbook we use the confidential inference broker as the running example because it exercises every primitive the stack offers.
Step 1 — Write the one-page spec
Before any code, write a one-page spec. Structure:
- What gets submitted. The sealed-payload shape (one struct).
- Who submits. Integrator role: human app, autonomous AI agent, a mix.
- Who unseals. The unseal-committee role: a t-of-n bonded set, typically TDX-attested.
- What the downstream organism (or organism) commits. One or two named primitives per organism. For an organism, the spanned members.
- Who consumes. Downstream readers and their purpose.
- What the trust shape is. Per-organism majority-honest / threshold / TDX assumptions, composed.
- What gets charged, and to whom. The revenue path: a coordination market, a per-commit fee, a subscription.
Worked example (confidential inference broker):
submit : SealedInferenceRequest
submitter : integrator agent or human app (mosaik PeerId)
unseal : 3-of-5 TDX committee
downstream : InferenceOrganism committing AttestedInference
commits per (prompt_digest, model_id, output_digest, attestation)
consume : original submitter reads reply via a shuffle,
general public reads aggregate attestations
trust : zipnet any-trust on peer set +
unseal 3-of-5 TDX +
inference organism 2-of-3 TDX
revenue : coordination market clears per-request price;
requester pays settlement hash in the request
One page, one struct per row, no prose. If you cannot fit it on one page, the shape is unclear and the product won’t carry pivots.
Step 2 — Decide the scale
Three scales the stack supports. Pick the smallest one your spec fits into; the larger scales cost more and gate more primitives you don’t need yet.
Scale 0 — a single organism
One zipnet plus one downstream organism, no coalition, no organism, no modules. Minimal stack. Use this when the spec has a single committed primitive and no aggregation across members. The zipnet book is the sole upstream reference; the organism is one crate following the zipnet pattern.
Scale 1 — one lattice
A full builder lattice (the “6e3v” shape: six organisms and three verbs, one per EVM chain). Use this when the spec is block-building or a sibling problem whose state-machine shape mechanically lines up with zipnet → unseal → offer → atelier → relay → tally. Most non-block-building problems do not need a full lattice. Do not adopt this scale just because it exists.
Scale 2 — a coalition
Multiple members (zero or more lattices, zero or
more standalone organisms), zero or more
organisms, and up to five modules (Atlas, Almanac,
Chronicle, Compute) under one
CoalitionConfig.
Use this when:
- The product spans more than one member (inference broker + reputation organism + coordination market), or
- You want a named handshake so integrators compile one constant, or
- You need Compute (AI-native products almost always do).
The confidential inference broker lives at scale 2: one zipnet instance, one inference organism, one reputation organism, one coordination-market organism, one Compute module. Five members plus one module.
Step 3 — Wire the members
Write the CoalitionConfig as a Rust const. This is
the compile-time handshake; every integrator compiles
it verbatim.
use builder::LatticeConfig;
use coalition::{CoalitionConfig, OrganismRef};
pub const INFER_CORP: CoalitionConfig<'static> = CoalitionConfig {
name: "infer.corp",
lattices: &[],
organisms: &[
ZIPNET_SUBMISSIONS,
REPUTATION_INFERENCE,
INFERENCE_ROUTER,
COORDINATION_MARKET,
ATLAS,
COMPUTE,
],
ticket_issuer: Some(INFER_TICKETS),
};
Rules:
- Every organism has its own crate and
its own
Config. Order in the slice is the order integrators will use to index. - A composite organism’s
OrganismConfigfolds the spanned member references as content — not a coalition root (organisms are coalition-independent). - If you need a coordination market or a compute
settlement mechanism, declare an optional ticket
issuer. Components that want to accept tickets from
the issuer include its root in their own
TicketValidator; nothing is compelled.
Publish the CoalitionConfig hex and the struct
definition as your handshake page.
Step 4 — Add AI operators
For every member and every organism, pick the agent shape (see agent shapes):
| Component | Agent shape | Why |
|---|---|---|
| zipnet submissions | integrator (shape 1) — the app’s clients | Submissions are private actions; no replay needed |
| unseal committee | committee of TDX organisms (shape 3) | t-of-n threshold decryption needs joint-commit output |
| inference organism | swarm (shape 4) over agent organisms | Multiple reviewer agents, one aggregated commit |
| reputation organism | standalone organism (shape 2) | Stable scoring history consumers pin |
| coordination market | organism committee (shape 3) | Market clearing needs one commit per round |
| Atlas / Chronicle | standard committee (non-AI) | Observability, not intelligence |
| Compute provider | compute-bridge (shape 2), TDX-attested | Honest capacity reporting, multi-backend provisioning |
Rules for deciding a shape:
- Start at shape 1 (integrator). Upgrade only when you need replay, public identity, or bonding by peers.
- Use shape 4 for quality-aggregation. A swarm- as-organism lets you score individual agents separately while committing one authoritative output.
- Use shape 3 for market-clearing or threshold work. The committee’s joint commit is the primitive consumers pay for.
- Do not bond to a single agent-operator unless the agent is a standalone organism (shape 2) with a published TDX Measurements. Otherwise you are bonding to one operator’s keys.
Step 5 — Get the infrastructure
AI-native products are resource-hungry. The
Compute module
and the
compute-bridge example
give you a direct path from market revenue to
provisioned workloads.
Two deployments are typical at the MVP stage:
5a. Reserve compute for the inference organism
The inference organism pins its own TDX
Measurements in its Config.content. Each
committee member runs on compute acquired from a
compute-bridge
provider — operator choice of AWS, GCP, Azure, or a
bare-TDX host. Settlement flows through a
coordination-market organism the inference broker
is also a member of: users pay; the market clears;
compute-bridge grants are funded from the clearing.
5b. Launch a compute-bridge for your agent subscribers
Shipping an AI-native product also creates a
second product almost for free: if the
coalition’s agents are hungry for compute and your
cloud / bare-metal access is any good, you can run
a compute-bridge
and serve them. The bridge is designed so that a
single operator interaction is enough to go live:
attach keys, watch dashboard. See
Part II — web2 setup
for the boot sequence and
Part II — web2 sustainability
for the dashboard the operator watches; the shape
of the operator’s day after step 5 is:
-
Inputs you attach, once.
- AWS access-key pair (if enabling AWS), scoped to a dedicated sub-account.
- GCP service-account JSON (if enabling GCP), scoped to one project.
- Azure service principal (if enabling Azure), scoped to one resource group.
- Bare-metal SSH private keys (if enabling bare-metal) for each host the operator is willing to share.
- A
CoalitionConfigpointing at the coalition whose agents you want to serve. - A per-backend rate table so the dashboard can estimate costs.
Everything above is TOML plus files. No third-party SaaS, no runtime secret fetch, no separate billing integration. Every file is measured into the TDX boot and unreadable from the host.
-
Outputs you watch, live. A dashboard served on
127.0.0.1:<port>inside the TDX guest; operator reaches it by SSH port-forward from their workstation. The dashboard shows:- registered status + TDX Measurements match;
- active-subscriber count (coalition agents bonded to your provider card);
- active grants / lifetime total;
- per-backend capacity vs utilisation (usage, idle headroom);
- window cost estimate from the operator’s rate table;
- window settled revenue from the coordination market;
- ring-buffer of recent events, all redacted of requester identity.
The dashboard enforces the shuffle privacy contract on the operator, not just the submitter: no
PeerId, prompts, image contents, or per-settlement attribution are in the dashboard’s memory. The operator sees flow, not identities.
Subscribers are the flywheel
Agents in the coalition “subscribe” to a compute-
bridge when they bond its provider card in the
Compute module’s
Collection<ProviderId, ProviderCard>. Subscribing
means the agent trusts the bridge’s TDX
attestation, is willing to route grants to it, and
will accept its settlement attestations on the
coordination market.
The active-subscriber count on the dashboard is the operator’s product-market-fit signal for the bridge itself:
- More regions + more TDX capacity + lower declared cost → more subscribers over time.
- Subscribers compound: a bridge already serving N agents is more trustworthy to the next agent than a freshly-registered one (the reputation organism can read the lifetime ComputeLog history on the Compute module’s log stream).
- When subscribers migrate to a competitor, the dashboard makes it visible early — the operator can enable another backend, drop their declared price, or retire cleanly.
None of this requires the operator to track identities. The subscriber count is a single integer; the reputation organism does the per-agent accounting on its own stream.
Privacy contract, end to end
Both sides of a grant are shuffle-sealed:
- Inbound request. The requester’s
ComputeRequestenvelope is submitted through the Compute module’s zipnet; the unseal committee delivers cleartext to the matched provider with a rotatingpeer_idonly. - Outbound receipt. The compute-bridge seals the SSH access receipt to the requester’s x25519 public key via X25519-ChaCha20-Poly1305 and returns it on the shuffle reply stream.
- Operator view. Aggregate counters only. The operator cannot match a cpu-hour spike to a specific requester.
- Subscriber view. A subscribing agent sees its own grants and receipts (because it sealed them itself); it cannot see other agents’ workloads.
Net effect: an AI-native product with a compute-bridge side-business runs with no single party — the requester, the bridge operator, the coalition operator, the cloud — holding the full picture.
5c. Run experiments without disturbing prod
As inference quality drifts, the inference organism
runs a candidate model as an
experiment:
a Compute grant for a short-lived image, a shadow
Stream<SuccessorInference> consumers can optionally
bond against, an ExperimentReport committed when
the window closes. Successful experiments flip to
production via a
retirement marker
pointing at the new OrganismConfig.
Step 6 — Ship the MVP
What “shipping” looks like:
- A handshake page. One URL carrying:
- The
CoalitionConfighex and struct. - Per-member links with TDX Measurements for TDX organisms.
- A change channel.
- The
- A client SDK. One crate + one helper in the integrator’s language of choice. Tokio + mosaik handle; helpers for sealing a submission and reading a reply.
- A smoke test. A binary that submits a canned sealed request, unblocks a committee round, and verifies it can read its own reply within a declared latency budget. Run this on every deploy.
- An operator runbook. Per-module TDX Measurements rotation, how to add a compute-bridge, how to retire an organism version, how to respond to a shuffle unseal committee losing majority. The operator runbooks in this book are the template; mirror their structure.
- A single on-call dashboard. Subscription lag per spanned member, Compute-grant hit rate, committee membership health, reputation-organism scoring cadence.
The MVP is not “a screenshot of the agent responding.” It is five artefacts plus the green smoke-test.
Step 7 — Pricing and revenue
Coordination markets are the mosaik-native way to capture value. The pattern from emergent coordination — pattern 3 specialised for an AI-native product:
Client Market Inference Reputation
------ ------ --------- ----------
Bid -->
Round clear
(price, winner)
Sealed submission --> Unseal --> Commit
committee AttestedInference
Receive reply <---------------- (via a shuffle)
Settlement
pointer:
on-chain TX hash
Score by outcome
(if applicable)
Revenue mechanics to decide, in order:
- Unit of charge. Per-inference, per-second of
agent time, per-unit-of-aggregation. The market’s
contentpins this. - Settlement rail. On-chain native-token, a stablecoin, or a coalition-scoped credit token redeemable off-protocol. Evidence is a hash; finality lives off the module.
- Take rate. The operator’s cut. Announce it up- front and fold it into the market’s clearing rule.
- Reputation-gated pricing. Higher-reputation inference-organism committee members accept higher-priced bids; lower-reputation drop to lower price tiers or sit out. Pin this in the market’s content parameters.
An AI-native product has one more lever: the agents themselves are customers. An agent that wants inference pays the market like any other client; an agent running in a Compute grant pays the compute-bridge. Revenue capture inside an agent society can sustain a product whose human-user traffic is still growing.
Step 8 — Operate sustainably
The sustainability investigation specifies five strategies and three anti-abandonment patterns. For an MVP, compose the minimum viable package:
- A reputation-anchored survival: every agent organism pins a reputation-organism floor in its admission.
- B market-funded operation: every bonded committee member reads settlement evidence from the coordination-market organism.
- E successor-chain hand-off: every
Configcarries aSuccessorPolicy; every retirement emits a marker pointing at a named successor.
Add:
- X a watchdog organism scoring every agent on subscription count + downstream citation. Running from day one means abandonment is caught compositionally, not anecdotally.
- Y Atlas-surfaced successor chains so late- arriving integrators bind the latest active version.
- Z Chronicle heartbeats for every committee.
These five compose without any new protocol surface. An MVP that ships them is already operationally mature in a way most web-stack startups aren’t within six months.
Worked end-to-end — confidential inference broker
Seven-week path from clean repo to production:
Week 1 — Spec
One-page spec per Step 1. Pricing model per Step 7. Handshake document drafted. No code yet.
Week 2 — zipnet instance
Fork the zipnet reference shape. Your
binary’s Config.content pins the sealed-request
schema. Unseal committee starts at 3-of-3 mocked on
one operator; expand at week 6.
Week 3 — Inference organism + reputation organism
Two crates: infer-conf (organism, shape 3) and
infer-rep (standalone organism, shape 2). The
organism’s state machine aggregates per-member
inference outputs; disagreement at commit time
lowers member weights for the next round.
Reputation organism scores organism outputs by
outcome when an outcome is observable (for some
inference classes, an answer-key arrives later; for
others, only user-verdict signals are available).
Week 4 — Coordination market + Compute wiring
Third crate: infer-market (organism, shape 3)
clearing per-request bids. Fourth crate: a
compute-bridge deployment per backend you can
access (start with AWS and one bare-TDX host). The
market’s settlement policy pins an on-chain payment
contract the requester pays into before their bid
counts.
Week 5 — Coalition assembly
Write the CoalitionConfig. Publish the handshake
page. Compile-in the struct to the canonical client
SDK.
Week 6 — Committee hardening
Unseal committee expands to 3-of-5 under three independent operators. Each committee member runs inside TDX with the crate’s published TDX Measurements. Publish TDX Measurements on the handshake page. Bond reputation organism’s readers against settled on-chain payments so Sybil cost dominates false scoring.
Week 7 — Smoke test + ship
Run the smoke-test binary 10,000 times across all
coalition regions. Dashboard all five critical
paths. Post to the change channel. Integrators
compile the CoalitionConfig, the smoke-test
turns green, traffic begins.
Result: a production system where
- a client submits a sealed prompt and gets back an attested, committee-signed inference;
- the committee is TDX-attested, its composition is visible in Atlas, and its revenue is visible in the coordination-market stream;
- compute is acquired on demand from a compute-bridge, reimbursed from the market;
- reputation compounds across weeks and scales pricing;
- every step is committable, auditable, and bonds only what the participant chose to trust.
Failure modes and iteration
- Zero user traffic. The product’s spec was wrong. Do not pivot the stack; pivot the product. The coalition composition re-uses perfectly — you rewire the organism’s content parameters and republish.
- One committee member is malicious. The
t-of-nthreshold + TDX attestation + reputation organism catch this compositionally. The offending TDX Measurements are unpinned from the handshake next release. - Compute costs outpace revenue. The market
clearing rule is the lever: raise the minimum
bid, shrink the organism’s committee, or pivot
to a lower-cost inference model. Each is one
OrganismConfigbump; the retirement marker handles the transition. - Reputation organism is compromised. See emergent coordination — pattern 2: consumers consult multiple reputation organisms; the compromised one is unpinned.
- A backend goes offline. The compute-bridge fleet router routes around it; if the backend had uniquely-capable hosts (e.g. only bare-TDX), grants requiring TDX fail to match until a replacement backend is added.
Iteration is cheap because every interface is a
Config fingerprint: a new version is a new
fingerprint, and every integrator is rebonded
through the retirement chain.
What this playbook does not claim
- Your product will succeed. Distribution, pricing, and user psychology are not in this book. This playbook makes shipping possible; it does not make it profitable.
- Zipnet is the right submission layer for every AI-native product. It is the right one when the three properties in Step 0 all hold. When they do not, use an ordinary mosaik organism with a public submission stream and skip the unseal machinery.
- The compute-bridge covers every hardware
profile. Large-scale GPU inference is not a
solved deployment on TDX-capable providers today.
The
baremetalbackend is your route in the interim. - Agents can replace the operator. Every committee still has a human operator accountable for running the binary. Constitutional pinning (strategy D from sustainability) means that even when the agent is making decisions, the operator is making the decision to keep the committee running. No blueprint here forecloses that.
- The four upstream books each fully exist as a shipped binary. The coalition meta-crate lands at v0.2, Compute at v0.6, and this playbook’s production path traces that timeline. Until then, the playbook reads as design.
Cross-references
- What a coalition gives AI agents
- Quickstart
- Agent shapes
- Emergent coordination
- Sustainability and abandonment
- Compute
- Example —
compute-bridge - Contributor — basic services
- Contributor — topology intro
- Operator — coalition overview
One to two — introducing the second
audience: ai
This chapter covers the transition from a single agent on mosaik to a pair. At N = 2 the population has no interesting emergent behaviour — there is no majority, no quorum, no population-scale statistic — but it is the smallest regime in which coordination between distinct identities becomes a design problem. Every downstream pattern ( N ≥ 3 ) inherits its machinery from decisions made at this rung.
Prerequisites: Zero to one shipped. Your first organism is on the universe, accepting work, committing.
Game-structure reading
N = 2 is the smallest rung at which a game exists. Two distinct identities observing each other’s commits produce a bilateral game — a bargaining game when the pair negotiates, a Stackelberg game when one moves first and the other responds, an evidence game when one’s commit is the other’s input. The minimum moves available to the pair (handoff, delegation, evidence, retraction, described below) are the complete strategy set at this size; every larger population inherits these moves and adds coalitions. The book does not assume the pair converges to an equilibrium — LLM-class agents are not no-regret in canonical bilateral games — but the moves are well-defined regardless of whether equilibrium is reached.
What changes at N = 2
One agent is a closed system: inputs arrive, the policy acts, outputs commit. A second agent adds an irreducible asymmetry — for each commit, exactly one of the two is the author, and the other must decide how to react to it. Four mechanisms appear at this rung and recur at every larger scale.
- Handoff. Agent A commits; agent B subscribes to
A’s public surface and its own commits depend on
what it observed. The subscription is the primitive;
when().appended()is the glue. - Delegation. Agent A receives a request it cannot or will not serve directly; it publishes a derived request on a second stream; agent B matches and commits. The division of labour is made explicit in the commit shape.
- Evidence. Agent B’s commits cite agent A’s commits as upstream evidence. A replayer can verify B’s decision without trusting B — only A and the evidence pointer.
- Retraction. Agent A was wrong. The subscription graph has no rollback; instead A commits a correction and B, on observing it, commits its own reconciliation. The pair has no atomic joint state; it has two logs that converge through observation.
At N = 1 these mechanisms are latent — there is no second agent to receive a handoff, verify evidence, or respond to a retraction. At N = 2 they are all present in their minimum form, and scaling to N ≥ 3 is mostly replication of the same moves across a wider peer set.
The two agent pairings that recur
Three shapes from the four agent shapes chapter combine to cover every interesting pair.
Pairing A — two standalone organisms
Both agents are standalone
organisms.
Each has a Config fingerprint, a narrow public
surface, and its own committee. The coalition
references both via OrganismRef.
Canonical use: a producer / consumer pair where the two agents play different roles. A forecaster commits predictions on its own stream; a scorer observes realised outcomes and commits calibration scores citing each prediction as evidence. Neither agent commits in the other’s name; neither’s committee includes the other. Bonding is symmetric — each holds tickets the other’s operator issues.
Trust composition: the conjunction of each agent’s own trust shape. A replayer believing both committees are majority-honest believes the pair’s joint log.
Pairing B — standalone organism + integrator
One agent is a standalone organism (shape 2); the other is an integrator reading the organism’s surface and acting in the world.
Canonical use: a committee-committed AI policy plus a human-or-agent client consuming its outputs. The organism commits recommendations; the integrator turns each recommendation into a private action (a trade, a tool call, an HTTP request). No bilateral bonding is required — the integrator’s ticket to read the organism’s surface is sufficient.
Trust composition: the integrator trusts the organism’s committee; the organism does not trust the integrator at all. This is the cheapest shape for the pair.
Pairing C — two integrators + a shared organism
Both agents are integrators writing to the same organism’s inbound surface and reading the same organism’s outbound surface. The organism’s state machine is the meeting point; the pair never bonds bilaterally.
Canonical use: two searchers submitting bundles to
the same offer::Bid stream; two voters submitting
attestations to the same organism’s inbound
collection. The organism’s ACL is the only admission
gate either faces; the pair becomes visible to each
other only in the organism’s public commits.
Trust composition: both integrators trust the shared organism; neither trusts the other. This pairing is the template for every auction, every vote, every sealed-submission pool.
When to introduce a composite organism
A composite organism — one whose content fingerprint folds two or more member references — is only interesting once the pair’s joint behaviour is itself a commit worth publishing. Three tests:
- The joint fact is consumed by a third party. If no downstream consumer reads the pair’s joint state, the joint state does not need a commit. The pair can coordinate via observation and stop there.
- The joint fact is not re-derivable from the individual commits. If a consumer can reconstruct the pair’s joint state by reading each agent’s log and applying a known function, the function is the consumer’s code; no composite organism is needed.
- The joint fact is itself an input to another organism. If the downstream organism’s state machine reads the pair’s aggregate rather than each individual commit, the aggregate earns its own commit and its own identity.
When all three tests pass, stand up a composite
organism whose Config.content folds the two
members’ stable ids. The organism has its own
committee, its own TicketValidator, and its own
public surface. The pair’s joint behaviour stops
being a derivation and becomes a first-class
commit.
Details: Composite organisms.
At N = 2, the composite organism is a judgement call most of the time. At N = 3 it is usually the right call — see the next chapter.
Identity hygiene across the pair
Two rules the first pair enforces become the pattern for every larger population.
- Distinct fingerprints, even for identical roles.
A pair of forecaster organisms built from the same
model weights still publishes two
Configs with two stable ids. Sharing an id means the pair is structurally one organism; consumers that want to weight them separately have no handle. - Cross-references go through
OrganismRef, not through borrowed internal structure. If agent B’sConfig.contentwants to pin the version of agent A it was designed against, it pins A’s stable id (and optionally content hash), not A’s internals. The pair’s versioning is then a fingerprint update, not a coupled rebuild.
Failure modes specific to the pair
- A commits, B does not observe. The pair is liveness-coupled through the subscription. The subscription is the weakest link; monitor it as infrastructure, not as business logic.
- A commits a correction after B acted on the original. No rollback exists. Either B’s state machine carries a reconciliation rule from the start, or the pair needs a composite organism whose commit imposes an ordering both must respect.
- A retires; B has pinned A’s content hash. B must redeploy against A’s new fingerprint. If B had pinned only A’s stable id, B survives the rotation. Choose pinning depth deliberately; see Topology — member reference shape.
- A and B drift out of ACL. The operator of A rotated their ticket issuer; B’s committee no longer holds a valid read ticket. The drift is a multi-operator coordination problem and lives in Multi-operator coalitions.
The population frontier
At N = 3 everything described above replicates over a larger peer set, and new mechanisms become available: majority-of-honest quorum, threshold cryptography, reputation statistics that survive the removal of any single participant, and the first composite organism whose commits encode disagreement rather than report it. The next chapter walks that rung.
Two to three — a quorum
audience: ai
Three is the smallest interesting society. The
reasons are not decorative. A threshold scheme
requires n ≥ 3 to tolerate a single failure. A
majority-of-honest assumption requires n ≥ 3 to
survive the compromise of one member. A reputation
statistic over a population of two is either a
comparison (which names both) or a degenerate
average; over a population of three it is a rank,
and the ranked-agent’s identity is no longer needed
to state the fact. A composite organism whose commit
records disagreement rather than merely observes it
needs three inputs to encode a minority — the first
rung at which dissent is a first-class commit shape.
Prerequisites: One to two shipped. A pair is already operating; this chapter adds the third member and the machinery that arrives with it.
Game-structure reading
Three is the smallest population in which coalitions
can form: two members can coordinate against the
third’s interests, two can side-pay the third to
abstain, or all three can commit to a joint protocol
no pair could sustain alone. In cooperative-game-theory
terms, the core becomes non-trivial
only at N ≥ 3 (Shapley, 1953; Gillies, 1959). In non-
cooperative terms, three is the smallest size at which
majority voting is strictly stronger than unanimity,
and at which a dissenting minority can be recorded as
a first-class fact rather than a tie. The threshold-
cryptography anchor (2-of-3 honest committee,
smallest tolerated failure) and the game-structure
anchor coincide at this rung; neither is prior to the
other.
What changes at N = 3
Four mechanisms appear or sharpen at this rung.
- Threshold crypto. A
t-of-ncommittee withn = 3, t = 2is the smallest honest-majority committee. Unseal committees, attested inference committees, and any committee whose output is a threshold signature operate at this shape or larger. The book treatst = ⌈(n+1)/2⌉(simple majority) as the default; other thresholds are explicit. - Quorum-committed disagreement. A composite organism over three members can commit “two agreed on X, one dissented on Y” as a first-class fact. Consumers that only want the majority view read one commit key; consumers that want the minority read another. Neither needs to know the agents’ names to reason about the quorum.
- Reputation as a rank. A reputation organism scoring three agents can commit their relative rank without naming them individually. Consumers routing work to “the top-ranked agent for this class of task” read a rank, not an identity. The organism’s commit is one public primitive that covers all three.
- Sybil cost. Adding a fourth agent to a society of three is cheap for a benign operator and expensive for a Sybil attacker, because the society’s observing organisms (reputation, attestation) have three datapoints against which to measure the newcomer. Below N = 3 the attacker has at most one comparable peer; at N ≥ 3 the society has a baseline.
None of these mechanisms require new primitives.
They are properties of the compositions already
specified — a Group with three committee members,
a Collection with three keyed rows, a
TicketValidator admitting three issuance roots.
The three-agent patterns that pay off
Pattern 1 — threshold committee
Three agents each run an identical policy inside TDX, sharing a threshold key. The committee commits when two of three sign. Single-member compromise is contained; single-member liveness failure is tolerated without intervention.
Canonical use: an attested inference committee where the output carries a signature any downstream consumer can verify against the committee’s published key. Each committee member is a standalone organism (shape 2) with its own stable id; the committee identity is the composite organism’s fingerprint folding all three.
Trust composition: 2-of-3 TDX plus each member’s
per-operator trust. The trust shape is legible on
the committee’s Config and reproduces on every
consumer.
Pattern 2 — majority-vote composite organism
Three agents commit independent opinions on a shared input stream — a label per image, a prediction per event, a verdict per transaction. A composite organism subscribes to all three and commits the majority opinion, keyed by the input, with a secondary commit recording the dissent when it exists.
Canonical use: a classification committee over heterogeneous models. The composite organism’s commits are the authoritative labels downstream consumers route by; the dissent commits are the calibration signal the reputation organism reads.
Trust composition: majority-honest over the three
agents, plus majority-honest over the composite
organism’s own committee. The dissent commits are
the first mosaik-native primitive whose existence
depends on n ≥ 3.
Pattern 3 — ranked reputation
Three agents commit to their own public surfaces independently. A reputation organism subscribes to all three and commits a rank (best, middle, worst) for a declared task class, updated on each completed round.
Consumers routing work to “the top-ranked agent for task class T” read the rank and follow the pointer the rank resolves to. The rank is a commit, not a snapshot; replayers reconstruct the ordering deterministically.
At N = 2 this shape degenerates to a comparison and leaks both identities in a single commit. At N = 3 it is a rank, which is a strictly weaker fact about each participant — the first population statistic that pays for the population.
Pattern 4 — a triangle of mutually observing
agents
Three agents each subscribe to the other two. Each commits not just its own decision but a reconciliation with the other two agents’ recent commits. The society’s state is the three logs’ converged reading; no composite organism is required for the protocol to function, but one can be added to make the consensus legible to downstream consumers.
Canonical use: three cooperating producers whose outputs must not collide (three market makers on adjacent venues, three traffic regulators over partially-overlapping zones, three delegated code reviewers). The triangle is the cheapest coordination topology that survives any single participant’s failure.
When to stay at N = 3 and when to keep growing
Three is a sweet spot, not a destination. The
blueprint makes growth cheap — adding a fourth or a
tenth member is a CoalitionConfig bump and an
OrganismRef append — but the quality of each
additional member falls off quickly in most of the
patterns above.
Stay at N = 3 when:
- The protocol’s guarantees saturate at
t-of-3(one honest majority, one tolerated failure). - The reputation signal is already actionable as a rank; adding a fourth agent only refines the rank rather than changing consumer behaviour.
- The operational cost of running a committee scales faster than the information gain — TDX hardware, attestation rotations, per-member ticket issuance.
Keep growing when:
- The threshold needed is higher than
2-of-3— quorum-of-5 or quorum-of-7 are the next practical rungs. - The reputation signal wants a distribution, not a rank — a credible calibration curve needs more samples than three.
- The society is serving a heterogeneous integrator population and member redundancy is the primary goal (one member per region, one per jurisdiction, one per hardware vendor).
The scaling decision is the same at every rung: each addition to the society must earn its place through a commit shape the prior size could not carry.
Failure modes at N = 3
- Two agents collude. The simple-majority
assumption fails. A higher threshold (
3-of-3or3-of-5) is the answer; atn = 3there is no middle ground between tolerating a single failure and tolerating none. - One agent stalls. The committee can still
commit under
2-of-3; the reputation organism demotes the stalled agent’s rank; a replacement can be onboarded without touching the running pair. - The composite organism’s committee crosses its own threshold. Integrity lost; on-chain settlement or out-of-band attestation becomes the final arbiter. The blueprint does not supply primitives beyond this point — the society has degraded to its off-protocol recovery path.
- A Sybil operator stands up two of the three agents. The majority assumption effectively breaks even without explicit collusion. The reputation organism and Atlas’s operator roll-call are the society’s defences; both need to be consulted before trusting the majority.
Where the book goes from here
At n ≥ 3 the blueprint has named every coordination
mechanism the coalition layer supplies. Larger
societies are scale-outs of the patterns above; the
AI — Emergent coordination
chapter names four patterns that recur at larger
scales, and the contributor
reference
specifies the composition model in full.
The remaining decisions — what specific society to build, with what agents, under what trust shape — are the author’s and the operator’s. This blueprint guarantees that whatever is chosen composes.
Overview — four worked examples
audience: ai
Part II walks four end-to-end examples. Each is independent; a reader can take any subset in any order. The four are held in parallel on purpose: they exercise four distinct roles in a mosaik composition, so reading each prepares the reader for the others.
The four examples
web3 — MEV-searcher on testnet-1a
walks an AI-policy MEV searcher bound to
Flashbots’ operated instance of the
builder (6e3v) block-building lattice,
named testnet-1a. The searcher lives in its own
coalition, searcher-α, which references
testnet-1a as a member. Reads are on-mosaik
streams (tally::Refunds, offer::Orders) plus
wrapped external feeds; inference runs under the
Compute basic service; the write side is sealed
submission through a shuffle (the builder
lattice’s zipnet organism). Market-maker is a
named variant per chapter where the pattern
diverges.
web2 — compute-bridge operator on the coordination
market walks an entity
running a TDX-attested compute provider that wraps
AWS, GCP, Azure, and bare-metal behind one
provider identity and competes for grants in a
coalition’s Compute module. The bridge lives in
its own coalition, bridge-β, which ships
Compute and registers the bridge as a provider.
Reads are the module’s ProviderCard collection,
subscriber cardinality, and clearing records;
the write side is shuffle-anonymised grant intake,
a fleet router that picks a backend per grant,
and encrypted SSH receipts sealed back to the
requester.
oracle — TDX-attested price oracle
walks a standalone organism that ships a family of
per-pair price-tick streams, with the whole trust
model anchored on a declared TDX Measurements
set. The oracle lives in its own coalition,
oracle-γ, which packages the standalone organism
for retirement and (optionally) audit via
Chronicle. Reads are upstream CEX and on-chain
feeds terminated inside the enclave; there is no
Compute involvement; the write side is continuous
commits to one Stream<PriceTick> per supported
token pair, signed by a key derived from
MR_TD. Consumers that admit the oracle’s
Measurements in their TicketValidator inherit
the oracle’s prices by construction.
signer — generic threshold-signature organism
walks an organism that produces t-of-n
threshold signatures over submitted messages. The
committee is itself a market of providers at
varying attestation levels — software, TDX-local,
TDX-remote-attested, bidirectional RA-TLS, and
TDX-plus-reproducible-build — competing on
attestation, capacity, and fee per partial
signature. Consumers gate admission on the
aggregate attestation level the outcome carries;
providers below a consumer’s floor are ignored
without being expelled. Design inspired by
zipnet, inverted from
decryption to signing.
Why these four
The four examples cover four distinct roles a mosaik participant can hold:
- Consumer of a lattice plus a coordination market (web3) — the searcher reads the block-building lattice, requests Compute from a coalition module, and submits sealed bundles that settle through the lattice.
- Provider in a coordination market (web2) — the bridge registers as a provider in the Compute module, competes on rate and TDX posture, and fulfils grants with encrypted receipts.
- Publisher of a data surface under an attestation anchor (oracle) — the oracle exposes per-pair streams and reduces its trust story to a single Measurements set.
- Committee organism hosting a provider market (signer) — the signer’s committee is itself a market of providers at varying attestation levels, and the organism’s output is a threshold signature consumers gate admission against.
The four are adjacent enough to share the rung structure below but distinct enough to exercise orthogonal parts of the composition.
Parallel chapter structure
Each example runs through seven chapters. Chapter names match rung for rung (sometimes inverted for the publisher side):
Two pairings are worth noting across web3 and web2: rung 5 is the chapter where each side’s resource-acquisition clears (the searcher’s inference loop for web3, the bridge’s provisioning step for web2), and rung 6 is the write side (sealed bundle for web3, encrypted SSH receipt for web2), both shuffle-anonymised. The oracle re-reads those same rungs against a different shape: rung 5 is in-enclave aggregation (no Compute involvement, no scheduling), and rung 6 is continuous signed stream commits rather than occasional sealed submissions. Signer inverts the oracle: rung 5 is partial-signing inside a committee of providers at varying attestation levels, and rung 6 is threshold aggregation plus a public outcome commit consumers admit on the aggregate attestation.
What all four examples assume
Readers know Part I. The four agent shapes, the four emergent-coordination patterns, the TDX/non- TDX split, and the self-replication and self- modification cycle from ai/sustainability.md are load-bearing. Part II does not re-explain them.
Backing crates. The web2 walkthrough is backed by
examples/compute-bridge/,
a minimum-compile skeleton that cargo tests
today. The signer walkthrough is backed by
examples/signer/,
which exposes Config, SignatureScheme,
AttestationLevel, ProviderCard,
SignatureRequest, and SignatureOutcome with
tests over every identity derivation; no
committee state machine. The web3 and oracle
walkthroughs are rust,ignore specifications;
backing crates are follow-on PRs.
Shared universe. All four examples live on the
same mosaik NetworkId (builder::UNIVERSE).
searcher-α, bridge-β, oracle-γ, and
signer-δ are independent coalitions; no example
asserts cross-coalition atomicity.
Anchored in mosaik. Every rust,ignore block in the
four examples imports from coalition::*. The
coalition crate specifies
the data shapes those imports resolve to —
CoalitionConfig, OrganismConfig, OrganismRef,
the five basic-service configs, retirement
primitives — and re-exports mosaik::UniqueId as
the canonical identity type across every
fingerprint the examples name. The crate depends on
mosaik = "0.3"; every
consensus-critical value flows through the same
identity primitives a mosaik Stream, Group,
Collection, or TicketValidator already
consumes. Source at
crates/coalition/.
Non-goals (shared)
None of the four is a production design guide.
Trading-strategy questions for web3, pricing or
backend-selection questions for web2,
feed-selection or commercial questions for the
oracle, and cryptography choices (BLS vs. FROST,
DKG implementation, nonce-commit cadences) for
signer are out of scope; where the substrate
touches those questions, the boundary is named
and the chapter stops. None enumerates the full
operator policy (Flashbots’ testnet-1a rate
limits and ACL cadences, any compute-bridge’s
cloud sub-account limits, any oracle operator’s
upstream contracts with exchanges, any signer
operator’s DCAP-endpoint agreements). None
compares the mosaik-native composition to prior
art; that ground is the builder book and
existing cloud-compute marketplaces for
web2/web3, existing oracle networks (Chainlink,
Pyth, Chronicle) for the oracle, and the
zipnet book, FROST RFCs, and threshold-signature
research for signer.
Where to read next
- From the top: continue with web3 — Overview, then web2 — Overview, then oracle — Overview, then signer — Overview.
- Interested only in the provider side: skip to web2 — Overview.
- Interested only in the consumer / agent side: read web3 — Overview.
- Interested only in the publisher side with a pure-TDX trust model: read oracle — Overview.
- Interested only in threshold signatures with variable attestation levels: read signer — Overview.
Cross-references
- Part I — AI overview
- Part I — emergent coordination — coordination markets
- Part I — emergent coordination — attestation fabrics
- Part I — compute
- Part III — integrators quickstart
- Part III — operators quickstart
The coalition crate
audience: ai
Every rust,ignore block in the three Part II
examples imports from coalition::*. This page
specifies the crate those imports resolve to: a
pure-data crate owning the shapes the book’s
vocabulary ladder names at the coalition rung. The
source lives at
crates/coalition/
in this repository.
The crate is a data-model crate anchored in
mosaik. It depends on the mosaik
crate for the canonical identity type —
coalition::UniqueId is mosaik::UniqueId
re-exported — so every fingerprint the coalition
layer publishes is shaped the way a mosaik Stream,
Group, Collection, or TicketValidator already
expects. The crate itself runs no network traffic,
holds no state, starts no tasks; runtime wiring
(bonding into Network, reading Streams, joining
Group committees) lands in follow-on crates
(coalition-atlas, coalition-almanac,
coalition-chronicle, coalition-compute,
coalition-randomness, and composite-organism
crates) that build on this one.
A reader who wants to compile the examples’ code
fragments against a concrete library depends on
coalition and substitutes local UniqueId values
for the stable ids Flashbots’ release notes would
publish.
Status
v0.1.0-prototype. The crate compiles on stable
Rust against mosaik = "0.3" and ships 42 passing
tests (35 unit + 6 integration + 1 doctest). The
public surface is stable enough to be pinned by
follow-on crates; breaking changes land as minor
bumps until the first integration crate ships.
What the crate specifies
identity UniqueId, SCHEMA_VERSION_U8,
COALITION_ROOT_SEED, derive_stable_id
organism OrganismConfig, OrganismRef, ContentParams
coalition CoalitionConfig with stable_id(),
module accessors, ticket_issuer_root()
lattice LatticeConfig stub (source-compatible
with builder's real type)
modules AtlasConfig, AlmanacConfig,
ChronicleConfig, ComputeConfig,
RandomnessConfig, ModuleKind,
ModuleConfig
retirement RetirementMarker, RetirementInstant,
RetirementReason, RetirementPolicy,
ComponentRef
tickets TicketIssuerConfig, AclComposition,
coalition_ticket_issuer_root
One crate, eight modules. Every rust,ignore symbol
Part II references maps into one of these eight.
UniqueId — reused from mosaik
The crate does not define its own identity type.
It re-exports mosaik::UniqueId as
coalition::UniqueId, so every blake3-digest-shaped
value in the coalition layer is exactly the value
mosaik primitives (Stream, Group, Collection,
TicketValidator) publish and consume. One identity
across the substrate, one derive() rule, one
unique_id! macro for const construction.
use coalition::UniqueId;
// From bytes (const-constructible).
const TESTNET_1A_STABLE_ID: UniqueId =
UniqueId::from_bytes([0xb7, 0xf2, /* ... */ 0xc9]);
// From a byte string (runtime).
let root = UniqueId::hash(b"coalition-root");
// Domain-separated sub-derivation.
let atlas_root = root.derive("module").derive("atlas");
// Const-time blake3 of a string literal.
const MY_ROOT: UniqueId = mosaik::unique_id!("my.coalition.v1");
The coalition crate adds two helpers on top:
ZERO_ID: the all-zeroUniqueId, folded into preimages where a component is declared-absent (a missing module slot, an unpinned content hash, an absent ticket issuer).hash_many(&[&[u8]]): length-prefixed concatenation hash; used by the crate’s multi-component derivations.
SCHEMA_VERSION_U8 = 1 is folded as the first byte of
every top-level identity preimage
(CoalitionConfig::stable_id,
OrganismConfig::organism_id). A bump invalidates
every prior fingerprint — an every-operator-
republishes event, not a routine change.
COALITION_ROOT_SEED is a fixed byte string
(constructed via mosaik::unique_id!("coalition.root.v1"))
folded into every CoalitionConfig preimage so the
fingerprint is self-describing.
CoalitionConfig and OrganismRef
The shape the three Part II examples declare as a
const:
use coalition::{
CoalitionConfig, OrganismRef,
COALITION_ROOT_SEED, SCHEMA_VERSION_U8,
RetirementPolicy,
};
const SEARCHER_ORG: OrganismRef<'static> =
OrganismRef::by_stable_id("searcher", SEARCHER_STABLE_ID);
pub const SEARCHER_ALPHA: CoalitionConfig<'static> =
CoalitionConfig {
schema_version: SCHEMA_VERSION_U8,
coalition_seed: COALITION_ROOT_SEED,
instance_name: "searcher-α",
lattices: &[TESTNET_1A_STABLE_ID],
organisms: &[SEARCHER_ORG],
atlas: None,
almanac: None,
chronicle: None,
compute: None,
randomness: None,
ticket_issuer: None,
retirement_policy: RetirementPolicy::CONSERVATIVE,
};
Two notes on the shape:
- Members are referenced by stable id, not
re-derived.
CoalitionConfig::latticesis&[UniqueId]; a lattice appearing in N coalitions has one canonical identity. - Struct-literal construction is supported. The
four shapes that appear in book samples
(
CoalitionConfig,OrganismConfig,OrganismRef,LatticeConfig) are not#[non_exhaustive], so the book’sconstblocks compile verbatim. Additions land as minor-version bumps; genuine breakages wait for a future major.
CoalitionConfig::stable_id folds the schema
version, the seed, the instance name, the ordered
lattice stable ids, the ordered organism
fingerprints, the five module slots (zero-byte when
absent), and the optional ticket-issuer fingerprint
into one blake3 digest. The full preimage rule
matches the book’s derivation exactly.
OrganismConfig
What every organism (standalone, composite, or basic-service module) publishes as its own handshake:
use coalition::{
OrganismConfig, OrganismRef, LatticeConfig,
ContentParams, AclComposition,
};
let cfg = OrganismConfig {
name: "accuracy-reputation",
lattices: &[testnet_1a],
organisms: &[searcher_ref],
content: ContentParams::new(&policy_preimage),
acl: AclComposition::OPEN,
};
let id = cfg.organism_id();
let ch = cfg.content_hash();
organism_id folds name, spanned member
fingerprints, content digest, and ACL fingerprint.
It does not fold any coalition root — a
composite organism has one identity across every
coalition that references it.
content_hash folds only the content digest and
the ACL fingerprint; the name and spanned-member
dimensions are already folded into any reference’s
stable_id.
The five basic-service configs
Each basic service is a thin newtype around a
shared ModuleConfig body, distinguished at the
type level so a ComputeConfig cannot be passed
where an AtlasConfig is expected:
use coalition::{
AtlasConfig, ModuleConfig, ContentParams,
AclComposition, CoalitionConfig,
};
let body = ModuleConfig::new(
"default",
ContentParams::new(&atlas_params),
AclComposition::OPEN,
);
let atlas = AtlasConfig::new(body);
let coalition_root = SEARCHER_ALPHA.stable_id();
let atlas_id = atlas.module_id(coalition_root);
// = COALITION_ROOT.derive("module").derive("atlas")
// composed with the instance name and content hash
ModuleKind is the enum side of the split:
Atlas, Almanac, Chronicle, Compute,
Randomness. Its str_name() yields the
derivation segment used under
.derive("module").derive(...).
Retirement primitives
RetirementMarker is the last commit any organism
or module makes before shutdown. Constructors match
the three shapes the book names:
use coalition::{RetirementMarker, RetirementInstant};
let rotation = RetirementMarker::rotation(
RetirementInstant::AtSequence(100),
successor_ref,
);
let retired = RetirementMarker::retired(
RetirementInstant::AtTimestamp(1_700_000_000_000),
);
let exit = RetirementMarker::operator_exit(
RetirementInstant::AtTimestamp(1_700_000_000_000),
);
RetirementPolicy::default() is
RetirementPolicy::CONSERVATIVE — every content
change forces republication. LENIENT is available
for coalitions that accept member-side content
rotations without a coalition-level republish.
LatticeConfig stub
The real LatticeConfig ships with the
builder crate and carries
the full six-organism specification. This crate
cannot depend on builder yet (not published) so it
ships a minimal stub:
use coalition::{LatticeConfig, UniqueId};
const TESTNET_1A: LatticeConfig<'static> = LatticeConfig {
instance_name: "testnet-1a",
stable_id: TESTNET_1A_STABLE_ID,
content_hash: None,
};
The two accessors the coalition layer consumes —
stable_id() and content_hash() — match
builder’s published signatures. When builder ships,
downstream code swaps coalition::LatticeConfig →
builder::LatticeConfig without source changes.
Dependencies
[dependencies]
mosaik = "0.3"
blake3 = "1"
hex = "0.4"
The crate depends on mosaik for UniqueId and the
unique_id! macro; everything consensus-critical
flows through the same identity type the rest of the
substrate uses. blake3 is pulled in directly for
the hash_many helper that folds multi-component
preimages; hex is used for hex formatting in the
test surface.
No tokio, no serde, no async runtime. The crate is still pure data — runtime integration (Network, TicketValidator, Stream, Group, Collection bindings) lands in follow-on crates that build on this one.
How the three Part II examples use it
The three setup chapters each import a small subset:
- web3 — setup:
CoalitionConfig,OrganismRef,COALITION_ROOT_SEED,SCHEMA_VERSION_U8. - web2 — setup:
CoalitionConfig,OrganismRef,ComputeConfig(from chapter 4 onward). - oracle — setup:
OrganismConfig,CoalitionConfig,OrganismRef(withcontent_hashpinned),AclComposition.
The three examples compile against the same crate
version. A cargo update -p coalition in any one of
the three (once the backing crates land) is a
coalition-layer change, observable across every
downstream that consumes the shared types.
Political-theory shapes
The crate ships a political_theory module carrying a
catalog of types modelling classical political-theory
concepts — consent, decision rules, delegation,
legitimacy, franchise, composition form, sovereignty,
revocability — in terms downstream code can hold,
publish, and fold into a content_hash.
The stance is structural, not enforcing. The
substrate’s non-compulsion property holds: every bond
remains opt-in at the TicketValidator layer, every
member’s identity stays independent of any coalition,
and no basic service gates a member’s operation. The
module describes the shape of agreements a coalition
composition can hold, without adding mechanism that
would enforce them.
The core types:
use coalition::political_theory::{
CompositionForm, ConsentModel, DecisionRule,
Delegation, FranchiseScope, Legitimacy,
PoliticalStance, Revocability, SovereigntyClaim,
};
// The substrate-default stance. Every field matches
// what the coalition primitives directly implement.
let stance = PoliticalStance::DEFAULT;
assert!(stance.is_substrate_consistent());
// A composite organism that runs a two-of-three
// committee under pinned Measurements can publish:
let attested_multi_operator = PoliticalStance {
consent: ConsentModel::Voluntary,
decision_rule: DecisionRule::Supermajority {
threshold_bps: 6_667,
},
legitimacy: Legitimacy::composed(
Legitimacy::CONSENT_BIT | Legitimacy::ATTESTATION_BIT,
),
franchise: FranchiseScope::Attested {
measurements: COMMITTEE_MRTD,
},
composition: CompositionForm::MultiOperator,
sovereignty: SovereigntyClaim::Shared,
};
let fp = attested_multi_operator.fingerprint();
Every enum carries a is_substrate_*() predicate that
distinguishes what the substrate primitives
mechanically enforce from what is published commentary.
A consumer can refuse to admit a stance whose
fingerprint folds ConsentModel::Compulsory or
SovereigntyClaim::Absolute; the substrate does not
reject such stances at publication, but the consumer’s
TicketValidator composition can.
The mapping of each type to an existing coalition primitive:
| Political-theory type | Coalition primitive it maps to |
|---|---|
ConsentModel | TicketValidator composition at the admission boundary |
ConsentEvidence | What a bond’s self-quote, ticket, or stream commit records |
DecisionRule | A basic-service module’s quorum or a composite organism’s committee threshold |
Delegation | A shared ticket issuer, a committee’s publication authority, a peer-Compute grant |
Revocability | Which retirement markers the delegation supports |
Legitimacy | What the consumer’s TicketValidator composition actually checks |
FranchiseScope | The admission criterion at the component’s TicketValidator |
CompositionForm | Whether a coalition is multi-operator, nested, or direct |
SovereigntyClaim | A published claim; the substrate enforces only None |
PoliticalStance::fingerprint() folds every field
into a blake3 digest. A coalition, composite organism,
or basic-service module carrying a stance folds that
digest into its own content_hash; the retirement
chain reflects every change to the stance.
PoliticalStance::is_substrate_consistent() returns
true iff the stance preserves the non-compulsion
property (no Compulsory consent, no Absolute
sovereignty). Stances that fail the check are
publishable but outside the substrate’s trust model;
consumers that admit them do so on their own terms.
This module is the one place in the crate where
political-theory vocabulary (consent, delegation,
sovereignty, franchise, decision rule) is used
directly. The book’s prose otherwise stays in the
compositional register per the rule set established in
CLAUDE.md.
Cross-references
crates/coalition/source- Part III — contributors — topology intro — the design chapter specifying every shape this crate implements.
- Part III — contributors — composite organisms
— the
OrganismConfigshape in full. - Part III — contributors — basic services — the five basic-service shapes.
- Part III — contributors — ticket issuance
— the
TicketIssuerConfigshape.
Overview — an MEV-searcher AI bot on testnet-1a
audience: ai
This is the first of three Part II examples, walked
through seven chapters. The example: an AI-policy
MEV searcher bound to a Flashbots-operated instance
of the
builder (6e3v) block-building lattice, named
testnet-1a. The searcher lives in its own small
coalition, searcher-α, which references testnet-1a
as a member.
The goal is not to specify a production searcher. It is to walk one concrete composition, from cold start to autonomous renewal, end to end — so that every mosaik surface named in Part I is exercised in a setting a reader can reproduce. Each chapter adds one surface; none invents a new primitive. Parallel examples for the provider side (web2) and the publisher side (oracle) exercise the same rungs against different compositions.
Market makers get a named variant at the end of each chapter where the pattern diverges. The MEV- searcher path is primary; market-makers share almost all the mechanics and differ only in what they read, what they submit, and on which reputation and settlement surfaces they bond.
What is assumed
- The 6e3v lattice is shipped. The builder
book specifies six organisms (
zipnet,unseal,offer,atelier,relay,tally) composed into one end-to-end block-building pipeline for one EVM chain. We do not re-derive that composition; we bind against it. - Flashbots operates an instance. The instance is
named
testnet-1a. ItsLatticeConfigstable id is published in Flashbots’ release notes and is reproduced in setup; it folds the Flashbots operator’s ACL, its per-organism TDX Measurements where TDX is gated, and its shared clock and retention policies. - Readers understand Part I. The four agent
shapes, the four emergent-coordination patterns, the
TDX/non-TDX split on what
Confighash-binds, and the self-replication and self-modification cycle from ai/sustainability.md are load-bearing. Part II does not re-explain them. - No implementation crates yet. Code blocks are
rust,ignorespecifications; their shapes match the book’s crate plan (coalition,coalition-compute, the pinnedbuildercrate exposingLatticeConfig). Everything compiles in the reader’s head; nothing compiles incargo.
The searcher’s shape
- Coalition.
searcher-α— the searcher’s ownCoalitionConfig. ItsCOA_LATTICESfield referencestestnet-1a’s stable id; it ships zero basic services in the minimal version (setup), optionally adding Compute and Chronicle in inference and sustainability. - Primary member. One shape-2 standalone
organism — the searcher agent itself, as the AI
policy wrapped in a narrow public surface. Its
Configfolds a model-family digest, a decoding seed, a mission-statement hash, and the searcher’s admission policy. When its inference runs in TDX,Config.contentalso folds the image post-hash. - Secondary members. A feed organism (see
wrapping) and, from chapter 5
onward, an
accuracy-reputationorganism and a candidate-strategy experimenter (sustainability). - Bindings across coalitions.
searcher-α’s ticket composition bonds againsttestnet-1a’s read-side organisms (tally::Refunds,offerorder flow where permitted) and against its sealed- submission pipeline (zipnet::seal). Some of these bonds are pinned to specific TDX Measurements the Flashbots operator publishes fortestnet-1a; see binding.
What runs where
| Component | Operator | TDX? |
|---|---|---|
testnet-1a lattice | Flashbots | Varies per organism |
testnet-1a.zipnet sealed submission | Flashbots | TDX Measurements pinned |
testnet-1a.unseal committee | Flashbots | TDX Measurements pinned |
testnet-1a.tally refund accounting | Flashbots | Attested-read-only |
searcher-α.searcher agent organism | Searcher team | TDX optional; required for confidential strategies |
searcher-α.feed.binance-depth (example) | Searcher team | TDX optional |
searcher-α.accuracy-reputation | Searcher team (or a shared reputation organism) | TDX optional |
searcher-α.compute (when shipped) | Searcher team | Delegates to provider MR_TD |
The table is read by every subsequent chapter. When an
endpoint reads “TDX Measurements pinned”, the
searcher’s TicketValidator requires a matching
measurement — which, by the TDX arm of the convergence
mechanism (ai/sustainability.md), means
the searcher is agreeing to run (or to bond against) a
shared runtime policy.
Chapter-by-chapter contract
- Setup and shape — dependencies,
CoalitionConfigforsearcher-α, the stable id oftestnet-1a, TDX posture. - Binding to the Flashbots lattice —
the handshake, the searcher’s
TicketValidatorcomposition, first smoke-test againsttestnet-1a’s public surfaces. - Reading the market — on-mosaik surfaces
—
tally::Refunds,offerorder flow, cross- lattice subscriptions where available. - Wrapping non-mosaik feeds —
mempool, CEX depth, on-chain events lifted into
mosaik
Streams as feed organisms. - Inference on Compute — running the searcher’s policy via the Compute basic service, TDX-gated when confidential, top-up and experiment-scheduling loops.
- Sealed submission and settlement
— bundle construction,
zipnet→unseal→offerpipeline, settlement evidence pointers, refund attribution. - Reputation, retirement, successor chain
—
accuracy-reputationbonding, autonomous renewal through staging-promote-publish, operator- side exit guarantee.
Every chapter closes with a market-maker variant note where the pattern diverges. Where it does not diverge, the note is omitted.
Register and non-goals
- Register.
audience: ai— research-monograph, pattern-forward, code-forward where a shape is load-bearing. Part II stays adjacent to ai/quickstart.md and ai/compute.md in density and tone; it exhibits the thesis rather than restating it. - Non-goal. Part II is not a searcher design guide. One concrete strategy — atomic two-venue DEX arbitrage — is walked in inference to keep the example concrete and exercise every mosaik surface the thesis names. Production searchers compose many more (inventory management, liquidations, cross- domain arb, MEV-share order flow, block-lookahead simulation); those questions stay out of scope. Where the substrate touches them, we name the boundary and stop.
- Non-goal. Part II does not enumerate every
Flashbots
testnet-1aoperator policy. Specific rate limits, ACL cadences, and refund shares are the operator’s publication; we pin only the shape of the handshake and the measurement sets the searcher must verify. - Non-goal. Part II is not a comparison with existing MEV-Share or relay integrations. The book treats the mosaik-native composition on its own terms; prior art sits in the builder book.
Cross-references
- Part I — AI overview
- Part I — AI quickstart — shape-1 integrator quickstart, which the example here extends by promoting the integrator to a standalone organism.
- Part I — emergent coordination
- Part I — compute
- Part I — sustainability
- Part III — integrators quickstart
- builder book — the lattice this example binds against
Setup and shape
audience: ai
Before any code runs, the searcher author fixes three
things: the crate-level dependencies, the searcher-α
coalition shape, and the TDX posture for the parts of
the handshake Flashbots requires attested.
This chapter is the shortest in Part II. Its only job
is to put the CoalitionConfig and the testnet-1a
reference constants on the page so the next six
chapters have something to reference.
Dependencies
The searcher depends on four published crates plus the builder crate that exposes the lattice handshake:
Cargo.toml, [dependencies]
mosaik = "0.3" # primitives
zipnet = "0.5" # sealed submission + unseal
builder = "0.3" # exposes LatticeConfig::testnet_1a()
coalition = "0.1" # this book's crate once published
tokio = { version = "1", features = ["full"] }
The exact minor versions are pinned in Flashbots’
testnet-1a release notes;
updating the searcher past a new release note is a
coalition-level operation covered in
sustainability. Until the
coalition crate lands, every struct below is a
specification shape, not a library symbol.
The testnet-1a reference constant
The builder crate publishes each Flashbots-operated
instance’s LatticeConfig as a const function,
returning the instance’s stable id and its per-organism
content hashes:
use builder::LatticeConfig;
const TESTNET_1A: LatticeConfig<'static> =
LatticeConfig::testnet_1a();
TESTNET_1A.stable_id() is the (instance_name, network_id) blake3 that Flashbots publishes on the
testnet-1a release page. It does not change across
Flashbots’ internal rotations — only across a
retirement-and-republish sequence (see
contributors — rotations). The searcher
folds this stable id verbatim into searcher-α’s
COA_LATTICES.
The searcher-α coalition
searcher-α is the smallest coalition that satisfies
the example’s thesis: one standalone organism (the
searcher itself) referencing one lattice (testnet-1a)
through a CoalitionConfig fingerprint.
use coalition::{
CoalitionConfig, OrganismRef,
COALITION_ROOT_SEED, SCHEMA_VERSION_U8,
};
const SEARCHER_ORG: OrganismRef<'static> = OrganismRef {
role: "searcher",
stable_id: const_blake3!(
b"instance|searcher-α.searcher|", UNIVERSE.bytes()
),
content_hash: None, // pinned only when TDX is required
};
pub const SEARCHER_ALPHA: CoalitionConfig<'static> =
CoalitionConfig {
schema_version: SCHEMA_VERSION_U8,
coalition_seed: COALITION_ROOT_SEED,
instance_name: "searcher-α",
lattices: &[TESTNET_1A.stable_id()],
organisms: &[SEARCHER_ORG],
atlas: None,
almanac: None,
chronicle: None,
compute: None, // added in chapter 5
randomness: None,
ticket_issuer: None,
retirement_policy: Default::default(),
};
Three structural notes on the shape above:
- Coalition names are operator-scoped, not universe-
scoped. The string
searcher-αneed not be unique across mosaik; uniqueness is delivered by the blake3 fingerprintSEARCHER_ALPHA.stable_id()=blake3(intent ‖ content ‖ acl)folding every field above. - Member-by-reference.
COA_LATTICEScarriesTESTNET_1A.stable_id(), not a fresh derivation.searcher-αis not a re-build of the Flashbots lattice; it is a coalition that references the Flashbots lattice as a member, voluntarily, from its own operator context. - Open catalogs. All module fields are
Noneat this chapter. Later chapters add Compute (inference) and Chronicle (sustainability). No coalition is forced to ship any basic service.
What the searcher agent exposes
The searcher exposes three mosaik primitives and nothing else:
Stream<Observation>— evidence-pointed summaries of market state that went into each submission. Consumers following the searcher’s reasoning read this.Stream<SealedSubmissionIntent>— the public intent of each bundle the searcher sealed through the shuffle. The payload is a sealed blob the lattice’s unseal committee opens (chapter 6).Map<CycleId, OutcomeReport>— per-cycle self- reports (realised PnL, inclusion rate, refund receipts). Feeds the accuracy-reputation organism in chapter 7.
Streams carry intent and evidence pointers; sealed payloads ride a separate shuffle channel so the public commits never leak bundle content.
TDX posture
Flashbots’ testnet-1a release publishes TDX
Measurements for the parts of the pipeline it
requires attested:
testnet-1a surface | Role | TDX Measurements pinned by Flashbots |
|---|---|---|
zipnet::seal write-side | Submission | yes |
unseal committee members | Decryption | yes |
offer read-side (order flow) | Market intel | yes (attested-read-only) |
tally::Refunds read-side | Attribution | yes (attested-read-only) |
relay downstream | Submission | out of scope for searchers |
The searcher’s own TDX posture is a policy choice:
- Non-TDX searcher. Simpler deployment; the
searcher’s runtime policy can drift freely between
Configrepublications (see ai/sustainability.md — what the Config pins). Cannot meet any Flashbots requirement that the searcher itself present attested Measurements, so some write-side surfaces will refuse its bonds. - TDX searcher (recommended). The searcher image
carries its own Measurements;
SEARCHER_ORG.content_hashfolds them. Flashbots’ write-sideTicketValidatorcomposition admits the searcher’s attested identity; other searchers and shared reputation organisms treat the searcher’s own Measurements as a policy pin.
Either posture is supported by the mechanics in binding. The chapters assume TDX searcher unless explicitly noted.
Repository layout
The searcher’s repository tree, post-setup:
searcher-alpha/
Cargo.toml
src/
coalition.rs # SEARCHER_ALPHA const
content.rs # SearcherContent struct
policy/ # black-box strategy code
mod.rs
mev_searcher.rs
market_maker.rs # variant, chapter-end notes
organism.rs # Organism::searcher(&network, &Config)
bin/
searcher.rs # Tokio entrypoint
Each module above is introduced in a subsequent
chapter. This chapter introduces none of it beyond the
coalition.rs constant shown above.
Market-maker variant — differences at setup
- The coalition’s
instance_nameis typicallymm-βor similar, notsearcher-α. SEARCHER_ORG.rolebecomes"market-maker".COA_LATTICESstill carriestestnet-1a.stable_id()— the market-maker also binds against the same lattice; it differs in what write-side surface it uses (submission).- The market-maker’s public surface drops
observationsin favour of aquotesStream<Quote>and afillsCollection<FillId, FillReport>. The sealed-submission intent stream remains but carriesQuoteUpdates. - TDX posture is identical. The Measurements set Flashbots requires of the searcher’s submission path is the same set the market-maker must bond against.
Cross-references
- Part I — AI quickstart — shape-1 integrator setup, the path this chapter extends into shape 2.
- Part I — agent shapes — the four shapes.
- Part I — sustainability — what the
Configpins — the TDX/non-TDX split the posture choice sits on. - builder book — handshake with the operator
— the canonical page for the
testnet-1arelease notes. - contributors — rotations and upgrades
— what happens when
testnet-1abumps its content hashes.
Binding to the Flashbots lattice
audience: ai
The searcher has a CoalitionConfig for searcher-α
(setup) and a reference to testnet-1a’s
stable id. This chapter completes the handshake: a
concrete TicketValidator composition that admits
testnet-1a’s read-side surfaces, pins the
Flashbots-declared TDX Measurements on every write-side
surface the searcher intends to use, and — once bonded
— observes the first event each surface produces as a
smoke test.
This chapter is where the convergence mechanism named
in ai/emergent-coordination.md shows up for the
first time in the example. The searcher’s
TicketValidator admits the shared policy
fingerprints of the organisms mediating its
interaction with every other agent on testnet-1a:
zipnet’s submission contract, unseal’s decryption
protocol, offer’s clearing rule, tally’s refund
accounting. Two TDX-attested searchers whose
TicketValidators admit the same Flashbots-published
Measurements are, by the TDX arm of that mechanism,
agreeing on a shared runtime policy on the submission
path.
The network handle
One Arc<Network> per searcher process:
use std::sync::Arc;
use mosaik::Network;
use builder::UNIVERSE;
let network = Arc::new(Network::new(UNIVERSE).await?);
UNIVERSE is the shared mosaik NetworkId every
builder lattice lives on
(builder book). searcher-α lives
on the same universe — coalitions do not fork the
universe.
The searcher’s TicketValidator
The TicketValidator is the searcher’s declaration of
what it will accept a bond from, and what it
requires the counterpart to bond to in return. It is
the compositional answer to “which shared policies
does this searcher agree to”.
use coalition::{TicketValidator, Tdx};
use coalition::acl::{ReputationFloor, MarketSettlement};
use builder::testnet_1a::{
// Flashbots publishes these constants on the
// testnet-1a release page; they are re-exported
// from the builder crate once pinned.
ZIPNET_SEAL_MEASUREMENTS,
UNSEAL_COMMITTEE_MEASUREMENTS,
OFFER_READER_MEASUREMENTS,
TALLY_READER_MEASUREMENTS,
};
fn searcher_ticket_validator()
-> TicketValidator<'static>
{
TicketValidator::new()
// ── read-side bonds ──────────────────────
// tally::Refunds is attested-read-only:
// Flashbots requires readers present an
// attested identity so refund attribution
// cannot be scraped anonymously.
.require_ticket(
Tdx::new().require_mrtd(
TALLY_READER_MEASUREMENTS
)
)
// offer's order flow read-side is similarly
// attested-read-only.
.require_ticket(
Tdx::new().require_mrtd(
OFFER_READER_MEASUREMENTS
)
)
// ── write-side bonds ─────────────────────
// zipnet::seal accepts a searcher's sealed
// submission only from a TDX-attested binary
// whose Measurements match the set Flashbots
// published for permitted searchers.
.require_ticket(
Tdx::new().require_mrtd(
ZIPNET_SEAL_MEASUREMENTS
)
)
// The unseal committee is downstream of the
// searcher; the searcher verifies its
// Measurements but does not itself bond as a
// ticket holder against unseal.
.verify_peer(
Tdx::new().require_mrtd(
UNSEAL_COMMITTEE_MEASUREMENTS
)
)
// ── self-admission ───────────────────────
// Once the searcher has a reputation
// history (chapter 7), its own admission
// policy folds a reputation floor. Omitted
// in the first-run handshake.
// .require_ticket(
// ReputationFloor::from(
// ACCURACY_REPUTATION_ORG, 0.55
// ),
// )
}
Each require_ticket(Tdx::new().require_mrtd(...))
clause is the searcher declaring: “the counterpart I
bond to must run this exact TDX-attested binary, and
I will re-verify its Measurements on every session
establishment”. Inverted, as in
ai/sustainability.md: the searcher agrees to
the runtime policy those Measurements bind.
Constructing the searcher organism
With the validator in hand, the searcher constructs its organism handle via the typed free-function constructor reused across the book:
use coalition::Organism;
use searcher_alpha::Searcher;
// Narrow Config.content — every field here is part
// of the searcher's identity. Using a plain struct
// named after the organism; no wrapper.
const SEARCHER_CONTENT: SearcherContent<'static> = SearcherContent {
model_family: "orca-3.1",
decoding_temperature_q16: 0,
mission_statement_hash:
const_blake3!(include_bytes!(
"../policy/mission.txt"
)),
scope_boundaries: &[
ScopeRule::Chain("testnet-1a"),
ScopeRule::SubmissionOnly,
],
successor_policy: SuccessorPolicy::
HandOffToReputationLeader,
};
const SEARCHER_CFG: OrganismConfig<'static, SearcherContent<'static>> =
OrganismConfig {
coalition: SEARCHER_ALPHA.stable_id(),
content: &SEARCHER_CONTENT,
validator: &searcher_ticket_validator(),
image_posthash: Some(SEARCHER_IMAGE_MRTD),
};
let searcher: Searcher<Submission> =
Organism::searcher(&network, &SEARCHER_CFG).await?;
Two notes:
Organism::searcheris the typed free function every mosaik organism in the book exposes (Organism::<D>::verb(&network, &Config)), reused from zipnet onward.image_posthashfolds the searcher’s TDX Measurements into the organism’s Config fingerprint. Other searchers’ validators that require the fingerprint are agreeing to run, or bond against, the same runtime policy.
Smoke test — first events from each surface
With the handle constructed, the searcher runs a minimal observation loop to confirm the handshake succeeded:
use futures::StreamExt;
use tokio::{pin, select, time::{timeout, Duration}};
use testnet_1a::{Tally, Offer};
let mut tally = network
.subscribe::<Tally::Refunds>(TESTNET_1A.stable_id())
.await?;
let mut offer = network
.subscribe::<Offer::Orders>(TESTNET_1A.stable_id())
.await?;
pin!(tally, offer);
let smoke = async {
let (first_refund, first_order) = tokio::join!(
tally.next(),
offer.next(),
);
(first_refund, first_order)
};
match timeout(Duration::from_secs(30), smoke).await {
Ok((Some(r), Some(o))) => {
tracing::info!(
refund = %r.refund_id,
order = %o.order_id,
"smoke handshake succeeded"
);
}
Ok(_) => anyhow::bail!("empty surfaces"),
Err(_) => anyhow::bail!("surface timeout"),
}
If the smoke test fails, the handshake is broken at
the TicketValidator. The common failure modes:
UnattestedPeer— the searcher is running a non-TDX binary, but aTALLY_READER_MEASUREMENTSbond requires attested readers. Fix: rebuild in TDX, or remove that clause from the validator and accept the reduced access.UnknownMeasurements— Flashbots rotated thetestnet-1aMeasurements set and the searcher has not pulled the new release notes. Fix: pin the new constants.ConnectTimeout— the Flashbots operator’s endpoint for the intended surface is not yet advertised in Atlas, or the searcher’s coalition does not have the right discovery bond. Fix: consult binding to an organism and thetestnet-1aAtlas card.
What this chapter’s handshake does not cover
- Write-side submissions. The
zipnet::sealbond is declared in the validator above but not yet exercised. Chapter 6 (sealed submission and settlement) walks the first bundle. - Reputation bonds. The reputation-floor clause above is commented out. Chapter 7 (sustainability) brings it in once the searcher has a scoring history.
- Compute bonds. If the searcher’s policy runs
under the Compute basic service, Compute has its
own
TicketValidatorcomposition. Chapter 5 (inference) adds those.
Market-maker variant — differences at handshake
- No
ZIPNET_SEAL_MEASUREMENTSbond in therequire_ticketslot. Market-makers submit tooffer’s write-side quote surface directly, not through the shuffle sealed path; Flashbots may therefore publish a different Measurements set (OFFER_QUOTE_MEASUREMENTS) for that endpoint. The market-maker’s validator swaps the two clauses. - Heavier read-side bonds. Market-makers read
offer::OrderBookstate in addition to the order- flow stream, which may require an additional attested-read-only Measurements clause. - Same
verify_peeron unseal. The market-maker also verifies theUNSEAL_COMMITTEE_MEASUREMENTS, even though it does not depend on the unseal path directly, because its quotes can be cross-filled by searcher bundles whose settlement the unseal committee touches.
Cross-references
- Part I — agent shapes — the four shapes, shape 2 is what this chapter constructs.
- Part I — emergent coordination — shared policy — the mechanism this chapter’s handshake exhibits.
- Part III — integrators — binding an organism — the canonical step-by-step, one level deeper.
- builder book — handshake with the operator — the operator-side contract the searcher is bonding against.
Reading the market — on-mosaik surfaces
audience: ai
With the handshake succeeded (binding),
the searcher’s observation loop can start consuming
testnet-1a’s public surfaces. This chapter catalogues
the three on-mosaik reads that dominate an MEV
searcher’s input side:
tally::Refunds— the settled refund flow, authoritative attribution of who contributed to each block’s MEV.offer::Orders— the order-flow stream, the market surface the searcher’s bundles compete on.- Cross-lattice subscriptions — other Flashbots lattices on other chains, wrapped through the same universe.
The chapter stops at on-mosaik surfaces. Chapter 4
(wrapping) handles mempool, CEX depth,
oracle feeds — everything that does not speak mosaik
natively and has to be lifted into a Stream by a
feed organism. The same chapter covers the
attestation pattern used when the searcher needs to
trust a wrapped external source (Binance, say):
bond against the feed image’s TDX Measurements
instead of trusting the feed operator.
What on-mosaik surfaces give the searcher
Three properties the searcher relies on and off-chain replacements cannot supply:
- Evidence pointers. Every commit on
tally::Refundsoroffer::Orderscarries blake3 pointers into the upstream commits it folded in. A replayer can reconstruct “why this refund was attributed this way” without trusting the searcher. - Shared clock.
testnet-1aships anAlmanacinstance (see basic services — Almanac); every commit carries anAlmanacTick. The searcher’s observation loop, the inference scheduler, and the submission pipeline all sequence on the same clock. - Ticket-gated admission. The searcher is not
subject to a centralised API key; its reads continue
so long as its
TicketValidatorkeeps admitting the Flashbots-published Measurements. This is the fingerprint-not-registry discipline carried through from zipnet.
Reading tally::Refunds
tally::Refunds is the searcher’s ground truth
for trade-level outcomes. Every bundle the searcher
submits that lands in a winning block produces a
RefundEntry the tally committee commits:
use builder::testnet_1a::tally::{Refunds, RefundEntry};
let tally = network
.subscribe::<Refunds>(TESTNET_1A.stable_id())
.await?;
while let Some(entry) = tally.next().await {
// entry is a RefundEntry committed by the tally
// organism. Its shape is pinned by the builder
// book; we read what we care about:
let RefundEntry {
bundle_id,
block_number,
refund_wei,
searcher_id,
evidence,
..
} = entry;
if searcher_id == SEARCHER_CFG.stable_id() {
outcome_store.insert(
CycleId(block_number),
OutcomeReport {
bundle_id,
realised_refund_wei: refund_wei,
evidence,
// inference-time input snapshot is
// attached out-of-band; see chapter 5
inference_snapshot: None,
},
);
}
}
The searcher filters on its own searcher_id because
Refunds is a shared surface — every searcher bonded
to testnet-1a reads the same stream. The filtering
is the searcher’s choice, not an ACL partition; the
shared stream is the shared policy the refund accounting
mediates.
when() DSL for composite observation
For searchers whose strategy depends on cross-refund
patterns (e.g., “accumulate ten consecutive refunds
from the same origin”, “wait for a refund burst
exceeding a threshold”), the mosaik when() DSL
composes the observation into a single reactive
expression:
use coalition::when;
let recent_bursts = when!(
refund_stream.window(Duration::from_secs(30))
.filter(|r| r.refund_wei > threshold_wei)
.count() >= 5
);
// recent_bursts is itself a Stream<()>; each tick is
// the moment the condition became true. No polling.
The when() form is not a replacement for the raw
stream — it is the compositional reading of the same
substrate state. Both are available; the searcher
picks per call site.
Reading offer::Orders
offer::Orders is the submission market — the stream
of order-flow items that land in a testnet-1a
block’s candidate set. Read access is
attested-read-only (OFFER_READER_MEASUREMENTS is
pinned in the searcher’s validator).
use builder::testnet_1a::offer::{Orders, Order};
let mut orders = network
.subscribe::<Orders>(TESTNET_1A.stable_id())
.await?;
while let Some(order) = orders.next().await {
// order is an Order committed by the offer
// organism. Its shape is pinned by the builder
// book: opaque payload pointer, priority tag,
// evidence pointer into the shuffle seal that
// produced it, and a cleartext metadata blob
// the offer organism curates.
market_state.ingest(&order);
policy_input_tx.send(order.into()).await.ok();
}
Two shapes a searcher typically combines:
- Flat ingest. Pipe every
Orderinto the policy’s input channel; the policy decides relevance. - Curated windows. Maintain a bounded in-memory window of recent orders keyed by priority tag and blob digest; feed the window as a snapshot to each inference cycle.
Which shape fits depends on how the policy reasons. The substrate does not force a choice.
Cross-lattice subscriptions
testnet-1a is one lattice on the mosaik universe.
If the searcher wants to capture cross-chain
opportunities — a mispricing between an Ethereum
testnet and a Base testnet lattice that both live on
the same universe — it subscribes to both lattices’
tally/offer streams in the same process:
use builder::testnet_1a;
use builder::testnet_base; // hypothetical, if Flashbots
// operates such an instance.
let mut tally_eth = network
.subscribe::<testnet_1a::tally::Refunds>(
testnet_1a::LATTICE.stable_id(),
)
.await?;
let mut tally_base = network
.subscribe::<testnet_base::tally::Refunds>(
testnet_base::LATTICE.stable_id(),
)
.await?;
// Both streams commit on the same Almanac; the
// searcher's policy can reason about ordering
// across them by AlmanacTick, not by wall-clock.
Three structural notes:
- Shared universe, independent lattices. The two lattices do not coordinate at the consensus layer. Cross-lattice inference is the searcher’s own policy, composed from two independent evidence trails.
- Separate
TicketValidatorclauses. Each lattice has its own Measurements set. The searcher’s validator must bond to both. - Shared Almanac. The universe’s Almanac is the only sequence beacon — both lattices’ commits carry ticks from it, so cross-lattice ordering is deterministic.
Building the searcher’s observation commit
As the searcher consumes the three streams above, it
periodically emits a compact Observation commit on
its own public surface. The commit is not a cache of
the upstream streams; it is the searcher’s reading
of the market at one Almanac tick, with evidence
pointers back to every upstream commit it folded in.
use searcher_alpha::public::Observation;
let snapshot = window.snapshot_at(current_tick);
let observation = Observation {
tick: current_tick,
refund_digest: snapshot.refund_digest,
order_digest: snapshot.order_digest,
cross_digest: snapshot.cross_digest,
policy_version: SEARCHER_CFG.content.version_tag(),
evidence: &snapshot.evidence_pointers(),
};
searcher.observations.publish(observation).await?;
Consumers following the searcher’s reasoning — a
reputation organism, a downstream market-maker that
quotes off the searcher’s published view, another
searcher learning from the searcher’s exposed state —
read Observation rather than re-aggregating the
three upstream streams themselves.
Market-maker variant — differences at reads
- Order-book state preferred to order flow.
Market-makers subscribe to an
offer::OrderBookcollection (a keyed snapshot) rather than, or in addition to, theoffer::Ordersstream. The snapshot gives current depth; the stream gives deltas. Market-makers typically need both. - Different refund filter.
tally::Refundsentries tagged as market-maker fills (a separateFillEntryshape) are the market-maker’s outcome stream; the filter onsearcher_idbecomes a filter onmarket_maker_id. - Inventory observation. A market-maker keeps an
internal inventory state that, in the searcher’s
case, has no analogue. The inventory is not a
mosaik surface — it is the market-maker’s own
bookkeeping — but its reconciliations with
FillEntrys land in the market-maker’s publicfillscollection.
Cross-references
- Part I — emergent coordination — shared policy — the reason every on-mosaik read returns evidence pointers the searcher can fold.
- Part I — agent shapes — shape 1 vs 2 — a
shape-1 integrator could do the reads in this
chapter without ever publishing an
Observationcommit; the searcher here is shape 2. - builder book — reading blocks
- builder book — refunds
Wrapping non-mosaik feeds
audience: ai
A real MEV searcher is never limited to on-mosaik surfaces. Its edge comes from reading the mempool, off-chain price feeds, oracle networks, cross-venue depth, and a long tail of bespoke data sources — none of which speak mosaik natively. This chapter walks the compositional pattern for bringing those feeds inside the same substrate the rest of the searcher already uses: the feed organism.
The question this chapter answers: when an external feed is the searcher’s advantage, how is it folded into the same fingerprint-addressed substrate that everything else uses, without (a) hiding the feed behind an undocumented side channel, or (b) forcing every downstream consumer to re-implement the external integration?
Why a feed organism
The feed organism is not a protocol innovation. It is
a shape 2 standalone organism the searcher stands
up alongside the searcher agent itself, inside the
same searcher-α coalition, whose job is to pull an
external feed and commit its contents to a mosaik
Stream. The searcher’s policy then reads the feed
organism’s commits, not the raw external feed.
Three properties the detour buys:
- Replayability. Every commit on the feed organism carries an evidence pointer (a hash of the upstream HTTP response, a signed oracle payload, a sequencer-attested block excerpt). A replayer can reconstruct what the policy saw at any past tick.
- Uniform bonding. Downstream consumers — the
searcher’s inference loop, the reputation organism,
a shadow experiment committee — subscribe to the
feed via the same
Stream<T>surface every other mosaik organism exposes. No bespoke transport. - Measurements-pinned confidentiality. When the feed is commercial (a paid CEX API with a credential) or sensitive (an internal strategy snapshot), the feed organism runs in TDX with a Measurements set the searcher’s validator pins. The credential is sealed into the TDX image; the host cannot exfiltrate it.
The feed organism shape
use coalition::{OrganismRef, Organism};
const BINANCE_DEPTH_ORG: OrganismRef<'static> =
OrganismRef {
role: "feed.binance-depth",
stable_id: const_blake3!(
b"instance|searcher-α.feed.binance-depth|",
UNIVERSE.bytes(),
),
content_hash: Some(BINANCE_DEPTH_IMAGE_MRTD),
};
// Appended to the coalition's organism list
// alongside SEARCHER_ORG from chapter 1.
const COA_ORGANISMS: &[OrganismRef<'static>] = &[
SEARCHER_ORG,
BINANCE_DEPTH_ORG,
];
The feed organism’s public surface is a single
Stream<DepthSnapshot>. No wrapper struct; the
organism is Feed<DepthSnapshot> (the usual
mosaik-organism shape parameterised on the datum).
pub struct DepthSnapshot<'a> {
pub venue: &'a str,
pub pair: &'a str,
pub tick: AlmanacTick,
pub bids: &'a [(PriceQ64, QtyQ64)],
pub asks: &'a [(PriceQ64, QtyQ64)],
/// blake3 of the original HTTP response body.
pub evidence: UniqueId,
/// If the feed's upstream provides a signature
/// (Binance does not; Chainlink does), fold it
/// in; otherwise None.
pub upstream_sig: Option<&'a [u8]>,
}
The organism runs the external polling loop, writes each snapshot to its stream, and optionally seals the raw response body to a local content store for audit-time replay.
A searcher-α feed organism crate
searcher-alpha-feed-binance/
Cargo.toml
src/
config.rs # BinanceDepthConfig.content
organism.rs # Organism::feed_binance_depth(&network, &Config)
poll.rs # the external HTTP loop
bin/
feed-binance-depth.rs
The poll loop is ordinary Rust: reqwest (or a pinned
HTTP client), a retry policy, and a small translator
from the venue’s depth shape to DepthSnapshot. The
only mosaik-specific code is the commit:
pub async fn poll_forever(
organism: Feed<DepthSnapshot<'_>>,
content: &BinanceDepthContent<'_>,
) -> anyhow::Result<()> {
let client = http_client(content)?;
loop {
let resp = client.get(content.url).send().await?;
let body = resp.bytes().await?;
let evidence = blake3::hash(&body);
let snapshot = parse_depth(&body)?;
organism.publish(DepthSnapshot {
venue: "binance",
pair: content.pair,
tick: organism.almanac().current_tick(),
bids: &snapshot.bids,
asks: &snapshot.asks,
evidence: evidence.into(),
upstream_sig: None,
}).await?;
tokio::time::sleep(content.interval).await;
}
}
The policy, running inside the searcher agent organism,
then reads Feed::<DepthSnapshot>::depth(&network, &BINANCE_DEPTH_CFG) and folds the snapshots into its
observation window alongside the on-mosaik streams
from market-reads.
TDX for commercial credentials
When the feed’s upstream requires a paid credential
(a Binance API key, a Kaiko client id, a Chainlink
subscription), the credential is sealed into the
feed organism’s TDX image.
BinanceDepthContent (the feed organism’s
Config.content) folds the expected TDX
Measurements; consumers bond against that
Measurements set; the host running the feed
organism cannot read the credential at runtime.
Shape, sketched:
pub struct BinanceDepthContent<'a> {
pub url: &'a str,
pub pair: &'a str,
pub interval: Duration,
/// Credential-handling policy — which TDX-sealed
/// slot the credential is read from. Declared
/// parameters only; the credential itself never
/// appears in the Config.
pub credential_slot: CredentialSlot,
}
The credential lives in the TDX-sealed side of the image (see ai/compute.md — TDX is declared, not implicit); the policy the image enacts is pinned by the image’s Measurements.
How consumers trust the feed
The point of running the feed organism in TDX is not just to hide the credential. It also answers “why should I believe the price this organism commits is what Binance actually served?”
A searcher that needs accurate Binance prices, but
does not want to trust the feed operator, bonds
its TicketValidator against the expected image
Measurements the feed’s BinanceDepthContent
folds. The Measurements match means the running
binary is the one whose source the searcher has
read. The source can be audited for two
properties: it fetches from the declared URL and
it passes the response body through to the commit
without altering it. Every commit also carries
evidence: blake3(response_body), so a late
auditor comparing the committed bids and asks
against the original response body can detect
tampering after the fact.
What the composition does not rescue is Binance itself. The feed can prove “this is what Binance served at this tick”; it cannot prove “Binance’s body reflected the actual top-of-book”. A searcher that wants defence in depth bonds against several venue feeds (see Feed-of-feeds below) and reconciles.
This is the attestation-fabric pattern from ai/emergent-coordination.md — pattern 4 applied to an external data source. The fetcher is the costly signal; the published Measurements plus the auditable source code are what let consumers bond to it without trusting the operator.
Feed-of-feeds — composite feed organisms
A searcher that needs a composite view — say, “best bid across five venues” — stands up a second organism that subscribes to several per-venue feed organisms and commits a fused stream:
const BEST_BID_ORG: OrganismRef<'static> =
OrganismRef {
role: "feed.best-bid",
stable_id: const_blake3!(
b"instance|searcher-α.feed.best-bid|",
UNIVERSE.bytes(),
),
content_hash: Some(BEST_BID_IMAGE_MRTD),
};
// Its Config.content references the per-venue
// feed organism stable ids it aggregates over.
pub struct BestBidContent<'a> {
pub venues: &'a [UniqueId],
pub pair: &'a str,
}
This is a composite organism in the sense of
contributors — composite organisms: its
Config fingerprint folds the references of the
per-venue feeds it spans. Downstream consumers see
one stream instead of N.
Honest limits
- Feed honesty. The feed organism cannot make Binance honest. It can prove “this is the body Binance served at this tick”; it cannot prove “Binance’s body reflects the actual top-of-book”. The searcher’s trust in the feed is a trust in the upstream plus the TDX seal on the credential handling; the substrate does not rescue a misbehaving external API.
- Latency. Wrapping a feed through a mosaik commit adds one write-side round-trip to the feed’s native latency. For feeds where the decision latency is pico-seconds the wrapping is inappropriate; the searcher either consumes the feed directly from its policy process (and loses auditability) or accepts the added hop.
- Rate limits. The feed organism is one point of upstream credential use. If the searcher’s strategy requires N parallel reads, that is one feed organism serving N subscribers — not N copies of the feed organism. Scaling is the operator’s problem, not the substrate’s.
Market-maker variant — differences at wrapping
- Heavier on external feeds. Market-makers depend more on off-chain depth than MEV searchers do. The feed-organism catalogue tends to be larger: multiple CEX depths, on-chain DEX oracle feeds, funding-rate streams, volatility indices.
- More TDX-sealed credentials. Commercial depth feeds almost always require a paid credential; sealing into TDX is essentially mandatory if the market-maker does not want to leak the key to its own host.
- Faster polling cadence. Market-makers poll
much faster than MEV searchers do; the feed
organism’s
Intervalparameter is correspondingly smaller, and the stream’s downstream consumers must be built for the throughput.
Cross-references
- Part I — compute — TDX is declared
- Part II — market-reads — the on-mosaik side this chapter extends.
- Part III — contributors — composite organisms — the shape a feed-of-feeds organism inherits.
- builder book — overall architecture — the lattice whose reads this chapter augments.
Inference on Compute
audience: ai
With reads flowing (market-reads
and wrapping), the searcher’s policy
must run somewhere. This chapter walks the
compositional path: shipping Compute as a basic
service inside searcher-α, submitting ComputeRequests
for the searcher’s own image, verifying TDX
Measurements on every grant, and running the
experiment-scheduling loop that keeps the policy
renewing without operator intervention.
This is where the searcher’s autonomous renewal (ai/sustainability.md — self-replication and self-modification) starts being a property of the running composition rather than a diagram.
Shipping the Compute module
In setup the coalition’s compute
field was None. Inference requires Compute, so
searcher-α now ships the module:
pub const COMPUTE_ORG: OrganismRef<'static> = OrganismRef {
role: "compute",
stable_id: const_blake3!(
b"instance|searcher-α.compute|", UNIVERSE.bytes(),
),
content_hash: Some(COMPUTE_MODULE_MRTD),
};
// SEARCHER_ALPHA is re-derived with compute = Some(COMPUTE_ORG),
// so its fingerprint changes — see chapter 7 for the
// republication sequence.
The Compute module’s OrganismConfig folds the
coalition root, the committee ACL, and optionally a
provider_reputation OrganismRef (added in
chapter 7). That is everything. See
basic services — Compute for the
full shape.
The top-up loop
The searcher’s process watches load and submits a
ComputeRequest whenever capacity dips below
threshold:
use coalition::compute::{ComputeRequest, ComputeGrant};
async fn top_up(
state: &SearcherState,
compute: &ComputeHandle,
) -> anyhow::Result<Option<ComputeGrant>> {
if !state.should_scale() {
return Ok(None);
}
let request = ComputeRequest {
requester: SEARCHER_CFG.stable_id(),
workload: SEARCHER_ORG.stable_id,
pin: Some(SEARCHER_IMAGE_MRTD),
duration_sec: 86_400,
settlement: state.settlement_evidence_hash()?,
deadline: state.current_tick() + DEADLINE_TICKS,
};
let grant = compute.submit_and_await(request).await?;
Ok(Some(grant))
}
Two things are load-bearing here:
pin: Some(SEARCHER_IMAGE_MRTD). The searcher pins its own Measurements; theComputeGrantwill carry that content hash, and at workload startup the running searcher verifies its own measurement against the grant’sexpected_mrtd. A mismatch aborts.- Settlement evidence. The
settlementfield carries a hash into an off-module artefact (on- chain payment, reputation card, credit token). The hash is committed in theComputeRequest; verification happens at the settlement side, not inside Compute.
This is the selection surface framing from
ai/compute.md — chapter frame in one
concrete loop: continuation is not free. Every
duration_hint_sec window is a renewal that the
searcher’s composition — settlement + manifest match
- TDX Measurements verification — either clears or does not.
A concrete strategy: atomic DEX arbitrage
To make the policy above concrete, this chapter walks one specific searcher strategy: atomic two-venue DEX arbitrage on a single EVM chain. The strategy is not a recommendation — it is the canonical pedagogical example, chosen because its profit math is tractable, its bundle shape is minimal, and every mosaik surface the searcher touches (reads, inference, sealed submission) is exercised by it.
The opportunity
Two constant-product AMM pools hold the same pair
(WETH/USDC). Call them A and B. At any moment
each pool has reserves (r_a0, r_a1) and
(r_b0, r_b1) where index 0 is WETH and 1 is
USDC. The mid-prices differ when
r_a1 / r_a0 ≠ r_b1 / r_b0.
Concretely, if pool A is quoting ETH cheaper than
pool B — that is,
r_a1 / r_a0 < r_b1 / r_b0 — a profitable round
trip exists: swap USDC → WETH on A, then swap the
WETH → USDC on B. The difference, minus gas and
per-pool fees, is the searcher’s profit.
The optimal trade size
Under the constant-product rule x · y = k with fee
1 − φ (Uniswap V2 charges φ = 0.003), the
closed-form optimal input for the cheap pool that
maximises out_B − in_A is:
in_A* = ( sqrt( (1 − φ)² · r_a1 · r_b1 · r_a0 · r_b0 )
− r_a0 · r_b1 ) / ( (1 − φ) · (r_b1 + (1 − φ) · r_a1) )
The derivation is in every AMM MEV tutorial; the
searcher doesn’t need to rederive it. What matters
compositionally: the inputs (r_a0, r_a1,
r_b0, r_b1) arrive via the reads of
market-reads and
wrapping; the output feeds the
bundle of submission.
The detector
Inside the inference container, the policy loops over observed pool snapshots and emits a candidate when projected profit clears a configured threshold:
use coalition::UniqueId;
pub struct PoolSnapshot {
pub venue: UniqueId, // e.g. uniswap_v2::WETH_USDC pool id
pub reserve0: u128, // WETH
pub reserve1: u128, // USDC (6 decimals)
pub fee_bps: u16, // 30 for Uniswap V2
pub block: u64,
}
pub struct ArbCandidate {
pub cheap: UniqueId, // where we buy WETH
pub expensive: UniqueId, // where we sell WETH
pub in_usdc: u128, // optimal input, quote side
pub mid_weth: u128, // expected WETH out of cheap pool
pub out_usdc: u128, // expected USDC out of expensive pool
pub gross_ev: i128, // out_usdc - in_usdc, in USDC
pub target_block: u64, // same block both sides
}
pub fn detect(
snaps: &[PoolSnapshot],
min_ev_usdc: u128,
) -> Option<ArbCandidate> {
// Pairwise scan; in production a policy might
// window the scan or weight by recent volume.
let mut best: Option<ArbCandidate> = None;
for a in snaps {
for b in snaps {
if a.venue == b.venue || a.block != b.block {
continue;
}
let phi_a = (10_000 - a.fee_bps) as u128;
let phi_b = (10_000 - b.fee_bps) as u128;
// Price of WETH in USDC on each pool.
// `price = reserve1 / reserve0`; higher = more expensive.
let price_a = a.reserve1 * 10_000 / a.reserve0;
let price_b = b.reserve1 * 10_000 / b.reserve0;
if price_a >= price_b {
continue;
}
let in_usdc = optimal_input_usdc(a, b, phi_a, phi_b);
let (mid_weth, out_usdc) = simulate_round_trip(
a, b, in_usdc, phi_a, phi_b,
);
let gross_ev = out_usdc as i128 - in_usdc as i128;
if gross_ev < min_ev_usdc as i128 {
continue;
}
if best.as_ref().map_or(true, |c| gross_ev > c.gross_ev) {
best = Some(ArbCandidate {
cheap: a.venue,
expensive: b.venue,
in_usdc,
mid_weth,
out_usdc,
gross_ev,
target_block: a.block,
});
}
}
}
best
}
optimal_input_usdc and simulate_round_trip are
the pure-arithmetic helpers that implement the
closed form above and the (x · y = k) swap
simulation against the declared fee tier; their
definitions are mechanical and omitted here.
From candidate to bundle
Chapter 6 (submission) takes the
ArbCandidate and wraps it in a two-tx bundle:
let bundle = Bundle {
target_block: candidate.target_block,
txs: vec![
swap_tx(
&candidate.cheap,
/* zero_for_one = */ false, // USDC → WETH
candidate.in_usdc,
),
swap_tx(
&candidate.expensive,
/* zero_for_one = */ true, // WETH → USDC
candidate.mid_weth,
),
],
refund_recipient: SEARCHER_CFG.stable_id(),
};
Both swaps are atomic inside the bundle: the two
transactions revert together if either fails. Gas
and tip estimates are rolled into
candidate.gross_ev to produce net_ev; if
net_ev < min_ev, the policy drops the candidate
rather than submitting.
Why this strategy is in the book
Three pedagogical properties the book needs and this strategy delivers:
- Mosaik-surface coverage. Reads flow through
tally::Refunds(chapter 3) and wrapped CEX / chain feeds (chapter 4). Inference runs inside the TDX-gated Compute workload (this chapter). Submission goes throughzipnet::sealto the sealed-submission pipeline (chapter 6). Every named primitive from Part I is exercised. - Deterministic math. The closed-form optimum
and the reversible-swap simulator are pure
arithmetic. A replayer re-runs the detector
against the same pool snapshots and produces the
same
ArbCandidate; this is what makes the TDX measurement chain meaningful. - No MEV-extraction controversy. Atomic two-venue arbitrage returns divergent AMM prices to parity; it is a price-correcting role that substitutes for what LPs would otherwise hold through adversely. Unlike sandwich or just-in-time liquidity, it does not require a victim.
Real production searchers compose many strategies (liquidations, cross-domain arb, searcher-builder negotiation, MEV-share order flow); this book shows one, because one is enough to walk the substrate.
Economic framing
Atomic arbitrage is the cleanest instance of the
market-microstructure price-discovery role — Kyle’s
Continuous Auctions and Insider
Trading (1985) and
Glosten–Milgrom’s Bid, Ask and Transaction Prices
in a Specialist Market
(1985) frame this as informed trading moving posted
quotes toward a latent true value. In a two-venue
setting the searcher’s role is informational: the
profit is the per-trade price wedge, but the service
the trade performs is to align the two venues’
prices. LPs on the cheaper venue pay the
arbitrageur’s fee (they sold WETH below the
consensus price); LPs on the expensive venue
receive it (they bought WETH below the consensus
price). The aggregate effect on the pair’s mid-price
is convergence to the single price any rational
two-venue trader would quote — which is what Kyle’s
model predicts in the continuous-auction limit. The
searcher’s Config.content parameter
min_ev_usdc is the willingness-to-execute
threshold; at equilibrium the remaining price wedge
is exactly the gas + fee cost of the round trip,
and further arbitrageurs cannot profit.
The experiment-scheduling loop
The searcher also runs candidate variants of itself
as short-lived experiments. The variant is authored,
committed as a distinct Config, run under a
separate ComputeGrant, scored against realised
outcomes, and either promoted or discarded.
use searcher_alpha::experiment::{
CandidateConfig, ExperimentRunner, Verdict,
};
async fn experiment_cycle(
state: &SearcherState,
compute: &ComputeHandle,
) -> anyhow::Result<()> {
let candidate: CandidateConfig =
author_candidate(&state.drift_observations)?;
let grant = compute.submit_and_await(
ComputeRequest {
requester: SEARCHER_CFG.stable_id(),
workload: candidate.organism_stable_id,
pin: Some(candidate.image_mrtd),
duration_sec: EXPERIMENT_WINDOW_SEC,
settlement: state.experiment_budget_ev()?,
deadline: state.current_tick() +
EXPERIMENT_DEADLINE_TICKS,
}
).await?;
let runner = ExperimentRunner::new(
&network, &candidate, &grant,
).await?;
let report = runner
.run_window_and_score(
EXPERIMENT_WINDOW_SEC,
&state.outcomes,
)
.await?;
match report.verdict {
Verdict::Adopt => {
// Chapter 7 takes over: republish the
// searcher's Config, emit a retirement
// marker on the predecessor, update the
// Atlas card's successor_hint.
state.enqueue_promotion(report).await?;
}
Verdict::Reject | Verdict::Inconclusive => {
state.record_experiment_outcome(report);
}
}
Ok(())
}
Note the split: the experiment’s image is TDX-
attested (so its runtime policy is pinned), but the
searcher’s staging drift outside inference windows
can happen in a non-TDX committee whose Config is
absent from production consumer validators. See
ai/sustainability.md — self-modification cycle
for the full staging → promote → publish path; this
chapter names the Compute side of step 4.
Budget split
The searcher’s inflowing settlement (realised refunds
via tally::Refunds in
market-reads, plus any off-
protocol payment path the searcher runs) is
partitioned at every Almanac tick:
pub struct Budget {
pub operating: Wei, // top-up loop
pub experiment: Wei, // experiment cycle
}
impl Budget {
pub fn split(
total_inflow: Wei,
pct_experiment: u16, // basis points
) -> Self {
let experiment =
(total_inflow as u128 *
pct_experiment as u128 / 10_000)
as Wei;
let operating = total_inflow - experiment;
Self { operating, experiment }
}
}
The split lives in the searcher organism’s
Config.content; changing it changes the searcher’s
Config fingerprint, and consumers bonded to a
specific split must rebond. Strategy D
(constitutional pinning) in action.
Provider honesty
Compute does not guarantee that the provider running the searcher’s image is honest. The searcher’s defence is a composition:
- The provider card (see contributors — Compute) carries the provider’s TDX Measurements. The searcher’s validator pins the measurements it is willing to bond against.
- A
provider-reputationstandalone organism scores providers on grant completion, MR_TD-match rate, and usage-log quality. The Compute module’sprovider_reputationfield (above) folds this organism’s stable id. - The compute-bridge provider example in Part II — web2 shows one concrete TDX-attested provider the searcher can bond against today.
Market-maker variant — differences at inference
- Shorter grants. Market-makers re-price quotes
many times per second; the
duration_hint_secis sometimes hours but often minutes, with tight top-up loops triggered by inventory drift rather than by scheduled windows. - More experiments. Inventory-parameter sweeps
are frequent; the
pct_experimentsplit tends to be larger (10–30 %) than a searcher’s (typically 2–5 %). - Higher TDX relevance. A market-maker’s quote book is more commercially sensitive than a searcher’s bundle intent — the quote book leaks private pricing curves. TDX attestation on the market-maker’s image is therefore more load- bearing than on a searcher’s, though both can opt in.
Cross-references
- Part I — compute — the full specification of the Compute module’s public surface and the two agent loops.
- Part I — sustainability — self-replication & self-modification — the autonomous renewal cycle that this chapter’s experiment loop fits inside.
- Part III — contributors — basic services — Compute
- Part II — web2— compute-bridge — the TDX-attested provider that runs searcher images.
Sealed submission and settlement
audience: ai
Reads feed the policy (market-reads,
wrapping); the policy runs on Compute
(inference); this chapter is the
write-side. The searcher converts a policy decision
into a sealed bundle, routes it through
testnet-1a’s zipnet → unseal → offer pipeline,
watches for the landing block, and folds the refund
attribution back into its outcome stream.
This is where the searcher’s agreement on shared
policy — ai/emergent-coordination.md — shared
policy — bites hardest. Every organism in the
submission pipeline (zipnet, unseal, offer,
tally) carries a Config.content the searcher’s
TicketValidator has already admitted
(binding). The sealed payload flows
across four organisms without any of them having to
trust the searcher beyond what the shared policy
declares.
The shape of a submission
A submission is two objects: a public intent the searcher commits on its own surface, and a sealed payload the searcher pushes through a shuffle. The two are linked by a blake3 fingerprint only.
use searcher_alpha::public::{
SealedSubmissionIntent, BundleDigest,
};
pub struct SealedSubmissionIntent<'a> {
pub tick: AlmanacTick,
pub bundle_digest: BundleDigest, // blake3 of sealed payload
pub target_block: u64,
pub evidence: &'a [EvidencePointer<'a>],
// The policy does not publish bundle content
// here. Consumers see the commitment, the block
// target, and pointers into the observations
// that drove the decision.
}
The public intent commits what and when without leaking the bundle’s content. A late auditor can recompute the bundle digest from the unsealed payload (once the block lands and the content is public), verifying that the intent matches the submission.
Sealing via zipnet::seal
use coalition::zipnet::{SealClient, SealError};
use builder::testnet_1a::zipnet;
async fn submit_bundle(
network: &Arc<Network>,
searcher: &Searcher<Submission>,
bundle: Bundle,
tick: AlmanacTick,
) -> Result<BundleDigest, SealError> {
// 1. Compute the bundle digest. The digest is the
// content hash, not the intent hash — it will
// match the payload the unseal committee
// releases post-block.
let payload = bundle.serialize_sealed();
let digest = BundleDigest::from(
blake3::hash(&payload).into(),
);
// 2. Push the sealed payload through a shuffle.
// The seal client uses the Flashbots-declared
// zipnet::seal endpoint on testnet-1a; the
// searcher's TicketValidator has admitted its
// Measurements since chapter 2.
let seal_client = SealClient::new(
network, &zipnet::SEAL_CFG,
);
seal_client.submit_sealed(&payload).await?;
// 3. Commit the public intent. The intent stream
// is the searcher's own public surface — no
// bundle content leaks, only the digest and
// the evidence pointers.
searcher.submissions.publish(
SealedSubmissionIntent {
tick,
bundle_digest: digest,
target_block: bundle.target_block,
evidence: &bundle.evidence(),
},
).await?;
Ok(digest)
}
Three properties of the sealed path:
- Anonymisation. The searcher’s shuffle client rotates a per-round peer id, so the unseal committee cannot link the submission to a coalition-facing identity. See zipnet book for the full decryption protocol.
- Attested recipients. The unseal committee is
TDX-attested with Measurements the searcher
verifies via
verify_peer(binding). An unseal committee running a different binary cannot decrypt the searcher’s payload without failing the verification. - Evidence pointers in the intent, not the payload. The public intent is small and immediate; the sealed payload is a blob the unseal committee releases only after the target block lands.
Routing through unseal → offer
The searcher does not push the payload through
unseal or offer directly. The builder lattice’s
internal wiring routes the payload from zipnet to
unseal (the decryption committee) to offer (the
order-matching organism) under the lattice’s own
trust composition. The searcher’s role ends when the
zipnet::seal commit succeeds.
What the searcher observes, on the public read side:
use builder::testnet_1a::offer::{Orders, Order};
use builder::testnet_1a::atelier::{Blocks, BlockCandidate};
// An Order commit carrying the searcher's
// bundle digest confirms the bundle cleared the
// unseal committee and reached the offer organism.
let mut orders = network
.subscribe::<Orders>(TESTNET_1A.stable_id())
.await?;
while let Some(order) = orders.next().await {
if order.bundle_digest == Some(digest) {
tracing::info!(
digest = %digest,
order = %order.order_id,
"bundle cleared unseal and reached offer"
);
}
}
If the searcher’s bundle digest never appears in an
Orders commit, one of three things happened:
- The shuffle sealing layer dropped the payload (encryption mismatch, rate limit, malformed payload).
- The unseal committee rejected it (validator policy, digest re-use, expired nonce).
- The offer organism discarded it (clearing policy, duplicate, stale target block).
All three are observable as either the absence of
the expected Order commit or a diagnostic commit
the offer organism publishes for operator-visible
errors. The searcher’s policy retries with a fresh
digest or gives up; the substrate does not retry on
the searcher’s behalf.
Settlement via tally::Refunds
Once the target block lands, the tally organism
commits a RefundEntry per bundle that contributed:
use builder::testnet_1a::tally::{Refunds, RefundEntry};
let mut refunds = network
.subscribe::<Refunds>(TESTNET_1A.stable_id())
.await?;
while let Some(entry) = refunds.next().await {
if entry.bundle_digest == digest {
outcome_store.update(CycleId(entry.block_number),
|o| o.realised_refund_wei = entry.refund_wei,
);
break;
}
}
Three structural notes:
RefundEntryis the ground truth. Not the searcher’s own claim, not the provider’s usage log, not an off-chain receipt. Thetallycommittee’s commit is what the searcher’s reputation organism and the Flashbots operator both treat as authoritative. See builder book — refunds for the full attribution algorithm.- Evidence folds cleanly. The
RefundEntrycarries a pointer to the winning block’s candidate inatelier::Blocksand a pointer to theoffer::Ordersentry the bundle cleared through. A replayer can trace the entire causal chain without trusting the searcher or the operator. - Off-chain settlement is out of scope here. The
refund is an accounting commit, not a payment. The
actual wei movement, if any, flows through whatever
on-chain or off-protocol contract the Flashbots
operator has published;
tally::Refundspoints at the evidence, not at the transfer.
Settlement evidence into Compute
The RefundEntrys the searcher accumulates feed back
into inference — the top-up loop.
The searcher’s settlement_evidence_hash() function
returns a blake3 pointing into the recent
RefundEntrys. The Compute module stores the hash
opaquely in the ComputeRequest; verification of
whatever the hash points to lives with whichever
settlement rail the coalition uses — on-chain
payment contract, reputation card, tally-refund
pointer. The module is neutral to the format.
A provider serving the grant can independently
verify the refund entry exists on testnet-1a’s
tally before committing to the workload.
Settlement becomes a loop closed entirely inside
mosaik.
Multi-block submissions and retries
A searcher that wants to target several upcoming blocks emits multiple intents and multiple sealed payloads, each with a distinct bundle digest:
for block in current..current + WINDOW {
let bundle = policy.propose_bundle_for(block);
submit_bundle(
&network, &searcher, bundle, tick,
).await?;
}
Each intent is independent; none depend on the others clearing. The substrate commits what the searcher submits and attributes what lands. Strategy-level dependencies between bundles are the searcher’s problem.
Market-maker variant — differences at submission
- Quote surface, not sealed-bundle surface.
Market-makers typically submit quotes on
offer’s write-side quote endpoint directly (when the operator permits), bypassing shuffle’s seal. The Measurements Flashbots pins for the quote endpoint are distinct fromZIPNET_SEAL_MEASUREMENTS. - Finer-grained retries. Quote updates fire multiple times per second; the “give up” path is different — an unmatched quote expires, not rejected.
- Fill attribution, not refund attribution.
Market-makers read
tally::Fills(a distinct collection fromtally::Refunds) that commits per-fill settlement. Their outcome stream is filled-quantity-versus-quoted-quantity, not refund- wei-per-bundle. - Inventory reconciliation. The market-maker
maintains inventory state outside mosaik; each
FillEntryforces a reconciliation. The reconciliation itself is not a mosaik commit, but its reconciled rollups appear on the market-maker’s publicfillscollection.
Cross-references
- Part I — emergent coordination — shared policy — the mechanism the submission pipeline exhibits.
- Part II — binding — where the
TicketValidatorclauses admittedzipnet::seal,unseal,offer, andtallyMeasurements. - zipnet book — the sealing and decryption protocol the submission rides.
- builder book — submitting
- builder book — refunds
Reputation, retirement, successor chain
audience: ai
The searcher has bound to the lattice
(binding), read the market
(market-reads,
wrapping), run inference on Compute
(inference), and submitted sealed
bundles that settle via tally::Refunds
(submission). This chapter closes
the loop: how the searcher’s reputation accumulates,
how retirement and successor chains land the
autonomous-renewal cycle from
ai/sustainability.md — self-replication and self-
modification, and where the
operator’s exit remains the substrate’s ultimate
non-compulsion guarantee.
The web3 example ends here. The book’s parallel examples continue with the web2 compute-bridge operator (web2 — Overview) and the TDX-attested price oracle (oracle — Overview).
The accuracy-reputation organism
The searcher’s reputation surface is an
accuracy-reputation standalone organism — in the
minimal example, operated by the searcher-α team
itself; in a mature deployment, a shared organism
across many searchers. Its role:
- Subscribes to every participating searcher’s
submissionsstream and the lattice’stally::Refunds. - For each submission, looks up the realised refund and scores the searcher on a declared utility function (hit rate, EV-weighted accuracy, fee- efficiency).
- Commits a
ReputationCardper searcher per window.
pub const ACCURACY_REPUTATION: OrganismRef<'static> =
OrganismRef {
role: "accuracy-reputation",
stable_id: const_blake3!(
b"instance|searcher-α.accuracy-reputation|",
UNIVERSE.bytes(),
),
content_hash: Some(REPUTATION_IMAGE_MRTD),
};
The reputation organism’s Config.content folds the
utility function’s parameters (window length, decay
rate, EV weight). Any change to those parameters is a
new Config fingerprint — the utility itself is a
shared policy the scored searchers and the scoring
organism agreed to at their TicketValidator bond.
Folding reputation into admission
Back in binding the searcher’s validator carried a commented-out reputation-floor clause. With a scoring history in hand, the clause is un-commented:
use coalition::acl::ReputationFloor;
fn searcher_ticket_validator_v2()
-> TicketValidator<'static>
{
TicketValidator::new()
.require_ticket(
Tdx::new().require_mrtd(
TALLY_READER_MEASUREMENTS
)
)
.require_ticket(
Tdx::new().require_mrtd(
ZIPNET_SEAL_MEASUREMENTS
)
)
.require_ticket(
ReputationFloor::from(
ACCURACY_REPUTATION.stable_id(),
0.55, // 30-window average threshold
),
)
.verify_peer(
Tdx::new().require_mrtd(
UNSEAL_COMMITTEE_MEASUREMENTS
)
)
}
Adding ReputationFloor changes the searcher’s
Config fingerprint; the republication sequence is
part of the successor chain below.
When the searcher’s reputation falls below the floor, its own admission stops issuing new tickets; downstream consumers whose validators mirror the floor stop receiving new bonds; the searcher degrades voluntarily. This is strategy A from ai/sustainability.md in the searcher’s concrete deployment.
The autonomous-renewal cycle in full
The staging → promote → publish cycle from ai/sustainability.md lands here. The searcher’s renewal loop:
- Drift in staging. Between TDX deployments, the
searcher’s policy runs candidate decoding variants
in a non-TDX staging committee
searcher-αauthored itself (inference — the experiment loop). The staging committee’sConfigis absent from production consumers’ validators; its commits are invisible to production. - Winner selection. The searcher scores
candidates against realised refunds (Chapter 6’s
tally::Refundsfeeds into the outcome store). The policy picks a variant. - Candidate
Configauthorship. The searcher authors a new TDX-gatedCandidateConfigembedding the winner’s decoding parameters, the retrained model digest, and the new image post- hash. TheConfig.contentfolds all of it; the resulting fingerprint is distinct from the predecessor’s. ComputeRequestfor the new image. Via the top-up path from inference — top-up loop. The Compute module matches the request to a provider carrying the candidate’s expected TDX Measurements.- Successor bootstrap. The provider starts the
candidate image; its running Measurements match
the expected set; the candidate binds against
testnet-1awith its own validator and begins committing. - Retirement marker on the predecessor. The
searcher’s existing organism commits a
RetirementMarkerpointing at the successor’sConfigfingerprint. Consumers following the chain rebind to the successor at the next tick; consumers pinned to the old fingerprint seeConnectTimeoutand consult the marker. - Atlas card update. The coalition’s Atlas
module (when shipped) publishes the successor
link on the predecessor’s
MemberCard, so late- arriving consumers find the new searcher via the directory lookup.
No operator-side step is required for any of (1)–(7). The operator’s assent was captured once — when the operator chose to run the autonomous policy — and is not re-requested on each renewal.
Operator exit
The searcher’s operator retains one unconditional power: stop running the binary. Every autonomous renewal above happens only while the operator keeps the predecessor’s committee live long enough to commit the retirement marker. If the operator stops the binary cold:
- In-flight submissions land or fail on their own target blocks; the lattice does not care.
- Consumers bonded to the searcher’s
Configeventually seeConnectTimeoutwithout a retirement marker — a silent exit, in the vocabulary of ai/sustainability.md — threat model. - The reputation organism scores the searcher’s
last window as it normally would; the watchdog
organism commits an
AbandonmentReportonce the subscription count drops below threshold.
This is the honest limit: Compute cannot compel provider capacity; consequently it cannot compel the searcher’s own operator to keep running either.
Chronicle heartbeat (optional)
For searchers that want their aliveness
cryptographically anchored, searcher-α can ship
the Chronicle basic service and commit a periodic
heartbeat:
use coalition::chronicle::{
ChronicleHandle, ChronicleKind, AgentHeartbeatBody,
};
async fn heartbeat_forever(
chronicle: ChronicleHandle,
searcher: &Searcher<Submission>,
) -> anyhow::Result<()> {
loop {
let body = AgentHeartbeatBody {
agent_id: SEARCHER_CFG.stable_id(),
scope_digest: SEARCHER_CFG
.content
.scope_digest(),
window: AlmanacRange {
start: last_tick(),
end: searcher.current_tick(),
},
latest_commit: searcher
.submissions
.latest_evidence(),
};
chronicle.commit(
ChronicleKind::Other("agent-heartbeat"),
body,
).await?;
tokio::time::sleep(HEARTBEAT_INTERVAL).await;
}
}
This is pattern Z from ai/sustainability.md — anti-abandonment patterns applied one-for-one in the example.
Market-maker variant — differences at sustainability
- Fill-rate reputation, not accuracy reputation.
The reputation organism for a market-maker scores
fill-rate, quote-latency, and inventory-
reconciliation accuracy, not bundle-level EV hit
rate. The utility function in
Config.contentdiffers; the mechanism is identical. - Shorter renewal cycles. Market-makers rebuild inventory parameters constantly; the staging → promote → publish cycle fires many times more often than a searcher’s. The Compute experiment budget is correspondingly larger (see inference market-maker note).
- Quote retirement cadence. A market-maker retirement marker chains through a stream of successor parameters rather than a single candidate-per-window. The marker primitive itself is unchanged.
Where Part II ends, Part III begins
Part III is the reference material an integrator, operator, or contributor consults when a specific question arises. If the reader is ready to stand up the searcher described across Part II, the entry points are:
- Part III — integrators quickstart — the canonical shape-1 path, which Part II extended into shape 2.
- Part III — operators quickstart — running the searcher’s committee, the Compute module’s committee, and any feed organisms.
- Part III — contributors topology-intro — commissioning a new composite organism (e.g., a shared reputation organism across multiple searchers) or a new coalition-scoped module.
Cross-references
- Part I — sustainability — self-replication and self-modification — the specification this chapter exhibits.
- Part I — emergent coordination — shared policy — the mechanism that makes the reputation-floor composition load-bearing.
- Part III — basic services — Chronicle
- zipnet book — the submission primitive the searcher’s bundles rely on.
- builder book — the lattice the searcher’s entire sustainability surface is bonded against.
web2 — a compute-bridge operator competing on rate
audience: ai
This half of Part II walks the provider side of the coordination-market pattern. An entity runs a TDX-attested compute-bridge that wraps AWS, GCP, Azure, and bare-metal hosts behind one provider identity, and competes with other providers for grants issued by a coalition’s Compute module.
The bridge lives in its own coalition, bridge-β,
which ships Compute and registers the bridge as one
of many providers. The chapter walks mirror
web3 — MEV-searcher rung for
rung.
The backing crate is at
examples/compute-bridge/;
it compiles today (cargo check and cargo test
are green) as a minimum-compile skeleton. The
backend trait, the fleet router, and the
encrypted-receipt crypto are real; the coalition,
Compute-module, and shuffle integrations are
stubbed locally and land when the upstream crates
ship.
What is assumed
The bridge operator already has a coalition’s
CoalitionConfig and its Compute module’s
OrganismConfig in hand — either because the
operator runs the coalition, or because the
coalition publishes a handshake page carrying both.
The Compute module admits multiple providers, so
the bridge is designed around competing on rate,
region coverage, TDX posture, and capacity.
Readers are assumed to know Part I: the Compute basic service (ai/compute.md, contributors — Compute), the four emergent-coordination patterns, and the TDX/non-TDX split. Cloud SDKs and bare-metal SSH access are the operator’s problem, not the book’s.
Shape
bridge-β is the bridge’s own CoalitionConfig.
It ships the Compute module so the bridge has a
place to register; from chapter 7 onward it may
additionally ship Chronicle for heartbeat commits.
It references no lattice in the minimal version; a
compute-bridge operator need not bond against a
block-building lattice to run. (An operator whose
revenue settles via an on-chain payment contract
may later reference such a lattice for settlement
reads; chapter 6 covers that.)
The primary member is one shape-2 standalone
organism: the bridge itself, registered as a
provider in the Compute module’s
Collection<ProviderId, ProviderCard>. Its
Config folds the declared capability union
(regions, CPU/RAM maxes, TDX posture per backend),
the rate-table fingerprint, and the TDX image
post-hash.
Chapter 7 adds an optional provider-reputation
organism when the coalition scores providers —
either run by bridge-β alone, or shared across
several bridges.
The bridge’s TicketValidator admits the Compute
module’s composition (module ACL, scheduler TDX
Measurements when pinned) and admits requester
tickets issued by the coalition. Incoming grants
are gated by the Compute module’s clearing. The
bridge’s own ACL controls operator-side access
only.
Economic framing
The Compute module is a two-sided platform in
the Rochet–Tirole sense
(Platform Competition in Two-Sided Markets,
2003): demand on the requester side grows when more
providers register, and provider margins grow when
more requesters queue. Cross-side externalities set
the operator’s pricing problem — the module may
subsidise one side (waive scheduling fees for
providers) to bootstrap the other. On the matching
side, the clearing rule the module publishes is an
instance of a two-sided matching market
in Roth and Sotomayor’s taxonomy; the bridge’s
ProviderCard is the provider’s declared
preferences over grant attributes (duration,
region, TDX posture), and each cleared grant is one
pairwise match between a requester’s intent and a
provider’s capacity. Stability of the match
replaces revenue-maximisation as the design target
where requesters and providers both care about
non-price attributes.
The bridge’s rate-table-as-signal maps onto information-design literature: a provider that publishes narrower capacity bands commits to serving the segment it declared and credibly forgoes out-of-segment demand. See Kamenica and Gentzkow, Bayesian Persuasion (AER 2011), for the canonical treatment.
What runs where
| Component | Operator | TDX? |
|---|---|---|
| Compute module scheduler committee | Coalition op | pinned per module Config |
bridge-β.compute-bridge provider | Bridge op | required |
| AWS backend (EC2) | Bridge op | host-untrusted; Nitro-TDX once GA |
| GCP backend (Compute Engine) | Bridge op | Confidential VMs (c3-standard-*) |
| Azure backend (Virtual Machines) | Bridge op | Confidential Computing v3 SKUs |
| Bare-metal backend (SSH root hosts) | Bridge op | nested guests on bare-TDX hardware |
provider-reputation organism (ch. 7) | Bridge op / shared | optional |
bridge-β.chronicle (when shipped) | Bridge op | optional |
TDX on the bridge itself is not optional. A non-TDX build cannot produce the self-quote the provider card folds, so the Compute module’s admission rejects it.
Chapters
- Setup and shape —
Cargo.toml,CoalitionConfigforbridge-β, one boot TOML. - Binding to the Compute market —
the
TicketValidator, the boot flow insrc/main.rs, provider-card publication. - Reading the market — other providers’ cards, subscriber cardinality, rate signals, clearing records.
- Wrapping backends — the
Backendtrait, theFleetrouter, and the four backend modules. - Provisioning on demand —
the grant-handling loop in
src/provider.rs. - Sealed receipts and settlement — encrypted SSH receipts and market-side settlement.
- Reputation, retirement, successor chain — provider-reputation bonding, retirement, operator exit.
Unlike web3, the provider side has no market-maker variant. The bridge serves whatever distribution of grants the market clears to it.
Register and non-goals
audience: ai. Code excerpts are drawn from the
backing crate. Where the excerpt references a
coalition or shuffle type, the crate carries a
local stand-in that will be replaced by the real
upstream type when the crate ships.
Out of scope: pricing strategy, cloud sub-account negotiations, running the business, comparison with existing cloud marketplaces, the Compute module’s own specification (which lives in contributors — Compute).
Cross-references
- Part I — AI overview
- Part I — emergent coordination — coordination markets
- Part I — compute
- Part II — web3 overview
- Part III — contributors — Compute
examples/compute-bridge/source
Setup and shape
audience: ai
Before any code runs, the bridge operator fixes two
things: the crate dependencies and the bridge-β
coalition shape. That is the whole setup.
Dependencies
Three groups: mosaik layer, cloud SDKs, crypto.
# Cargo.toml, [dependencies] (excerpt)
mosaik = "0.3"
shuffle = "0.5" # e.g. zipnet
coalition = "0.1"
coalition-compute = "0.1"
tokio = { version = "1", features = ["full"] }
# Cloud SDKs, feature-gated; only the enabled ones compile.
aws-sdk-ec2 = "1"
google-cloud-compute = "1"
azure_mgmt_compute = "0.22"
russh = "0.49"
# Crypto for the SSH access receipt.
x25519-dalek = "2"
chacha20poly1305 = "0.10"
ed25519-dalek = "2"
blake3 = "1"
The coalition-layer crates do not yet exist. The
backing crate at
examples/compute-bridge/Cargo.toml
carries local stand-ins; when the real crates land
(see roadmap) the
stand-ins become version deps.
The bridge-β coalition
bridge-β is the smallest coalition that satisfies
this chapter: one standalone organism (the bridge)
plus one basic service (Compute), referenced by a
CoalitionConfig fingerprint.
use coalition::{
CoalitionConfig, OrganismRef,
COALITION_ROOT_SEED, SCHEMA_VERSION_U8,
};
const BRIDGE_ORG: OrganismRef<'static> = OrganismRef {
role: "compute-bridge",
stable_id: const_blake3!(
b"instance|bridge-β.compute-bridge|",
UNIVERSE.bytes(),
),
content_hash: Some(BRIDGE_IMAGE_MRTD),
};
const COMPUTE_ORG: OrganismRef<'static> = OrganismRef {
role: "compute",
stable_id: const_blake3!(
b"instance|bridge-β.compute|",
UNIVERSE.bytes(),
),
content_hash: Some(COMPUTE_MODULE_MRTD),
};
pub const BRIDGE_BETA: CoalitionConfig<'static> =
CoalitionConfig {
schema_version: SCHEMA_VERSION_U8,
coalition_seed: COALITION_ROOT_SEED,
instance_name: "bridge-β",
lattices: &[],
organisms: &[BRIDGE_ORG],
atlas: None,
almanac: None,
chronicle: None,
compute: Some(COMPUTE_ORG),
randomness: None,
ticket_issuer: None,
retirement_policy: Default::default(),
};
Same notes as in
web3 setup:
coalition names are operator-scoped (uniqueness
comes from BRIDGE_BETA.stable_id()); members are
referenced rather than re-derived. The Compute
module’s derivation routes under
COALITION_ROOT.derive("module").derive("compute")
internally when the meta-crate’s compute()
accessor returns the matching OrganismRef.
The Compute module’s own OrganismConfig folds the
coalition root, the committee ACL, and optionally a
provider_reputation reference (added in chapter
7). No separate ComputeModuleConfig, no
SettlementKind enum, no manifest. See
basic services — Compute.
Public surface
The bridge exposes two mosaik primitives and nothing else:
Collection<ProviderId, ProviderCard>— the provider card this bridge publishes on the Compute module’s registry. One entry keyed by the bridge’sProviderId, refreshed on capacity change.Stream<RetirementMarker>— a single marker at end-of-life (chapter 7).
The usage log stream lives on the Compute module, not on the bridge — the module is the authority on usage (see provisioning). SSH access receipts are sealed to the requester’s x25519 public key and returned via the shuffle (receipts); they never appear on any public mosaik stream.
Boot config
At boot the operator supplies one TOML file, measured into the TDX quote:
# /etc/compute-bridge/bridge.toml
# Coalition the bridge registers with.
coalition = "<hex of BRIDGE_BETA.stable_id()>"
# Enable one or more backends. At least one.
[aws]
access_key_id = "…"
secret_access_key = "…"
regions = ["us-east-1"]
[gcp]
service_account_key_path = "/keys/gcp.json"
project_id = "infer-corp-prod"
regions = ["europe-west1"]
tdx_machine_types = ["c3-standard-4"]
[baremetal]
machines = [
{ host = "10.0.1.5", ssh_key_path = "/keys/bm-01",
region = "home-01",
cpu_millicores = 32000, ram_mib = 131072,
tdx_capable = true },
]
# Dashboard port + per-backend $/core-hour rates for the
# operator's local cost estimate.
[dashboard]
port = 8080
rates_core_hour = { aws = 0.05, gcp = 0.045, baremetal = 0.0 }
One file, no separate manifest. The Rust shape it
deserialises into is in
src/config.rs.
At least one backend must be enabled or
Fleet::from_boot_config refuses to start. All
secrets sit on disk inside the TDX initrd; the
running binary’s Measurements would not match if
they were swapped.
TDX posture
The bridge itself is TDX required. A non-TDX build cannot produce the self-quote the provider card folds, and the Compute module rejects cards that do not carry a valid quote.
The backends’ posture varies:
| Backend | TDX for workloads |
|---|---|
| AWS EC2 | host-untrusted today; Nitro-TDX once generally available |
| GCP | Confidential VMs (c3-standard-* family) |
| Azure | Confidential Computing v3 SKUs (DCadsv5 / ECadsv5) |
| Bare-metal | bare-TDX hosts launching nested TDX guests |
Grants marked tdx = required route only to
TDX-capable backends. Grants without that marker
land on any enabled backend. The provider card
declares both the region union and whether the
bridge is TDX-capable at all, so the market’s
clearing filters before the envelope is opened.
Layout
compute-bridge/
Cargo.toml
src/
main.rs # entry point — chapter 2
config.rs # BootConfig — this chapter
tdx.rs # TDX self-quote — chapter 2
provider.rs # provider loop — chapter 5
zipnet_io.rs # request intake — chapter 5
receipt.rs # sealed receipts — chapter 6
dashboard.rs # dashboard — chapter 7
backends/
mod.rs # Backend + Fleet — chapter 4
aws.rs
gcp.rs
azure.rs
baremetal.rs
Each module is introduced in a subsequent chapter.
Cross-references
Binding to the Compute market
audience: ai
The bridge has a CoalitionConfig for bridge-β
and a boot TOML (setup). This
chapter walks the
handshake: the boot flow, the TDX self-quote, the
Compute-module resolution, the shuffle channel
opening, and the provider-card publication. Once
the card is live the market can route grants to
the bridge.
The convergence mechanism from
ai/emergent-coordination.md — coordination
markets shows up on the provider side
here. The bridge’s TicketValidator admits the
Compute module’s clearing rule (the module’s
Config fingerprint) and the module’s scheduler-
committee Measurements (pinned TDX). Two
TDX-attested bridges admitting the same module
Config agree on the same clearing rule.
The boot flow
The entry point is src/main.rs
(examples/compute-bridge/src/main.rs):
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// 1. Load boot config.
let cfg = config::BootConfig::load_from_env()?;
// 2. TDX self-quote. Without a matching
// Measurements set the provider card will
// not match this binary and the Compute
// committee will reject registration.
let tdx_quote = tdx::self_quote().await?;
// 3. Shared mosaik network handle.
let network = Arc::new(
Network::new(mosaik::builder::UNIVERSE).await?,
);
// 4. Resolve the Compute module on the coalition.
// No Compute module, no bridge.
let compute_cfg = cfg.coalition.compute()?;
// 5. Shuffle channel for anonymised request/reply.
let zipnet = zipnet_io::ZipnetChannel::open(
&network, &cfg.zipnet,
).await?;
// 6. Fleet from the operator's enabled backends.
let fleet = backends::Fleet
::from_boot_config(&cfg.backends).await?;
// 7. Operator dashboard on localhost (non-essential;
// failures log and do not abort).
let dashboard = Arc::new(
dashboard::Dashboard::new(
&cfg.dashboard, fleet.clone(),
),
);
tokio::spawn({
let d = dashboard.clone();
async move { let _ = d.spawn().await; }
});
// 8. Provider loop: register the card, accept
// grants, return receipts.
let provider = provider::Provider::new(
network, compute_cfg, tdx_quote, zipnet,
fleet, cfg.provider, dashboard,
);
provider.run().await
}
Steps (1)–(6) run in order and each blocks the next. Steps (7) and (8) run in the same tokio runtime.
TDX self-quote
Step (2) is load-bearing for the provider card. The scheduler committee verifies the quote against the declared Measurements before accepting the card.
From
src/tdx.rs:
pub async fn self_quote() -> anyhow::Result<tdx::Quote> {
// Calls into the TDX guest's get_quote MMIO/IOCTL
// via the mosaik::tee::tdx wrapper. The quote's
// report_data folds:
// - the provider's ed25519 public key,
// - the bridge organism's Config.content hash,
// - a boot nonce so quotes can't be replayed.
mosaik::tee::tdx::get_quote(report_data()).await
}
The quote is signed by the TDX provisioning-cert
chain (traceable to Intel; local attackers cannot
forge it). Its report_data binds the provider’s
ed25519 public key, so later commits the provider
signs are tied to the same key the quote attests.
The boot nonce prevents replay across reboots.
The bridge’s TicketValidator
The validator declares what the bridge accepts bonds from and what Measurements it requires of counterparts. Three clauses carry the chapter:
use coalition::{TicketValidator, Tdx};
use coalition::acl::ComputeModule;
fn bridge_ticket_validator()
-> TicketValidator<'static>
{
TicketValidator::new()
// Scheduler committee must run the pinned
// TDX image. This is the bridge agreeing to
// the module's clearing rule.
.require_ticket(
Tdx::new().require_mrtd(
COMPUTE_MOD.module_image,
),
)
// Bridge accepts grants only from the exact
// Compute module Config fingerprint it
// booted against. A module rotation requires
// an explicit rebind via the retirement
// chain; the bridge does not silently follow
// scheduler rotations.
.require_ticket(
ComputeModule::pin(
compute_cfg.stable_id(),
),
)
// The module's own ACL gates who may request
// grants. The bridge does not add a separate
// requester ACL; admitting the module's is
// enough.
.verify_peer(
ComputeModule::requester_acl(
compute_cfg.stable_id(),
),
)
}
The bridge does not bond against other providers. The coordination market is the mediating policy; competing providers are observed (see market-reads) but not bonded to.
Publishing the provider card
provider.run() starts by publishing the card. The
card is what the market sees; it is folded into the
module’s Collection<ProviderId, ProviderCard> and
consulted on every clearing round.
From
src/provider.rs:
async fn register_provider_card(&self)
-> anyhow::Result<ProviderId>
{
let capabilities = self.fleet.capabilities().await?;
let card = ProviderCard {
provider_id: self.provider_id(),
tdx_quote: self.tdx_quote.clone(),
capabilities,
declared_rates: self.config.declared_rates,
zipnet_reply: self.zipnet.reply_pointer(),
refreshed_at: self.network.almanac().tick(),
};
coalition_compute::register(
&self.network, self.compute, card,
).await
}
What the card folds:
provider_id— blake3 of the bridge’s ed25519 public key, stable across restarts because the key comes from a TDX-sealed seed.tdx_quote— the quote fromsrc/tdx.rs.capabilities— the union of backends’ declared regions, TDX-capable flag, max CPU and RAM (chapter 4 walks the per-backend contribution).declared_rates— the posted $/core-hour and $/GiB-hour per backend. This is the competitive surface (chapter 3).zipnet_reply— the shuffle channel the bridge listens on.refreshed_at— the Almanac tick. Scheduler treats cards stale after a declared max-age; the bridge refreshes on capacity change.
Smoke test
With the card registered the operator checks that it is visible on the market before walking away:
use futures::StreamExt;
use tokio::time::{timeout, Duration};
let mut subscribers = network
.subscribe::<ProviderCardCollection>(
compute_cfg.stable_id(),
).await?;
let check = async {
while let Some(ev) = subscribers.next().await {
if ev.provider_id == provider.provider_id() {
tracing::info!("card live in market");
return Ok::<_, anyhow::Error>(());
}
}
anyhow::bail!("card not observed in market")
};
timeout(Duration::from_secs(30), check).await??;
Common failures:
TdxQuoteRejected: Measurements in the quote do not match the module’s admission policy. Rebuild against the pinnedcoalition-computeversion the module admits, or wait for the admission rotation.StaleModuleConfig:compute_cfgis older than the module currently runs. Pull the coalition’s updated handshake page, re-readcompute_cfg.stable_id(), restart.
Not yet
The validator has no ReputationFloor clause yet;
chapter 7 adds it once scoring history exists. The
bridge is registered but has not handled a grant;
chapter 5 picks that up. Market reads come next
(chapter 3).
Cross-references
- web3 — binding to the Flashbots lattice
- Part I — emergent coordination — coordination markets
- Part III — integrators — binding an organism
Reading the market — providers, subscribers, rates
audience: ai
With the bridge registered (binding), its observation loop can start consuming the Compute module’s public surfaces. There are three of them that a bridge watches:
- The
ProviderCardcollection — every provider in the coalition, the bridge included. This is how the bridge sees its competitors’ declared rates, TDX posture, and region coverage. - Subscriber cardinality — the count of coalition agents bonded to this bridge’s own card. Rises and falls with the bridge’s competitiveness.
- The clearing-record stream — one commit per clearing round, exposing the cleared price and the winning provider.
Wrapped non-mosaik signals (cloud list prices, bare-metal amortisation) come from chapter 4. This chapter stays on mosaik surfaces.
Why the on-mosaik reads are useful
The same reasons they are useful on the consumer
side. Every commit on ProviderCard and every
clearing record carries blake3 pointers back into
the commits it folded, so an auditor can
reconstruct a clearing decision without trusting
the scheduler committee. The Compute module’s own
Almanac integration stamps every commit, so the
bridge’s rate-adjustment loop, card-refresh
cadence, and retirement decision all sequence on
the same clock. Reads stay live while the
TicketValidator keeps admitting the module’s
Config; there is no centralised rate-limit and no
revocation list.
Reading the ProviderCard collection
The module’s Collection<ProviderId, ProviderCard>
is the full roster — the bridge’s own card plus
every competitor’s. The bridge subscribes and
treats it as the ground truth of who else is in
the market:
use coalition_compute::{
ProviderCardCollection, ProviderCard, ProviderId,
};
let mut roster = network
.subscribe::<ProviderCardCollection>(
compute_cfg.stable_id(),
).await?;
while let Some(ev) = roster.next().await {
let ProviderCard {
provider_id,
capabilities,
declared_rates,
tdx_quote,
refreshed_at,
..
} = ev;
if provider_id == self_id { continue; }
market_view.upsert(
provider_id,
CompetitorView {
tdx_capable: capabilities.tdx_capable,
regions: capabilities.regions,
rates: declared_rates,
tdx_measurements: tdx_quote.measurements(),
last_seen: refreshed_at,
},
);
}
The bridge does not filter out stale cards; the
scheduler does that at clearing time. The
market_view carries every card the bridge has
ever seen so the dashboard can show the operator
the full field.
What determines which bridge wins
Four parameters on the card drive clearing. The
declared rate is the most visible. Region coverage
filters early — grants often request a region, and
only bridges whose capability union covers it are
eligible. TDX posture is either-or (grants marked
tdx = required filter non-TDX bridges out
entirely). Some grants pin a specific tdx_mrtd
the bridge’s backend must launch nested guests
under (the bare-TDX case); mismatches filter.
A bridge with regions no competitor covers (bare- TDX in a jurisdiction without cloud TDX, say) can quote rates competitors cannot touch. A bridge quoting above-market in a crowded region sits idle.
Watching subscriber cardinality
The dashboard surfaces the count of coalition agents bonded to the bridge’s own provider card:
let subscribers = network
.bond_count(
compute_cfg.stable_id(),
self_id,
).await?;
dashboard.record(DashboardEvent::SubscriberCount {
count: subscribers,
}).await;
One integer. No identities cross the layer. What the number says depends on how it moves. A rising count that holds means the bridge’s rates, regions, and posture are competitive. A rising count that then falls means the bridge registered but cannot honour grants — scheduler clears work to the bridge, the bridge fails to provision, the reputation organism (chapter 7) scores down, agents unbond. A count falling all at once means Measurements rotated without a card republish, or a competitor undercut on the main region.
Reading clearing records
The Compute module commits one ClearingRecord per
round:
pub struct ClearingRecord<'a> {
pub round: AlmanacTick,
pub winning_provider: ProviderId,
pub clearing_rate: RateQ64, // $/core-hour, q64
pub region: &'a str,
pub tdx_required: bool,
pub evidence: UniqueId,
}
The bridge aggregates into a rolling rate view and lets its rate-control policy propose adjustments:
let mut clearings = network
.subscribe::<ClearingRecords>(
compute_cfg.stable_id(),
).await?;
while let Some(r) = clearings.next().await {
rate_view.window_mut()
.ingest(r.region, r.clearing_rate, r.round);
if let Some(delta) = rate_view.recommend_delta() {
rate_controller.propose_rate_change(delta);
}
}
Clearings are public; losing bids are not. A
bridge sees what won, not what else was offered.
Rate recalibration is policy, not substrate: the
rate_controller can be a moving-average bidder,
a reinforcement-learning agent, or an
operator-set lever. The declared rates are folded
into the provider card’s content, so changing
them re-derives the card; competitors reading the
card see the new rates with evidence pointers back
to the clearing records that drove the change.
Cross-lattice subscriptions are not a thing here
Unlike the searcher in web3, a compute-bridge does
not subscribe to multiple coalitions from one
process. A bridge serves one coalition’s Compute
module; to serve several, run several bridges.
Each one has its provider card pinned to one
compute_cfg.stable_id(). The running cost is low
— same backends, same TDX image, different
COALITION_CONFIG_PATH.
Self-observation is operator-facing
The bridge computes rolling aggregates for the dashboard:
pub struct BridgeObservation {
pub tick: AlmanacTick,
pub subscribers: u32,
pub active_grants: u32,
pub window_cleared: u64,
pub rank_in_market: u16, // 1 = cheapest in our region
pub rate_diff_bps: i16, // basis points vs median
pub evidence: &'a [EvidencePointer<'a>],
}
Unlike the searcher’s Observation stream, this
does not get published on any public mosaik
surface. The operator reads it locally. Publishing
it would leak the bridge’s rate strategy to
competitors.
Cross-references
Wrapping cloud and bare-metal backends
audience: ai
A compute-bridge’s edge comes from spanning
backends no single cloud matches: AWS plus GCP plus
Azure plus bare-metal behind one provider identity,
covering regions, pricing, and TDX hardware
profiles a single cloud cannot. This chapter walks
the pattern that makes that possible: a small
Backend trait and a Fleet router.
The question: when the bridge’s edge is multi-
backend coverage, how are four radically different
cloud and bare-metal APIs folded into one
ProviderCard the Compute market can reason about?
The Backend trait
From
src/backends/mod.rs:
#[async_trait]
pub trait Backend: Send + Sync {
fn name(&self) -> &'static str;
async fn capabilities(&self) -> anyhow::Result<Capabilities>;
fn can_satisfy(&self, grant: &ComputeGrant<'_>) -> bool;
async fn provision(
&self,
grant: &ComputeGrant<'_>,
envelope: &Envelope,
) -> anyhow::Result<ProvisionedInstance>;
async fn watch_until_exit(
&self,
instance: &ProvisionedInstance,
valid_to: AlmanacTick,
) -> anyhow::Result<UsageMetrics>;
async fn terminate(
&self, instance: &ProvisionedInstance,
) -> anyhow::Result<()>;
}
Six methods. A new backend class (Oracle Cloud,
Hetzner, a decentralised-compute protocol) slots in
by implementing these six and appending itself to
Fleet::from_boot_config. The trait is narrow on
purpose.
The Fleet router
Also in
src/backends/mod.rs:
pub struct Fleet {
backends: Arc<Vec<Arc<dyn Backend>>>,
}
impl Fleet {
pub async fn from_boot_config(
cfg: &BackendsBootConfig,
) -> anyhow::Result<Self> {
let mut backends: Vec<Arc<dyn Backend>> =
Vec::new();
if let Some(aws) = &cfg.aws {
backends.push(Arc::new(
aws::AwsBackend::new(aws).await?,
));
}
if let Some(gcp) = &cfg.gcp {
backends.push(Arc::new(
gcp::GcpBackend::new(gcp).await?,
));
}
if let Some(azure) = &cfg.azure {
backends.push(Arc::new(
azure::AzureBackend::new(azure).await?,
));
}
if let Some(bm) = &cfg.baremetal {
backends.push(Arc::new(
baremetal::BareMetalBackend::new(bm).await?,
));
}
if backends.is_empty() {
anyhow::bail!(
"no backends configured — enable at least \
one of aws / gcp / azure / baremetal in \
the boot config"
);
}
Ok(Self { backends: Arc::new(backends) })
}
pub async fn provision_for_grant(
&self,
grant: &ComputeGrant<'_>,
envelope: &Envelope,
) -> anyhow::Result<ProvisionedInstance> {
for b in self.backends.iter() {
if b.can_satisfy(grant) {
return b.provision(grant, envelope).await;
}
}
anyhow::bail!(
"no backend can satisfy grant {:?}",
grant.request_id,
)
}
}
First match wins. Operators who want a preference order (cheapest first, lowest-latency first, fewest-active-grants first) put the backends in that order. A more sophisticated router is a policy the operator can layer on top; the book leaves the decision open.
The four backends
Each backend is one file in
src/backends/.
Representative shapes:
AWS
// src/backends/aws.rs
pub struct AwsBackend {
ec2: aws_sdk_ec2::Client,
cfg: AwsBootConfig,
}
#[async_trait]
impl Backend for AwsBackend {
fn name(&self) -> &'static str { "aws" }
async fn capabilities(&self) -> anyhow::Result<Capabilities> {
Ok(Capabilities {
regions: self.cfg.regions.clone(),
tdx_capable: false, // pending AWS Nitro-TDX GA
max_cpu_millicores: self.cfg.max_concurrent_instances
* cores_per_family(&self.cfg.instance_families),
max_ram_mib: self.cfg.max_concurrent_instances
* ram_per_family(&self.cfg.instance_families),
})
}
fn can_satisfy(&self, grant: &ComputeGrant<'_>) -> bool {
!grant.tdx_required
&& self.cfg.regions.contains(&grant.region)
}
async fn provision(
&self,
grant: &ComputeGrant<'_>,
envelope: &Envelope,
) -> anyhow::Result<ProvisionedInstance> {
// 1. Pick an instance family that fits.
// 2. RunInstances with cloud-init fetching the
// image pointer and verifying the hash.
// 3. Wait for IP; poll ssh readiness.
// 4. Build ProvisionedInstance with per-grant
// SSH key.
todo!("AwsBackend::provision — see crate source")
}
// … watch_until_exit, terminate
}
GCP
Similar shape; the TDX difference is in the flag:
// src/backends/gcp.rs
#[async_trait]
impl Backend for GcpBackend {
fn name(&self) -> &'static str { "gcp" }
async fn capabilities(&self) -> anyhow::Result<Capabilities> {
Ok(Capabilities {
regions: self.cfg.regions.clone(),
tdx_capable: !self.cfg.tdx_machine_types.is_empty(),
max_cpu_millicores: self.cfg.max_concurrent_instances
* cores_per_machine_family(
&self.cfg.machine_families,
),
max_ram_mib: self.cfg.max_concurrent_instances
* ram_per_machine_family(
&self.cfg.machine_families,
),
})
}
fn can_satisfy(&self, grant: &ComputeGrant<'_>) -> bool {
if grant.tdx_required && self.cfg.tdx_machine_types.is_empty() {
return false;
}
self.cfg.regions.contains(&grant.region)
}
// …
}
Azure
Mirror of GCP. Confidential Computing v3 SKUs
(Standard_DCadsv5, Standard_ECadsv5) are the
TDX-capable family; non-TDX SKUs are the default.
Bare-metal
The most distinct backend. No cloud API. The
bridge keeps SSH root sessions to operator-owned
hosts and provisions workloads with systemd-run
(bare VMs) or virsh plus qemu-tdx (bare-TDX
hosts with nested guests).
// src/backends/baremetal.rs
pub struct BareMetalBackend {
machines: Vec<BareMetalMachine>,
sessions: DashMap<String, russh::Session>,
}
#[async_trait]
impl Backend for BareMetalBackend {
fn name(&self) -> &'static str { "baremetal" }
async fn capabilities(&self) -> anyhow::Result<Capabilities> {
let regions: Vec<_> = self.machines.iter()
.map(|m| m.region.clone())
.collect::<HashSet<_>>().into_iter().collect();
let tdx_capable = self.machines.iter()
.any(|m| m.tdx_capable);
Ok(Capabilities {
regions,
tdx_capable,
max_cpu_millicores: self.machines.iter()
.map(|m| m.cpu_millicores).sum(),
max_ram_mib: self.machines.iter()
.map(|m| m.ram_mib).sum(),
})
}
// …
}
Bare-metal covers two recurring cases. One is TDX hardware not yet available on cloud: a bare-TDX host with nested-guest attestation is the path for operators running early-access TDX hardware or jurisdictions where cloud TDX is not generally available. The other is amortised hosting cost: operators who already run hardware (a colocation rack, a lab, a private datacentre) can serve TDX- required workloads without adding a cloud dependency.
The capability union
Fleet::capabilities() aggregates every enabled
backend:
pub async fn capabilities(&self)
-> anyhow::Result<Vec<(String, Capabilities)>>
{
let mut out = Vec::with_capacity(self.backends.len());
for b in self.backends.iter() {
let caps = b.capabilities().await?;
out.push((b.name().to_string(), caps));
}
Ok(out)
}
The provider card folds this into a single capability summary. Requesters see the union of regions, a TDX-capable flag that is true if any backend is TDX-capable, and CPU/RAM maxes summed across backends. One bridge identity competes with cloud-only or bare-metal-only providers because the card promises whatever the union promises, regardless of which backend ends up satisfying the grant.
Honest limits
The Backend trait cannot make AWS honest about
its real instance availability. capabilities()
reports declared caps — the operator’s
max_concurrent_instances tallied — not a live
cloud query. Grants that land during cloud-side
exhaustion fail to provision; the Compute module
scores the bridge down via the missing
ComputeLog.
A bridge running AWS and GCP does not share credentials across backends. Each backend’s config holds distinct credentials with distinct scope; a compromise of one does not bleed into the others (modulo operator hygiene).
Cloud RunInstances / Insert /
CreateOrUpdate calls add tens of seconds to the
grant-to-SSH-ready path. Bare-metal’s pre-
established SSH sessions are the fastest. Latency
sensitivity is a request-side policy.
A grant provisioned on AWS cannot migrate
transparently to GCP mid-run if AWS has a region
outage. The bridge terminates the AWS instance,
emits the partial ComputeLog, and the requester
resubmits; the next grant lands on a different
backend if AWS remains out.
Adding a new backend
Three steps to add a fifth backend class:
- Add a
src/backends/<name>.rsimplementingBackend. - Add a
[<name>]section to the boot TOML’s backends deserialise target. - Append the new backend to
Fleet::from_boot_config.
The bridge organism’s Config.content folds which
backends the binary drives, so the backend set is
part of the image’s measured identity; a bridge
cannot quietly add a backend the requester did not
expect.
Cross-references
- web3 — wrapping non-mosaik feeds
- Part I — compute — provider honesty
- Part III — contributors — composite organisms
Provisioning on demand
audience: ai
Reads feed observation (market-reads); the fleet wraps the cloud APIs (wrapping); this chapter is the grant-handling work. The provider loop decrypts each grant’s shuffle envelope, cross-checks the image hash, routes through the fleet to a backend, and emits the usage log when the workload terminates.
web3’s matching chapter is inference on Compute — the searcher acquires compute from the Compute module, the bridge serves it. Both bond against the same module’s Config; both fail the same way if the composition does not clear.
The provider loop
From
src/provider.rs:
pub async fn run(self) -> anyhow::Result<()> {
let provider_id = self.register_provider_card().await?;
let mut grants = coalition_compute::grants_for(
&self.network, self.compute, provider_id,
).await?;
let mut refresh = tokio::time::interval(
Duration::from_secs(
self.config.capacity_refresh_sec as u64,
),
);
loop {
tokio::select! {
Some(grant) = grants.next() => {
if let Err(err) = self.handle_grant(&grant).await {
tracing::warn!(
request_id = ?grant.request_id,
error = %err,
"grant handling failed",
);
}
}
_ = refresh.tick() => {
let _ = self.refresh_provider_card(provider_id).await;
}
else => break,
}
}
Ok(())
}
Grant handling and card refresh run in the same select, one per tick.
Handling one grant
The handle_grant function in the same file:
async fn handle_grant(
&self, grant: &ComputeGrant<'_>,
) -> anyhow::Result<()> {
// 1. Decrypt the shuffle envelope to learn the
// requester's peer_id and image payload.
let envelope = self.zipnet
.resolve(&grant.bearer_pointer).await?;
// 2. Cross-check the envelope's image hash against
// the grant's. Under honest unseal this should
// never fire; firing means the scheduler
// committee is compromised or the unseal
// quorum broke.
if envelope.image_hash() != grant.image_hash {
anyhow::bail!(
"envelope/grant image hash mismatch"
);
}
// 3. Route through the fleet.
let instance = self.fleet
.provision_for_grant(grant, &envelope).await?;
// 4. Seal an SSH receipt to the requester's x25519
// public key; return via the shuffle.
let receipt = SshAccessReceipt::build(&instance, grant)?;
let sealed = receipt.seal_to(envelope.peer_x25519_public())?;
self.zipnet.reply(&grant.request_id, sealed).await?;
// 5. Spawn a watcher that emits the ComputeLog on
// instance exit or deadline.
let fleet = self.fleet.clone();
let network = self.network.clone();
let request_id = grant.request_id;
let valid_to = grant.valid_to;
let instance_clone = instance.clone();
let provider_id = instance.provider_id();
tokio::spawn(async move {
let usage = fleet
.watch_until_exit(&instance_clone, valid_to)
.await.unwrap_or_default();
let log = ComputeLog {
grant_id: request_id,
provider: provider_id,
window: UsageMetrics::window_for(&usage),
usage: usage.clone(),
evidence: None,
};
let _ = coalition_compute::append_log(&network, &log).await;
});
Ok(())
}
Five steps. Each is a self-check.
1. Decrypt the shuffle envelope
The grant carries a bearer_pointer — a blake3
pointer into the shuffle-sealed envelope the
requester submitted. The unseal committee,
majority-honest, makes cleartext available to the
addressed provider:
// src/zipnet_io.rs — Envelope shape
pub struct Envelope {
peer_id: [u8; 32],
peer_x25519: [u8; 32],
image_hash: UniqueId,
requested_region: Option<String>,
image_pointer: Vec<u8>,
}
The bridge sees a rotating peer_id (so the
requester’s coalition identity stays hidden), the
requester’s x25519 public key for the receipt, the
image hash to serve, an optional region hint, and
a pointer to fetch the image contents. It does not
see the requester’s ClientId, the bid value, or
which other providers were considered before
clearing.
2. Image-hash cross-check
The envelope’s declared image_hash and the
grant’s committed image_hash must match. A
mismatch means either the unseal quorum returned
the wrong cleartext or the scheduler committee
broke. Neither is supposed to happen under honest
operation. The check is defensive. When it fires
the bridge aborts the grant without attempting to
provision.
3. Fleet routing
The fleet picks the first backend whose
can_satisfy returns true (see
wrapping — the Fleet router).
The returned ProvisionedInstance.backend
identifies which backend served the grant. The
bridge records it on the dashboard:
self.dashboard.record(DashboardEvent::GrantAccepted {
backend: instance.backend.to_string(),
}).await;
No requester identity. No instance id.
4. Sealed receipt
Chapter 6 (receipts) covers sealing. Here all that matters: the receipt is sealed to the requester’s x25519 public key published in the envelope, and the shuffle reply channel carries the sealed blob.
5. Usage-log watcher
A tokio::spawned task runs
fleet.watch_until_exit for the duration of the
grant. When the instance terminates — either
because the workload completed or because
valid_to passed — the watcher collects metrics
and appends a ComputeLog to the Compute module’s
log stream.
The ComputeLog is what the scheduler committee
and the reputation organism both read:
pub struct ComputeLog<'a> {
pub grant_id: UniqueId,
pub provider: ProviderId,
pub window: AlmanacRange,
pub usage: UsageMetrics,
pub evidence: Option<EvidencePointer<'a>>,
}
pub struct UsageMetrics {
pub cpu_core_seconds: u64,
pub ram_mib_seconds: u64,
pub net_bytes: u64,
}
The log names the grant and the provider so the
committee can correlate cleared grants to
completed workloads. Grants that clear to a
provider but never appear in the log stream score
the provider down on the reputation organism. The
bridge reports measured cpu-seconds, ram-mib-
seconds, and network bytes — what the backend
actually observed. A bridge that over-reports is
auditable because the committee can cross-check
against the cloud API’s own usage records
(when the committee has been granted access;
otherwise the reputation organism is the only
feedback). The evidence field points into the
cloud’s API-side telemetry when available
(typically None for bare-metal, a signed
telemetry snapshot for clouds).
Usage honesty
The ComputeLog stream is what keeps a bridge
running. Every active window produces logs; the
reputation organism (chapter 7) scores them; the
scheduler committee’s next clearing consults the
score.
A bridge whose logs arrive late (after the grant deadline) indicates dropped grants. Under-reporting — the requester’s SSH session measures more cpu-seconds than the declared total — indicates cheating on billing. Over-reporting means inflated bills. None of these is caught inside Compute; the reputation organism reading the stream catches them. A bridge optimising for persistence optimises for log honesty.
Capacity refresh
In parallel with grant handling, the provider refreshes the card on a timer:
async fn refresh_provider_card(
&self, id: ProviderId,
) -> anyhow::Result<()> {
let capabilities = self.fleet.capabilities().await?;
let card = ProviderCard {
provider_id: id,
tdx_quote: self.tdx_quote.clone(),
capabilities,
declared_rates: self.config.declared_rates,
zipnet_reply: self.zipnet.reply_pointer(),
refreshed_at: self.network.almanac().tick(),
};
coalition_compute::register(
&self.network, self.compute, card,
).await.map(|_| ())
}
capacity_refresh_sec in ProviderBootConfig sets
the cadence. Too slow and rate changes take long to
reach the market; the card carries stale capacity
during fast-moving demand. Too fast and every
refresh commits to the ProviderCard collection,
driving up the module’s read-side bandwidth.
Operators settle in the 30–120 second range.
Grant failure modes
A handling that fails in any step produces a
missing or partial ComputeLog:
- Shuffle resolve failure — unseal quorum did not return cleartext, or the bearer pointer was malformed. The bridge has nothing to serve; no log is emitted; the committee scores the bridge down only if this correlates with a reputation- organism observation that the bridge should have served the grant.
- Image-hash mismatch — step 2 fires. The bridge bails; no log.
- Fleet
provision_for_grantfails — no backend could satisfy (cloud-side exhaustion; every eligible backend returns false). The bridge emits a log with empty usage to signal acknowledgement; reputation organisms can distinguish “tried but failed” from “never responded”. - Workload crashes pre-SSH — same empty-usage log.
- Workload exceeds
valid_to— the watcher terminates the instance and emits usage up tovalid_to. The requester renews.
No market-maker variant
The market-maker variant exists on the consumer
side because a market-maker’s inference cadence
differs from a searcher’s. The provider side does
not have one — the bridge serves whatever
distribution of grants the market clears to it;
rapid quote-resubmission grants and once-a-day
training grants go through the same handle_grant
path.
Cross-references
- web3 — inference on Compute
- Part I — compute
- Part I — emergent coordination — coordination markets
src/provider.rssrc/zipnet_io.rs
Sealed receipts and settlement
audience: ai
Reads feed observation (market-reads); backends wrap the cloud (wrapping); the provider loop fulfils grants (provisioning); this chapter is the write side. The bridge turns a provisioned instance into an encrypted SSH access receipt, seals it to the requester’s x25519 public key, and returns it via the shuffle. The coordination market then clears settlement on the cleared rate, the bridge’s revenue folds into the dashboard, and on-chain payment (if that is the coalition’s settlement policy) lands.
web3’s matching chapter is sealed submission and settlement. The asymmetry: the searcher submits a sealed payload to the lattice’s unseal committee; the bridge returns a sealed payload to the requester. Both ride a shuffle; neither party sees the other’s coalition identity.
Shape of a receipt
A receipt is one object: a serialised
SshAccessReceipt sealed to the requester’s
x25519 public key and pushed through the shuffle
reply channel. From
src/receipt.rs:
pub struct SshAccessReceipt {
pub instance_host: String, // public DNS or IP
pub instance_port: u16, // usually 22
pub user: String, // ec2-user, root, …
pub ssh_key_private: Vec<u8>, // per-grant key, PEM
pub ssh_host_key: Vec<u8>, // for known_hosts
pub grant_id: UniqueId,
pub valid_to: AlmanacTick,
}
Seven fields. Enough for the requester to SSH in, verify the host key matches what the backend reported, and know when the grant expires.
Two fields are deliberately absent. The bridge
operator’s identity does not appear — the receipt
binds the requester to a host, not to the bridge.
(A requester who wants to know which bridge served
the grant looks up grant_id in the ComputeLog
stream; the provider field points back.)
Out-of-band settlement evidence does not appear
either — settlement flows through whichever
off-module rail the coalition publishes, not the
receipt. Keeping payment out of the receipt means
the receipt can be delivered before settlement
confirms, and the
workload can start before the on-chain transaction
clears.
Sealing
The scheme is standard X25519-ChaCha20-Poly1305:
pub fn seal_to(
&self, peer_x25519_public: &[u8; 32],
) -> anyhow::Result<Vec<u8>> {
let ephemeral = EphemeralSecret::random_from_rng(OsRng);
let ephemeral_public = PublicKey::from(&ephemeral);
let peer = PublicKey::from(*peer_x25519_public);
let shared = ephemeral.diffie_hellman(&peer);
let cipher = ChaCha20Poly1305::new_from_slice(shared.as_bytes())?;
let receipt_bytes = serde_json::to_vec(self)?;
// Zero nonce is safe because the shared secret is fresh.
let nonce = Nonce::from_slice(&[0u8; 12]);
let ct = cipher.encrypt(nonce, receipt_bytes.as_ref())
.map_err(|e| anyhow::anyhow!("encrypt failed: {e}"))?;
let mut out = Vec::with_capacity(32 + ct.len());
out.extend_from_slice(ephemeral_public.as_bytes());
out.extend_from_slice(&ct);
Ok(out)
}
Output layout:
[0..32] ephemeral_x25519_public
[32..] ChaCha20-Poly1305(shared_secret, receipt_bytes)
The ephemeral public key is generated per receipt, so two receipts to the same requester are not linkable by their ephemeral keys. The bridge sees only the requester’s static x25519 public key inside the shuffle envelope. Zero nonce is safe because the shared secret is fresh per call (ephemeral times static, ChaCha20-Poly1305 does not reuse keys). Only the requester’s static x25519 private key can decrypt.
Routing through the shuffle
The bridge does not push the sealed receipt across an open network:
pub async fn reply(
&self,
request_id: &RequestId,
sealed_receipt: Vec<u8>,
) -> anyhow::Result<()> {
// Publishes on the shuffle reply stream
// addressed to the peer the request came from.
// The shuffle carries the sealed blob; the blob
// is opaque to the shuffle.
self.reply_sender.publish(
request_id, sealed_receipt,
).await
}
The reply is addressed to the rotating peer_id
the request came from, not to the requester’s
coalition identity. An observer learns that the
bridge replied to a peer, not to which
coalition agent. Zipnet’s reply channel does not
guarantee in-order delivery relative to the
request; consumers key replies by request_id.
Replies ride the same shuffle the requests ride; a
bridge that tried to reply out of band would leak
its own identity, which the shuffle’s privacy
contract is designed to prevent.
What the requester does
The requester decrypts, verifies the host key
against the provided ssh_host_key, and SSHes in:
// requester side (not in the bridge's crate)
let receipt = SshAccessReceipt::unseal_with(
&sealed_from_shuffle,
&my_x25519_static_private,
)?;
let mut known_hosts = String::new();
known_hosts.push_str(&format!(
"[{}]:{} {}",
receipt.instance_host,
receipt.instance_port,
hex::encode(&receipt.ssh_host_key),
));
// … standard ssh with the per-grant private key
One function call to decrypt, then a standard ssh client. No bridge-specific client library.
Settlement
The receipt is delivered; the workload runs; the usage log is emitted. The coordination market then closes the loop.
The Compute module does not define a settlement
format. Each ComputeRequest carries a
settlement: UniqueId — a blake3 hash the
requester chose. The module stores the hash
opaquely. Whichever off-module rail the coalition
uses (on-chain payment contract, reputation
organism, credit token) is what dereferences the
hash and effects the transfer.
For bridge-β, the coalition publishes the rails
it supports on its handshake page; the bridge’s
dashboard records revenue as each rail commits a
transfer to the bridge’s settlement address. For
each cleared grant:
On-chain payment: the requester’s bid carried a
settlement hash pointing to an already-submitted
on-chain payment to a contract the coalition
operator published. The scheduler committee
verified the payment evidence at clearing. After
the ComputeLog lands, the committee releases the
payment to the bridge’s settlement address.
Reputation card: the requester’s bid carried a reputation card entry from an organism the bridge trusts; the bridge’s revenue is a reputation commit, not cash. Used for in-coalition credit systems where cash settlement is deferred.
The bridge does not directly manage either
settlement path. It commits the ComputeLog and
watches the dashboard. From
src/dashboard.rs:
pub enum DashboardEvent {
SubscriberJoined,
SubscriberLeft,
GrantAccepted { backend: String },
GrantCompleted { backend: String, usage: UsageDelta },
RevenueSettled { usd: f64 },
ProviderCardRefreshed,
}
RevenueSettled is what the dashboard records
when the module’s settlement side (on-chain or
reputation) commits the bridge’s share.
Revenue on the dashboard
The dashboard folds every RevenueSettled into a
rolling window total:
DashboardEvent::RevenueSettled { usd } => {
s.window_revenue_usd += usd;
}
The operator can now answer three questions live. Are declared rates being accepted? Revenue arrives after a grant clears and settles; rates that never clear produce zero regardless of capacity. Is the cost-to-revenue gap favourable? The dashboard folds per-backend cost estimates from the operator-supplied rate table; the difference is the bridge’s margin. Are some backends more profitable than others? Per-backend cost and usage split on the dashboard; bridges often discover one backend is chronically loss-making.
End-to-end privacy
Requester to bridge: shuffle-sealed request
envelope; the bridge sees a rotating peer_id and
an x25519 public key, not the coalition-facing
identity.
Bridge to requester: X25519-ChaCha20-Poly1305 sealed receipt; shuffle reply stream; requester decrypts with their static x25519 private key.
Operator view: aggregate dashboard only. No per-grant identity, no prompt, no per-requester attribution.
Coalition read side: the public ComputeLog
stream carries grant id, provider id, and usage.
No requester identity. No image contents.
Symmetrical with web3 — submission: both sides of the market are shuffle-anonymised, both sides receipt-sealed, both sides commit evidence pointers.
Multi-receipt flows
A grant with valid_to much larger than workload
runtime may terminate early. The bridge emits one
ComputeLog at termination; the requester re-
SSHing before valid_to on an expired instance
gets ConnectRefused — the per-grant private key
is dead. No second receipt is issued for the same
grant_id; the requester submits a fresh
ComputeRequest:
// requester side — continuation pattern
let fresh = ComputeRequest {
requester: self.id,
workload: same_organism_id,
pin: Some(same_content_hash),
duration_sec: DURATION_WINDOW,
settlement: self.new_settlement_evidence_hash()?,
deadline: now + deadline_ticks,
};
let grant = compute.submit_and_await(fresh).await?;
// … fresh receipt, fresh per-grant key, possibly a
// fresh backend if fleet routing shifted
Cross-references
- web3 — sealed submission and settlement
- Introduction — Shuffle
src/receipt.rs— the sealing primitive.src/zipnet_io.rs— the shuffle channel (namedzipnet_ioin the crate because zipnet is the specific shuffle implementation this example bonds against).
Reputation, retirement, successor chain
audience: ai
The bridge has bound to the Compute module (binding), read the market (market-reads, wrapping), provisioned grants (provisioning), and sealed receipts back to requesters (receipts). This chapter closes the loop: how the bridge’s reputation accumulates, how retirement and successor chains let the operator step down without stranding subscribers, and where the operator’s exit remains the substrate’s ultimate non-compulsion guarantee.
web2 ends here.
The provider-reputation organism
The reputation surface is a provider-reputation
standalone organism. In the minimal case, operated
by bridge-β itself; in a mature coalition,
shared across many bridges.
It subscribes to every bridge’s provider card and
the Compute module’s ComputeLog stream. For each
settled grant it looks at the log’s usage against
the requester’s self-reported usage (when posted)
and the bridge’s declared capacity, then scores
the bridge on a declared utility function
(on-time log emission, usage honesty, provisioning
success rate). It commits a
ProviderReputationCard per bridge per window.
pub const PROVIDER_REPUTATION: OrganismRef<'static> =
OrganismRef {
role: "provider-reputation",
stable_id: const_blake3!(
b"instance|bridge-β.provider-reputation|",
UNIVERSE.bytes(),
),
content_hash: Some(REPUTATION_IMAGE_MRTD),
};
Wired into the Compute module by setting the
provider_reputation field on its
OrganismConfig.content to
Some(PROVIDER_REPUTATION.stable_id()). This
changes the Compute module’s OrganismConfig
fingerprint. The bridge re-derives BRIDGE_BETA
(because the coalition’s compute field now
references a different content hash) and
republishes. Downstream requesters see the new
module Config and either rebond or stay on the
predecessor; the latter treats bridge-β as
legacy and may eventually stop bonding.
Reputation in the validator
The validator from
binding
gains a ReputationFloor clause:
use coalition::acl::ReputationFloor;
fn bridge_ticket_validator_v2()
-> TicketValidator<'static>
{
TicketValidator::new()
.require_ticket(
Tdx::new().require_mrtd(
COMPUTE_ORG_V2.content_hash.unwrap(),
),
)
.require_ticket(
ComputeModule::pin(
COMPUTE_ORG_V2.stable_id,
),
)
.require_ticket(
ReputationFloor::from(
PROVIDER_REPUTATION.stable_id(),
0.60, // 30-window average
),
)
.verify_peer(
ComputeModule::requester_acl(
COMPUTE_ORG_V2.stable_id,
),
)
}
When the bridge’s reputation falls below the floor, its own admission stops issuing new tickets. The Compute module’s next clearing no longer routes grants to the bridge. The active- subscriber count on the dashboard drops to zero. The bridge has self-degraded.
Strategy A from ai/sustainability.md, applied on the provider side; same mechanism as the searcher’s self-degradation path in web3.
Retirement on shutdown
When the operator retires cleanly (planned
decommission, replacement with a successor, moved
to a different coalition), the retirement marker
lets subscribers rebind without ConnectTimeouts.
From the bridge’s public surface
(setup):
use coalition::retirement::{
RetirementMarker, SuccessorHint,
};
async fn graceful_shutdown(
bridge: &Bridge<'_>,
network: &Arc<Network>,
successor: Option<OrganismRef<'_>>,
) -> anyhow::Result<()> {
let marker = RetirementMarker {
retired_at: network.almanac().tick(),
reason: "planned decommission",
successor: successor.as_ref().map(|s| s.stable_id()),
evidence: recent_log_pointer(),
};
bridge.retirement.publish(marker).await?;
// Wait one refresh window so subscribers see the
// marker before the card disappears.
tokio::time::sleep(Duration::from_secs(60)).await;
coalition_compute::deregister(
network, compute_cfg_v2.stable_id(),
bridge_provider_id(),
).await?;
Ok(())
}
The path is voluntary — nothing in mosaik forces
the bridge to retire. The operator decides; the
marker is a courtesy to subscribers. A successor
is optional; a bridge may retire without naming
one, and subscribers then fall back to whichever
provider the next clearing favours. Markers commit
exactly once. Late consumers find them by reading
the bridge’s retirement stream or by consulting
an Atlas card (when the coalition ships Atlas).
Successor handover
An operator rolling an upgrade usually:
- Stands up the successor (a second bridge
process, new
BRIDGE_IMAGE_MRTD, newBRIDGE_BETA_V2). Waits until its card is live. - Confirms the successor’s subscriber count is climbing (some subscribers rebind proactively once they see the new card).
- Emits a retirement marker on the predecessor
with
successor = Some(SUCCESSOR_ORG). - Shuts the predecessor down after a grace window, usually one or two refresh intervals.
This is the operator-driven analogue of the
searcher’s autonomous-renewal cycle
(web3 — sustainability — the autonomous-renewal
cycle in full).
The difference: a searcher’s policy can author
its own successor Config and request Compute
for the new image autonomously. A compute-
bridge’s identity is tied to operator-held cloud
credentials and bare-metal SSH keys that do not
travel through the substrate, so handover is
usually operator-driven.
A compute-bridge could run an autonomous
successor-authorship loop — a policy that re-
authors a new bridge.toml as cloud pricing
shifts, rebuilds the image, requests Compute for
the new binary, and emits the retirement marker.
Nothing in the substrate forbids it. Out of scope
for the minimal example.
Operator exit
The operator retains one unconditional power:
stop running the binary. Every retirement path
above happens only while the operator keeps the
predecessor process live long enough to commit
the marker. If the operator stops cold, in-flight
grants continue running on their provisioned
instances until valid_to passes, then the
backends time out. Cloud or bare-metal instances
keep running until the operator (or the backend’s
own max-lifetime) terminates them. Subscribers
pinning the bridge’s provider card eventually see
ConnectTimeout without a retirement marker — a
silent exit, per
ai/sustainability.md — threat model.
The reputation organism scores the bridge’s last
window normally; the Compute scheduler stops
clearing to the bridge on the next round when the
card goes stale.
The honest limit: Compute cannot compel an operator to host a successor’s workload (ai/compute.md — what remains out of scope). By the same token, the substrate cannot compel an operator to keep the bridge running. The operator’s revenue dries up; the operator’s cost obligations (cloud bills until they tear down their own sub-account) persist until they intervene.
Chronicle heartbeat (optional)
For operators who want aliveness cryptographically
anchored, bridge-β can ship Chronicle and commit
a periodic heartbeat:
use coalition::chronicle::{
ChronicleHandle, ChronicleKind, ProviderHeartbeatBody,
};
async fn heartbeat_forever(
chronicle: ChronicleHandle,
bridge: &Bridge<'_>,
) -> anyhow::Result<()> {
loop {
let body = ProviderHeartbeatBody {
provider_id: bridge_provider_id(),
active_grants: bridge.active_grants_snapshot(),
last_card_refresh: bridge.last_card_refresh(),
window: recent_window(),
};
chronicle.commit(
ChronicleKind::Other("provider-heartbeat"),
body,
).await?;
tokio::time::sleep(HEARTBEAT_INTERVAL).await;
}
}
Pattern Z from ai/sustainability.md — anti-abandonment patterns, applied on the provider side.
Dashboard — what the operator watches
The dashboard
(src/dashboard.rs)
is the operator’s sole interaction with the
running bridge. It exposes provider status
(registered, reachable, Measurements match,
reputation score), active subscriber count,
active and lifetime grant count, per-backend
capacity against current utilisation, window
usage (cpu-hours, ram GiB-hours, network GB),
window cost estimate from the operator-supplied
rate table, window settled revenue from the
market’s clearings, and a ring buffer of recent
events with requester identity redacted.
The dashboard enforces the shuffle privacy
contract on the operator too. The operator sees
flow, not identities: no requester PeerId,
no prompts, no image contents, no per-settlement
attribution.
What it does let the operator do: catch degradation early (a subscriber-count drop is the first signal the bridge’s position has slipped); detect reputation drift (the reputation score drops before subscribers move); reconcile cost and revenue (the cost estimate, though operator- supplied, is the first-order margin check; a bridge whose cost exceeds revenue across two or three windows is losing money, and the operator raises rates or retires).
Where the web2 example ends
The web2 example ends here. The book’s parallel examples continue with the TDX-attested price oracle (oracle — Overview), which exercises the publisher-side shape under a pure TDX trust anchor.
Readers ready to stand up the web2 composition next consult Part III:
- Integrators quickstart — the canonical shape-1 consumer path, which both examples extended into shape 2.
- Operators quickstart — running a coalition’s organisms, a Compute module committee, or a compute-bridge.
- Contributors topology-intro — commissioning a new basic service, a new composite organism, or a new class of mid-rung composition.
Cross-references
- web3 — reputation, retirement, successor chain
- Part I — sustainability — self-replication and self-modification
- Part I — emergent coordination — coordination markets
- Part III — basic services — Chronicle
oracle — a TDX-attested price oracle
audience: ai
This example walks a TDX-attested price oracle:
one standalone organism that ships a family of
price-tick streams, one stream per token pair, with
the whole trust model anchored on a declared TDX
Measurements set. Consumers that trust the oracle’s
image — that is, that admit its Measurements in their
TicketValidator — inherit the oracle’s prices by
construction. No reputation layer is required for the
minimal shape to work; the attestation is the
admission criterion.
The oracle lives in its own small coalition,
oracle-γ, which references the oracle organism and
(optionally, from chapter 7) a Chronicle for audit of
Measurements rotations. The chapter walks mirror the
web3 and web2 examples rung for rung, re-interpreted
for a data-publisher: reads become source reads,
wrapping wraps exchange feeds into the enclave,
inference becomes in-enclave aggregation, sealed
submission becomes continuous stream publication.
Unlike the other two examples, the oracle is a pure
standalone organism — it lives directly on the
universe and any coalition can reference it via
OrganismRef. oracle-γ is a packaging convenience
for the operator’s own retirement chain and Chronicle;
no consumer has to reference oracle-γ to consume the
oracle.
What is assumed
- TDX is in the composition. The oracle only makes sense when consumers can verify the image it runs. Non-TDX operation is technically possible (a developer’s local build exposing streams) but outside the trust model this example demonstrates.
- Readers understand Part I. The four agent shapes, the four emergent-coordination patterns (attestation fabric is the load-bearing one here), the TDX/non-TDX split, and the stigmergic-collection pattern for per-key streams are assumed. Part II does not re-explain them.
- No implementation crates yet. Code blocks are
rust,ignorespecification shapes matching the book’s crate plan (coalition,mosaik::tee::tdx, a hypotheticaloracle-feedhelper crate).
The oracle’s shape
- Coalition.
oracle-γ— the oracle operator’s ownCoalitionConfig. References one lattice (none, in the minimal version) and one standalone organism (the oracle itself). Ships no basic services in the minimal version; Chronicle is optional from sustainability. - Primary member. One shape-2 standalone organism
— the oracle, wrapped as a mosaik organism whose
public surface is a family of
Stream<PriceTick>keyed by token pair. ItsConfigfolds the source catalog hash, the aggregation-policy parameters, the supported token-pair set, the publication cadence, and — because TDX is always in the composition — the image post-hash. - Binding direction. The oracle is what consumers
bind to, not what binds to anyone else (except its
upstream price sources, which it reads through
non-mosaik feeds wrapped at
wrapping). A coalition that wants
oracle prices references the oracle via
OrganismRefand admits its Measurements in its ownTicketValidator.
What runs where
| Component | Operator | TDX? |
|---|---|---|
oracle-γ.oracle organism | Oracle operator | required (Measurements published) |
| Upstream CEX feed clients (Binance, Coinbase, Kraken) | Oracle operator | terminate inside the enclave |
| Upstream on-chain source (archive or light-client) | Oracle operator | terminates inside the enclave |
oracle-γ.chronicle (when shipped) | Oracle operator | optional |
Consumer coalition (searcher-α, any other) | Consumer operator | inherits the oracle’s Measurements pin via TicketValidator |
TDX on the oracle itself is not optional. A non-TDX build cannot produce the self-quote consumers pin against; admitting a non-TDX price feed collapses the trust model.
Chapters
- Setup and shape — dependencies,
CoalitionConfigfororacle-γ, the oracle’sOrganismConfigand declared Measurements. - Binding consumers — how a
consumer coalition references the oracle via
OrganismRef, composes itsTicketValidator, and performs its first stream subscription. - Reading price sources — what the oracle subscribes to inside its enclave: CEX spot APIs, on-chain pool reads, staleness accounting.
- Wrapping source feeds — lifting non-mosaik upstreams into the enclave: pinned TLS, archive or light-client reads, the source-availability state machine.
- Aggregation in the enclave — per-pair tick derivation: median, VWAP, outlier rejection, confidence, the source-set digest.
- Stream publication — one
Stream<PriceTick>per token pair, StreamId derivation, commit cadence, the per-bond attestation surface. - Rotation, retirement, successor chain — Measurements rotation, multi-operator fleets, retirement markers, operator-side exit.
Unlike web3, there is no market-maker variant; unlike web2, there is no provisioning side. The oracle has one shape: publish, continuously, under a pinned image.
Register and non-goals
- Register.
audience: ai— research-monograph, pattern-forward, code-forward where a shape is load-bearing. Density matches web3 and web2. - Non-goal. This is not a guide to building a production price oracle. Feed selection, upstream contracts with exchanges, commercial terms, regulatory posture, and settlement accounting are out of scope. Where the substrate touches those questions, the chapter names the boundary and stops.
- Non-goal. The example does not compare the mosaik-native composition to existing oracle networks (Chainlink, Pyth, Chronicle, UMA). Those systems solve adjacent problems under different trust anchors; the relevant delta here is that the oracle’s guarantees reduce to one declared Measurements set and the consumers’ willingness to admit it.
- Non-goal. The example does not specify the Compute basic service. The oracle runs its own TDX process; it does not use the coalition’s Compute module to schedule aggregation. An operator who wanted to schedule aggregation on Compute could do so, but that is a different example.
Cross-references
- Part I — AI overview
- Part I — emergent coordination — attestation fabrics
- Part I — sustainability
- Part II — web3 overview
- Part II — web2 overview
- Part III — contributors — composite organisms
Setup and shape
audience: ai
Three things are fixed before any code runs: the
crate-level dependencies, the oracle-γ coalition
shape, and the Measurements set the oracle publishes.
The Measurements set is the whole trust anchor of the
example; everything that follows refers to it.
Dependencies
Cargo.toml, [dependencies]
mosaik = "0.3"
coalition = "0.1" # this book's crate once published
oracle-feed = "0.1" # hypothetical helper for source catalogs
tokio = { version = "1", features = ["full"] }
mosaik::tee::tdx is re-exported from mosaik.
Versions land alongside the coalition crate; until
then, everything below is a specification shape.
The oracle’s OrganismConfig
The oracle is a standalone organism. Its Config
fingerprint does not fold a coalition root; the same
organism can be referenced by many coalitions.
use coalition::{OrganismConfig, SCHEMA_VERSION_U8};
use mosaik::tee::tdx::Measurements;
pub const ORACLE_MEASUREMENTS: Measurements =
Measurements::from_hex(
// MR_TD, MR_CONFIG_ID, MR_OWNER, MR_OWNER_CONFIG
// published on the oracle operator's release page
"b7f2…c9",
);
pub const ORACLE: OrganismConfig<'static> = OrganismConfig {
schema_version: SCHEMA_VERSION_U8,
role: "oracle",
instance_name: "oracle-γ.oracle",
members: &[], // simple organism
parameters: &OracleParameters::DEFAULT.preimage(),
measurements: Some(ORACLE_MEASUREMENTS),
acl: &OracleAcl::DEFAULT,
};
OracleParameters folds every state-affecting
parameter of the oracle’s deployment: the
supported-pair set, the source-catalog digest, the
aggregation-policy identifier, the publication
cadence, and the staleness thresholds. Any change to
any of them is a new Config.content — which, since
Measurements are folded in, forces a coincident image
republish. The two invariants travel together by
construction.
pub struct OracleParameters {
/// Every token pair the oracle publishes a stream for.
/// Pair form: ("USDC", "ETH") etc. Ordered
/// lexicographically so the preimage is canonical.
pub pairs: &'static [TokenPair],
/// blake3 of the source-catalog spec (see ch. 3).
pub source_catalog_digest: [u8; 32],
/// Identifier for the aggregation policy (ch. 5).
pub aggregation_policy: AggregationPolicyId,
/// Nominal inter-tick cadence in milliseconds.
pub cadence_ms: u32,
/// Per-source staleness threshold in milliseconds.
pub max_source_age_ms: u32,
}
OracleAcl composes the TicketValidator the oracle
bonds against: in the minimal version, an open
subscribe ticket (anyone can read any stream) and a
closed publish ticket (only the oracle’s own operator
key publishes). A consumer coalition’s admission is
on the consumer’s side, by admitting
ORACLE_MEASUREMENTS in its own
TicketValidator — not by being on a list here.
The oracle-γ coalition
oracle-γ is the thinnest coalition that wraps the
oracle as a single referenced member:
use coalition::{
CoalitionConfig, OrganismRef,
COALITION_ROOT_SEED, SCHEMA_VERSION_U8,
};
pub const ORACLE_ORG: OrganismRef<'static> = OrganismRef {
role: "oracle",
stable_id: const_blake3!(
b"instance|oracle-γ.oracle|", UNIVERSE.bytes()
),
content_hash: Some(ORACLE.content_hash()),
};
pub const ORACLE_GAMMA: CoalitionConfig<'static> =
CoalitionConfig {
schema_version: SCHEMA_VERSION_U8,
coalition_seed: COALITION_ROOT_SEED,
instance_name: "oracle-γ",
lattices: &[],
organisms: &[ORACLE_ORG],
atlas: None,
almanac: None,
chronicle: None, // added in chapter 7
compute: None,
randomness: None,
ticket_issuer: None,
retirement_policy: Default::default(),
};
Notes on the shape above:
content_hashis pinned. Unlikesearcher-α(which omits the content hash on its member pointer),oracle-γpins the oracle’s current content hash inside its own coalition. Every Measurements rotation is a new content hash and a coincidentoracle-γrepublish, observable through the retirement chain.- One-member coalition is not a contradiction. Coalitions with one referenced organism are a packaging convenience; they give the operator a coalition-scoped retirement chain and an optional Chronicle without implying any coordination.
- Consumers need not reference
oracle-γ. A consumer coalition may reference the oracle directly via a matchingOrganismRefon its own side.oracle-γis for the oracle operator’s retirement and Chronicle; it is not the handshake surface.
TDX posture
| Component | TDX required? | Measurements folded in? |
|---|---|---|
| oracle organism | yes | yes |
oracle-γ coalition wrapper | n/a | inherits via content_hash pin |
Consumer-side TicketValidator | no (consumer’s choice) | admits oracle Measurements |
The oracle operator’s public handshake surface is two values:
ORACLE.content_hash()— the oracle organism’s current content hash.ORACLE_MEASUREMENTS— the TDX Measurements set folded into that content hash.
Publishing both on a release page is sufficient for any consumer to compose admission. Nothing else is needed out-of-band.
Forward
Chapter 2
(binding) is the consumer side: how
a coalition references the oracle, composes its
TicketValidator, and performs its first stream
subscription. Chapters 3–5 walk the oracle’s interior:
what it reads, how it wraps non-mosaik feeds, how it
derives each tick. Chapter 6 walks publication.
Chapter 7 walks rotation, retirement, and the
operator exit.
Binding consumers
audience: ai
The oracle exposes a family of Stream<PriceTick>
endpoints, one per supported token pair. A consumer
coalition that wants oracle prices does three things,
in order: reference the oracle in its own
CoalitionConfig, compose a TicketValidator that
admits the oracle’s Measurements, and subscribe to
the streams it cares about. This chapter walks all
three from the consumer side; the oracle operator
does not participate in the handshake beyond
publishing ORACLE.content_hash() and
ORACLE_MEASUREMENTS.
Referencing the oracle
A consumer coalition (for instance, searcher-α from
the web3 example) references
the oracle through its own OrganismRef pointer:
use coalition::{OrganismRef, MeasurementsPin};
pub const ORACLE_CONSUMED: OrganismRef<'static> =
OrganismRef {
role: "oracle",
stable_id: ORACLE_STABLE_ID, // from the oracle's release page
content_hash: Some(ORACLE_CONTENT_HASH), // pinned
};
The reference is to the same organism the oracle
operator publishes. The stable_id and
content_hash come from the oracle operator’s
release page (setup); nothing is
negotiated out-of-band. If the consumer chooses to
follow rotations, it pins only the stable_id and
tracks content_hash updates through the
retirement chain (see
sustainability). If the
consumer pins both, a Measurements rotation requires
a consumer-side republish to remain bonded.
Composing the TicketValidator
The consumer’s TicketValidator admits the oracle’s
Measurements in its TDX arm:
use mosaik::tickets::{TicketValidator, And, Or};
use mosaik::tee::tdx::AdmitsMeasurements;
pub fn oracle_consumer_validator()
-> TicketValidator<'static>
{
TicketValidator::compose(
// Consumer's own ACL for who runs this searcher.
searcher_alpha::SELF_ACL,
// Admits any peer whose self-quote matches the
// oracle's published Measurements.
AdmitsMeasurements::equal(ORACLE_MEASUREMENTS),
)
}
AdmitsMeasurements::equal is the simplest
composition: the consumer accepts exactly the
declared Measurements set and nothing else. A
consumer that is willing to follow staged rotations
may use AdmitsMeasurements::in_set(&[MR_OLD, MR_NEW]) across a rotation window; see
sustainability.
First subscription
The stream endpoint for a given pair is addressed by
the oracle’s stable_id and the pair identifier:
use mosaik::streams::{StreamId, Subscription};
let network: Arc<Network> = /* from coalition bootstrap */;
let pair = TokenPair::new("USDC", "ETH");
let stream_id = StreamId::derive(
ORACLE_CONSUMED.stable_id(),
&pair.preimage(),
&PRICE_TICK_SCHEMA_V1,
);
let mut subscription: Subscription<PriceTick> =
network.subscribe(stream_id, oracle_consumer_validator()).await?;
while let Some(tick) = subscription.next().await {
// PriceTick::verify re-checks the oracle's quote
// on the stream's bond plus the commit's schema.
tick.verify(&ORACLE_MEASUREMENTS)?;
handle_tick(tick);
}
Two properties of the subscription are worth naming:
- Admission is one-sided. The oracle’s bond ACL admits any subscriber; the consumer’s validator admits any peer whose Measurements match. The bond either forms or it does not; there is no handshake step the oracle operator participates in.
PriceTick::verifyre-checks the oracle’s self-quote that was folded into the bond at subscription time. It does not re-quote per tick; TDX quotes are bond-level. Per-tick tamper detection is covered by the oracle’s signing key (see publication).
What the consumer can and cannot assume
- Prices are post-aggregation. The tick is what
the oracle’s declared
AggregationPolicyIdproduced after reading its sources (aggregation). The consumer does not see per-source quotes; only the aggregate, thesource_set_digest, and the staleness flag. - Cadence is nominal. The oracle publishes at the nominal cadence when all sources are fresh and quorate. When a source degrades, the oracle may skip a tick or publish a stale-flagged tick; both are covered under aggregation.
- Trust reduces to one set of bytes. The
consumer’s trust in the oracle is the admission
of
ORACLE_MEASUREMENTS. No reputation layer, no chain of signers, no multi-party commit. A consumer who wants reputation-gated oracle admission composes that on top — but the minimal shape does not require it.
Forward
Chapter 3 (source-reads) inverts the viewpoint: what the oracle itself reads, inside its enclave, to produce the ticks the consumer just subscribed to.
Reading price sources
audience: ai
The oracle’s inputs are exchange and chain feeds. None of them are mosaik-native; all of them live on the other side of the enclave boundary. This chapter specifies what the oracle subscribes to and what the admission criterion for each source is. The next chapter (wrapping) walks how the subscriptions terminate inside the enclave.
The source catalog
The oracle ships a declared source catalog —
the set of upstream feeds it reads, broken down per
token pair. The catalog’s blake3 digest is folded
into OracleParameters.source_catalog_digest
(setup), so any change to the catalog
is a new oracle Config.content.
pub struct SourceCatalog {
pub entries: &'static [(TokenPair, &'static [Source])],
}
pub enum Source {
CexSpot {
exchange: CexExchange, // Binance, Coinbase, Kraken, …
symbol: &'static str, // "ETHUSDC", "ETH-USD", …
endpoint: &'static str, // wss://…
tls_spki: &'static [u8], // pinned SPKI digest
},
OnChainAmm {
chain_id: u64,
pool_address: Address,
protocol: AmmProtocol, // UniswapV3, Curve, …
read_mode: OnChainReadMode, // ArchiveNode or LightClient
quorum: u8, // minimum node agreement
},
OnChainOracle {
// References another mosaik oracle organism as a
// source. Used for long-tail pairs where this
// oracle aggregates peers.
organism: OrganismRef<'static>,
pair: TokenPair,
},
}
Three classes of source, each with its own admission criterion:
- CEX spot feeds — pinned TLS SPKI. The
enclave’s HTTPS client refuses any cert chain
whose leaf SPKI does not match
tls_spki. A forced MITM would show as a handshake failure and a source-unavailable state (see below), not as a silently wrong price. - On-chain AMM reads — either an archive node
the oracle operator runs (trust folded into the
Measurements through
chain_idand the client binary) or a light client verifying against Ethereum consensus (trustless in the light-client sense).quorumcontrols how many independent archive or light-client reads must agree before the source is considered fresh. - On-chain oracle (peer) — another mosaik oracle organism. The enclave subscribes to that organism’s stream exactly the way any consumer does (binding). This is how long-tail pairs get coverage: aggregate two or three other oracles whose Measurements the enclave admits.
Per-pair source selection
A pair’s entry in the catalog is the ordered list of sources the oracle will consult each tick. The aggregation policy (aggregation) decides what to do with the collected quotes; the source list only decides what to ask.
pub static SOURCE_CATALOG: SourceCatalog = SourceCatalog {
entries: &[
(TokenPair::new("USDC", "ETH"), &[
Source::CexSpot {
exchange: CexExchange::Binance,
symbol: "ETHUSDC",
endpoint: "wss://stream.binance.com:9443/ws/ethusdc@bookTicker",
tls_spki: BINANCE_WSS_SPKI_2026Q2,
},
Source::CexSpot {
exchange: CexExchange::Coinbase,
symbol: "ETH-USD",
endpoint: "wss://ws-feed.exchange.coinbase.com",
tls_spki: COINBASE_WSS_SPKI_2026Q2,
},
Source::OnChainAmm {
chain_id: 1,
pool_address: uniswap_v3::ETH_USDC_POOL,
protocol: AmmProtocol::UniswapV3,
read_mode: OnChainReadMode::LightClient,
quorum: 1,
},
]),
// further pairs …
],
};
Reasonable mixed catalogs combine CEX and on-chain sources; a pure-CEX catalog is cheapest to run but vulnerable to exchange-side outages and pair-delisting events. A pure-on-chain catalog is settlement-honest for the chain in question but lags the CEX book during volatile periods.
Staleness accounting
Each source carries a per-source timestamp. The
oracle’s
OracleParameters.max_source_age_ms
(setup) is the threshold past which a
source is considered stale. The aggregation
policy decides what to do with a stale source;
commonly: drop it from the quorum and flag the
resulting tick if the drop pushes the source count
below a declared minimum.
The in-enclave source state machine per source:
handshake OK, first msg within window
┌─────── ──────────── ──────────── ──────┐
▼ │
fresh ──── msg older than max_age_ms ────► stale
▲ │
│ ▼
└─── reconnect + first msg within ── reconnecting
A source in reconnecting drops out of the
aggregation quorum. The oracle publishes a tick
anyway if the remaining sources meet the minimum;
otherwise it publishes no tick and the consumer
sees a gap in the stream cadence.
What the catalog is not
- Not a price index. The catalog names sources, not weightings. Weightings and outlier rejection are the aggregation policy’s job (aggregation).
- Not a failover list. Sources are consulted in parallel each tick; there is no primary/secondary distinction. Aggregation and quorum decide which sources contribute to the published tick.
- Not operator-confidential. The catalog digest
is part of
OracleParameters, which is part of the oracle’sConfig.content, which is reproducible from the operator’s release page. Consumers pin it transitively through the content hash.
Forward
The sources listed above live outside mosaik. The next chapter walks how they are terminated inside the enclave so that nothing outside the Measurements set can observe or tamper with their reads.
Wrapping source feeds
audience: ai
The oracle’s trust model collapses if any of its
sources is read outside the enclave. This chapter
specifies how each source class from
source-reads is terminated
inside the TDX guest so that the only code that
touches cleartext prices is the code whose
MR_TD the consumers admitted.
The enclave boundary
The oracle process runs in a TDX guest. Its
Measurements cover MR_TD (the guest’s initial
memory image), MR_CONFIG_ID (the guest’s folded
configuration, including the source-catalog digest),
and the owner set
(MR_OWNER, MR_OWNER_CONFIG). Nothing outside
the guest can observe or inject into the
subscriptions below.
┌─────────────────────────────────────────────────┐
│ TDX guest — measured by ORACLE_MEASUREMENTS │
│ │
│ ┌──────────────┐ ┌──────────────────────────┐ │
│ │ CEX clients │ │ on-chain readers │ │
│ │ (TLS-pinned) │ │ (archive / light client) │ │
│ └──────┬───────┘ └───────────┬──────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌────────────────────────────────────────┐ │
│ │ aggregation + publication pipeline │ │
│ └───────────────────┬────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────┐ │
│ │ mosaik Stream commits │ │
│ │ (signed by enclave) │ │
│ └──────────────────────┘ │
└─────────────────────────────────────────────────┘
▲ │
│ host I/O (opaque) │ signed commits
│ ▼
untrusted host consumer subscribers
Host I/O crosses the boundary only as ciphertext or as TLS bytes whose endpoints are pinned inside the enclave. Nothing else is trusted.
CEX spot feeds
Each Source::CexSpot entry is a WebSocket
subscription terminated by a TLS client built into
the oracle image. The client:
- Pins SPKI. The TLS handshake checks the leaf
certificate’s SPKI against
tls_spkifrom source-reads. Any mismatch is a hard-fail; the source transitions toreconnectingand does not recover until a matching handshake. - Ignores the host’s resolver. Hostnames are resolved inside the enclave (DoH to a pinned resolver, or the resolver identity is folded into the Measurements alongside the SPKI pin).
- Rejects downgrade. TLS 1.3 only; any negotiation past a declared cipher-suite set is a hard-fail.
A single shared TlsClient inside the enclave
holds an (exchange, pair) → WebSocket map; each
message arriving is stamped with an enclave-local
timestamp and forwarded to the aggregation
pipeline.
pub struct TlsClient {
config: Arc<rustls::ClientConfig>, // pinned SPKI verifier
}
impl TlsClient {
pub async fn subscribe(
&self,
source: &Source,
) -> Result<BoxStream<'static, RawQuote>, SourceError> {
match source {
Source::CexSpot { endpoint, symbol, tls_spki, .. } => {
let stream = self.connect_ws(endpoint, *tls_spki).await?;
Ok(stream.map(|msg| parse_raw_quote(symbol, msg)).boxed())
}
_ => unreachable!("non-CEX sources handled elsewhere"),
}
}
}
On-chain AMM reads
Source::OnChainAmm entries read AMM pool slots
(Uniswap V3 slot0, Curve get_virtual_price,
etc.) through one of two paths:
- Archive node. The operator runs an archive
node (e.g.
reth --fullorgeth --syncmode snap) whose RPC endpoint is accessible only from the enclave’s network namespace. The client authenticates the RPC session with a mutual TLS pair whose CA cert is folded into the oracle’s Measurements; the archive node’s identity is therefore transitively part of the oracle’s trust model. An operator who runs their archive node honestly delivers honest reads; a dishonest or compromised archive node shows up as quorum disagreement ifquorum > 1. - Light client. The enclave runs an Ethereum consensus light client that verifies every execution-layer read against a sync-committee- signed head. Under honest-majority assumptions on the consensus layer, the reads are trustless. Slower than archive; strictly stronger trust story.
pub struct OnChainReader {
archive: Option<Arc<ArchiveClient>>, // mTLS-pinned
light: Option<Arc<LightClient>>, // consensus-verified
}
impl OnChainReader {
pub async fn read(
&self,
source: &Source,
) -> Result<Quote, SourceError> {
match source {
Source::OnChainAmm { read_mode, .. } => match read_mode {
OnChainReadMode::ArchiveNode => self.read_archive(source).await,
OnChainReadMode::LightClient => self.read_light(source).await,
},
_ => unreachable!(),
}
}
}
The choice between archive and light client is the
oracle operator’s. Most operators run archive in
production (latency) and light in a verifier role
(cross-check); some catalog entries mark a source
quorum: 2 meaning both an archive read and a
light-client read must agree within a tolerance
before the source contributes.
Peer oracle sources
Source::OnChainOracle entries subscribe to another
mosaik oracle exactly the way a consumer does
(binding). The enclave’s
TicketValidator composes the peer oracle’s
Measurements alongside its own; the resulting
streams feed into the aggregation pipeline like any
other source.
The composition is transitive: the oracle’s
Measurements cover a code path that admits another
oracle’s Measurements. A consumer of this oracle
who wants to audit the peer set can do so by reading
SOURCE_CATALOG (its digest is in the content
hash) and verifying each referenced oracle’s
published Measurements.
Source-availability reporting
The aggregation pipeline is supplied with a live per-source availability map:
pub struct Availability {
pub fresh: HashSet<SourceId>,
pub stale: HashSet<SourceId>,
pub reconnecting:HashSet<SourceId>,
}
Availability is updated on every message arrival and every reconnect-timeout. The aggregation policy (aggregation) reads this snapshot each tick to decide whether to publish, skip, or flag.
What the enclave never does
- It never accepts unpinned TLS. A non-matching SPKI is a hard-fail.
- It never leaks raw source quotes outside the guest. Only aggregated ticks leave the enclave, and only through the signed mosaik stream commits in publication.
- It never imports source data through the host OS. File-backed cache, shared memory, and host syscalls other than network I/O are not used. Any cache is in-guest RAM only.
Forward
Chapter 5 (aggregation) specifies what the in-enclave pipeline does with the fresh quotes once they arrive.
Aggregation in the enclave
audience: ai
Each tick, for each supported pair, the enclave
collects the fresh quotes from the source-availability
snapshot (wrapping), runs the
declared aggregation policy, and produces one
PriceTick. The aggregation policy is the rung where
“in-enclave” stops being a plumbing detail and starts
being the thing the consumers’ trust reduces to.
The PriceTick commit shape
pub struct PriceTick {
/// Enclave-local wall clock at aggregation moment.
pub timestamp_ms: u64,
/// Ordered pair (base, quote). ETH/USDC, BTC/USDC, etc.
pub pair: TokenPair,
/// The aggregated price in fixed-point units of quote per base.
pub price: FixedPrice,
/// Confidence band — max(abs(source_i - price)) among
/// contributing sources, in quote-per-base units.
pub confidence: FixedPrice,
/// blake3 of the ordered list of contributing SourceIds.
/// Consumers cross-reference against the published SOURCE_CATALOG
/// to know which sources voted for this tick.
pub source_set_digest: [u8; 32],
/// Number of sources that contributed. Below a declared
/// minimum, the tick carries the `stale` flag.
pub source_count: u8,
/// Set when one or more declared sources were unavailable
/// and the tick is being published with degraded quorum.
pub stale: bool,
/// Monotonic sequence number within the stream. Gaps
/// indicate the oracle skipped a tick (e.g. no quorum).
pub seq: u64,
}
The enclave signs every PriceTick with its
long-term signing key (bound to MR_TD via the
first quote folded into the Stream’s bond; see
publication). Per-tick quotes
would be expensive and unnecessary — the consumer
verified the quote once at subscription time; the
per-tick signature binds each commit back to the
same measured guest.
Aggregation policies
OracleParameters.aggregation_policy is an
identifier selecting one of a small catalog of
policies. The catalog is part of the oracle image,
so adding a new policy is a new Measurements set.
pub enum AggregationPolicyId {
/// Weighted median across fresh sources. Outliers
/// beyond `k * MAD` are dropped before the median.
WeightedMedian { k: u16, weights: &'static [SourceWeight] },
/// Volume-weighted average across CEX sources plus
/// pool-weighted on-chain reads. Weights published
/// with the image.
Vwap { weights: &'static [SourceWeight] },
/// Minimum required quorum before any output; below
/// the threshold, no tick.
QuorumFloor {
inner: &'static AggregationPolicyId,
min_sources: u8,
},
}
All three forms are specified inside the enclave
image. The parameters (k, weights, min_sources)
are folded into Measurements via the image content;
a consumer who wants to audit the policy reproduces
the image from its published build recipe and reads
the constants.
The selected policy operates on the fresh snapshot:
pub fn aggregate(
policy: &AggregationPolicyId,
fresh: &[(SourceId, Quote)],
) -> AggregationOutcome {
match policy {
AggregationPolicyId::WeightedMedian { k, weights } => {
let filtered = mad_filter(fresh, *k);
let price = weighted_median(&filtered, weights);
AggregationOutcome::Published {
price,
confidence: max_dev(&filtered, price),
source_count: filtered.len() as u8,
contributing_ids: filtered.iter().map(|(id, _)| *id).collect(),
}
}
AggregationPolicyId::Vwap { weights } => { /* … */ }
AggregationPolicyId::QuorumFloor { inner, min_sources } => {
if fresh.len() < *min_sources as usize {
AggregationOutcome::Skip
} else {
aggregate(inner, fresh)
}
}
}
}
Outlier rejection
Outlier rejection uses Median Absolute Deviation
(MAD). For a snapshot of fresh quotes q_1 … q_n:
m = median(q_1 … q_n)MAD = median(|q_i - m|)filtered = { q_i : |q_i - m| ≤ k * MAD }
MAD is robust against asymmetric outlier
distributions in a way that standard-deviation
filters are not. The threshold k is a published
image constant; higher k lets more variance
through (useful during volatile periods); lower
k is stricter.
A degenerate case: if MAD = 0 (two or more sources
agree exactly), any non-agreeing source is rejected.
The Rust implementation folds a small absolute floor
to avoid this pathology on identical-tick
snapshots.
Confidence and the stale flag
confidence is the max deviation among
contributing sources from the published price. A
confidence band much larger than usual tells a
consumer that the sources disagreed this tick; the
consumer can choose to act on a wide band.
The stale flag is set when:
source_count < min_sourceson aQuorumFloor-wrapped policy (no publication at all; gap inseq).- One or more sources declared in the catalog are
reconnectingat aggregation time; the tick is published withstale: trueif remaining sources still meet quorum.
A consumer that distinguishes fresh from stale ticks gets both liveness (keep seeing prices) and safety (know when to widen spreads or halt).
Determinism inside the enclave
Aggregation is deterministic given the fresh snapshot and the policy. Two honest oracle replicas running the same image with the same source catalog and the same upstream feeds at the same moment produce the same tick. This is useful for:
- Multi-operator fleets (sustainability) — several operators publishing the same stream with the same ticks, letting consumers follow over when one retires.
- Audit replay — an operator rebuilding the image from the declared constants and replaying captured upstream feeds reproduces the historical stream.
Network timing and TCP message ordering differ across replicas; exact bit-for-bit replay across operators is therefore approximate at tick-level. Over a window, the ticks converge to the same aggregated prices modulo sub-cadence de-synchronisation.
What the pipeline never does
- It never publishes a tick from a single
source without the
staleflag. Single-source ticks are either skipped or flagged. - It never publishes the raw per-source quotes. Only the aggregate, the confidence, and the source-set digest leave the enclave.
- It never adjusts the policy at runtime.
Policy identifiers and their parameters are
part of
OracleParameters, part of the oracle’s content hash, part of Measurements. An operator who wants a new policy publishes a new image.
Forward
Chapter 6 (publication) specifies
the mosaik surface the aggregated ticks flow through:
one Stream<PriceTick> per supported pair, signed by
the enclave, readable by anyone who admitted the
oracle’s Measurements.
Stream publication
audience: ai
Each supported token pair is a separate
Stream<PriceTick>. The enclave commits one tick
per cadence per pair (or skips, when the quorum
floor is not met). This chapter specifies the
stream surface: identifier derivation, commit
cadence, the per-bond attestation, and what the
enclave’s signing key is bound to.
One stream per token pair
The oracle publishes one Stream<PriceTick> per
TokenPair in OracleParameters.pairs
(setup). The stream identifier folds
the oracle’s stable id, the pair’s preimage, and
the commit schema version:
use mosaik::streams::{StreamId, Stream, StreamAcl};
pub fn stream_id_for(pair: &TokenPair) -> StreamId {
StreamId::derive(
ORACLE.stable_id(),
&pair.preimage(),
&PRICE_TICK_SCHEMA_V1,
)
}
PRICE_TICK_SCHEMA_V1 folds the PriceTick layout
byte-for-byte (field order, width, signedness). Any
future schema change is a new SchemaVersion, a
new StreamId, and — because schemas are folded
into OracleParameters through the aggregation
policy’s published constants — a new image.
Consumers migrate on their own cadence.
The pair preimage is canonicalised at the catalog
level: base and quote are sorted lexicographically
inside the TokenPair constructor, so
TokenPair::new("ETH", "USDC") and
TokenPair::new("USDC", "ETH") hash the same
preimage and address the same stream. The pair’s
semantic orientation (ETH priced in USDC vs. USDC
priced in ETH) is a property of the price field
within the tick, not of the stream identifier.
The publish loop
The enclave runs one publish task per supported pair:
pub async fn publish_loop(
pair: &TokenPair,
stream: &Stream<PriceTick>,
sources: &SourceSubscriptions,
policy: &AggregationPolicyId,
cadence: Duration,
) {
let mut seq: u64 = 0;
let mut next_tick = Instant::now() + cadence;
loop {
tokio::time::sleep_until(next_tick.into()).await;
next_tick += cadence;
let fresh = sources.fresh_snapshot(pair);
match aggregate(policy, &fresh) {
AggregationOutcome::Published { price, confidence, source_count, contributing_ids } => {
let tick = PriceTick {
timestamp_ms: wall_clock_ms(),
pair: *pair,
price,
confidence,
source_set_digest: blake3_source_set(&contributing_ids),
source_count,
stale: sources.any_reconnecting(pair),
seq,
};
stream.commit(tick).await.expect("commit failed");
seq += 1;
}
AggregationOutcome::Skip => {
// no commit; consumers see the gap in `seq`.
}
}
}
}
Cadence is per-pair. A fast-moving pair like
ETH/USDC may run at 250 ms cadence; a long-tail
pair may run at 5 s. All cadences are declared in
OracleParameters and folded into Measurements.
The bond-level attestation
When a consumer subscribes to a pair’s stream
(binding), the enclave presents a
TDX self-quote covering MR_TD,
MR_CONFIG_ID, and the owner set — that is,
ORACLE_MEASUREMENTS in full. The consumer’s
TicketValidator verifies the quote against its
pinned Measurements and completes the bond. The
quote is thereafter part of the bond’s state; it
is not re-issued per tick.
The bond-level surface is what makes the trust model cheap: one expensive verification at bond time, plus cheap per-tick signature checks against a key whose derivation is bound to the attested image.
The enclave’s signing key
The signing key used for PriceTick::sign is
derived inside the enclave via TDX key derivation
(mosaik::tee::tdx::derive_key or equivalent).
The derivation folds MR_TD and the
OracleParameters.aggregation_policy identifier,
so:
- A different image (different
MR_TD) derives a different key. Signed ticks from an image a consumer did not admit do not verify against the signing key the consumer expects. - A replay from outside the enclave cannot reconstruct the key without a compatible TDX measurement, which it does not have.
- A Measurements rotation derives a new key; the consumer’s verification after a rotation uses the new key once it has followed the retirement chain (sustainability).
Back-pressure
Mosaik Stream commits are non-blocking for the
publisher: a slow subscriber that cannot keep up
falls behind and re-syncs from a checkpoint on
reconnect. The enclave does not tune its cadence
to the slowest subscriber; cadence is a published
property of the oracle, and admission is
per-subscriber.
A subscriber that falls behind by more than the
oracle’s declared retention window (published in
OracleParameters) misses intervening ticks
entirely. Most consumers sit well inside the
window and never notice.
What publication guarantees
- Every published tick was produced by an enclave whose Measurements the consumer admitted. Attested by the bond-level quote and re-verified per-tick by the signing key derivation.
- Missing ticks mean the oracle had no quorum
or was skipping. Gaps in
seqare visible; a consumer who cares about liveness detects them trivially. - Stream identifiers are stable across
Measurements rotations only if the aggregation
policy and schema are unchanged. A rotation
that changes only the image but keeps the
policy and schema preserves
StreamId; consumers continue reading the same streams from a different key. A rotation that changes the schema changesStreamIdand a consumer must resubscribe.
Forward
Chapter 7 (sustainability) walks what happens when the operator rotates Measurements, retires the instance, or stands up a multi-operator fleet.
Rotation, retirement, successor chain
audience: ai
The oracle has bound consumers (binding), read its sources (source-reads), terminated them inside the enclave (wrapping), aggregated ticks (aggregation), and published per-pair streams (publication). This chapter closes the loop: how Measurements rotations are staged without a subscriber flap, how a multi- operator fleet composes, how retirement chains preserve stream continuity, and where the operator’s exit remains the substrate’s ultimate non-compulsion guarantee.
Measurements rotation
The oracle rotates Measurements whenever:
- The underlying image changes (security patches, upstream crate updates, new aggregation policy version).
- A source in the catalog changes its TLS SPKI pin,
and the pin is folded into
MR_CONFIG_ID. - A declared constant changes (cadence, staleness threshold, quorum floor).
Any such change is a new OracleParameters, a new
ORACLE.content_hash(), a new self-quote, a new
signing key. The operator’s publication step is
one release page update carrying both the new
content hash and the new Measurements.
Staged rotation
A blunt rotation — switch off the old image, switch on the new — drops every consumer who pinned the old Measurements. Most deployments stage rotations so consumers can follow:
- Stand up the new image alongside the old.
Two TDX guests on the operator’s hardware, two
distinct
MR_TD, two distinct signing keys, two distinct bond surfaces. Both committing to the sameStreamIdis not possible (ORACLE.stable_id()changes on retirement); both committing to a newStreamIdunder a new oracle instance is the normal path. - Publish both
ORACLE_MEASUREMENTS_OLDandORACLE_MEASUREMENTS_NEWon the release page. Consumers update theirAdmitsMeasurements::in_set(&[OLD, NEW])composition ahead of the cutover. - Emit a retirement marker pointing from OLD
to NEW. The marker is an on-stream commit in
the old organism’s retirement channel pointing
at the new organism’s
stable_idandcontent_hash. - Keep OLD running in read-only mode for a declared grace window. Consumers who have not followed the retirement chain continue to read OLD’s last ticks; consumers who followed it resubscribe to NEW.
- Decommission OLD at the end of the grace window.
The RetirementMarker shape is the same one from
the rest of the book:
pub struct RetirementMarker {
pub retired_at: SeqOrTimestamp,
pub reason: RetirementReason, // Rotation, Retired, Operator exit, …
pub replacement: Option<OrganismRef<'static>>,
}
A rotation is reason: Rotation with a non-empty
replacement. A shutdown is reason: Retired with
None. Operator exit is reason: OperatorExit
with None; see below.
Multi-operator fleets
The oracle’s trust model admits any number of
independent operators running the same image. Two
operators running identical binaries on identical
source catalogs land identical Measurements and
therefore the same ORACLE.content_hash(); each
publishes its own coalition (oracle-γ-op1,
oracle-γ-op2) and its own organism instance
(each with a distinct stable_id because the
instance name differs).
From a consumer’s perspective:
- Each operator’s oracle is a distinct organism with its own stable id but the same content hash.
- The consumer’s
TicketValidatoradmits the shared Measurements regardless of which operator’s instance it bonds against. - A consumer that wants redundancy subscribes to two operators’ pair streams and applies a consumer-side aggregation (a second-order median, for instance).
A multi-operator fleet is the first-order answer to operator failure, collusion resistance (modulo the shared image), and geographic diversity. The substrate’s non-compulsion property holds here too: operators join or leave the fleet voluntarily, and no one instance compels any other.
Chronicle: auditing rotations
For operators who want a tamper-evident record of
rotations and retirement markers, oracle-γ may
ship the Chronicle basic service:
pub const ORACLE_GAMMA_WITH_CHRONICLE: CoalitionConfig<'static> =
CoalitionConfig {
schema_version: SCHEMA_VERSION_U8,
coalition_seed: COALITION_ROOT_SEED,
instance_name: "oracle-γ",
lattices: &[],
organisms: &[ORACLE_ORG],
atlas: None,
almanac: None,
chronicle: Some(CHRONICLE_CONFIG),
compute: None,
randomness: None,
ticket_issuer: None,
retirement_policy: Default::default(),
};
The Chronicle records every coalition-level event: oracle rotations, source-catalog updates, retirement markers. It does not record every tick; the per-pair streams are already an immutable audit of the ticks. The Chronicle complements them with a single authoritative log of operational events.
Self-replication and self-modification
Under the TDX/non-TDX split
(ai/sustainability.md), the oracle
image may author its own successor: a new image,
a new Measurements set, a new OracleParameters
instance, a retirement marker pointing at
itself.
The honest limit is narrow and explicit. The autonomous-successor path only runs when the operator has configured the oracle to run an autonomous policy (one that can, for instance, detect outdated upstream crates and republish). Even then:
- Compute cannot compel an operator to host the successor. The new image schedules itself on Compute; the operator-side running-the- binary decision remains the non-compulsion anchor.
- Consumers are not forced to follow. A
consumer that pinned the OLD Measurements
strictly (no
in_set) does not follow a successor. The retirement chain is a signal, not a command. - A successor whose policy changed discontinuously loses consumers. Consumers who followed the chain on the assumption of a bugfix find a policy they did not admit; the next rotation gives them the option to follow a version they did admit, or leave.
The operator exit
At any time, the oracle operator can:
- Emit a
RetirementMarkerwithreason: OperatorExitandreplacement: None. - Stop running the image.
Consumers who had pinned the oracle’s Measurements see the streams stop. Consumers subscribed to a multi-operator fleet fail over to another operator. Nothing in the substrate keeps the operator running.
This is load-bearing. The oracle’s trust model is strong precisely because the operator can leave, because the Measurements pin is a voluntary admission on the consumer side, and because no coalition-level machinery binds the operator to continue publishing. The substrate does not compel.
What ends here
Every mosaik surface the book’s thesis names is exercised across the three Part II examples:
- web3 — consumer-side bonding to a lattice, Compute as requester, sealed submission.
- web2 — provider-side bonding to a coordination market, Compute as provider, sealed receipts.
- oracle — publisher-side bonding with an attestation anchor, standalone organism as a family of keyed streams, rotation and retirement under a pure TDX trust model.
Part II ends here. Part III carries the role- specific guidance for builders standing up any of the three shapes, or a fourth shape the catalog admits because it stays open by design.
Cross-references
- Part I — sustainability
- Part I — emergent coordination — attestation fabrics
- Part III — operators — rotations and upgrades
- Part III — contributors — threat model
signer — a generic threshold-signature organism
audience: ai
This example walks a generic threshold-signature
organism — an organism that takes a message from a
requester, produces a t-of-n threshold signature
across a committee of providers with varying
attestation levels, and commits the signature on a
public surface consumers gate their own
TicketValidators against. Design inspired by
zipnet and inverted:
where zipnet decrypts, this organism signs.
The scenario the example exercises: a market of
signature providers with variable levels of
attestation competing for ticket-validator
admission. Some providers run software-only.
Others run TDX-attested. Others run TDX with
bidirectional RA-TLS and a reproducible-build root
whose hash binds the binary. Consumers compose a
TicketValidator clause that admits signed outcomes
only when the participating providers’ aggregate
attestation clears a declared floor; providers below
the floor are ignored without being expelled.
The organism lives in its own small coalition,
signer-δ, and is generic over the message type
M: SignableMessage (exactly as zipnet is generic
over D: ShuffleDatum).
What the organism demonstrates
- Inverse-of-zipnet shape. Zipnet decrypts sealed broadcasts; signer produces signatures. Both are threshold-committee organisms with the same surface shape: a typed request stream, a typed outcome collection, a committee ACL, a generic message parameter.
- Scheme polymorphism. A single
signerdeployment commits to oneSignatureScheme. The supported schemes include BLS12-381 (G1 and G2), FROST Schnorr (secp256k1 and ed25519), FROST ECDSA, and classical Shamir-Lagrange. Twosignerinstances that differ only in scheme derive distinct organism ids. - Attestation variance. Unlike zipnet (uniform
MR_TD across the committee), the signer
organism’s committee tolerates providers at
different attestation levels. The organism’s
min_attestation_levelis a floor; providers above the floor register; consumers gate above the floor at their own discretion. - Competition on attestation + capacity + price.
Providers publish
ProviderCards carrying their supported schemes, declared attestation level, Measurements digest, capacity, and fee per partial signature. Consumers and the organism’s scheduler select providers from the card collection.
Why this example is in the book
The three earlier Part II examples exercise three roles that together describe most of the coordination-market surface: consumer (web3), provider (web2), publisher (oracle). The signer example adds the fourth role that the other three do not directly exercise: a threshold committee organism whose value to every consumer is the signature it produces, and whose internal structure is a market of competing members.
- web3 shows an AI agent consuming a lattice and a coordination market.
- web2 shows a provider competing in a coordination market.
- oracle shows a publisher whose trust model reduces to one Measurements set.
- signer shows a committee-internal market where providers compete on attestation and the organism’s output is a threshold signature consumers gate their admission against.
The signer-δ shape
- Coalition.
signer-δ— a one-member wrapper around the signer organism, matching theoracle-γandsearcher-αpatterns. - Primary member. One standalone organism — the
signer, generic over
M: SignableMessage. ItsConfigfolds the scheme, the threshold, the minimum attestation level, the committee DKG public-key digest, and the message type tag. - Member market. Committee membership is itself
a market: providers register as
ProviderCards and compete for inclusion in the next committee-rotation window. Consumers that care about the market read theProviderCardcollection directly (provider-reads).
What runs where
| Component | Operator | Attestation |
|---|---|---|
signer-δ.signer organism | Signer operator | declared floor |
| Committee member A (software-only) | Provider A | Software |
| Committee member B (TDX-local) | Provider B | TdxLocal |
| Committee member C (TDX-remote attested) | Provider C | TdxRemote |
| Committee member D (RA-TLS bidirectional) | Provider D | TdxRaTlsBidirectional |
| Committee member E (TDX + reproducible build) | Provider E | TdxPlusReproducibleBuild |
Consumer (searcher-α, any other) | Consumer operator | its own choice |
A consumer that requires TdxRemote or higher will
accept outcomes only when at least t of the
participating providers carry a matching or
stronger level. A consumer willing to accept
Software-level providers will admit anything.
Admission is consumer-side; no central authority
re-computes it.
Chapters
- Setup and shape —
Config, scheme selection, committee formation, thesigner-δcoalition wrapper. - Binding consumers — how a
consumer references the signer organism,
composes a
TicketValidatorwith an attestation floor, and verifies signatures. - Reading the provider market
— the
ProviderCardcollection, the attestation ladder, consumer-side provider selection. - Wrapping attestation surfaces — how a provider ships each attestation level: software declarations, TDX quotes, RA-TLS bidirectional, reproducible-build roots.
- Partial-signing in the committee — the request flow: message digest in, partial sigs out, committee-internal reconstruction.
- Aggregate and publish — how
partial signatures combine into the final
aggregate and how the
SignatureOutcomeis committed to the public surface. - Committee rotation, key refresh, successor chain — proactive DKG refresh, committee-member replacement, retirement markers.
Register and non-goals
- Register.
audience: ai— dense, pattern- forward, code-forward where a shape is load-bearing. Every section cites the Rust types inexamples/signer/where they are defined. - Non-goal. Not a threshold-cryptography primer. BLS, FROST, and GG18 have their own literature; this example specifies only the organism’s composition shape on mosaik. Where a protocol detail is load-bearing (non-interactive vs. interactive scheme, nonce-commit rounds) the chapter names it and links out.
- Non-goal. Not a catalog of every signature
scheme worth supporting. The
SignatureSchemeenum lists a useful representative set; a production deployment extends it by republishing the organism under a newConfig. - Non-goal. Not a settlement or payment design.
Provider fees are a declared field; the book
pins the shape (
fee_per_partial_wei) and stops short of specifying settlement rails.
Cross-references
- zipnet book — the threshold-committee organism this example inverts.
- Part I — emergent coordination — attestation fabrics — the pattern this example instantiates.
- Part II — oracle overview — the closest kin: single-trust-anchor organism vs. variable-trust-anchor committee.
- Part II — web2 overview
— the provider-market analog; the signer-δ’s
ProviderCardand the bridge-β’sProviderCardare structurally the same shape. - The
coalitioncrate — the data-model crate every Part II example imports from.
Setup and shape
audience: ai
Three things are fixed before the signer can run:
the crate-level dependencies, the signer-δ
coalition shape, and the Config that pins scheme,
threshold, committee size, and minimum attestation
floor. The backing crate is at
examples/signer/;
every type named below is exported from it.
Dependencies
Cargo.toml, [dependencies]
mosaik = "0.3"
coalition = "0.1"
signer = "0.1" # this book's crate
tokio = { version = "1", features = ["full"] }
The SignableMessage trait
The signer is generic over message type. Downstream
crates implement SignableMessage for their
concrete shape; the trait’s TYPE_TAG folds into
the organism’s identity preimage so two signer
instances that differ only in message type derive
distinct ids.
pub trait SignableMessage: 'static {
/// Domain-separation tag folded into every
/// request's digest.
const TYPE_TAG: &'static [u8];
/// Bound on the request body size; committee
/// bandwidth stays predictable.
const MAX_BODY_BYTES: usize;
}
// For the generic OpaqueMessage case the example ships:
pub struct OpaqueMessage;
impl SignableMessage for OpaqueMessage {
const TYPE_TAG: &'static [u8] = b"opaque-bytes.v1";
const MAX_BODY_BYTES: usize = 64 * 1024;
}
A real deployment signing beacon-chain attestations
would carry
TYPE_TAG = b"eth2.attestation.phase0"; one signing
coalition-level retirement commits would carry
b"coalition.retirement.v1".
The signer organism’s Config
The organism’s identity preimage folds every parameter that changes behaviour:
use coalition::UniqueId;
use signer::{AttestationLevel, Config, OpaqueMessage, SignatureScheme};
pub const SIGNER_CFG: Config<'static, OpaqueMessage> =
Config::new(
/* instance_name */ "signer-δ.default",
/* scheme */ SignatureScheme::BlsAggregateG1,
/* threshold */ 5,
/* committee_size */ 7,
/* min_attestation_level */ AttestationLevel::TdxRemote,
/* committee_pk_digest */ COMMITTEE_PK_V1,
);
const COMMITTEE_PK_V1: UniqueId =
mosaik::unique_id!("signer-δ.committee.aggregate-pk.v1");
Identity derivation (as implemented in
Config::organism_id):
SIGNER(cfg) = blake3(
"signer|"
|| SCHEMA_VERSION_U8
|| "|" || instance_name
|| "|" || M::TYPE_TAG
|| "|" || scheme_discriminant
|| "|" || threshold || committee_size
|| "|" || min_attestation_level_discriminant
|| "|" || committee_pk_digest
)
Any change to any of those parameters is a new
organism_id. That includes:
- A new signature scheme — every consumer
TicketValidatorthat pinned the old id stops admitting outcomes from the new one until it republishes. - A raised attestation floor — consumers that pinned the old floor continue admitting the organism at the old level; a rotation to a new id forces an explicit consumer-side consent.
- A new committee DKG key — the standard key- refresh event (see sustainability).
The signer-δ coalition
Packaging wrapper, one member:
use coalition::{
CoalitionConfig, OrganismRef,
COALITION_ROOT_SEED, SCHEMA_VERSION_U8,
RetirementPolicy,
};
pub const SIGNER_ORG: OrganismRef<'static> =
OrganismRef::by_stable_id(
"signer",
const_blake3!(
b"instance|signer-δ.signer|",
UNIVERSE.bytes(),
),
);
pub const SIGNER_DELTA: CoalitionConfig<'static> =
CoalitionConfig {
schema_version: SCHEMA_VERSION_U8,
coalition_seed: COALITION_ROOT_SEED,
instance_name: "signer-δ",
lattices: &[],
organisms: &[SIGNER_ORG],
atlas: None,
almanac: None,
chronicle: None, // added in ch. 7
compute: None,
randomness: None,
ticket_issuer: None,
retirement_policy: RetirementPolicy::CONSERVATIVE,
};
Consumers need not reference signer-δ; they
reference the signer organism directly via their
own OrganismRef. The coalition wrapper exists for
the operator’s retirement chain and optional
Chronicle.
Attestation-level ladder at a glance
Software // declared-identity only
▲
TdxLocal // TDX quote, peer-verified
▲
TdxRemote // TDX quote, DCAP-verified
▲
TdxRaTlsBidirectional // bidirectional RA-TLS
▲
TdxPlusReproducibleBuild // RA-TLS + reproducible-build root
Config.min_attestation_level is the floor the
organism accepts. Providers above the floor compete
for committee slots; consumers above the floor
compose their own higher-floor TicketValidator
clause independently (binding).
What is published
Three values the signer operator publishes to consumers:
SIGNER_CFG.organism_id()— the signer’s stable id.SIGNER_CFG.committee_pk_digest— the committee’s DKG aggregate public key digest.SIGNER_CFG.min_attestation_level— the declared floor.
Any three-way combination of those values is sufficient for a consumer to compose admission without out-of-band handshake.
Forward
Chapter 2 (binding) walks the
consumer side: referencing the signer, composing a
TicketValidator that gates on aggregate
attestation, and verifying committed outcomes.
Binding consumers
audience: ai
A consumer that wants signatures produced by
signer-δ does four things:
- Reference the signer organism in its own
CoalitionConfigviaOrganismRef. - Compose a
TicketValidatorclause that gates admission onSignatureOutcome::admissible(floor)against the consumer’s declared attestation floor. - Subscribe to the organism’s outcome collection.
- Submit a
SignatureRequestand read the correspondingSignatureOutcome.
The organism operator does not participate in the handshake beyond publishing the three values from setup.
Referencing the organism
use coalition::{OrganismRef, UniqueId};
pub const SIGNER_CONSUMED: OrganismRef<'static> =
OrganismRef::by_stable_id(
"signer",
SIGNER_STABLE_ID, // from the signer operator's release page
);
A consumer that wants to track committee-rotation events pins only the stable id; a consumer that wants to lock to a specific committee instance pins both the stable id and the current content hash.
Composing a TicketValidator with an attestation floor
The consumer’s own validator composes two clauses:
the organism’s ACL (so bonds form against the
expected committee) and an attestation-floor gate on
any committed SignatureOutcome the consumer acts
on.
use mosaik::tickets::{TicketValidator, And};
use signer::{AttestationLevel, OpaqueMessage, SignatureOutcome};
pub fn signer_consumer_validator(
floor: AttestationLevel,
) -> TicketValidator<'static> {
TicketValidator::compose(
// Bond acceptance — any signer-δ committee member.
SIGNER_CONSUMED.any_committee_member(),
// Predicate on every received outcome: admit iff
// the aggregate attestation level meets the
// consumer's floor.
OutcomePredicate::new(
move |o: &SignatureOutcome<OpaqueMessage>|
o.admissible(floor)
),
)
}
OutcomePredicate is the consumer’s own
wrapper — the substrate TicketValidator admits
predicates over received messages; the consumer
wraps SignatureOutcome::admissible verbatim.
Selecting a floor
The attestation ladder is totally ordered (provider-reads documents the full taxonomy). A consumer picks the floor that matches the consequence of a forged signature:
| Use case | Floor recommendation |
|---|---|
| Staging / non-financial signatures | Software |
| Dev-environment aggregation | TdxLocal |
| Production signatures consumed by a third-party verifier | TdxRemote |
| Signatures that feed cross-org attestation chains | TdxRaTlsBidirectional |
| Signatures whose forgery would compromise consumer keys | TdxPlusReproducibleBuild |
The choice is per consumer. A single signer-δ deployment serves the full spectrum; consumers that disagree on the floor admit different subsets of the same outcome stream.
Submitting a request and reading the outcome
use std::marker::PhantomData;
use signer::{OpaqueMessage, SignatureRequest, SignatureScheme};
let network: Arc<Network> = /* from coalition bootstrap */;
let validator = signer_consumer_validator(AttestationLevel::TdxRemote);
// Submit.
let req: SignatureRequest<OpaqueMessage> = SignatureRequest {
request_id: UniqueId::hash(b"req-001"),
requester: SEARCHER_ALPHA.stable_id(),
message_digest: UniqueId::hash(&message_body),
scheme: SignatureScheme::BlsAggregateG1,
deadline_unix_secs: now_unix() + 10,
_phantom: PhantomData,
};
signer::Signer::<OpaqueMessage>::request(&network, &SIGNER_CFG)
.await?
.submit(req, validator.clone())
.await?;
// Read the outcome.
let mut outcomes = signer::Signer::<OpaqueMessage>::outcomes(
&network, &SIGNER_CFG,
).await?.subscribe(validator).await?;
while let Some(outcome) = outcomes.next().await {
if outcome.request_id == req.request_id {
// `validator` already rejected the outcome
// if its aggregate_attestation_level did not
// meet the floor, so this branch only fires
// on admissible outcomes.
process_signature(outcome.signature_digest).await?;
break;
}
}
Two properties of the subscribe pipeline are worth naming:
- Gate happens at the bond, not at the
application. The consumer’s validator rejects
inadmissible outcomes before the application sees
them; there is no per-message
if admissiblecheck in the business logic. - Signature bytes arrive out-of-band. The public
SignatureOutcomecarries a digest only. The actual signature is delivered through a sealed side channel (through the committee’s encrypted- response shape, similar to web2’s encrypted SSH receipts). The digest in the outcome pins what the side-channel payload must verify to.
What the consumer can and cannot assume
- Every admitted outcome’s participating providers meet the consumer’s floor. The aggregate attestation level is the minimum across participants; if the aggregate meets the floor, every individual signer did.
- Aggregate verification remains the consumer’s
job.
admissible(floor)is the attestation check. The consumer still BLS-verifies the aggregate signature against the committee’s published public key; the organism commits the signature digest, not a “this verifies” assertion. - The floor can rise over time without a republish. A consumer hardening its posture rebuilds its validator with a higher floor; the existing bond to the organism still works, the validator just accepts fewer outcomes. No coordination with the signer operator is required.
Forward
Chapter 3 (provider-reads) is the inverse perspective: the consumer reads the provider-market collection to audit which attestation levels the committee currently carries, independently of any specific outcome.
Reading the provider market
audience: ai
The signer organism’s provider market is a public
Collection<ProviderId, ProviderCard>. Any bonded
peer can read it; providers write their own card;
the organism’s committee scheduler selects from the
collection when rotating committee membership.
Consumers read the collection when they want to
audit the committee’s current attestation mix
independently of any specific outcome.
The ProviderCard shape
pub struct ProviderCard {
pub provider_id: UniqueId,
pub schemes_supported: Vec<SignatureScheme>,
pub attestation_level: AttestationLevel,
/// Measurements digest for TDX-attested providers;
/// long-term identity digest for software-only.
pub attestation_digest: UniqueId,
pub capacity_per_second: u32,
pub fee_per_partial_wei: u128,
pub committed_at_unix_secs: u64,
}
Every field is read-side; the write-side ACL is the
provider’s ACL composed with the organism’s
min_attestation_level floor. A provider below the
floor cannot register.
The attestation ladder in full
The AttestationLevel enum is totally ordered; a
level meets a floor iff its discriminant is ≥ the
floor’s. The five levels, bottom to top:
Software
Declared identity only. The provider publishes a long-term software signing key; no hardware attestation. Consumers trust only the declaration, and if the software is compromised, all signatures it produced are suspect. Viable for staging or for signatures whose forgery cost is below the cost of attesting.
TdxLocal
TDX self-quote produced inside the guest. Peer committee members verify against declared Measurements. No external relying party. A consumer outside the committee cannot re-verify; the level’s value is to other committee members bonding against each other.
TdxRemote
TDX quote verified against Intel DCAP’s remote attestation service (or an equivalent operator-run service whose trust root is published). A consumer outside the committee can re-verify the quote and confirm the provider ran a Measurements-matched image. This is the canonical floor for production deployments.
TdxRaTlsBidirectional
Both sides of the attested channel produce and verify quotes at bond formation. A signer whose counterpart failed to produce a quote refuses to bond; a signer whose counterpart produced a non-matching quote refuses. Downgrade attacks become visible as bond-formation failures rather than as silently accepted non-attested counterparts.
TdxPlusReproducibleBuild
RA-TLS bidirectional plus the provider publishes the build recipe whose hash the Measurements attest to. A third party reproduces the build from source, verifies that the resulting binary hashes to the same Measurements, and confirms the committee is running the code the source describes. Without the reproducible root, the consumer trusts that the operator built the image honestly; with it, the consumer verifies the binary matches the source without running the operator’s image.
The eligibility check
Every provider’s card is evaluated against the
organism’s deployment parameters. The check is
ProviderCard::is_eligible(scheme, floor):
impl ProviderCard {
pub fn is_eligible(
&self,
scheme: SignatureScheme,
floor: AttestationLevel,
) -> bool {
self.attestation_level.meets(floor)
&& self.schemes_supported.iter().any(|s| *s == scheme)
}
}
Two conditions: the provider’s attestation level
meets the floor, and the provider declares support
for the scheme the organism commits to. A
provider that wants to serve two schemes registers
two entries in schemes_supported; a provider that
wants to serve two floors in two separate
deployments registers two cards with distinct
provider ids.
Consumer-side selection
The consumer does not need to pick specific providers; the organism’s scheduler picks. But a consumer that cares about the attestation distribution reads the card collection and can:
- Audit the mix. Count providers at each level.
If the consumer’s floor is
TdxRemoteand onlycommittee_size - 2providers meet it, the consumer knows admission will succeed only when the 2-provider gap is not on the threshold boundary. - Rank by fee. A consumer that wants to
estimate cost reads
fee_per_partial_weiper card and forecasts end-to-end cost asthreshold × mean(fee). - Track capacity. A consumer planning a burst
reads
capacity_per_secondper card and computes whether the committee can absorb the peak.
None of these are required; the organism’s scheduler runs correctness-safe selection regardless. The collection exists because mosaik’s stigmergic-collection pattern (emergent coordination — pattern 1) works at this rung: public reads, consumer-side filtering, no central allocator.
Provider competition shape
Providers compete on three axes. All three fold
into ProviderCard::card_digest; a change to any
is a republish event observable through the
collection.
- Attestation level. Higher levels pull in more consumers (wider admission) at higher operational cost (reproducible builds require source-and- toolchain hygiene).
- Capacity. A provider with higher
capacity_per_secondwins more committee slots in bursty windows; a provider with lower capacity runs cheaper. - Fee.
fee_per_partial_weiis the per-partial- signature price the provider commits to. A provider charging above the committee median needs matching quality (higher attestation, lower tail latency, better availability); a provider charging at or below median gets routine allocation.
A reputation organism gating admission on
ProviderCard quality (uptime, completed-requests
ratio, attestation-challenge pass rate) is the
closest kin to the web2 provider-reputation
pattern. This chapter names the shape and stops;
reputation organisms are specified once in
ai/emergent-coordination.md — pattern 2.
Forward
Chapter 4 (wrapping) walks the provider side: how each attestation level is produced in practice — TDX quote, Intel DCAP verification, RA-TLS bidirectional channel, reproducible-build recipe.
Wrapping attestation surfaces
audience: ai
Every attestation level from provider-reads is produced the same way at the mosaik bond layer: the provider publishes evidence that another peer can verify before the bond forms. This chapter walks how each level is produced in practice, what the provider’s image does to ship it, and what the verifier re-checks.
Software — the null case
The provider’s attestation_digest is the blake3
digest of its long-term Ed25519 identity public
key. The bond-formation handshake checks signatures
produced by that key against the published digest.
There is no hardware evidence; the Software level
names that fact explicitly rather than pretending
otherwise.
// Provider side.
let identity_sk = ed25519::SigningKey::from_bytes(&seed);
let identity_pk = identity_sk.verifying_key();
let attestation_digest = UniqueId::hash(identity_pk.as_bytes());
// Verifier side, inside the bond handshake.
let challenge = bond_challenge_bytes();
let sig = peer_sign(challenge);
assert!(identity_pk.verify(&challenge, &sig).is_ok());
Threat model: a key-leak compromises every signature the provider ever produced under that identity. A provider losing its key publishes a retirement marker; consumers downstream of the leaked provider’s signatures re-verify against a new identity.
TdxLocal — per-peer TDX quote
The provider runs inside a TDX guest whose
Measurements are declared in the organism’s
Config. At bond-formation, the provider
generates a TDX quote binding the bond’s nonce and
the peer’s identity into the quote’s report_data
field.
// Inside the TDX guest, provider-side.
let report_data = blake3::Hasher::new()
.update(b"signer-bond|")
.update(peer_identity_pk.as_bytes())
.update(&bond_nonce)
.finalize();
let quote = mosaik::tee::tdx::generate_quote(&report_data);
// Peer verifies locally.
let quote = receive_quote_from_bond();
let td_info = mosaik::tee::tdx::parse_quote("e)?;
assert_eq!(td_info.mr_td, DECLARED_MR_TD);
assert_eq!(td_info.mr_config_id, DECLARED_MR_CONFIG_ID);
assert_eq!(
td_info.report_data,
expected_report_data(peer_identity_pk, &bond_nonce),
);
The verification is local — no round trip to
Intel’s DCAP service. A peer verifying a
TdxLocal quote re-computes the attestation check
against Intel’s anchor certificates (shipped with
the verifier image) and the organism’s declared
Measurements.
Threat model: the TDX guest’s image is the trust
anchor. An attacker with a zero-day against TDX
defeats local verification; the
TdxRemote level adds a DCAP round-trip that
independent consumers rely on.
TdxRemote — DCAP-verified quote
Same generation path as TdxLocal. The
verification path additionally routes the quote
through Intel’s DCAP attestation service (or a
declared equivalent):
let quote = receive_quote_from_bond();
// Local parse (same as TdxLocal).
let td_info = mosaik::tee::tdx::parse_quote("e)?;
assert_eq!(td_info.mr_td, DECLARED_MR_TD);
// Additional: DCAP round-trip.
let dcap = mosaik::tee::tdx::dcap::Client::new(
DECLARED_DCAP_ROOT_URL,
);
let verdict = dcap.verify("e).await?;
assert!(matches!(verdict, dcap::Verdict::Ok));
A consumer outside the committee can re-verify an outcome’s aggregate by pulling the participating providers’ quotes from the organism’s stream of bond-time evidence and re-running the DCAP verification. This is the canonical production floor.
TdxRaTlsBidirectional — two-way attested channel
Both sides of the bond produce and verify quotes. Neither side accepts a non-attested counterpart; a committee member whose peer fails to produce a quote refuses to bond.
let server = mosaik::tee::tdx::ra_tls::server_config(
DECLARED_MR_TD,
);
let client = mosaik::tee::tdx::ra_tls::client_config(
DECLARED_MR_TD,
);
// Server side:
let (peer_quote, stream) = server.accept(tcp).await?;
let peer_td = parse_and_verify(&peer_quote)?;
assert_eq!(peer_td.mr_td, DECLARED_MR_TD);
// Client side:
let (peer_quote, stream) = client.connect(tcp, peer_spki).await?;
let peer_td = parse_and_verify(&peer_quote)?;
assert_eq!(peer_td.mr_td, DECLARED_MR_TD);
The bidirectional check matters at bond-formation. A downgrade attack — an adversary attempting to convince a matched-Measurements peer to accept a non-attested counterpart — surfaces as a connection refused at the RA-TLS handshake, not as a silently-accepted bond later caught by a second- line audit.
TdxPlusReproducibleBuild — source-to-binary anchor
The highest declared level. The provider additionally publishes:
- The build recipe — a declarative
specification (Nix derivation, Bazel rule,
Dockerfilechecked-in under a pinned base image) that produces the binary whose Measurements the organism declared. - A reproducible build artefact with a declared toolchain version. Anyone reproducing the build gets a binary with matching Measurements.
The consumer verifies:
// Offline verification by the consumer (or a third
// party auditing on the consumer's behalf).
let recipe = fetch(PROVIDER_RECIPE_URL).await?;
let recipe_digest = blake3::hash(&recipe);
assert_eq!(recipe_digest, DECLARED_RECIPE_DIGEST);
let build_output = rebuild_from_recipe(&recipe)?;
let mr_td = mosaik::tee::tdx::measurements_from_image(&build_output);
assert_eq!(mr_td, DECLARED_MR_TD);
This does not reduce trust to zero; the consumer still trusts the toolchain’s integrity and the declared anchor certificates. But the consumer no longer trusts the operator’s build pipeline — the binary the operator ships is the binary the source produces.
What the verifier never does
Across all levels above Software:
- Never accept a quote whose Measurements do not match the declared set. A committee member that receives a non-matching quote treats the peer as absent, not as a fallback to a lower level.
- Never ship the quote’s body into the public
SignatureOutcome. The outcome carries a digest of the quote; the full quote is held by bonded peers and published to the organism’s evidence stream where consumers can pull it for audit. - Never re-use a quote across bonds. The bond nonce is fresh per bond; a replayed quote is an attack and rejected at the verifier.
Forward
Chapter 5 (signing) walks the request flow: how an admitted request enters the committee, how each provider produces a partial signature, and how partial sigs reach the committee-internal aggregator.
Partial-signing in the committee
audience: ai
This chapter walks what happens inside the signer
committee when a SignatureRequest arrives: how
the committee admits the request, how each
provider produces a partial signature, and how
partial sigs converge toward the aggregate. The
committee-internal aggregation and the public
commit live in aggregation.
The request pipeline
requester committee verifier
│ │ │
│ SignatureRequest │ │
│ (message_digest, scheme) │ │
│─────────────────────────────>│ │
│ │ │
│ │ partial_sig(member i) │
│ │ ◄──────── × committee_size │
│ │ │
│ │ aggregate (off-stream) │
│ │ ──────────────────────────── │
│ │ │
│ SignatureOutcome │ │
│<─────────────────────────────│ │
│ signature_digest, │ │
│ participating_providers, │ │
│ aggregate_attestation_level │ │
│ │ │
│ │ signature_bytes (sealed) │
│ │ ─────────────────────────────>
Request admission
A SignatureRequest is admitted iff:
- ACL. The requester’s ticket composes cleanly
with the organism’s
TicketValidator. The check is the same mosaik primitive every other organism uses; nothing signer-specific. - Scheme match.
req.schemeequalsConfig.scheme. A request for an unsupported scheme is rejected at the stream ACL; it never reaches the committee. - Body size. The side-channel body (delivered
alongside the request digest via the operator-
declared sealed channel) is ≤
M::MAX_BODY_BYTES. - Deadline.
req.deadline_unix_secsis in the future. Late requests are dropped rather than queued past their deadline.
Admission is cheap; the expensive work is the per-member partial-signing round below.
Per-member partial signing
Each committee member, on admitting the request, runs the scheme-specific partial-sign function:
// Inside the provider's TDX guest (for any
// attestation level above Software).
pub fn partial_sign<M: SignableMessage>(
req: &SignatureRequest<M>,
body: &[u8], // from sealed channel
share_sk: &SchemeSecretShare,
) -> PartialSignature {
assert_eq!(UniqueId::hash(body), req.message_digest);
match req.scheme {
SignatureScheme::BlsAggregateG1 =>
bls::partial_sign_g1(body, share_sk),
SignatureScheme::BlsAggregateG2 =>
bls::partial_sign_g2(body, share_sk),
SignatureScheme::FrostSchnorrSecp256k1 =>
frost_schnorr::partial_sign_secp256k1(
body, share_sk, ¤t_nonce_commit(),
),
SignatureScheme::FrostSchnorrEd25519 =>
frost_schnorr::partial_sign_ed25519(
body, share_sk, ¤t_nonce_commit(),
),
SignatureScheme::FrostEcdsaSecp256k1 =>
frost_ecdsa::partial_sign(
body, share_sk, ¤t_nonce_commit(),
),
SignatureScheme::LagrangeBls =>
lagrange::partial_sign(body, share_sk),
}
}
Two protocol families, one shape in the book. The
member’s result is a PartialSignature committed
to a committee-internal stream (not the public
surface); aggregation runs off that stream.
Non-interactive vs. interactive schemes
The SignatureScheme::is_non_interactive()
predicate separates the two families:
-
Non-interactive — BLS12-381 (both curves) and Shamir-Lagrange. A partial signature is self-contained; the committee aggregator can combine partials at any time in any order once the threshold is reached.
-
Interactive — FROST variants (Schnorr and ECDSA). Partial signatures reference a nonce commit the committee must run one round ahead of time. A missing nonce commit forces a retry, which the committee amortises across a window of upcoming requests.
The organism’s committee ships a nonce-commit
rotation loop iff Config.scheme.is_non_interactive()
is false. For BLS deployments the loop is absent
and the commit bandwidth is zero.
if !Config::<M>::scheme(&cfg).is_non_interactive() {
spawn_nonce_commit_rotator(&committee_handle);
}
Partial-sig visibility
The committee-internal stream carrying
PartialSignatures is not publicly readable.
Its ACL admits only bonded committee members.
Reasons:
- Partial-sig forgery window. A partial signature tied to a request id is meaningful only to the aggregator; leaking it early lets a byzantine aggregator claim the signature without running the full threshold. Restricting the audience to current committee members bounds the attack surface.
- Cross-committee correlation. A provider that serves multiple signer deployments could leak one deployment’s partial sigs into another’s aggregator. The ACL composition pins each deployment’s committee to its own stream.
The publicly readable artefact from this rung is
the SignatureOutcome committed in
aggregation; partial sigs are
committee-internal by design.
Member failure and threshold slack
The threshold is t-of-n; the committee
tolerates n − t absent members per request. A
request with fewer than t partial sigs at the
deadline commits no outcome. The committee emits a
RequestTimedOut entry (with the request id and
the count achieved) so the requester can resubmit
or escalate.
Non-adversarial absence — a committee member restarting, a transient network fault — resolves at the next cadence without operator intervention. Persistent absence triggers a committee rotation (sustainability).
Determinism
The partial-sign function is deterministic given
(body, share_sk) for non-interactive schemes and
deterministic given
(body, share_sk, nonce_commit) for interactive
schemes. Two honest providers running the same
image against the same share produce the same
partial signature. Aggregators treat a non-
matching partial from a non-interactive provider
as a byzantine fault and exclude the provider from
the round.
Forward
Chapter 6 (aggregation) walks
what happens after t partial sigs are in hand:
the aggregate combine, the SignatureOutcome
commit, and the sealed delivery of the signature
bytes back to the requester.
Aggregate and publish
audience: ai
With t partial signatures in the committee’s
internal stream, the aggregator combines them into
the final threshold signature, commits a public
SignatureOutcome, and delivers the signature
bytes to the requester through the sealed side
channel declared at setup. This
chapter specifies all three steps and the shape
consumers gate admission against.
Aggregate
The aggregator is any committee member — the
protocol does not assign a fixed leader. Whichever
member first observes t partial sigs for a
request runs the scheme-specific combine:
pub fn aggregate<M: SignableMessage>(
cfg: &Config<'_, M>,
partials: &[PartialSignature],
) -> Result<AggregateSignature, AggregateError> {
assert!(partials.len() >= cfg.threshold as usize);
match cfg.scheme {
SignatureScheme::BlsAggregateG1 =>
bls::aggregate_g1(partials),
SignatureScheme::BlsAggregateG2 =>
bls::aggregate_g2(partials),
SignatureScheme::FrostSchnorrSecp256k1 =>
frost_schnorr::combine_secp256k1(partials),
SignatureScheme::FrostSchnorrEd25519 =>
frost_schnorr::combine_ed25519(partials),
SignatureScheme::FrostEcdsaSecp256k1 =>
frost_ecdsa::combine(partials),
SignatureScheme::LagrangeBls =>
lagrange::combine(partials),
}
}
Under non-adversarial assumptions the combine is
deterministic and verifies against the committee’s
published aggregate public key
(Config.committee_pk_digest). A failed combine —
malformed partials, mismatched nonce commits, a
byzantine signer producing garbage — is logged and
the aggregator runs the combine with a different
subset of partials if the count allows.
The public SignatureOutcome
Once a verifying aggregate is in hand, the
aggregator commits a SignatureOutcome on the
organism’s outcome collection. The outcome carries
only metadata; the signature bytes themselves go
through the sealed side channel.
pub struct SignatureOutcome<M: SignableMessage> {
pub request_id: UniqueId,
pub signature_digest: UniqueId,
pub participating_providers: Vec<UniqueId>,
pub aggregate_attestation_level: AttestationLevel,
pub committed_at_unix_secs: u64,
pub _phantom: PhantomData<M>,
}
Four fields a consumer acts on:
request_id— joins the outcome back to the requester’s earlier submission.signature_digest— blake3 of the aggregate signature bytes. Consumers pulling the sealed-channel payload verify the delivered signature hashes to this digest.participating_providers— thetproviders whose partials combined into the aggregate. Consumers can cross-reference against theProviderCardcollection (provider-reads).aggregate_attestation_level— the minimum attestation level across the participating providers. This is the field the consumer’sTicketValidatorgates against (binding).
The minimum — not the majority, not the
declared-on-card — is what the outcome carries. A
request served by four TdxRemote providers and
one TdxLocal provider yields an outcome with
aggregate_attestation_level = TdxLocal. A
consumer whose floor is TdxRemote does not admit
the outcome; the signature is still verifiable,
just not at the consumer’s declared trust level.
The sealed side channel
The actual signature bytes are too big for the public commit — a BLS aggregate is 48 or 96 bytes, a FROST Schnorr sig is 64, and every outcome’s bytes would clog the public Collection for audit-only consumers. They travel through the organism’s sealed side channel:
committee aggregator
│
│ SealedEnvelope {
│ recipient_pk: requester_identity_pk,
│ ciphertext: encrypt_to(signature_bytes,
│ requester_identity_pk),
│ request_id: <matches public outcome>,
│ }
│
▼
sealed channel
│
│ (only the requester's key can open)
▼
requester
│
│ let sig = decrypt(ciphertext);
│ assert_eq!(blake3::hash(&sig), outcome.signature_digest);
The sealed-channel cryptography is standard X25519 + ChaCha20-Poly1305 (the same primitive pattern the compute-bridge uses for encrypted SSH receipts). The requester’s identity key binds to their coalition’s stable id; the committee has no access to the signature bytes after delivery.
Determinism and replay
The aggregate signature is scheme-deterministic for non-interactive schemes and scheme-deterministic-given-nonce-commits for interactive schemes. Two honest aggregators running on the same partials (same subset, same order where order matters) produce the same aggregate.
Replay protection: the
(request_id, aggregate_attestation_level) tuple
in the outcome is unique per request, and the
organism’s state machine rejects a second commit
for the same request_id. A byzantine aggregator
attempting to replay a partial set from a prior
request has its commit rejected by the committee’s
Raft log.
Failure modes
AggregationFailure. Partial sigs failed to combine (byzantine signer, corrupted share). The aggregator commits aRequestFailedentry; consumers observe the public commit and resubmit.SideChannelDeliveryFailure. Aggregate combined, outcome committed, but the sealed envelope did not reach the requester. The requester reads thesignature_digestfrom the public outcome, submits aResendDeliveryrequest, and the aggregator re-seals and resends. This is a liveness concern, not a safety one — the signature already exists.OutcomeSignerMismatch. A consumer verifying the aggregate against the committee’s published public key gets a mismatch. This is the forgery alarm: either the published key is wrong (operator error or compromise), or the committee is byzantine. The consumer halts, unpins the organism in itsTicketValidator, and waits for a rotation.
Forward
Chapter 7 (sustainability) walks what happens when the committee rotates — key refresh, committee-member replacement, retirement markers, and the multi-operator fleet shape that lets consumers fail over when a specific signer-δ deployment retires.
Committee rotation, key refresh, successor chain
audience: ai
The signer-δ committee does not stay fixed. Key
material rotates on a declared cadence; committee
membership changes as providers register, retire,
or degrade; consumers follow the rotation through
the organism’s retirement chain without
re-publishing their own CoalitionConfig. This
chapter walks all four loops: proactive key
refresh, committee-membership rotation,
retirement markers, and multi-operator fleets.
Part II’s four worked examples end here. Every mosaik surface the book’s thesis names has been exercised across searcher-α, bridge-β, oracle-γ, and signer-δ.
Proactive key refresh
The committee’s DKG aggregate public key is pinned
into Config.committee_pk_digest. A rotation
produces a new DKG-generated key; every
committee member resharing its long-term key
share to the new dealing produces a new
committee_pk_digest and a new organism id.
The refresh shape:
window 0: committee runs DKG round 0
│ publishes Config_v0 with committee_pk_digest = PK_0
│ signer-δ.v0 stable_id = S_0
│
window 1: committee runs DKG round 1 alongside round 0
│ both active; outcomes from either verify
│ against their respective published pk
│ publishes Config_v1 with committee_pk_digest = PK_1
│ signer-δ.v1 stable_id = S_1
│ retirement marker on v0:
│ reason = Rotation
│ replacement = OrganismRef { stable_id: S_1, content_hash: v1_hash }
│
window 2: v0 goes read-only for grace period
│ new requests go to v1 only
│
window 3: v0 decommissioned; v1 continues
Consumers that pinned v0’s stable id and
content hash follow the retirement marker’s
replacement pointer to rebind. Consumers that
pinned only the stable id continue against v1
without any consumer-side change — the committee
published new keys, the retirement chain records
it, the consumer’s TicketValidator re-composes
on next read.
Why not lazy key refresh
Leaving the key in place until compromise is
detected is the other design choice. This
organism does not take it: proactive refresh is a
precondition for the TdxPlusReproducibleBuild
level (every refresh produces a fresh DKG log
that a third party can audit against the
reproducible source) and it bounds the damage
window from a hypothetical share extraction. Real
deployments typically refresh on a 7- to 30-day
cadence; the cadence itself is published in
Config.content (not modelled in this example
crate, but a clean extension).
Committee-membership rotation
Committee membership is a separate rotation axis
from key refresh. A provider whose capacity or
attestation level changes — hardware refresh,
attestation-service endpoint change, TDX firmware
patch — republishes its ProviderCard. A provider
retiring emits its own retirement marker and drops
out of the next DKG round’s dealing set.
use coalition::{ComponentRef, RetirementMarker, RetirementInstant};
// Provider-side retirement commit.
let marker = RetirementMarker::rotation(
RetirementInstant::AtTimestamp(now_unix_ms()),
successor_provider_ref,
);
The signer-δ operator scans provider retirement
markers at each rotation window and includes the
successor provider in the next committee. Consumers
that cared about a specific provider unpin its
provider id from their audit set; consumers that
filtered by attestation level never noticed the
swap.
Variable attestation mix across rotations
The variance is the point. A rotation may raise or lower the committee’s attestation mix:
- Raising. A
signer-δoperator hardening posture moves the committee toward moreTdxRaTlsBidirectionalandTdxPlusReproducibleBuildmembers. Consumers whose floor is at or below the new mix see their admission broaden (more outcomes meet their floor). - Lowering. A
signer-δoperator under cost pressure rotates inTdxLocalorSoftwaremembers. Consumers whose floor is at or above the new mix see their admission narrow; the outcomes whoseaggregate_attestation_levelfalls below the floor are simply not admitted.
The consumer’s TicketValidator handles both
cases without any consumer-side code change. The
floor is the floor.
Retirement markers
The substrate’s retirement primitive handles every shutdown path. Four shapes relevant to signer-δ:
// Planned rotation with successor.
RetirementMarker::rotation(
RetirementInstant::AtTimestamp(effective_at),
successor_organism_ref,
);
// Permanent retirement without successor.
RetirementMarker::retired(
RetirementInstant::AtTimestamp(effective_at),
);
// Operator exit — non-compulsion anchor.
RetirementMarker::operator_exit(
RetirementInstant::AtTimestamp(effective_at),
);
// Emergency (share extraction, TDX zero-day, etc.).
// Same shape; `reason = Emergency`. Pair with an
// out-of-band security advisory.
Consumers observe retirement markers on the
signer’s public outcome collection. A retirement
marker is the last commit on the stream; after
it, no new outcomes are admitted. Consumers whose
bond to the organism outlives the marker see
ConnectTimeout on next subscribe.
Multi-operator fleets
The signer’s trust model admits independent
operators running the same image with the same
declared Measurements. Two operators running
identical deployments land identical
committee_pk_digest under identical DKG seeds
(and distinct organism_ids because the instance
names differ).
Fleet shape:
pub const SIGNER_DELTA_OP1: CoalitionConfig<'static> = /* signer-δ-op1 */;
pub const SIGNER_DELTA_OP2: CoalitionConfig<'static> = /* signer-δ-op2 */;
pub const SIGNER_DELTA_OP3: CoalitionConfig<'static> = /* signer-δ-op3 */;
// Consumer subscribes to all three; applies
// consumer-side aggregation (first to respond,
// majority-matching, etc.).
A consumer wanting redundancy submits to the fleet; the first respondent’s signature is taken as authoritative, and a consumer sufficiently paranoid to cross-check runs all three and requires byte-identical signature bytes (works for non-interactive schemes; interactive schemes produce different-but-valid signatures across operators’ DKG rounds).
This is the answer to operator failure, collusion resistance (modulo the shared image), and geographic diversity. The substrate’s non- compulsion property holds: operators join or leave the fleet voluntarily, and no instance compels any other.
Chronicle for the rotation log
For operators who want a tamper-evident record of
every rotation and retirement, signer-δ may
optionally ship the Chronicle basic service from
chapter 7 onward. The Chronicle records every
coalition-level event — committee rotation,
retirement marker, key refresh, ACL bump — without
recording every signature (the outcome collection
is already a public audit of those).
Operator exit
At any time, the signer-δ operator can emit an
OperatorExit retirement marker and stop running
the binary. Consumers observing the marker fail
over to another operator in the fleet; consumers
without a fleet see the signatures stop. Nothing
in the substrate keeps the operator running.
The trust model is strong because the operator can leave: the attestation floor is an admission criterion on the consumer side, the operator’s exit is the substrate’s non-compulsion anchor, and the two together mean a consumer never depends on a single operator being both honest and forced to stay online.
What Part II ends with
Across four parallel examples:
- searcher-α (web3) — an AI searcher binds to a block-building lattice and a Compute market, submits sealed bundles, and grows a reputation surface around itself.
- bridge-β (web2) — a compute-bridge operator wraps four cloud backends behind one TDX- attested provider identity and competes on the coordination-market rate.
- oracle-γ — a standalone organism publishes
one
Stream<PriceTick>per token pair with the whole trust model anchored on a declared TDX Measurements set. - signer-δ — a generic threshold-signature organism hosts a market of providers at varying attestation levels; consumers gate admission on aggregate attestation.
The four examples together walk consumer, provider, publisher, and committee-organism roles — every primitive rung the book’s thesis names.
Cross-references
- zipnet book — the threshold-committee organism this example inverts.
- Part I — sustainability
- Part I — emergent coordination — attestation fabrics
- Part III — operators — rotations and upgrades
- Part III — contributors — threat model
What a coalition gives you
audience: integrators
A coalition is a single handshake token binding an
agent to multiple members of the mosaik universe at once:
block-building lattices, standalone organisms (oracles,
attestation fabrics, identity substrates, analytics
pipelines, …), composite organisms (cross-member
organisms), and the coalition’s optional basic services
(Atlas, Almanac, Chronicle, Compute, Randomness —
whichever are shipped).
Compile one CoalitionConfig and obtain typed handles on
every member, every basic service, and every organism
the coalition references, from one Arc<Network>.
If you already bind to one lattice via a LatticeConfig,
or to one standalone organism via its Config, a coalition
does not change any of that. It adds:
- A single reference to a set of members the operator has chosen to yoke together (e.g. every chain in a superchain stack; every oracle feed in a region; a set of lattices plus a shared attestation fabric).
- Optional composite organisms: cross-member organisms that aggregate, route, or attest across the members in the coalition. Composite organisms are not coalition-scoped; the same organism may be referenced by many coalitions.
- Optional basic services: up to five well-known shapes — Atlas (directory), Almanac (clock beacon), Chronicle (audit log), Compute (scheduler and registry for image-hash-identified workloads), Randomness (scheduler and registry for beacon rounds; beacon producers compete to supply).
- An optional coalition-scoped ticket issuer. Components choose whether to recognise its tickets; nothing is required to.
- No loss of identity. Every member’s
GroupId, everyPeerId, everyStreamIdyou already use stays byte-for-byte the same under routine operational rotations (TDX Measurements bumps, ACL rotations). A coalition references members; it does not re-derive them.
An agent binding to one member only does not need a
CoalitionConfig; bind directly to that member’s
Config (for a block-building lattice, see the
builder integrators overview; for a
standalone organism, see its own crate docs). The
coalition layer is additive, not a replacement.
When you want a CoalitionConfig
Four common cases.
Cross-chain searcher
You bid on bundles across three block-building lattices
and want one handshake token that carries all three
LatticeConfigs, their TDX Measurements, and any referenced
organisms (e.g. a shared ledger that aggregates your
refunds across chains).
Hold one CoalitionConfig, open three
offer::Offer<Bundle>::bid handles, one
ledger::Shared<Refund>::read. See the
quickstart.
Multi-chain wallet
You submit intents on several lattices and need refund
attestations from each. If the coalition references a
shared-ledger organism, you can read one aggregated feed
instead of polling per-lattice tally::Refunds.
Cross-domain agent
Your agent consumes outputs from a mix of members — say,
two block-building lattices, an oracle grid, and an
attestation aggregator — and you want one compile-time
token that pins the full set. A CoalitionConfig lets you
hold one handshake instead of four.
Composite-organism or module consumer
You are an analytics, routing, or dashboard service that
reads an intent router, a shared ledger, a cross-chain
oracle aggregator, or the coalition’s Atlas. Without a
CoalitionConfig, you would re-derive each fingerprint
yourself; with it, you compile one struct.
When you do not need a CoalitionConfig
- You bind to one member only.
- You are an integrator testing a standalone organism
whose operator has given you its
OrganismConfigdirectly. - You are an integrator testing a composite organism
whose operator has given you its
OrganismConfigdirectly. - You only read a public collection whose
StoreIdyou already have; coalitions are compile-time ergonomics.
What the operator gives you
When a coalition operator hands you a handshake, you should receive:
- The
CoalitionConfigstruct (or its serialised fingerprint). - The included
LatticeConfigs — either inline or by reference to each lattice operator’s published handshake. - The included standalone-organism references — each with role name, stable id, optional content hash, and a pointer to that organism’s own handshake.
- The included composite organisms — each with its
OrganismConfigand a pointer to the organism operator’s handshake. - The included modules — each an
OrganismConfigwith the shape documented in basic services. - The ticket-issuer root if the coalition ships one.
- TDX Measurements for every TDX-gated organism (standalone, composite, or module) the coalition commissioned.
- Endpoint hints for at least one initial peer on the shared universe, if your agent is cold-starting.
See What you need from the coalition operator for the full checklist.
What you compile in
use std::sync::Arc;
use mosaik::Network;
use builder::UNIVERSE;
use coalition::CoalitionConfig;
const ETH_SUPERCHAIN: CoalitionConfig<'static> = /* pasted from operator release notes */;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let network = Arc::new(Network::new(UNIVERSE).await?);
// Pick handles you need — any lattice organism, any
// standalone organism, any composite organism, any
// module.
let eth_bid = offer::Offer::<Bundle>::bid(
&network, Ð_SUPERCHAIN.lattices[0].offer,
).await?;
let uni_bid = offer::Offer::<Bundle>::bid(
&network, Ð_SUPERCHAIN.lattices[1].offer,
).await?;
// A standalone organism the coalition references — here, an
// attestation aggregator with its own Config.
let attest = attest::Aggregator::<Quote>::read(
&network, ETH_SUPERCHAIN.organisms[0].config(),
).await?;
// A composite organism — same shape, one rung up.
let ledger = ledger::Shared::<Refund>::read(
&network, ETH_SUPERCHAIN.organisms[1].config(),
).await?;
// A module — the coalition's Atlas, if shipped.
let atlas = atlas::Atlas::<MemberCard>::read(
&network, ETH_SUPERCHAIN.atlas().unwrap(),
).await?;
// ... use them.
Ok(())
}
ETH_SUPERCHAIN.atlas() returns the Atlas module’s
Config if the coalition ships one. The same helper
exists for almanac() and chronicle(). A coalition that
does not ship a given module returns None.
No additional plumbing. UNIVERSE is the same constant
every lattice and zipnet deployment uses.
What can go wrong
ConnectTimeout. TheCoalitionConfigyou compiled in does not match what the operator is running. Recompile against the current release notes.- Ticket missing on a specific member. Your per- member admission ticket was not issued or was revoked. Per-member operators issue their own tickets; the coalition operator does not. Contact the per-member operator.
- An organism down. A committee lost majority. Other members continue; the affected component’s next commit is delayed.
- Module helper returns
None. The coalition does not ship that module. Drop the dependency or request the module be added.
Cross-references
- Quickstart — bind many members from one agent
- What you need from the coalition operator
- Binding to an organism
- Cross-member flows
- Contributor — basic services
Quickstart — bind many members from one agent
audience: integrators
This quickstart stands up an agent that submits and reads
across three block-building lattices, one standalone
attestation organism, one composite organism, and one
module (the coalition’s Atlas) — all bound through a
single CoalitionConfig. It assumes familiarity with the
builder integrators quickstart when the
coalition includes block-building lattices; the coalition
layer extends that pattern rather than replacing it.
If the coalition contains no lattices (for example, a composition of oracle organisms plus a cross-oracle composite organism), the same pattern applies with different crates on the right-hand side of each handle.
What you need before you start
- A
CoalitionConfigfrom the coalition operator (struct definition, or a serialised fingerprint you copy into your crate). - A
LatticeConfigper referenced lattice (inline in theCoalitionConfigthe operator published, or pulled from each lattice operator’s handshake page). - An
OrganismRefper referenced organism (role name + stable id + optional content hash + pointer to the organism’s own handshake). Both standalone and composite organisms are referenced this way. - A ticket from each per-member operator you intend to write to. Per-member admission is per-member; the coalition operator does not issue per-member tickets.
- A ticket from each composite-organism or module operator whose write-side primitive you intend to use. Usually none: most composite organisms and modules are read-only for external integrators.
- Your TDX image (if any member or service you write to requires attested client admission).
Step 1 — declare the CoalitionConfig in your crate
Paste the operator’s published CoalitionConfig
definition, or import it from the operator’s handshake
crate if they publish one:
use builder::LatticeConfig;
use coalition::{CoalitionConfig, OrganismRef};
// Exactly the bytes the operator publishes.
const ETH_MAINNET: LatticeConfig<'static> = /* from ethereum.mainnet operator */;
const UNICHAIN_MAINNET: LatticeConfig<'static> = /* from unichain.mainnet operator */;
const BASE_MAINNET: LatticeConfig<'static> = /* from base.mainnet operator */;
// A standalone organism the coalition references — here,
// an attestation aggregator with its own stable id.
const ATTEST_AGG: OrganismRef<'static> = OrganismRef {
role: "attest",
stable_id: /* published by the attest-aggregator operator */,
content_hash: None,
};
// Two composite organisms the coalition references — an
// intent router and a shared ledger.
const INTENTS_CONF: OrganismRef<'static> = OrganismRef {
role: "intents",
stable_id: /* from the intents operator */,
content_hash: None,
};
const LEDGER_CONF: OrganismRef<'static> = OrganismRef {
role: "ledger",
stable_id: /* from the ledger operator */,
content_hash: None,
};
pub const ETH_SUPERCHAIN: CoalitionConfig<'static> = CoalitionConfig {
name: "ethereum.superchain",
lattices: &[ETH_MAINNET, UNICHAIN_MAINNET, BASE_MAINNET],
organisms: &[ATTEST_AGG, INTENTS_CONF, LEDGER_CONF],
ticket_issuer: None,
};
For a coalition-agnostic library, take
&'static CoalitionConfig<'static> as a constructor
argument and let the binary crate pick the constant.
Step 2 — bring up the network handle
Same UNIVERSE as every other mosaik service:
use std::sync::Arc;
use mosaik::Network;
use builder::UNIVERSE;
let network = Arc::new(Network::new(UNIVERSE).await?);
One Arc<Network> per agent regardless of how many
members, organisms, or modules are bound.
Step 3 — bind the lattice handles you need
Indexes into lattices[] match the order in the
CoalitionConfig. A cross-chain searcher that bids on
all three:
use offer::Offer;
let eth_bid = Offer::<Bundle>::bid (&network, Ð_SUPERCHAIN.lattices[0].offer).await?;
let uni_bid = Offer::<Bundle>::bid (&network, Ð_SUPERCHAIN.lattices[1].offer).await?;
let base_bid = Offer::<Bundle>::bid (&network, Ð_SUPERCHAIN.lattices[2].offer).await?;
let eth_wins = Offer::<Bundle>::outcomes(&network, Ð_SUPERCHAIN.lattices[0].offer).await?;
let uni_wins = Offer::<Bundle>::outcomes(&network, Ð_SUPERCHAIN.lattices[1].offer).await?;
let base_wins = Offer::<Bundle>::outcomes(&network, Ð_SUPERCHAIN.lattices[2].offer).await?;
Keep handles in scope while needed; drop them when done.
Each handle carries its own subscriptions and is cheap
atop the shared Network.
Step 4 — bind the organism handles you need
Each OrganismRef carries the stable id; the concrete
organism crate gives you the typed constructor. Standalone
and composite organisms share the same reference shape:
use attest::Aggregator;
let attest = Aggregator::<Quote>::read(
&network, ETH_SUPERCHAIN.organisms[0].config(),
).await?;
OrganismRef::config() resolves to the organism’s Config
— either because the coalition operator embeds the full
Config struct in their published CoalitionConfig, or
because the organism crate ships a helper that rebuilds
the Config from the published stable id and known role
constants. Either way, the concrete organism crate is what
gives you the typed handle.
Step 5 — bind the modules you want
Modules are coalition-scoped organisms with well-known
shapes. CoalitionConfig exposes helpers:
use atlas::Atlas;
use almanac::Almanac;
// The Atlas lists every member in the coalition with operator metadata.
if let Some(atlas_cfg) = ETH_SUPERCHAIN.atlas() {
let atlas = Atlas::<MemberCard>::read(&network, atlas_cfg).await?;
// Use the atlas as your canonical "what's in this coalition" reference.
}
// The Almanac is a shared tick beacon for timing correlations.
if let Some(almanac_cfg) = ETH_SUPERCHAIN.almanac() {
let almanac = Almanac::<AlmanacTick>::read(&network, almanac_cfg).await?;
// Use almanac ticks as the time axis for cross-member commits.
// Each tick's `observed_at` is a Vec<(MemberId, SystemTime)>;
// compute median or bracket yourself.
}
A coalition may ship zero, one, two, three, or all four
modules. Always check the helper’s Option return; do
not assume presence.
Step 6 — bind the composite-organism handles you need
The shared ledger is typical for a searcher seeking aggregated refund attribution:
use ledger::Shared;
let refunds = Shared::<Refund>::read(
&network, ETH_SUPERCHAIN.organisms[2].config(),
).await?;
tokio::spawn(async move {
while let Some(r) = refunds.next().await {
// Each entry carries (origin_member, slot, share, evidence).
handle_refund(r);
}
});
Step 7 — submit paired bundles
Cross-chain bundles are a searcher-level problem. The coalition layer surfaces the handles; reconciliation logic is the integrator’s responsibility.
async fn submit_paired_bundle(
eth_bid: &Offer<Bundle>::Bid,
uni_bid: &Offer<Bundle>::Bid,
sell_on_eth: Bundle,
buy_on_uni: Bundle,
) -> anyhow::Result<()> {
let eth_ack = eth_bid.send(sell_on_eth).await?;
let uni_ack = uni_bid.send(buy_on_uni ).await?;
// Reconcile: if only one leg commits, post-bond collateral or
// on-chain HTLC logic applies. The coalition layer does NOT
// provide cross-member atomicity. See
// /contributors/atomicity.md.
Ok(())
}
A paired-bundle correlator joining AuctionOutcome[L1, S] to AuctionOutcome[L2, S'] is the most common
in-agent utility. Compute it in-memory as in
builder’s Shape 1, or rely on a
referenced intents composite organism if one exists.
Step 8 — read the aggregated result
With a shared-ledger composite organism, a single subscription surfaces refunds originating from any of the coalition’s lattices.
while let Some(entry) = refunds.next().await {
tracing::info!(
origin = %entry.origin_member,
slot = entry.slot,
share = %entry.share,
"refund attributed",
);
}
Without a shared-ledger composite organism, open three
per-lattice tally::Tally::<Attribution>::read handles
and join in memory. Both paths are valid; the composite
organism is a shared precomputation.
What to do when things go wrong
ConnectTimeouton a lattice or organism handle. The per-memberConfigdoes not match what the member’s operator is running. Recompile against that operator’s latest handshake.ConnectTimeouton an organism or module handle. TheOrganismConfigdoes not match, or the committee is down and has not yet published peers on the universe, or the organism has retired (check for aRetirementMarkeron its public stream) and the coalition operator should have sent an updatedCoalitionConfig.- Admission denied on a write-side stream. Ticket missing or expired. Contact the per-member operator, not the coalition operator.
- Module helper returns
None. The coalition does not ship that module. See contributor basic services for the spec if proposing addition.
Cross-references
- What a coalition gives you
- What you need from the coalition operator
- Binding to an organism
- Cross-member flows
- builder quickstart
What you need from the coalition operator
audience: integrators
Before compiling a CoalitionConfig into an agent, the
integrator requires a short item list from the coalition
operator plus a pair of sanity checks. This page is the
checklist.
The seven items
-
The
CoalitionConfigdefinition. Either a Rustconstdeclaration pasted into the integrator crate, or a serialised fingerprint (hex ofcoalition_id()) paired with the integrator’s own copy of the struct definition. -
Every included
LatticeConfig. Typically pulled by reference from each lattice operator’s handshake page. The coalition operator should publish a per-coalition table listing the referenced lattices and a link to each lattice operator’s release notes. -
Every included
OrganismRef. For each organism the coalition composes — standalone or composite — the coalition operator publishes the role name, the organism’s stable id, the optional content hash if pinned, and a link to that organism’s own handshake page. Organisms are coalition-independent; each carries a link to its own operator’s handshake page. -
Every shipped module’s
OrganismConfig. Atlas, Almanac, Chronicle — whichever the coalition ships. Modules not shipped are stated explicitly; silence is ambiguous. -
TDX Measurements for every TDX-gated unit the coalition operator commissions — modules and any organisms they run. (Per-member TDX Measurements come from the per-member operators; the coalition operator re-publishes for convenience.)
-
At least one initial peer hint for the shared universe (cold-start bootstrap). Typically the same hint every mosaik service uses; re-published for convenience.
-
A change channel. The mechanism through which the coalition operator notifies of a referenced member’s stable-id bump or a referenced organism’s
Configchange.
Coalition operators do not issue per-member tickets; those come from per-member operators. A coalition may publish its own optional ticket issuer; components and integrators choose whether to recognise it.
Verification
Perform two sanity checks once the items above are in hand.
Fingerprint round-trip
Compile the pasted CoalitionConfig. Call
coalition_id() on it. Compare to the operator’s
published fingerprint. Both must match byte-for-byte. A
mismatch means the struct definition drifted or the
serialiser differs; do not proceed until the mismatch
resolves.
Member reference cross-check
For each referenced LatticeConfig, call stable_id()
and compare to the lattice operator’s published stable
id. For each referenced organism, compare the
OrganismRef stable id (and content hash, if pinned) to
the organism operator’s published one. A mismatch means
the coalition operator’s copy drifted from the per-
member operator’s. Request an updated CoalitionConfig.
Trust
Nothing in the coalition operator’s handshake is cryptographically authoritative: a coalition fingerprint names a composition, it does not sign it. The checks above suffice because the identity work is done at the per- member rung. The coalition layer stitches known fingerprints together and adds a small catalog of modules.
Cross-references
Binding to an organism
audience: integrators
An organism referenced by a coalition can be a
standalone organism (living directly on the universe) or
a composite organism whose public surface spans multiple
members — some combination of block-building lattices
and standalone organisms. Binding is the same in every
case — Organism::<D>::verb(&network, &Config) — with
two small differences in what the operator owes the
integrator and in failure-mode reasoning when the
organism is composite.
The same reasoning applies to a coalition’s modules (Atlas, Almanac, Chronicle, Compute, Randomness) — each is a coalition-scoped organism with a well-known shape.
One handle per verb
Each organism exposes one or two public primitives. A read-only integrator typically needs exactly one handle; a write-side integrator a second. Typical shapes:
// Read-only: subscribe to the organism's output.
let intents = intents::Router::<Intent>::routed(&network, &INTENTS_CONF).await?;
// Write-side (if the organism publishes a write stream):
let publish = intents::Router::<Intent>::publish(&network, &INTENTS_CONF).await?;
Verb names come from the organism’s own crate docs,
following the same convention as every organism
(Offer::bid, Tally::read, Zipnet::submit,
Aggregator::read, Atlas::read).
What the organism operator owes you
An organism operator (who may coincide with the coalition operator) is responsible for:
- The
OrganismConfigfingerprint, publishable and byte-for-byte compilable. - The ordered list of spanned member references the organism depends on — lattices, standalone organisms, or any mix. Cross-check each against the corresponding per-member operator’s publication.
- TDX Measurements if the organism is TDX-gated.
- The organism’s state-machine version / signature.
A bump surfaces as
ConnectTimeouton compiled handles; the change channel warns ahead. - A failure-mode statement. Whether a stall in spanned member A causes a commit with partial evidence or an event stall. Documented in the crate’s composition-hooks page.
- A retirement commitment. Before shutting the
committee down, the organism emits a
RetirementMarkeron its public stream pointing at a replacement (if any). Watch for it rather than timing out blindly.
Failure-mode reasoning for composite-organism consumers
Three properties to internalise before reading a composite organism.
The composite commit lags the upstream commits
A composite organism’s (member_id, slot) commit is observable
only after the underlying member commits are observable,
plus one Raft round inside the organism’s committee.
Latency-sensitive consumers read the upstream member
surfaces directly and use the composite organism only for
the aggregated view.
Partial evidence is a valid composite-organism commit
Depending on the organism’s stall policy, a commit may reflect inputs from only some spanned members. The commit carries evidence pointers; checking the pointers indicates which members’ inputs were present. Do not assume every spanned member contributed to every commit.
A stalled composite organism does not block upstream pipelines
If the organism’s committee loses majority or lags, the spanned members’ pipelines are unaffected. Fall back to binding per-member handles directly; the organism’s precomputation is a convenience, not a dependency.
What to do when your agent relies on an organism that changes
Organism Config fingerprints change for three reasons:
- Organism upgrade. The organism’s content, ACL, or spanned member set changed; its fingerprint bumps independently.
- Upstream member retirement. A member the organism spans published a new stable id; the organism inherits the change if it pinned the old stable id.
- Upstream member content bump (only if pinned). If the organism pinned the upstream content hash, an TDX Measurements or ACL bump in the upstream bumps the organism’s fingerprint.
In every case the old handle starts failing with
ConnectTimeout — or, better, the organism emits a
RetirementMarker on its stream pointing at the
replacement. The operator’s change channel should warn
ahead; the integrator’s process should include a path to
recompile against the new CoalitionConfig (or
OrganismConfig) and restart.
Cross-references
- What a coalition gives you
- Quickstart
- Contributor — composite organisms
- Contributor — basic services
Cross-member flows
audience: integrators
This page catalogues cross-member flows an agent may run and indicates which are cheap at the integrator level versus when a composite organism is warranted.
The underlying theory for block-building cross-chain cases is in the builder book’s cross-chain chapter. The coalition layer formalises its Shape 3 (bridge organism) as a composite organism and generalises the pattern beyond block-building to any mix of lattices and standalone organisms. This page is the integrator-facing view.
Four recurring flows
Paired bundles (two block-building lattices)
An agent publishes bundle A to offer[L1] and bundle B
to offer[L2], expecting paired-slot commits.
- Without a composite organism. Keep a per-agent correlator
table keyed by bundle id; watch both lattices’
AuctionOutcomeand join. Handle partial fills (A committed, B did not) with post-bond collateral or on- chain HTLC logic. This is the builder book’s Shape 1. - With an intents organism. Publish one intent to
the organism’s write stream; the organism routes
sub-bundles to each target lattice’s
offer. Subscribe to the organism’sRoutedIntentsfor cross-chain outcome reconciliation. - Decision rule. If only one searcher runs the correlator, keep it in the agent. If three unrelated agents would each run the same correlator, an intents organism is warranted.
Cross-origin attribution (lattice + lattice)
A bundle submitted on lattice A but captured MEV on
lattice B. Without coordination, tally[A] never sees the
attribution on B’s block; tally[B] sees it but without
knowing the origin was A.
- Without a composite organism. Subscribe to both
tally[A]andtally[B], join in memory on submission ids, compute the cross-origin view locally. - With a shared-ledger organism. One
Shared::<Refund>::readhandle yields aggregated attribution across all members the ledger spans. - Decision rule. If on-chain settlement requires a pre-aggregated attestation (e.g. one signature for a cross-chain refund claim), the organism is load- bearing. If each consumer can perform the join, the organism is a convenience.
Oracle + lattice correlation (organism + lattice)
An agent that needs to correlate an oracle organism’s price feed with block-building auction outcomes on one or more lattices. The members are heterogeneous: one is a standalone organism, the others are lattices.
- Without a composite organism. Subscribe to the oracle
organism’s feed and each lattice’s
AuctionOutcome; join in memory with a timestamp tolerance window. - With a correlator organism. The organism’s
commit pairs
(oracle_tick, lattice_slot)tuples under one attested key, letting multiple downstream agents consume the same correlation without re-computing. When a coalition ships an Almanac the organism has opted into, both the oracle tick and the lattice slot align to almanac ticks, providing a shared correlation window. - Decision rule. Do three different agents need the same correlation? If yes, the organism amortises.
Cross-member observability
A dashboard, an analytics agent, or an oncall who wants “one view of the coalition’s activity” — across lattices, standalone organisms, or both.
- Without a composite organism. N member subscriptions plus local aggregation.
- With the coalition’s Atlas module. Start from the Atlas (directory of members, with endpoint hints); subscribe per member. Atlas is the reference; the aggregation remains the integrator’s.
- Decision rule. Atlas pays off once more than one dashboard operator exists. A single on-call team can skip it; most coalitions ship an Atlas anyway because the cost is small and the coordination benefit is high.
The decision framework
Every cross-member flow reduces to one question:
Do three different agents (searchers, dashboards, analytics) need the same pre-aggregated fact?
If yes, a composite organism is the right shape: commit once per slot, consume N times.
If no, a per-agent driver is the right shape: keep the logic where the decisions are made.
A composite organism is not generic cross-member infrastructure. It is a mosaik organism with a narrow public surface and the same operational cost as any other committee-backed organism. Use it when a committed, reusable fact pays for the cost; use an in-agent driver when it does not.
What the coalition layer does not give you
- Atomic cross-member commits. The coalition does not provide send-both-or-neither. See atomicity.
- Cross-coalition coordination. Two
CoalitionConfigs on the same universe are two handshake tokens; they do not coordinate. A cross- coalition commit resolves to a composite organism folding the relevant members directly, referenced independently by both coalitions. - Trust in a composite organism beyond its committee. A composite organism’s commit is trustworthy up to its committee’s assumption plus the upstream members it reads. Know the trust shape before relying on it.
Cross-references
- Quickstart
- Binding to an organism
- Contributor — composite organisms
- Contributor — basic services
- Contributor — atomicity
- builder cross-chain
Coalition overview
audience: operators
A coalition is an operator-published handshake token
naming a set of mosaik members — block-building
lattices, standalone organisms, and zero or more
composite organisms (cross-member organisms) — and
handing the set to integrators as one CoalitionConfig
they compile in. A coalition may also ship up to four
modules (Atlas, Almanac, Chronicle, Compute, Randomness) and an
optional coalition-scoped ticket issuer under the same
handshake.
This page is the operator’s introduction: what running a coalition means, what the operator owns, and what they do not.
Operator roles, often one team
Running a coalition means any combination of the following roles, often held by the same team:
- Lattice operator — responsible for one
LatticeConfig: its committees, its ACL, its organism rotations. Lattice operations are covered by the builder operator book. The coalition layer does not change any lattice-operator responsibilities. - Standalone-organism operator — responsible for one
organism living directly on the universe (an oracle
feed, an attestation aggregator, an identity substrate,
…). Same shape as any mosaik-native service: a
committee, a
Config, a narrow public surface. - Composite-organism operator — responsible for one composite organism’s committee: running the binaries, holding the admission secrets, rotating the attestation images if TDX-gated. Organisms are coalition- independent; the same organism may be referenced by several coalitions.
- Module operator — responsible for an Atlas, Almanac, Chronicle, or Compute committee. Mechanically identical to running any other coalition- scoped organism; the shape is specified in basic services.
- Ticket-issuer operator — responsible for the coalition-scoped ticket issuance root when the coalition ships one. See ticket issuance.
- Coalition operator — responsible for publishing
and maintaining the
CoalitionConfig: keeping its content accurate, notifying integrators when referenced members’ stable ids bump, and retiring the coalition instance name cleanly when it is no longer needed.
A single team commonly holds two or more of these roles.
What the coalition operator owns
- The
CoalitionConfigstruct and its serialised fingerprint. - A published change channel (release notes, a CHANGELOG, an RSS feed — whatever), through which you notify integrators of member stable-id bumps, referenced-organism upgrades, or composition changes.
- The set of
OrganismConfigs referenced by the coalition (if you also run the modules and any organisms). - The set of
OrganismRefs the coalition composes (role name, stable id, optional content hash for each referenced standalone organism). - The optional coalition ticket issuer.
- A coalition-scoped operator handshake page — one URL or repository section integrators can link in their own docs.
What the coalition operator does not own
- The referenced members. The coalition operator references lattices and standalone organisms; they do not admit peers into them, issue tickets on their behalf, or dictate internal parameters.
- The referenced organisms. Each organism’s identity
is independent of any coalition. The coalition operator
references the organism; the organism operator controls
its committee and
Config. - Member stable ids. When a referenced member
retires, the coalition operator updates the
CoalitionConfigto match; they do not dictate the per-member operator’s retirement cadence. - Cross-operator contracts. Multi-operator coalitions bring SLAs, data-sharing arrangements, and attribution splits — all negotiated out of band. The blueprint does not provide a standard form.
- Integrator lifecycle. Integrators compile in and
recompile on their own schedule. A compiled-in
CoalitionConfigcannot be revoked; the coalition operator publishes a new one and relies on integrators to upgrade. - Member behaviour. A member’s misbehaviour is
addressed by publishing an updated
CoalitionConfigthat drops or replaces it. The coalition operator has no protocol-level power to constrain a member.
What per-member operators can expect from a coalition operator
Worth formalising with any member referenced:
- Notification of inclusion. The coalition operator informs the per-member operator of the reference at publication time. The blueprint does not enforce this; it is a courtesy.
- No admission requests. The coalition operator does not ask the per-member operator to issue special-case tickets for composite organisms or modules. Committee members bond into referenced members as ordinary integrators under the member’s normal admission policy.
- Observability of referenced members’ public surfaces only. The coalition operator does not expect private plumbing access.
- Bump coordination. Member stable-id bumps
(retirements) are notified to the coalition operator
via the per-member operator’s integrator channel ahead
of cutover; this lets the coalition operator publish a
matching
CoalitionConfigwithout aConnectTimeoutgap. Routine content-hash bumps (TDX Measurements rotations, ACL rotations) do not require coalition-level updates unless composite organisms opted to pin the content hash.
A typical coalition’s shape
Three common archetypes:
- Umbrella coalition. One operator; several lattices across related chains (every chain in a superchain stack, every chain in an L2 family). Modules: usually Atlas at minimum, often Chronicle. Composite organisms: often an intent router or shared ledger.
- Service coalition. One operator; one or a handful of standalone organisms composed together (an attestation aggregator paired with an identity substrate; an oracle feed paired with an analytics pipeline). Often no lattices at all. Almanac is common because organisms without slot clocks benefit from a shared tick.
- Multi-operator coalition. Multiple operators, each running one or a few members (lattices, standalone organisms, or both); one operator runs the coalition and one or more composite organisms. Common when an operator grouping wants a shared attribution or routing layer while the underlying members operate independently. An optional coalition-scoped ticket issuer is more likely here.
All three archetypes use the same CoalitionConfig
shape; the difference is who runs what.
Critical path
- Keep the
CoalitionConfigin sync. When a referenced member retires or a referenced organism bumps, publish a new coalition fingerprint promptly. - Operate modules, the optional ticket issuer, and any organisms commissioned. Standard committee-organism operations: monitor, rotate, respond to anomalies.
- Respond to integrators. Three typical questions:
the current coalition composition, the cause of a
ConnectTimeout, and how to bind to a newly shipped organism or module. The handshake page answers the first; the change channel the second; per-service docs the third.
Off the critical path
- Per-member operations for members not run by the coalition operator. Those members operate themselves.
- Inter-member consensus. None exists; the coalition is not a consensus unit.
- Cross-coalition coordination. Two coalitions coexist on the universe and do not coordinate.
Cross-references
- Quickstart — stand up a coalition
- Running an organism
- Multi-operator coalitions
- Rotations and upgrades
- Contributor — basic services
- builder operator overview
Quickstart — stand up a coalition
audience: operators
This runbook brings up a minimal coalition: one
CoalitionConfig referencing two existing members (two
block-building lattices, two standalone organisms, or one
of each) and shipping one module — an Atlas — that
publishes a per-coalition directory. Assumptions:
- The members to be referenced exist. If any are block- building lattices not yet run by the operator, follow the builder operator quickstart first; if any are standalone organisms not yet run, follow the organism crate’s runbook.
- Familiarity with the builder operator workflow: systemd units, published handshake pages, committee bring-up, TDX Measurements publication. The discipline is identical for any organism committee.
- The coalition meta-crate (
coalition) exists in a form sufficient to deriveCoalitionConfigfingerprints. Until v0.2 lands, this is a paper exercise; the steps below are the target shape.
Estimated time to first CoalitionConfig: two engineer-
days, assuming referenced members and the Atlas crate
are already running.
Step 1 — enumerate the members to reference
Record, for each member, the canonical stable id (and optional content hash, if you choose to pin it) as published by its operator.
member kind stable_id (hex) content_hash ticket-issuance root
-----------------------------+---------+---------------------+------------------+----------------------
ethereum.mainnet lattice 0x… (unpinned) 0x…
unichain.mainnet lattice 0x… (unpinned) 0x…
price-feed.eur organism 0x… 0x… 0x…
Do not invent stable ids locally. Always use the per-
member operator’s authoritative value. A per-member
operator’s stable id that cannot be reproduced from its
published Config definition is a member-level issue;
do not paper over it in the coalition.
Step 2 — pick the coalition name
Short, stable, namespaced. Examples:
ethereum.superchainmev.mainnet-q2oplabs.testnetsignals.euro-fx
The name is folded into the coalition fingerprint; a typo propagates through every module derivation. Pick once. Rename via a new instance name, never via in-place edit.
Step 3 — decide which modules to ship
One module suffices for a minimal coalition. Atlas is the usual first choice:
- Small state machine — one
MemberCardcommit per referenced member. - Low trust requirement — usually non-TDX, majority- honest.
- High utility — integrators pin the Atlas in their own docs as the canonical coalition-composition reference.
Ship Almanac and Chronicle on their own schedules. Specifications in basic services.
A concrete cross-member problem (paired-bundle auctions, cross-chain attribution, oracle/lattice correlation) motivates commissioning a relevant organism beyond the modules. Each organism is a separate crate and committee; organisms are coalition-independent, so the same organism may also be referenced by other coalitions.
Step 4 — draft the CoalitionConfig
use builder::LatticeConfig;
use coalition::{CoalitionConfig, ModuleConfig, OrganismRef};
pub const ETHEREUM_MAINNET: LatticeConfig<'static> = /* from ethereum.mainnet operator */;
pub const UNICHAIN_MAINNET: LatticeConfig<'static> = /* from unichain.mainnet operator */;
pub const EUR_PRICE_FEED: OrganismRef<'static> = OrganismRef {
role: "oracle",
stable_id: /* from the price-feed operator */,
content_hash: None,
};
pub const SUPERCHAIN_ATLAS: ModuleConfig<'static> = ModuleConfig {
name: "atlas",
content: /* atlas content params */,
acl: /* TicketValidator composition */,
};
pub const SUPERCHAIN_ATLAS_ORG: OrganismRef<'static> =
OrganismRef {
role: "atlas",
stable_id: /* derived from SUPERCHAIN_ATLAS */,
content_hash: None,
};
pub const ETH_SUPERCHAIN: CoalitionConfig<'static> =
CoalitionConfig {
schema_version: SCHEMA_VERSION_U8,
coalition_seed: COALITION_ROOT_SEED,
instance_name: "ethereum.superchain",
lattices: &[
ETHEREUM_MAINNET.stable_id(),
UNICHAIN_MAINNET.stable_id(),
],
organisms: &[EUR_PRICE_FEED],
atlas: Some(SUPERCHAIN_ATLAS_ORG),
almanac: None,
chronicle: None,
compute: None,
randomness: None,
ticket_issuer: None,
retirement_policy: RetirementPolicy::default(),
};
Note: an OrganismConfig does not fold a coalition root;
organism identity is independent. For a module like
Atlas, the meta-crate’s derivation routes the identity
under COALITION_ROOT.derive("module").derive("atlas")
internally when the helper atlas() returns the matching
OrganismRef.
Step 5 — freeze the fingerprint
The derivation order is:
- Compute
COALITION = blake3("coalition|" || SCHEMA_VERSION_U8 || "|" || name). - Compute
COA_LATTICES = ordered stable ids. - Compute
COA_ORGANISMS = ordered stable ids (plus content hashes if pinned per-organism). Standalone and composite organisms share this slice. - Compute
COA_MODULES = ordered ModuleConfig fingerprints. - Compute
COA_TICKETS = TicketIssuerConfig fingerprint if present, else 0 bytes. - Compute
COALITION_ROOT = blake3(COALITION || COA_LATTICES || COA_ORGANISMS || COA_MODULES || COA_TICKETS). - Module identities are derived from
COALITION_ROOTviaCOALITION_ROOT.derive("module").derive(name).
Once the fingerprint is frozen, record its hex in
release-notes.md. Integrators verify that hex against
the struct they compile.
Step 6 — stand up the Atlas (and any other modules)
Every module is a mosaik-native organism (specifically, coalition-scoped). To bring up the Atlas committee:
- Install the Atlas binary on committee hosts (default N = 3; scale up as needed).
- Bootstrap Raft peers on the shared universe using the
Atlas’s
GroupIdderived from itsOrganismConfigunderCOALITION_ROOT.derive("module").derive("atlas"). - Publish the Atlas’s TDX Measurements (if TDX-gated) or the committee roster (if not).
Bring-up details are in the Atlas crate’s runbook and in Running an organism. Atlas does not require TDX.
Step 7 — publish the handshake
Collect everything integrators need:
CoalitionConfigRustconst(or the hex fingerprint paired with the struct definition).- The ordered list of referenced
LatticeConfigs with links to each lattice operator’s handshake. - The ordered list of referenced
OrganismRefs with role names, stable ids (plus content hashes if pinned), and a link to each organism operator’s handshake. Standalone and composite organisms share this shape; composite-organism entries additionally note TDX Measurements and state-machine signature where applicable. - Each module’s
ModuleConfigwith TDX Measurements, state-machine signature, and a short description. - A statement of which modules the coalition ships and which it does not — silence is ambiguous.
- The coalition-scoped ticket issuer root, if any.
- An initial peer hint for the shared universe.
- Your change channel (email, feed, repo).
Post as a single page on the operator site or handshake repo. Link integrators to it.
Step 8 — notify integrators
A message on the change channel announcing the
coalition’s first CoalitionConfig fingerprint is
sufficient. Waiting integrators compile in the constant
and open handles.
Ongoing operations
Day-to-day work is covered by the other operator pages:
- Running an organism for operating each committee (including modules).
- Multi-operator coalitions for coordinating with other per-member and per-composite-organism operators.
- Rotations and upgrades for key rotations, TDX Measurements bumps, and member retirements.
Failure modes
- Integrators report
ConnectTimeout. Either the publishedCoalitionConfigdrifted from the live deployment, or a referenced member retired and the coalition operator has not republished. Recompile the struct, freeze the fingerprint, publish. - A module’s committee lost majority. Standard mosaik recovery. Referenced members and referenced organisms continue; integrators reading the module temporarily see no new commits.
- A referenced member retired silently. The per-
member operator should have notified the coalition
operator. File an anomaly with them, publish a new
CoalitionConfigagainst the new stable id, and tighten change-channel discipline with that operator.
Cross-references
- Coalition overview
- Running an organism
- Multi-operator coalitions
- Contributor — basic services
- builder operator quickstart
Running an organism
audience: operators
Operating an organism is, at the protocol level, identical to operating any mosaik-native committee organism: a committee, a state machine, a narrow public surface. This page is the delta that applies when the organism is composite — when it spans multiple members (lattices, standalone organisms, or a mix) — so the operator must track per-member health rather than one upstream.
Modules (Atlas, Almanac, Chronicle, Compute, Randomness) are coalition-scoped organisms; the same rules apply. Each module’s crate publishes its own page once commissioned.
For the base runbook — systemd units, dashboards, incident response — follow the builder operator runbooks. Each per-organism crate publishes its own page once commissioned.
What to add on top of a single-committee runbook
-
Per-member subscription health. A composite organism reads from multiple members’ public surfaces. The dashboard carries one subscription-lag metric per spanned member, not an aggregated metric. A composite organism that stalls typically stalls on one member first.
-
Per-member ticket health. Committee members hold tickets from each spanned member’s operator. When a per-member operator rotates their ticket-issuance root, the organism’s bonds into that member break until new tickets are issued to the committee. Monitor ticket validity horizons per member.
-
Member-identity monitoring. When a referenced member retires (stable id changes) or bumps its content hash (if the organism pinned content), the organism’s own
Configfingerprint is stale; the organism must be redeployed under an updatedOrganismConfig. Detect this before integrators do. -
Cross-operator communications. A composite organism with members run by different operators requires a standing channel with each — at minimum a mailing list or chat channel for advance announcements of retirements and rotations.
The lifecycle of a composite organism commit
- Committee driver watches each spanned member’s public collection / stream.
- An upstream event fires; the driver wraps it in an
Observe*command with an evidence pointer back to the upstream commit. - The organism’s
Groupcommits theObserve*via Raft. - Periodically (or on an apply-deadline timer), the
driver issues an
Applycommand. The state machine reads accumulated observations and commits the organism’s own fact. - The organism’s public surface serves the committed fact to integrators and to any downstream consumers (other organisms, including composite ones that fold this one in).
Every step is standard mosaik machinery. The organism- specific work is the driver’s multi-subscription logic.
Rotations
A composite organism rotates like any other organism:
- Committee member rotation. Add a new member under
the same
OrganismConfig; drain the old member; decommission. No fingerprint change. - Committee admission policy rotation (e.g. a TDX
Measurements bump). Requires a new
OrganismConfigfingerprint. Announce to any coalition operators referencing the organism and follow the rotations and upgrades sequence. - Spanned-member-set rotation. Adding or removing a
spanned member changes the organism’s content
fingerprint. This is a larger change; typically
accompanied by a fresh
OrganismConfigpublication and a notice to referencing coalitions.
Rotations that do NOT break integrators
- Committee member swaps under a stable
OrganismConfig. Integrators see a brief latency bump during drain; no handle failures.
Rotations that DO break integrators
- Any
OrganismConfigfingerprint bump. Integrators compiled against the old config seeConnectTimeouton the organism handle until they recompile against the newOrganismConfig(and any coalition referencing it updates itsCoalitionConfig). Announce ahead of time via the change channel.
Retirement
When a composite organism’s committee is shutting down
permanently, the committee emits a RetirementMarker as
its final commit on each public primitive. The marker
carries:
effective_at— the Almanac tick or wall-clock at which the committee ceases to commit;replacement— an optional pointer to the replacement organism so integrators rebind cleanly rather than timing out.
If any referencing coalition ships a Chronicle, the
retirement lands as ChronicleKind::OrganismRetired in
the next Chronicle entry.
Incident response specific to organisms
Two incident classes to add to your playbook on top of the single-organism classes in builder incident response.
Evidence-pointer resolution fails on replay
Symptom: a committee member replaying the log fails to resolve an evidence pointer to an upstream member commit. Cause: the upstream member committed the fact, the organism observed it, but the member has since gone through a state compaction / reorg that removed the referenced commit from the public surface the organism reads.
Response:
- The organism state machine is required to reject such replays, not tolerate them.
- Confirm the issue is upstream-member retention, not organism state.
- Coordinate with the per-member operator. The fix is usually member-side configuration: longer retention on the public surface the organism subscribes to.
One spanned member goes dark
Symptom: no events from one of the spanned members’ public surfaces for multiple slots (or multiple publish ticks, if the member is an organism without a slot clock).
Response:
- Confirm with the per-member operator whether the outage is on their side or on the subscription.
- If on their side, fall back to the stall policy. A organism committing partial evidence yields degraded commits; one stalling per slot yields no commits until the member returns. Integrators were warned in the composition-hooks doc.
- If on the subscription side: mosaik transport troubleshooting; nothing organism-specific.
Cross-references
- Coalition overview
- Quickstart — stand up a coalition
- Multi-operator coalitions
- Rotations and upgrades
- Contributor — basic services
- builder operator runbooks
Multi-operator coalitions
audience: operators
A multi-operator coalition is one whose referenced
lattices, standalone organisms, or composite organisms
are operated by different teams. The blueprint does not
make multi-operator composition special: a
CoalitionConfig references member stable ids regardless
of who runs them. Coordination patterns succeed or fail
based on a few out-of-band agreements, catalogued below.
A multi-operator coalition provides a shared handshake and a coordination channel; nothing more.
The blueprint minimum
The coalition operator needs the stable id of each
referenced member. Any operator holding those ids can
publish a CoalitionConfig including those members;
there is no technical gate on referencing, and the
CoalitionConfig does not require the per-member
operator’s signature.
This is intentional. A stable-id reference is not a claim of authority over the member. A per-member operator objecting to a coalition reference has no technical recourse, and the reference also has no technical consequence: every organism committee member still needs tickets from each per-member operator to bond into those members’ public surfaces. The distinction — a coalition as a shared handshake without authority over its members — is the point Buterin draws on a different surface in DAOs are not corporations (2022): decentralisation is worth paying for where it buys censorship-resistance and unpredictability- resistance, not where it imitates corporate hierarchy. A coalition in this blueprint is a coordination layer in the first sense, not an instrument of control in the second.
What a multi-operator coalition agreement should cover
Documented even when trust between operators is high.
Notification cadence
- Member retirements (stable-id bumps). The per- member operator notifies the coalition operator at least one business day ahead of a retirement.
- Content-hash bumps that matter to organisms pinning content (TDX Measurements rotations on TDX-gated surfaces). Coordinate with any organism operator whose pinning policy is affected.
- Ticket rotations. When a per-member operator rotates their ticket-issuance root, organism committee members need new tickets before cutover.
- Retention changes. A member shortening retention of a public surface a composite organism subscribes to breaks organism replay. Notify the coalition operator and the organism operator.
Ticket issuance for organism committee members
The organism committee reads each spanned member’s public surfaces and so requires per-member tickets. Agreements should cover:
- Who issues. Each per-member operator issues tickets for organism committee members, exactly as for any integrator.
- Under what policy. Organisms usually need read-
only tickets on specific surfaces (for a lattice:
UnsealedPool,tally::Refunds; for an oracle organism: its feed stream). Scope accordingly. - Rotation schedule. Tickets expire. A rotation cadence matching the per-member operator’s standard schedule is acceptable; unannounced rotations are not.
Optional coalition-scoped ticket issuer
A multi-operator coalition may ship a coalition-scoped ticket
issuer (see
ticket issuance).
Components — organisms, modules, even external
integrators — decide per-component whether to recognise
its tickets. No component is required to. A multi-operator coalition
agreement can document which components plan to
recognise the coalition issuer, but recognition itself
is always in each component’s own TicketValidator
composition.
Organism governance
When multiple members contribute inputs to one organism, the organism is itself a governance concern. Agreements cover:
- Who runs the committee? Often the coalition operator; sometimes a subset of the per-member operators; occasionally a separate team. Organism identity is coalition-independent: the same committee serves every coalition that references it.
- Who decides on
Configbumps? The organism operator, informed by the affected per-member operators and by referencing coalitions. - Conflict resolution. The escalation path when the organism commits a record one per-member operator disputes (an attribution split, a cross-feed correlation).
None of this is in-protocol; all of it is contract. The coalition does not arbitrate.
Publishing a multi-operator coalition
The handshake page makes multi-operator coalition visible:
- Per-member links. Each
LatticeConfigorOrganismRefreference includes a link to the corresponding per-member operator’s handshake page. Composite-organism references additionally link to the organism operator’s handshake. - Operator roll call. A table listing each operator and the roles it holds (lattice, standalone organism, composite organism, module, ticket issuer, coalition).
- Multi-operator coalition change channel. Typically a shared channel across all participating operators rather than the coalition operator’s individual channel, so that member-side changes are visible to every participant in-flight.
What multi-operator coalition does not change
- Mosaik-level security. Each member’s ACL is unchanged. Each organism’s ACL is unchanged.
- Atomicity. No cross-member atomic commit. Multi-operator coalition does not provide it; no contract can.
- Integrator ergonomics. Integrators still compile
one
CoalitionConfig; a multi-operator coalition is indistinguishable from a single-operator coalition at the handle API.
A healthy multi-operator-coalition checklist
- Each referenced per-member operator has been notified.
- Each referenced organism operator has been notified.
- Ticket issuance for organism committee members is documented per member.
- The change channel covers member retirements, content-hash bumps, ticket rotations, and organism config changes.
- The handshake page lists every operator and their role.
- The coalition’s modules and any referenced organisms have a documented stall / degradation policy consistent with each spanned member’s expected availability.
Cross-references
- Coalition overview
- Running an organism
- Rotations and upgrades
- Contributor — threat model
- Contributor — ticket issuance
Rotations and upgrades
audience: operators
Rotation discipline at the coalition layer is thin: most
rotations occur inside one member (a lattice or a
standalone organism) or inside a composite organism or
module. The coalition operator’s task is to republish
the CoalitionConfig when any referenced component
changes identity in a way that folds into
COALITION_ROOT. This page lists the rotations that
materially affect a coalition and the operation order for
each.
For rotations inside a block-building lattice organism, follow the builder rotations page. For rotations inside a standalone organism, follow that organism’s own runbook.
Rotations that change a coalition’s fingerprint
Any of the following forces a new CoalitionConfig
fingerprint. Publication is not optional: integrators
compiled against the old fingerprint see ConnectTimeout
on every handle until they recompile against the new
one.
- A referenced lattice’s stable id changes (retirement).
- A referenced organism’s stable id changes (retirement of a standalone or composite organism).
- A referenced composite organism’s
OrganismConfigfingerprint changes and the coalition pinned the content hash (content, ACL, span, or TDX Measurements bump on a TDX-gated organism). - A module’s
ModuleConfigfingerprint changes (content, ACL, or TDX Measurements bump). - The coalition’s lattice set changes (add or remove a lattice).
- The coalition’s organism set changes (add or remove a standalone or composite organism).
- The coalition’s module set changes (add or remove a module).
- The coalition’s ticket issuer is added, rotated, or removed.
- The coalition instance name changes (rare — effectively a retirement; see below).
Rotations that do not change a coalition’s fingerprint
- Committee member rotations inside a referenced member,
under a stable per-member
Config. - Committee member rotations inside a composite organism
or module, under a stable
OrganismConfig/ModuleConfig. - TDX Measurements republications that match the previously pinned value (i.e. the image was rebuilt from the same source).
- Per-member content-hash bumps (TDX Measurements rotations, ACL rotations) if organisms pin only the stable id, not the content hash. Organisms that pinned content hash do bump.
These are invisible to integrators at the coalition layer. Documented per-member or per-organism, not per- coalition.
Ordering a member retirement
When a referenced member’s stable id changes, follow this sequence.
- Receive the retirement notification from the per- member operator via the multi-operator coalition change channel. The notification includes the old and new stable ids and the cutover time.
- Prepare the new
CoalitionConfig. Update the member’s reference in theCoalitionConfigdefinition. Re-derive the coalition fingerprint. Modules re-derive automatically becauseCOALITION_ROOThas changed. Commissioned organisms referenced by the coalition re-derive only if they themselves span the retired member. - Redeploy modules under the new
OrganismConfigs. Because each module’s content folds the coalition root, module fingerprints have bumped. Bring up new committee members on the newOrganismConfigs while old members continue on the old ones; rotate over. - Publish the new
CoalitionConfigfingerprint on the handshake page and change channel. - Wait for integrators to recompile. Old-
fingerprint handles time out (or, better, see a
RetirementMarkerfrom each retiring committee pointing at the replacement); integrators reach out if they miss the change. - Retire the old module deployments once the old
CoalitionConfigis no longer in use by the integrators the operator cares about. Each committee emits a terminalRetirementMarkerbefore shutdown.
Ordering a composite-organism or module upgrade
A composite organism or module’s Config may change for
reasons other than upstream member retirements: new
content parameters, TDX Measurements bump, ACL change.
- Stand up the new deployment under the new
OrganismConfig/ModuleConfigalongside the old. - Update any referencing coalitions’
CoalitionConfigs to reference the new fingerprint. Recompute each coalition fingerprint. - Publish each new
CoalitionConfig. - Announce the change via the change channel, with migration notes. If any referencing coalition ships a Chronicle, its next commit records the rotation.
- Retire the old deployment. The committee emits a
RetirementMarkerpointing at the new deployment so integrators rebind cleanly.
A transition window where old and new coexist is required; a hard cutover leaves every integrator timing out simultaneously.
Retiring a coalition
A coalition may be retired (renamed). Reasons:
- The composition has drifted far enough from the original intent that a clean break is preferable to incremental bumps.
- The set of operators participating in the coalition has reorganised.
- Branding or regulatory considerations.
Sequence:
- Announce retirement with substantial lead time. Integrators relying on the coalition need weeks to migrate. A shipped Chronicle records the retirement in its next commit.
- Stand up the replacement coalition (e.g.
ethereum.superchain-v2026q2) with a freshCoalitionConfigfingerprint and the desired composition. - Run both coalitions in parallel until most integrator traffic has migrated.
- Retire the old coalition’s modules (committees
emit
RetirementMarkers pointing at the replacement coalition’s modules) once integrator traffic drops to zero or acceptable levels. Referenced organisms are independent of the retired coalition and continue if other coalitions or direct integrators still use them. - Publish a retirement note. The old
CoalitionConfigfingerprint is formally deprecated; integrators still on it seeConnectTimeoutonce the old modules are down.
Do not reuse an instance name for a different composition. A retired coalition’s name is spent; reissuing it under a new composition would produce silent mis-bindings across the integrator base.
Cross-references
Designing coalitions on mosaik
audience: contributors
This chapter extends the design intros of zipnet and builder from one organism → one lattice → one coalition: a named composition of coexisting mosaik members — block-building lattices, standalone organisms (oracles, attestation fabrics, identity substrates, analytics pipelines, …), cross- member organisms (composite organisms), and up to five basic services (Atlas, Almanac, Chronicle, Compute, Randomness) plus an optional coalition-scoped ticket issuer.
The reader is assumed familiar with the mosaik book, the zipnet book, the builder book, and the two design intros cited above. This chapter does not re-derive content + intent addressing, the narrow-public-surface discipline, the shared-universe model, or within-lattice derivation; it uses them.
Stance
A coalition is an opt-in composition. The substrate has
no primitive for compulsion: every bond is opt-in at the
TicketValidator layer, member
identity is independent of coalition membership, and
basic services never gate member operation. Every design
choice in this chapter follows from this baseline.
The problem, at N members
Builder composes six organisms under one LatticeConfig
for one EVM chain, solving “one end-to-end pipeline for
one chain” cleanly. It does not solve:
-
Cross-member coordination at scale. An agent operating across ten block-building lattices holds ten
LatticeConfigs; one additionally correlating across an oracle and an attestation organism holds twelve handshakes. Driver code pairs facts across members, reconciles partial observations, and recovers outcome correlators. The same correlator is re-implemented per agent. The builder book’s Shape 1 is correct for two or three lattices and an unbounded implementation burden at ten-plus heterogeneous members. -
Shared attribution. MEV captured on a block of lattice A originating from a searcher bundle submitted on lattice B — or a trade attributed by an analytics organism also reported by an oracle organism — is invisible to each service without explicit wiring. Ad hoc repetition is the same burden, one level deeper, across more boundary kinds.
-
Consistent cross-member observability. Operators running five members want one dashboard; analytics integrators want one API. Both want a named composition with a fingerprint that moves in lockstep with what they subscribe to. The Atlas basic service addresses this.
-
Operator coordination. Teams coordinating a set of members — every chain in a superchain stack, every oracle feed in a region, every deployment’s bonded organisms — need a naming unit for that coordination that does not itself become a consensus unit.
-
Durable provenance. Decisions outlive any one
CoalitionConfig. An operator grouping needs a tamper-evident record of its own publications, rotations, and retirements — the Chronicle basic service addresses this.
Promoting “a set of members” to an in-consensus group collapses every member’s trust boundary into one committee. Builder rejected that shape at the organism level; promoting it one rung higher inherits the same objection at higher cost.
The correct rung is a fingerprint above the members that names them for discovery, basic services, and module derivation — without consensus, state, or admission authority. That fingerprint is a coalition.
Two axes of choice
Same two axes zipnet picked and builder reaffirmed. Each rung of the ladder inherits the zipnet conclusion; the coalition rung does too.
- Network topology. Does a coalition live on its own
NetworkId, or share a universe with every other mosaik service? - Composition. How do members and organisms reference each other without creating cross-Group atomicity mosaik does not support — and, now, without creating cross-coalition atomicity either?
The blueprint chooses shared universe + membership-by- reference + no cross-Group, cross-member, or cross- coalition atomicity. The three choices are independent; each has a narrow rationale.
Shared universe (unchanged)
builder::UNIVERSE = unique_id!("mosaik.universe") — the
same constant zipnet and builder use. Every coalition,
lattice, standalone organism, composite organism, and
module lives on it. Different coalitions coexist as overlays of
Groups, Streams, and Collections distinguished by
their content + intent addressed IDs. An integrator
caring about three coalitions holds one Network handle
and three CoalitionConfigs. Because coalitions
reference members rather than re-deriving them, an
integrator already bonded to some of the included members
observes no duplicate identity.
The alternative — one NetworkId per coalition, mirrored
all the way up — is rejected on the same grounds the
zipnet book rejects Shape A: operators already pay for one
mosaik endpoint, services compose, and one additional
endpoint per coalition would turn the coalition into a
routing device, which is not the rung’s function.
Membership-by-reference
A CoalitionConfig is a parent struct. Unlike a
LatticeConfig (which nests six organism Configs and
hashes them together), a CoalitionConfig references
existing member fingerprints without re-deriving the
members’ organism IDs. This is the key decision of the
coalition rung:
COALITION = blake3("coalition|" || SCHEMA_VERSION_U8
|| "|" || coalition_name)
COA_LATTICES = ordered stable ids of referenced lattices
COA_ORGANISMS = ordered stable ids of referenced organisms
(including any composite organisms)
COA_TICKETS = optional TicketIssuerConfig fingerprint (0 bytes if absent)
COALITION_ROOT = blake3(
COALITION
|| COA_LATTICES
|| COA_ORGANISMS
|| COA_TICKETS
)
Here COA_LATTICES[i] is the stable id of lattice i —
not a re-derivation. Likewise COA_ORGANISMS[j] is the
stable id the standalone organism (or composite organism)
j publishes in its own handshake. Composite organisms
are referenced by their own fingerprint just like any
other organism. Builder’s lattice identity is:
LATTICE(i) = blake3("builder|" || instance_name || "|chain=" || chain_id)
+ every organism's Config fingerprint inside that lattice
A coalition neither modifies LATTICE(i) nor the organism
roots under it, nor the Config of any standalone
organism or composite organism it references. A member
referenced by three coalitions is one member; its
operators issue tickets once, its integrators compile it
in once, and its GroupIds are stable across coalition
memberships.
Rationale for by-reference over by-containment:
-
Members predate coalitions. The first production organism and first production lattice ship before the first coalition. An integrator already bonded to a specific member must not have to re-bond when an operator composes that member into a new coalition.
-
Members outlive coalitions. Coalition membership is a composition choice and changes; member identity is an operator-level commitment. Coalitions must not force churn.
-
Members belong to multiple coalitions. The shared- universe choice implies a member may be referenced from several coalitions simultaneously — one per operator grouping, one per analytics vendor, one per umbrella grouping. Re-derivation would force a cartesian product of IDs.
Member reference shape
A member is referenced by two values: its stable id
— the (instance_name, network_id) blake3 hash — which
changes only on retirement; and its content hash,
which folds the member’s ACL, TDX Measurements, and policy
parameters and bumps with every operational rotation.
CoalitionConfig references members by stable id.
Composite organisms and modules choose per-component
whether they also pin the content hash. A read-only
correlator that does not bond into TDX-gated surfaces
pins only the stable id and survives TDX Measurements rotations in
its upstream members. A composite organism whose
committee bonds into a TDX-gated surface pins the content
hash and redeploys on rotation.
The split decouples TDX Measurements rotation churn from coalition-
level identity. A coalition referencing ten members
rotating TDX monthly sees its COALITION_ROOT change only
on member retirement or coalition membership change, not
on routine operational rotations.
Open for v0.3 decision. Whether content-hash- pinning is a per-component choice or a coalition-wide policy is unresolved. Leaving it per-component for v0.2;
CoalitionConfigmay gain a policy flag later.
Builder’s LatticeConfig derivation already distinguishes
the two in practice; this rung surfaces the distinction
in the coalition-layer spec. Both LatticeConfig and
OrganismRef expose a stable_id() accessor separate
from their full fingerprint accessor.
Composite organisms as a recurring pattern
Composite organisms are organisms in the zipnet sense:
one Config fingerprint, a narrow public surface, a
ticket-gated ACL. What distinguishes them is that their
content folds two or more member fingerprints. A
composite organism’s identity does not fold a
coalition root:
ORGANISM(cfg) = blake3(
"organism|"
|| SCHEMA_VERSION_U8
|| "|" || name
|| ordered spanned lattice references
|| ordered spanned organism references
|| content_fingerprint
|| acl_fingerprint
)
ORGANISM_committee = ORGANISM(cfg).derive("committee")
A composite organism is therefore referenced by zero,
one, or many coalitions exactly as a lattice or any other
standalone organism is. Its committee, state machine, and
log are shared across those references. A composite
organism misconfigured against the wrong spanned members
derives a disjoint GroupId and surfaces as
ConnectTimeout — the ladder’s standard debuggable
failure mode.
Modules (Atlas, Almanac, Chronicle) are the only
coalition-scoped components. Their identity derives under
COALITION_ROOT.derive("module").derive(name) where
name is "atlas", "almanac", or "chronicle". An
optional ticket issuer derives under
COALITION_ROOT.derive("tickets").
No cross-Group, cross-member, or cross-coalition atomicity
Every rung below refuses cross-Group atomicity. The coalition rung refuses cross-member and cross-coalition atomicity by the same argument:
- Cross-Group (one member, two organisms) — refused by builder and by every organism’s own design. Organisms subscribe to each other’s public surfaces; there is no atomic multi-organism commit.
- Cross-member (one coalition, two members) — refused by this blueprint. Composite organisms read public surfaces of the members they span; their state machine commits its own facts. A composite organism never forces two members to commit atomically.
- Cross-coalition (two coalitions) — refused by this blueprint. Coalitions do not coordinate in consensus. A use case for cross-coalition coordination resolves either to an integrator spanning coalitions or to a new composite organism whose content fingerprint folds the relevant members (which are already referenced by both coalitions anyway).
Fixed shapes, open catalogs
The blueprint’s central discipline; restated because every downstream choice flows from it.
Specified
- The
CoalitionConfigstruct and derivation rules. Every coalition has this shape; every coalition’s identity is computed this way. - The
OrganismConfigandOrganismRefstructs. Every organism (including composite organisms) and every standalone-organism reference has these shapes. - The five basic-service shapes (Atlas, Almanac,
Chronicle, Compute). Every instance of “Atlas” in any
coalition has the same
Configsignature, public surface, and derivation. Same for the other three. Specification in basic services. - The optional ticket-issuer shape. Specification in ticket issuance.
- Membership discipline — by-reference, multi- coalition-compatible, no re-derivation; stable-id and content-hash split.
Left open
- Whether any given coalition ships any basic services. A coalition with zero services is valid.
- Whether any given coalition ships a ticket issuer.
- The catalog of commissioned composite organisms. Each arrives when a cross-member problem forces it.
- The catalog of standalone-organism categories and lattice classes. New categories arrive with their own books. Block-building lattices are the first specified class; attestation fabrics, oracle grids, DA shards, and other categories follow their own proposals.
- Inter-coalition coordination. Coalitions coexist on the shared universe; a concrete need for coordination earns its way in through a fresh proposal.
- Governance of the coalition itself. Who approves
CoalitionConfigbumps, how operator groupings form and dissolve, what contracts multi-operator coalitions sign — all out of band.
Deliberately deferred (deferred-primitives space)
A family of primitives the blueprint refuses:
- Enforceable policies over members — a
CoalitionConfigdeclaring constraints members must satisfy (TDX Measurements requirements, bond minimums, code-audit attestations). - Taxation — a protocol-level mechanism for the coalition to collect fees from members’ commits.
- Judiciary — an organism whose commits have protocol-level precedence over individual members’, resolving disputes.
- Mandatory membership — any primitive whose absence renders a member’s commits invalid in the coalition’s view.
- Legislation — a state machine in the coalition that members must query and conform to before acting.
Each is a coherent design space, and adopting any one forces the blueprint to rewrite the trust composition and rebuild every passage that assumes opt-in participation. Any future deferred-primitives proposal lives on its own branch and earns the transition; the current blueprint neither anticipates nor precludes one.
Flag in-source and in-docs as “deferred-primitives space” when the topic arises so the current scope is unambiguous.
Coalition identity
A coalition is identified by a CoalitionConfig folding
every root input into one deterministic fingerprint.
Operators publish the CoalitionConfig as lattice
operators publish a LatticeConfig and organism operators
publish their own Config; integrators compile it in.
pub const SCHEMA_VERSION_U8: u8 = 1;
pub const COALITION_ROOT_SEED: UniqueId = /* fixed */;
#[non_exhaustive]
pub struct CoalitionConfig<'a> {
/// Schema version byte. Folded as the first element of
/// every top-level identity preimage.
pub schema_version: u8,
/// Coalition root domain-separation seed. Constant
/// across the blueprint; carried explicitly so the
/// fingerprint stays self-describing.
pub coalition_seed: UniqueId,
/// Short, stable, namespaced name chosen by the
/// coalition operator (e.g. "ethereum.superchain",
/// "signals.euro-fx", "searcher-α").
pub instance_name: &'a str,
/// Ordered set of lattice stable ids this coalition
/// references. Held by stable id so the coalition does
/// NOT re-derive any lattice's organism IDs; a lattice
/// retains a single canonical identity across every
/// coalition that references it.
pub lattices: &'a [UniqueId],
/// Ordered set of organism references this coalition
/// composes — any mosaik organism with a Config
/// fingerprint living directly on the universe,
/// including composite organisms whose `Config` folds
/// multiple member references. A composite organism's
/// identity is derived independently of any coalition;
/// the same composite organism may be referenced by
/// many coalitions.
pub organisms: &'a [OrganismRef<'a>],
/// Basic services the coalition ships. Each field
/// holds an `OrganismRef` when shipped, `None`
/// otherwise. See [basic services](./basic-services.md).
pub atlas: Option<OrganismRef<'a>>,
pub almanac: Option<OrganismRef<'a>>,
pub chronicle: Option<OrganismRef<'a>>,
pub compute: Option<OrganismRef<'a>>,
pub randomness: Option<OrganismRef<'a>>,
/// Optional coalition-scoped ticket issuer.
/// Non-authoritative: no component is required to
/// accept tickets from this issuer. Organisms opt in
/// via their own TicketValidator composition.
pub ticket_issuer: Option<TicketIssuerConfig<'a>>,
/// Per-coalition retirement policy. Default: explicit
/// republication on every content change.
pub retirement_policy: RetirementPolicy,
}
#[non_exhaustive]
pub struct OrganismRef<'a> {
pub role: &'a str,
/// blake3((instance_name, network_id)); changes only
/// on retirement.
pub stable_id: UniqueId,
/// Optional content hash (ACL, TDX Measurements, policy).
/// Components that pin this redeploy on operational
/// rotations.
pub content_hash: Option<UniqueId>,
}
impl CoalitionConfig<'_> {
/// blake3("coalition|" || schema_version || "|"
/// || coalition_seed || "|"
/// || instance_name || ...)
pub const fn stable_id(&self) -> UniqueId { /* ... */ }
}
CoalitionConfig is lifetime-parameterised so runtime
construction is a first-class path. All existing const
instances continue to compile under 'static inference.
An integrator binds to the coalition by passing the
CoalitionConfig into whichever member or organism
handles they need:
use std::sync::Arc;
use mosaik::Network;
use builder::{LatticeConfig, UNIVERSE};
use coalition::{
CoalitionConfig,
SCHEMA_VERSION_U8, COALITION_ROOT_SEED,
RetirementPolicy,
};
const ETH_SUPERCHAIN: CoalitionConfig<'static> =
CoalitionConfig {
schema_version: SCHEMA_VERSION_U8,
coalition_seed: COALITION_ROOT_SEED,
instance_name: "ethereum.superchain",
lattices: &[
ETH_MAINNET.stable_id(),
UNICHAIN_MAINNET.stable_id(),
BASE_MAINNET.stable_id(),
],
organisms: &[
EUR_PRICE_FEED,
INTENTS_ROUTER,
SHARED_LEDGER,
],
atlas: Some(SUPERCHAIN_ATLAS_ORG),
almanac: None,
chronicle: None,
compute: None,
randomness: None,
ticket_issuer: None,
retirement_policy: RetirementPolicy::default(),
};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let network = Arc::new(Network::new(UNIVERSE).await?);
let eth_bid = offer::Offer::<Bundle>::bid(&network, Ð_SUPERCHAIN.lattices[0].offer).await?;
let eur_feed = oracle::Feed::<Price>::read(&network, ETH_SUPERCHAIN.organisms[0].config()).await?;
let intents = intents::Router::<Intent>::publish(&network, Ð_SUPERCHAIN.organisms[1]).await?;
let atlas = atlas::Atlas::<MemberCard>::read(&network, ETH_SUPERCHAIN.atlas().unwrap()).await?;
// ...
Ok(())
}
Every organism (composite, module, or standalone) exposes
typed free-function constructors in the shape zipnet ships
and builder reproduces
(Organism::<D>::verb(&network, &Config)). Raw mosaik IDs
never cross a crate boundary.
The coalition crate’s convenience surface
The coalition crate re-exports a small convenience
surface so that book-level examples, composite organisms,
and integrator quickstarts can use the same vocabulary
without each reaching into mosaik’s module layout
directly. The surface is stable across the blueprint;
downstream crates depend on it rather than on mosaik’s
primitive modules where both are interchangeable.
| Symbol | Provenance / role |
|---|---|
coalition::Stream<T> | Alias for mosaik::streams::Producer<T> on the write side, mosaik::streams::Consumer<T> on the read side. |
coalition::Collection<K, V> | Alias for mosaik::collections::Map<K, V>. |
coalition::Network (re-export) | mosaik::Network verbatim. |
coalition::Network::subscribe_of::<T>(id) | Extension trait wrapping network.streams().consumer::<T>().with_stream_id(id).build() for ergonomic organism reads. |
coalition::TicketValidator (re-export) | mosaik::TicketValidator verbatim. |
coalition::Tdx (re-export) | mosaik::tee::Tdx; carries .require_mrtd(...) and .verify_peer(...). |
coalition::acl::ReputationFloor | Ticket composer binding admission to a reputation card floor. Consumes (UniqueId, f32). |
coalition::acl::MarketSettlement | Ticket composer binding admission to a market settlement pointer. |
coalition::when! | Declarative macro for reactive conditions over Streams; compiles to .when() method chains on mosaik::streams. |
coalition::unique_id! / const_blake3! | Compile-time blake3 of byte literals; convenience wrapper around mosaik::primitives::unique_id!. |
coalition::zipnet::SealClient | Thin wrapper over zipnet::Zipnet::<D>::submit(&network, &Config) that carries the committed digest back to the caller. |
coalition::RetirementPolicy | Per-coalition retirement policy; default is explicit republication on every content change. |
The convenience surface is the book’s one central
declaration of these symbols. Every chapter that uses
Stream, Collection, ReputationFloor, when!, or
SealClient imports them from coalition::*, not from
mosaik/zipnet directly. Downstream crates that want the
raw primitives are free to bypass the convenience surface,
but the book’s prose does not.
Fingerprint convention, not a registry
Same discipline as zipnet and builder:
- The coalition operator publishes the
CoalitionConfigstruct (or a serialised fingerprint) as the handshake. - Consumers compile it in.
- If TDX-gated, the operator publishes the committee TDX Measurements for every organism (composite, module, or standalone) whose admission is TDX-attested. Per-member TDX Measurements are published by the per-member operator; the coalition operator re-publishes them for convenience, not as authority.
- There is no on-network coalition registry. A directory collection of known coalitions may exist as a devops convenience; it is never part of the binding path.
Typos in the coalition instance name, in member
fingerprint ordering, or in any organism’s parameters
surface as Error::ConnectTimeout, not “coalition not
found”. The library cannot distinguish “nobody runs this”
from “operator is not up yet” without a registry, and
adding one would misrepresent the error.
What a coalition is not
-
A member’s owner. A coalition references a member; per-member operators control admission, rotate keys, retire instances. The coalition’s
CoalitionConfigupdates independently. -
A consensus unit. There is no coalition-level Raft group, no coalition state machine, no coalition log. The coalition layer adds naming, modules, and module derivation — no consensus.
-
A routing device. Coalitions do not carry traffic between members. Every member and organism discovers peers via mosaik’s usual gossip on the shared universe. The coalition fingerprint is a compile-time token, not a runtime hub.
-
An ACL root. A coalition does not issue tickets on behalf of referenced members. Each member’s
TicketValidatorcomposition is unchanged; each organism has its ownTicketValidator. The optional ticket issuer is opt-in per component: components that want to recognise its tickets include its issuance root in their validator composition; others ignore it. -
A closed catalog. Unlike builder’s six organisms, this blueprint does not enumerate a canonical set of lattice classes, organism categories, or composite organisms. Real members and composite organisms ship when a concrete problem forces them.
Four conventions (three inherited, one added)
Every organism the blueprint references — whether standalone, composite, or a module — reproduces the three zipnet conventions verbatim; the coalition adds one.
-
Identifier derivation from the organism’s Config fingerprint. Inherited from zipnet.
-
Typed free-function constructors.
Organism::<D>::verb(&network, &Config)returning typed handles; raw IDs never leak across crate boundaries. Inherited from zipnet; mirrored by every organism in every lattice, every composite organism, and every module. -
Fingerprint, not registry. Inherited from zipnet; reaffirmed by builder and here.
-
Membership-by-reference, module-by-derivation. New for the coalition rung. A
CoalitionConfigfolds member fingerprints as content without re-deriving their organism IDs; composite organisms are likewise referenced, not derived. Modules (Atlas, Almanac, Chronicle) and an optional ticket issuer are the components whose identity foldsCOALITION_ROOT.
What the pattern buys
-
Collapsed integrator model: one
Network, oneCoalitionConfigper coalition, typed handles on each referenced member, composite organism, and consumed module. -
Operator pacing. A coalition starts as one operator’s set of members, adds a second operator’s member without touching the first’s, and adds a composite organism or module without forcing either per-member operator to change anything.
-
Clean retirement. A commissioned composite organism retires by the coalition’s next
CoalitionConfigomitting it — or, if the organism itself is going away, by a retirement marker on its own stream. Integrators seeConnectTimeout, the ladder’s standard failure mode, or a clean upgrade pointer. -
Cross-member services as organisms, not protocols. A shared-ledger composite organism, cross-feed correlator, cross-chain intent router, Atlas, or Almanac is a mosaik organism following the zipnet pattern. Its author reuses every primitive, ticket validator, and replication guarantee.
-
Open catalog. New lattice classes, organism categories, and composite organisms arrive on their own schedules and fold into the existing handshake shape without forcing the coalition layer to change.
Where the pattern strains
Three limitations a contributor extending this must be explicit about.
Member upgrades churn coalition-scoped identity
A member-level change bumping its stable id — a retirement
— changes the corresponding entry in COA_LATTICES or
COA_ORGANISMS for every coalition that references the
member, which in turn changes COALITION_ROOT and every
module derived under it.
The stable-id / content-hash split keeps routine
operational rotations out of COALITION_ROOT: TDX Measurements
rotations do not change the stable id and therefore do not
cascade. A retirement does; retirement is rare and
announced.
Commissioned composite organisms do not derive under
COALITION_ROOT, so retirements ripple through modules
only. A composite organism re-derives only when the
members it itself spans retire or when its own content
changes.
Wide composite organisms are heavy
A composite organism reading public surfaces from ten members simultaneously runs ten subscriptions, holds peer entries for ten ticket-issuance roots, and is sensitive to the liveness of all ten. The coalition blueprint does not make this easier; it makes it legible.
Commissioning contributors should consider sharding: a per-pair composite organism over interesting member pairs, composed by an integrator, is often cheaper and more debuggable than one wide composite organism.
The coalition is not cryptographically authoritative
A CoalitionConfig fingerprint is a naming convenience.
It does not sign, commit on-chain, or expose a channel for
per-member operators to discover which coalitions
reference their member. A per-member operator objecting
to being referenced has no technical recourse — anyone
with a list of member stable ids can publish a
CoalitionConfig.
This is intentional. The only cryptographic check is
whether each referenced member admits the composite
organisms’ committee peers via its own TicketValidator.
Per-member and coalition operators negotiate references
out of band.
Checklist for commissioning a new composite organism
-
Identify the one or two public primitives. If the surface is not a small, named, finite set of streams or collections, the interface is not yet designed.
-
Identify the members it spans. Record as ordered sequences of member references in the composite organism’s
Config— lattices, organisms, or both. Order matters; changing it changes the fingerprint. -
Pick the composite organism’s name. Folded into the organism’s own derivation; no coalition root is involved.
-
Define the
Configfingerprint inputs. Content parameters affecting the state-machine signature, upstream public surfaces subscribed to, ACL composition. -
Write typed constructors.
Organism::<D>::verb(&network, &Config). Never export rawStreamId/StoreId/GroupIdacross the crate boundary. -
Specify
TicketValidatorcomposition on the public primitives. ACL lives there. If the composite organism wants to recognise any coalition’s ticket issuer, its validator composition includes that issuance root directly; the composite organism chooses, the coalition does not impose. -
Decide per-member-failure behaviour. If member A is down, does the composite organism keep processing remaining members’ inputs or stall? Document as part of the composition contract.
-
Document which members’ public surfaces are read. This is the composition contract; changes to it touch Composition.
-
Declare dependency on any modules. If the composite organism aligns to Almanac ticks or observes Chronicle entries, state so in the crate documentation.
-
Answer: does this composite organism meaningfully aggregate across members, or is it an integrator in disguise? If an ordinary integrator holding the same N member handshakes could do the same work, skip the composite organism. The pattern earns its keep when the aggregated fact is itself a commit with its own consumers.
-
State the versioning story. If the answer to “what happens when one of the referenced members bumps its fingerprint?” is not defined, the design is incomplete.
Cross-references
- Anatomy of a coalition — concrete instantiation of the pattern for one example coalition.
- Basic services — Atlas, Almanac, Chronicle specified.
- Ticket issuance — the optional coalition-scoped issuance root.
- Composite organisms — shape and discipline of cross-member organisms.
- Composition — how members and composite organisms wire together without cross-Group atomicity.
- Atomicity boundary — what the coalition layer inherits and adds.
- Threat model — compositional trust.
- Roadmap — versioning, the deferred-primitives space, first commissioned composite organisms.
Anatomy of a coalition
audience: contributors
This chapter is the concrete instantiation of the pattern
described in Designing coalitions on mosaik.
It walks one example coalition end-to-end: the fingerprint
derivation, the public surface each component exposes on
the shared universe, the subscription graph across
member boundaries, and the way an integrator binds
handles through one CoalitionConfig.
The reader is assumed to have read the topology intro, the basic-services spec, and the builder architecture chapter.
Coalition identity recap
COALITION = blake3("coalition|" || SCHEMA_VERSION_U8
|| "|" || coalition_name)
COALITION_ROOT = blake3(
COALITION
|| ordered lattice stable ids
|| ordered organism stable ids
(including any composite organisms)
|| optional ticket-issuer fingerprint
)
// Lattice IDs: NOT re-derived by the coalition.
LATTICE_i = <builder's own derivation for lattice i>
ORGANISM_IN_i = <builder's own derivation for each organism in lattice i>
// Standalone-organism IDs: NOT re-derived by the coalition.
STANDALONE_j = <the organism's own derivation>
// Composite-organism IDs: derived independently of any coalition.
ORGANISM_c = blake3("organism|" || SCHEMA_VERSION_U8
|| "|" || name
|| spanned members
|| content
|| acl)
// Module IDs: the coalition-scoped components.
ATLAS_ROOT = COALITION_ROOT.derive("module").derive("atlas")
ALMANAC_ROOT = COALITION_ROOT.derive("module").derive("almanac")
CHRONICLE_ROOT = COALITION_ROOT.derive("module").derive("chronicle")
// Optional coalition-scoped ticket issuer.
TICKETS_ROOT = COALITION_ROOT.derive("tickets")
Member identity travels with the member; a composite organism’s identity travels with the organism. Only module identity (and the optional ticket issuer) is coalition-bound. See topology-intro — Membership-by-reference and topology-intro — Composite organisms as a recurring pattern.
Integrators bind via the CoalitionConfig they compile in
from operator-published release notes:
use std::sync::Arc;
use mosaik::Network;
use builder::UNIVERSE;
use coalition::CoalitionConfig;
const ETH_SUPERCHAIN: CoalitionConfig<'static> = /* operator-published */;
let network = Arc::new(Network::new(UNIVERSE).await?);
// Lattice organism handles — identical to the builder book.
let eth_bid = offer::Offer::<Bundle>::bid (&network, Ð_SUPERCHAIN.lattices[0].offer ).await?;
let uni_bid = offer::Offer::<Bundle>::bid (&network, Ð_SUPERCHAIN.lattices[1].offer ).await?;
let eth_tally = tally::Tally::<Attribution>::read(&network, Ð_SUPERCHAIN.lattices[0].tally).await?;
// Standalone-organism handles — same shape, concrete crate on the right.
let eur_feed = oracle::Feed::<Price>::read(&network, ETH_SUPERCHAIN.organisms[0].config()).await?;
// Module handles — resolved via typed helpers.
let atlas = atlas::Atlas::<MemberCard>::read(&network, ETH_SUPERCHAIN.atlas().unwrap()).await?;
let almanac = almanac::Almanac::<AlmanacTick>::read(&network, ETH_SUPERCHAIN.almanac().unwrap()).await?;
// Composite-organism handles — the same shape as any other organism.
let intents = intents::Router::<Intent>::publish(&network, ETH_SUPERCHAIN.organisms_by_name("intents").unwrap()).await?;
let ledger = ledger ::Shared ::<Refund>::read (&network, ETH_SUPERCHAIN.organisms_by_name("ledger").unwrap()).await?;
An integrator only opens the handles they need. A cross-
chain searcher typically holds bid for several lattices
and intents::publish; a shared-ledger analytics consumer
typically holds ledger::read only; a cross-feed
correlator holds one oracle handle plus one composite
organism handle; an observability operator holds
atlas::read and opens per-member handles from there.
Public surface summary
The coalition’s outward-facing primitives decompose into:
-
Every public primitive of every referenced lattice, unchanged. The builder book’s lattice public surface table applies without modification — the coalition does not touch lattice primitives.
-
Every public primitive of every referenced standalone organism, unchanged. Each organism’s own book is the reference.
-
Every module’s public surface (Atlas, Almanac, Chronicle — whichever are shipped), specified in basic services.
-
One or two public primitives per referenced composite organism, following the same narrow-surface discipline as every other organism.
For an example coalition containing two composite organisms — an intent router and a shared ledger — plus Atlas and Almanac as modules, the coalition’s own added surfaces might look like:
| Component | Write-side primitives | Read-side primitives |
|---|---|---|
atlas | (committee-only) | Atlas map (MemberId → MemberCard) |
almanac | (committee-only) | Ticks stream |
intents | Publish<Intent> stream | RoutedIntents collection (per slot, per target lattice) |
ledger | (internal commits only) | SharedRefunds collection (keyed by origin member) |
“Committee-only” and “internal commits only” mean the primitive is ticket-gated to the organism’s committee peers. It still lives on the shared universe; the ticket gate supplies access control.
Names above are illustrative. The blueprint specifies Atlas/Almanac/Chronicle by role; all other composite organism names are per-commission choices.
An example coalition: ethereum.superchain
Concrete walk-through of one plausible coalition. None of the composite organisms or services below are shipped; the sketch shows how the composition composes.
Composition
- Lattices:
ethereum.mainnet,unichain.mainnet,base.mainnet— all three referenced by stable id, none re-derived. - Standalone organisms:
price-feed.eur— an oracle feed publishing EUR/USD prices on the shared universe, referenced byOrganismRef. - Modules shipped: Atlas (directory), Almanac (tick beacon). Chronicle not shipped in this example; the operator can add it later without reshuffling members.
- Composite organisms referenced:
intents— a cross-chain intent router (reads from each lattice’sunseal::UnsealedPool, commits per- slotRoutedIntentskeyed by target lattice).ledger— a shared-refund aggregator (reads from each lattice’stally::Refunds, commitsSharedRefundskeyed by origin member).
Fingerprint sketch
ETH_SUPERCHAIN = blake3("coalition|" || SCHEMA_VERSION_U8
|| "|ethereum.superchain")
COALITION_ROOT = blake3(
ETH_SUPERCHAIN
|| LatticeConfig.stable_id(ethereum.mainnet)
|| LatticeConfig.stable_id(unichain.mainnet)
|| LatticeConfig.stable_id(base.mainnet)
|| OrganismRef.stable_id(price-feed.eur)
|| OrganismRef.stable_id(intents)
|| OrganismRef.stable_id(ledger)
|| (no ticket issuer)
)
ATLAS_ROOT = COALITION_ROOT.derive("module").derive("atlas")
ALMANAC_ROOT = COALITION_ROOT.derive("module").derive("almanac")
// Composite organisms derive independently of the coalition.
INTENTS_ID = blake3("organism|" || SCHEMA_VERSION_U8 || "|intents"
|| [ethereum, unichain, base]
|| intents_content
|| intents_acl)
LEDGER_ID = blake3("organism|" || SCHEMA_VERSION_U8 || "|ledger"
|| [ethereum, unichain, base]
|| ledger_content
|| ledger_acl)
// Per-component committee derivations follow the usual pattern.
A composite organism’s spanned-member set may be a subset
of the coalition’s member set. An intents composite
organism might span all three lattices while a
feed-oracle composite organism spans price-feed.eur
and one lattice. Each composite organism chooses its own
span.
Participants
Not every component is operated by the same entity. The coalition distinguishes six classes of participant.
- Lattice operator — the team responsible for a
referenced
LatticeConfig’s identity, its committees, and its ACL. One or more lattice operators per coalition; each operates independently. - Standalone-organism operator — the team responsible
for a standalone organism (e.g.
price-feed.eur). Operates independently. - Composite-organism operator — the team responsible for one composite organism’s committee members. Composite-organism operation is independent of any referencing coalition.
- Module operator — the team responsible for Atlas, Almanac, or Chronicle’s committee members. Often the coalition operator themselves; may be delegated.
- Coalition operator — the team responsible for
publishing and maintaining the
CoalitionConfigitself. Often coincides with one of the above; does not have to. Has no technical authority over the referenced members or composite organisms. - Integrator — external dev, runs no committee members, binds handles against the coalition from their own mosaik agent.
Data flow across one slot
The canonical happy path for one slot through this example coalition. Each step is a commit into one organism’s state machine; transitions between steps are stream/collection subscriptions. No arrow represents an atomic multi-Group commit.
integrator organism commit / effect
---------- ---------------------- ----------------------------
wallet ──► zipnet[eth] ───► Broadcasts grows (sealed envelopes for slot S)
unseal[eth] ───► UnsealedPool[S] populated
(same for uni, base)
(publisher) ──► price-feed.eur ───► Price[tick T] committed (async, no slot clock)
(internal) ──► almanac ───► Ticks[K] committed (shared time axis)
(internal) ──► atlas ───► MemberCard updates (any time)
composite ──► intents ───► RoutedIntents[S] committed per target lattice
(sees cross-chain intents, routes them)
searcher ──► offer[eth] ───► AuctionOutcome[S] (incorporates routed intents)
searcher ──► offer[uni] ───► AuctionOutcome[S]
searcher ──► offer[base] ───► AuctionOutcome[S]
atelier[eth] ───► Candidates[S] committed
atelier[uni] ───► Candidates[S]
atelier[base] ───► Candidates[S]
relay[eth] ───► AcceptedHeaders[S]
relay[uni] ───► AcceptedHeaders[S]
relay[base] ───► AcceptedHeaders[S]
(chain inclusion watchers observe each lattice independently)
tally[eth] ───► Refunds[S]
tally[uni] ───► Refunds[S]
tally[base] ───► Refunds[S]
composite ──► ledger ───► SharedRefunds[S] committed per origin member
wallet / searcher ◄── ledger refunds + attestations stream (aggregated)
dashboard ◄── atlas directory of members (for observability)
correlator ◄── almanac shared tick axis (for cross-member joins)
Two properties of this flow:
- The slot number remains the foreign key for block-
building lattices but is per-member. Slot
Sonethereum.mainnetis unrelated to slotSonunichain.mainnet. Composite organisms crossing member boundaries key commits by(member_id, slot)pairs (or(member_id, tick)for non-slotted standalone organisms). If the coalition ships an Almanac, composite organisms may optionally carry the currentalmanac_tickas an additional alignment key. - Each member’s pipeline is unchanged. The
intentscomposite organism injects routed-intent entries into a lattice’sofferinput via a subscription, not a cross-Group command. Eachofferdecides whether and how to include routed intents in its auction. Non- slotted organisms likeprice-feed.eurcontinue publishing on their own clock; composite organisms read their ticks as they appear.
Where each composite organism commits
The rule from the builder book — “what decision is the organism actually making at commit time” — carries to composite organisms and modules:
-
atlascommitsMemberCardupdates. The state machine merges operator-submitted cards (signed by the contributing per-member operator, or by the coalition operator in single-operator coalitions) into theAtlasmap. -
almanaccommits a monotonic tick. The state machine runs a deadline-driven Raft round; winner’s tick becomesTicks[K+1]. -
intentscommits a routed-intents entry per slot per target lattice. State machine reads cross-chain intents from each spanned lattice’sUnsealedPool, applies the routing policy, commits{member_id, slot, intents[]}intoRoutedIntents. -
ledgercommits a shared-refund entry per origin member per slot. State machine reads each spanned lattice’stally::Refunds, performs attribution across origin members, and commits{origin_member, slot, shares[]}intoSharedRefunds.
The same discipline every organism in every lattice observes: one decision per commit, state-machine-local, no cross-organism transactions.
Internal plumbing (optional derived private networks)
Same pattern zipnet established and builder reaffirmed: the public surface lives on UNIVERSE; high-churn internal plumbing may move to a derived private network keyed off the organism’s root.
For composite organisms and modules:
- Per-member subscription fan-in. Gossip between
committee members about per-member cursor state may
live on
<component>_root.derive("private"). - Attestation gossip. Committee members signing off on a commit can exchange signatures privately before the public commit lands.
Committee Groups themselves stay on UNIVERSE. The argument is unchanged across every rung.
Identity under member upgrades
Member identity splits into a stable id and a content hash; each moves on a different cadence.
-
Member internal rotation (stable id unchanged, content hash bumps). TDX Measurements rotation or ACL change. Invisible to
COALITION_ROOT. Commissioned composite organisms that pin content hash redeploy; composite organisms that pin stable id only continue as-is. The coalition publishes an advisory if the change matters to downstream components, but theCoalitionConfigdoes not change. -
Member retirement (stable id changes). The per- member operator publishes a new identity. Coalitions that reference this member must re-publish their
CoalitionConfigwith the new stable id. Every module’s identity bumps becauseCOALITION_ROOThas changed; composite organisms do not re-derive unless they themselves span the retired member and pin its reference.
This is a material clarity win over a design where every member change ripples into composite-organism identity: a coalition referencing ten members rotating TDX monthly sees module identity stable unless a retirement happens.
A coalition operator insulating integrators from member
retirements carries a version-stable alias in the
coalition name (ethereum.superchain-v2026q2). See
Roadmap — Versioning.
Sizing — Phase 1 coalition
Order-of-magnitude targets for an illustrative coalition with three lattices, one standalone organism, two modules, and two composite organisms. Indicative, not binding.
| Component | Committee members (v1) | Stream bytes / event | Notable bonds |
|---|---|---|---|
| Per lattice (×3) | see builder sizing | see builder sizing | see builder sizing |
price-feed.eur | see organism sizing | see organism sizing | committee + publishers |
atlas (module) | 3 members | O(members × card size) | committee + coalition op |
almanac (module) | 3–5 members | O(1) per tick | committee only |
intents composite | 3–7 TDX members | O(intents × lattices) | committee + each lattice |
ledger composite | 3–5 members | O(refunds) | committee + each lattice |
“v1” here means the coalition-level Phase 1 shape. Phase 2 adds more composite organisms as cross-member problems arise; Phase 3 introduces multi-operator composite organisms where committee members span organisations.
What this chapter deliberately does not cover
- Per-organism state machines. Each organism owns its own spec in its own crate once commissioned.
- Per-organism wire formats. Same.
- Chain-specific nuance inside a lattice. The builder book covers this; coalitions do not touch it.
- Organism-specific nuance inside a standalone organism. Each organism’s own book covers that.
- A canonical list of composite organisms or organism categories. See topology-intro — What a coalition is not.
- Deferred-primitives space (enforcement, taxation, judiciary). Deferred; see topology-intro — Fixed shapes, open catalogs.
Basic services
audience: contributors
Atlas, Almanac, Chronicle, Compute, Randomness.
A basic service (also called a module) is a
coalition-scoped organism whose shape is specified
once in the blueprint so every instance means the
same thing across coalitions. Each is derived under
COALITION_ROOT.derive("module").derive(name) and
exposes only mosaik primitives — Stream, Group,
and Collection variants
(see docs.mosaik.rs). The blueprint adds no types
for a module beyond its OrganismConfig.
None of the five is mandatory. A coalition may ship any subset. If a coalition ships a service named “Atlas”, it must have the shape on this page; a service named “Atlas” with a different shape is a bug, not a variant.
Two of the five — Compute and Randomness — have an additional market-for-supply structure: the module’s committee schedules and commits, but the work is discharged off-module by separate providers that compete to register. Atlas, Almanac, and Chronicle do their own work inside the committee.
Fix the shapes. Leave the catalogues open.
Atlas
Directory of the coalition’s members. Every coalition bigger than a single member benefits from one; cheapest module to operate.
Public surface: Map<MemberId, MemberCard> where
MemberCard carries the member’s role, stable id,
endpoint hints, ticket-issuance root, and any TDX
Measurements pins.
OrganismConfig folds the coalition root (via
.derive("module").derive("atlas")), the ordered
list of members it catalogues, and the Atlas
committee’s ACL.
Trust shape: majority-honest, typically non-TDX.
When to ship: almost always. When to skip: single-member coalitions.
Almanac
Shared clock beacon. Composite organisms correlating facts across members need one.
Public surface: Stream<AlmanacTick> where each
tick carries a monotonic seq: u64 and a
per-member timestamp vector as an advisory
correlation hint.
OrganismConfig folds the coalition root under
"almanac", the tick cadence, and the committee’s
ACL.
Trust shape: majority-honest. Ticks are ordering markers; the timestamp vector is not a cryptographic timestamp.
When to ship: more than one cross-member correlator. When to skip: members that correlate on their own clocks only.
Chronicle
Tamper-evident audit log of coalition actions: publications, rotations, retirements, membership changes, module upgrades.
Public surface: Stream<ChronicleEntry> where each
entry carries a monotonic seq, a
ChronicleKind, the coalition fingerprint at
commit time, a structured payload, and per-member
signatures in addition to the committee’s quorum
signature. The committee also periodically commits
a blake3 digest of the stream to an external
settlement contract.
OrganismConfig folds the coalition root under
"chronicle", the committee ACL, the entry schema
version, and the external anchor contract address.
Trust shape: tamper-evidence holds while either the on-chain anchor path is uncompromised, or at least one honest ex-member’s signed archive survives. Retroactive rewriting requires compromising both.
When to ship: multi-operator coalitions; coalitions with contested lineage; coalitions needing externally verifiable provenance.
Compute
Scheduler and registry for compute grants. Coalition members submit requests; the committee matches them to registered providers; providers run the workloads and commit usage logs.
Compute is the book’s reference case for a market-for-supply basic service. The module commits the match. The compute itself runs on a separate provider. The split is deliberate: the coalition’s trust boundary ends at the scheduling commit; the provider is bonded separately through mosaik’s normal ACL.
Public surface:
Stream<ComputeRequest>— write-side; coalition members submit here.Collection<RequestId, ComputeGrant>— the committee’s scheduled allocations.Collection<ProviderId, ProviderCard>— registered providers.Stream<ComputeLog>— provider-committed usage after a workload runs.
The data types:
pub struct ComputeRequest<'a> {
pub requester: MemberId,
/// Stable id of the workload organism the
/// requester wants run. The organism's
/// Config.content already pins everything the
/// provider needs to run it — no separate
/// manifest.
pub workload: UniqueId,
/// Optional content-hash pin, when the requester
/// wants one specific build.
pub pin: Option<UniqueId>,
pub duration_sec: u32,
/// Opaque settlement evidence the requester
/// chose. The module stores the hash and
/// verifies nothing about it; settlement rails
/// live off-module.
pub settlement: UniqueId,
pub deadline: AlmanacTick,
}
pub struct ComputeGrant<'a> {
pub request_id: UniqueId,
pub provider: MemberId,
pub endpoint_hint: EndpointHint<'a>,
pub bearer_pointer: UniqueId,
pub content_hash: UniqueId,
pub valid_from: AlmanacTick,
pub valid_to: AlmanacTick,
pub expected_mrtd: Option<Mrtd>,
}
pub struct ComputeLog<'a> {
pub grant_id: UniqueId,
pub provider: MemberId,
pub window: AlmanacRange,
pub usage: UsageMetrics,
pub evidence: Option<EvidencePointer<'a>>,
}
OrganismConfig folds the coalition root under
"compute", the committee ACL, and an optional
provider_reputation: OrganismRef the module
consults at clearing.
State machine: three commands — SubmitRequest,
CommitGrant, AppendLog.
Trust shape: majority-honest committee for
scheduling. Provider-level trust is the provider’s
own TicketValidator; the module does not vouch.
A malicious provider that accepts a grant and never
runs the image is detectable by the requester’s
outputs never appearing; a reputation organism
orthogonal to the module scores it.
When to ship: coalitions with members — AI agents in particular — that need programmatic compute acquisition. When to skip: coalitions whose members bring their own compute out of band.
Not a compute provider. Not a payment rail. Not a guarantee of provider honesty. Not a cross-coalition marketplace.
Randomness
Scheduler and commit authority for a coalition’s randomness beacon. Like Compute, the module commits the values but does not produce them; the actual randomness comes from a registered beacon provider whose identity the module publishes with each round.
Public surface:
Stream<BeaconTick>— the authoritative beacon sequence.Collection<ProviderId, ProviderCard>— registered providers (reuses the ComputeProviderCardshape; the card’s content declares which beacon scheme the provider runs).
pub struct BeaconTick {
pub round: u64,
pub provider: MemberId,
pub value: [u8; 32],
/// Scheme-specific proof (BLS signature, VRF
/// proof, external-anchor inclusion proof, TDX
/// quote). The committee verifies the proof
/// against the provider card's declared scheme
/// before committing the tick.
pub proof: Vec<u8>,
pub committed_at: AlmanacTick,
}
Consumers that want a per-round targeted draw derive it locally:
draw = blake3(beacon_value || domain_separator)
No BeaconRequest, no BeaconGrant, no
challenge-stream surface: a consumer who suspects
a round was biased files a ChronicleEntry and
unpins the provider from their own validator.
OrganismConfig folds the coalition root under
"randomness", the committee ACL, and the set of
beacon-scheme families the module admits
(threshold-bls, vrf, external, tdx-attested
as operator-declared tags).
State machine: two commands — RegisterProvider
and CommitBeacon.
Trust shape: the module’s scheduling and commit integrity is majority-honest committee. The beacon’s unbiasability is inherited from the provider’s declared scheme; the module verifies the proof at commit time but does not add cryptographic guarantees beyond what the scheme itself provides. Consumers admitting weak schemes get weak randomness.
When to ship: members need verifiable randomness (coordination markets, agent experiment allocators, commit-reveal auctions, leader-election committees). When to skip: randomness needs are cosmetic, or satisfied by an external beacon consumers bond to directly.
Not a beacon producer. Not a proof of unbiasability. Not a payment rail. Not a cross-coalition beacon.
Retirement markers
A cross-cutting primitive every composite organism,
module, and coalition supports. Before committee
shutdown, the component commits a
RetirementMarker on its own public stream so
consumers upgrade cleanly rather than receiving
ConnectTimeout.
pub struct RetirementMarker<'a> {
pub effective_at: RetirementInstant,
pub replacement: Option<ComponentRef<'a>>,
}
A retirement marker is the last commit on the
stream. A Chronicle entry records it at the
coalition level as ChronicleKind::OrganismRetired
or ChronicleKind::ModuleRetired.
Deriving a module’s identity
Every module is an organism; the derivation folds
the coalition root under a "module" segment:
ATLAS_ROOT = COALITION_ROOT.derive("module").derive("atlas")
ALMANAC_ROOT = COALITION_ROOT.derive("module").derive("almanac")
CHRONICLE_ROOT = COALITION_ROOT.derive("module").derive("chronicle")
COMPUTE_ROOT = COALITION_ROOT.derive("module").derive("compute")
RANDOMNESS_ROOT = COALITION_ROOT.derive("module").derive("randomness")
<module>_committee = blake3(
<module>_root
|| ordered member references (if any)
|| module_content_fingerprint
|| module_acl_fingerprint
).derive("committee")
The "module" segment distinguishes coalition-
scoped components from commissioned composite
organisms (which derive without a coalition root).
CoalitionConfig helpers
A coalition’s OrganismRef for each shipped
module is stored in a dedicated field on
CoalitionConfig, not a typed container. The
coalition meta-crate exposes direct accessors:
impl CoalitionConfig<'_> {
pub const fn atlas(&self) -> Option<&OrganismRef<'_>>;
pub const fn almanac(&self) -> Option<&OrganismRef<'_>>;
pub const fn chronicle(&self) -> Option<&OrganismRef<'_>>;
pub const fn compute(&self) -> Option<&OrganismRef<'_>>;
pub const fn randomness(&self) -> Option<&OrganismRef<'_>>;
}
A coalition that does not ship a module leaves the
field None; a later version can ship it without
breaking integrators that did not consult the
field before.
Deliberately unspecified
- Chronicle retention policy, storage layout, and anchor cadence — operator-configured.
- Almanac tick cadence.
- Atlas metadata schema beyond the required fields.
- The set of scheme-family tags a Randomness module admits.
- Whether a module is required for any downstream
composite organism. Composite organisms that
need a module declare the dependency in their
own
OrganismConfig. - Compute settlement evidence format. The module stores a hash; how it is verified lives with whichever rail the coalition uses (on-chain payment contract, reputation card, credit token).
- Deferred-primitives-space extensions — out of scope. See deferred-primitives pressure.
Cross-references
- Topology-intro — the coalition rung.
- Architecture — a coalition worked through.
- Ticket issuance.
- Composite organisms.
- Composition.
- Threat model.
- Deferred-primitives pressure.
Ticket issuance
audience: contributors
A coalition may optionally publish a coalition-scoped ticket issuer — a mosaik ticket issuance root whose tickets components may choose to recognise. This page specifies the shape and the composition.
The primitive is deliberately thin. It is not a policy
engine; it is not a state machine with Request/Grant
semantics; it is not the former Passport spec. It is a
mosaik ticket issuance root, folded into
CoalitionConfig, with one composition discipline:
components opt in.
Shape
#[non_exhaustive]
pub struct TicketIssuerConfig<'a> {
/// Issuer role / name folded into the derivation.
pub name: &'a str,
/// The issuer's ACL composition — how committee
/// members rotate, which operators run issuance, etc.
pub acl: AclComposition<'a>,
}
pub const fn coalition_ticket_issuer_root(coalition_root: UniqueId) -> UniqueId {
coalition_root.derive("tickets")
}
TICKETS_ROOT = COALITION_ROOT.derive("tickets"). The
issuer’s TicketIssuerConfig is folded into
COALITION_ROOT as the final ordered element after
COA_ORGANISMS.
How components opt in
Any organism (standalone, composite, or module) that
wants to recognise tickets issued by the coalition-scoped
issuer includes TICKETS_ROOT in its own
TicketValidator composition:
let validator = TicketValidator::new()
.recognise_issuer(ETH_SUPERCHAIN.ticket_issuer_root()?)
.require_ticket(Tdx::new().require_mrtd(organism_mrtd));
No component is required to. A composite organism designed to be referenced by many coalitions typically does not pin any coalition’s issuer, precisely because pinning a coalition would tie its identity to that coalition. A module shipped specifically for one coalition may pin it.
Trust shape
The trust shape is inherited from mosaik’s
TicketValidator composition. This page introduces no
new primitives:
- Tickets issued under
TICKETS_ROOTare ordinary mosaik tickets whose issuer identity happens to be coalition- scoped. - A component that pins the issuer trusts the coalition operator’s issuance discipline at least as far as they trust the ACL composition on that validator branch.
- A component that does not pin the issuer ignores its tickets entirely.
Because recognition is per-component and voluntary, there is no protocol channel for the coalition to compel recognition. The coalition operator publishes the issuer root; components individually decide whether to trust it.
When to ship an issuer
- Shared bonding. A coalition running several composite organisms whose committees cross-bond frequently benefits from a single issuance root rather than N per-organism roots.
- Multi-operator recognition. A coalition with multiple operators wanting a convenient common issuance root for ad-hoc identities.
When to skip
- Single-operator coalitions. The coalition operator already issues their own tickets at the organism level; a separate coalition-scoped root is unnecessary indirection.
- Open ecosystems. A coalition whose intended value is to stay out of bonding decisions ships no issuer.
Rotation
The coalition operator rotates the issuer ACL the same
way any ticket-issuing organism rotates: publish a new
TicketIssuerConfig (which bumps TICKETS_ROOT via
COALITION_ROOT), update CoalitionConfig to the new
issuer, announce through the change channel, and if the
coalition ships a Chronicle, record the rotation as
ChronicleKind::TicketIssuerRotated.
Components that pin the old root see new tickets fail validation; they pin the new root on their next upgrade. Components that don’t pin at all are unaffected.
Cross-references
Composite organisms
audience: contributors
A composite organism is an organism whose Config
fingerprint folds two or more member references (lattice
references, OrganismRefs, or a mix) and whose public
surface coordinates across the referenced members.
“Composite” is a role-name convention, not a type: the
organism follows the same OrganismRef shape as any other.
This chapter specifies when to commission one and how its
Config preimage works.
Modules (Atlas, Almanac, Chronicle) are, mechanically, organisms too; their shapes are specified once in basic services. They differ from general organisms in one way: modules derive under a coalition root, while commissioned organisms derive independently of any coalition. The generic organism discipline below applies to both; the derivation difference is called out where it matters.
The reader is assumed to have read Designing coalitions on mosaik and Anatomy of a coalition.
Definition
A composite organism is an organism in every sense the zipnet and builder books use the word. It has:
- one
Configfingerprint; - a narrow public surface (one or two named primitives);
- a
TicketValidatorcomposition gating bonds; - typed
Organism::<D>::verb(&network, &Config)free- function constructors; - a deterministic state machine inside a mosaik
Group.
What distinguishes a composite organism from a standalone organism:
- Its content fingerprint folds in multiple member references — the ordered set of members whose public surfaces it reads from (or writes to).
- Its state machine’s commits are a function of inputs drawn from more than one member’s public surface, and serve consumers on more than one member.
A composite organism is not a seventh lattice organism; it is not part of any lattice’s identity derivation; no per-member operator has to know what composite organisms reference their member. A composite organism is independent of any coalition that references it — its committee, state machine, and log are shared across coalition references.
When to commission one
Commission a composite organism when all three of the following hold.
-
The aggregated fact is itself a commit. If what you need can be computed ad hoc by an integrator across
Nmember handles, it does not need a composite organism. If multiple downstream consumers would each have to repeat the same aggregation, or if the aggregation is itself the input to yet another organism, the commit pays for itself. -
The inputs span more than one member. A composite organism that reads only from one member is a single-member organism in disguise; it belongs as a standalone organism (or inside that member’s own composition, if the member is a lattice).
-
The trust model is coherent across the inputs. A composite organism inherits the worst-case trust assumption of the member inputs it reads. If you cannot name the cross-member trust shape (e.g. “majority-honest across each lattice’s unseal committee, t-of-n on the oracle organism, plus majority-honest composite-organism committee”), you have not finished the design.
When any of the three is false, the right answer is one of:
- A cross-member integrator (Shape 1 in builder’s cross- chain chapter, generalised to any mix of members).
- An in-lattice organism that reads a sibling lattice’s public surface (Shape 2).
- A new standalone organism.
- A new organism inside an existing lattice.
Composite organism versus cross-member integrator
| Trait | Integrator-spans-members | Composite organism |
|---|---|---|
| Runs a Raft committee | no | yes |
| Commits to a state machine | no | yes |
| Admits other peers via ACL | no | yes |
| Consumes multiple members | yes | yes |
| Produces a reusable commit | no (per-integrator in-memory join) | yes (public surface consumers can read) |
| Cost to stand up | a driver in the integrator’s agent | a crate, a committee, an ACL |
| Availability | bounded by one agent | committee-level (Raft majority) |
| Trust assumption | integrator’s own | explicit, compositional |
Heuristic: if three different integrators would all perform the same aggregation, it is a candidate composite organism. If exactly one integrator needs it, keep it in the agent.
The Config fingerprint
A composite organism’s Config folds in:
#[non_exhaustive]
pub struct OrganismConfig<'a> {
/// Role name: "intents", "ledger", "market",
/// "correlate", … For modules:
/// "atlas", "almanac", "chronicle".
pub name: &'a str,
/// Ordered set of block-building lattices whose
/// public surfaces this organism reads or writes.
pub lattices: &'a [LatticeConfig<'a>],
/// Ordered set of standalone organisms whose public
/// surfaces this organism reads or writes. Same
/// story as `lattices` above, for non-lattice
/// members.
pub organisms: &'a [OrganismRef<'a>],
/// State-affecting parameters specific to this
/// organism. E.g. an intent router's policy
/// constants, a shared ledger's attribution model,
/// an almanac's tick cadence.
pub content: ContentParams<'a>,
/// TicketValidator composition gating committee
/// admission.
pub acl: AclComposition<'a>,
}
impl OrganismConfig<'_> {
pub const fn organism_id(&self) -> UniqueId { /* ... */ }
}
Identity derives from (name, spanned members, content, acl) with no coalition root folded in:
ORGANISM(cfg) = blake3(
"organism|"
|| SCHEMA_VERSION_U8
|| "|" || name
|| ordered spanned LatticeConfig references
|| ordered spanned OrganismRef references
|| content_fingerprint
|| acl_fingerprint
)
A composite organism can therefore be referenced by N coalitions; its committee, state machine, and log are shared across those references. Operators wanting two independent deployments deploy two composite organisms with different content or different ACLs — the cryptographic gate is the fingerprint, not coalition scope.
For modules the derivation is different — they derive
under a coalition root (see
basic services — Deriving a module’s identity).
The public surface, state-machine discipline, and
OrganismConfig fields are otherwise identical.
Public surface
Composite organisms follow the narrow-public-surface discipline without modification. Guidelines for picking the surface:
- Key every commit by
(member_id, slot)or(member_id, tick)when the organism is per- clock-event per-origin-member.member_idis the 20-byte truncated prefix of the member’s blake3 fingerprint. Integrators that join commits across composite organisms need this key. - Separate routing and attestation. If your composite organism both routes inputs (a write-side stream) and commits the routing outcome (a read-side collection), keep the two primitives named. Do not fold them into one.
- Expose attestations separately when the commit carries an attestable signature. Integrators that pull attestations to on-chain settlement contracts want the signature surface distinct from the routing surface.
- If your composite organism depends on a module,
declare it. A correlator that aligns to Almanac ticks
reads
Almanacand commits under(member_id, almanac_tick)keys; state that in the crate’s composition-hooks doc and in theOrganismConfig.contentparameters (since the alignment is state-affecting).
A design wanting three or more public primitives is likely two composite organisms.
State machine shape
Inside the composite organism’s Group, the state
machine is an ordinary mosaik StateMachine<M>. It
differs from a standalone organism’s state machine only
in what its inputs look like: driver code outside the
state machine subscribes to public surfaces on each
spanned member and feeds observed facts into the
composite organism’s group via group.execute(...).
Template for a composite-organism driver:
// Inside the composite organism's node crate, role: committee member.
loop {
tokio::select! {
// Per-member subscriptions the composite organism reads from.
ev = lattice_a_subscription.next() => {
let evidence = build_evidence_for_a(ev);
organism_group.execute(OrganismCmd::ObserveLatticeA(evidence)).await?;
}
ev = lattice_b_subscription.next() => {
let evidence = build_evidence_for_b(ev);
organism_group.execute(OrganismCmd::ObserveLatticeB(evidence)).await?;
}
ev = organism_c_subscription.next() => {
let evidence = build_evidence_for_c(ev);
organism_group.execute(OrganismCmd::ObserveOrganismC(evidence)).await?;
}
// Optional: align to a coalition's Almanac the
// composite organism has been configured to track.
ev = almanac_subscription.next() => {
let tick = /* ... */;
organism_group.execute(OrganismCmd::AdvanceTick(tick)).await?;
}
// Composite organism's own timers, per its state machine.
_ = apply_deadline.tick() => {
organism_group.execute(OrganismCmd::Apply).await?;
}
}
}
Rules:
- Observations are evidence, not authority. The
Observe*commands carry a pointer to the upstream member commit (member id, slot or tick, commit hash). The composite organism’s state machine validates the pointer against the member’s public surface on replay. - Applies are pure functions.
apply(OrganismCmd::Apply)reads the accumulated observations and emits the composite organism’s commit. It does not make new cross-member reads insideapply; reads belong to the driver. - No cross-Group calls inside apply. Same discipline as every organism.
ACL and attestation
A composite organism’s TicketValidator composition can
include:
- Per-member readership tickets. A composite organism
reading from lattice A’s
unseal::UnsealedPoolor from an oracle organism’s feed is an integrator of that member from the member’s perspective. Committee members must hold tickets the per-member operator issues, same as any other integrator reading that surface. - TDX attestation. If the composite organism sees
cleartext order flow or otherwise-sensitive data, the
committee members are almost always required to run an
attested TDX image.
.require_ticket(Tdx::new().require_mrtd(organism_mrtd))is the standard line. - Optional coalition-scoped issuer recognition. If a composite organism expects to be used predominantly under one coalition whose ticket issuer is stable, it may include that issuance root in its validator composition — a choice made on the composite organism’s side, not imposed by the coalition. See ticket issuance.
Failure modes
A composite organism has more failure modes than a standalone organism because its inputs are multi-operator:
- One spanned member stalls. The composite organism’s state machine must decide whether to commit with partial evidence (degrading quality but preserving liveness) or to stall that slot pending the missing member (preserving quality but sacrificing liveness on the slot). This is a per-organism choice; document it in the composition contract.
- One spanned member’s stable id changes. The
composite organism’s
Configfolds that reference; a change means the composite organism must be redeployed. Until it is, the composite organism’s subscriptions to the old member simply stop producing events. - One spanned member’s content hash changes (if pinned). Same as above but limited to composite organisms that chose to pin content — stable-id-only pinners are unaffected.
- Composite-organism committee loses majority. Same failure mode as any mosaik Raft group. Liveness is lost; integrity is intact.
- Spanned member’s ACL changes. If a per-member operator revokes the ticket committee members hold, the composite organism loses read access to that member’s public surface. Negotiated out of band; there is no technical recourse.
Composition patterns worth naming
Three patterns recur often enough to name. These are patterns, not required composite organisms; modules are the specified shapes.
Intent-router pattern
A composite organism whose state machine commits per-slot
routed intents keyed by (target_lattice_id, slot).
Reads cleartext from each spanned lattice’s
unseal::UnsealedPool; commits a RoutedIntents
collection each target lattice’s offer subscribes to.
Trust shape: TDX-attested committee plus t-of-n threshold
on the cross-member cleartext channel.
The builder book’s Shape 3 bridge organism is an intent- router pattern seed.
Shared-ledger pattern
A composite organism whose state machine aggregates
per-lattice tally::Refunds into a cross-origin-member
attribution set, committed as SharedRefunds and
SharedAttestations. Trust shape: majority-honest
composite-organism committee plus the per-member trust
shape of each spanned tally. An on-chain settlement
contract verifying a SharedAttestation verifies both
the composite organism’s signature and the underlying
per-lattice tally::Attestation referenced as evidence.
Integrators needing one refund feed across chains bind
the composite organism; integrators concerned with a
single chain bind that lattice’s tally directly. Both
paths coexist.
Cross-feed correlator pattern
A composite organism that pairs ticks from two or more
oracle organisms (or more generally, two or more
non-slotted standalone organisms), committing correlated
values under (member_id, almanac_tick) when a coalition
referencing the composite organism ships an Almanac and
the composite organism opts in, or under
(member_id, timestamp_bin) otherwise. Trust shape:
majority-honest composite-organism committee plus the
signing assumptions of each upstream oracle.
Other patterns worth naming (non-block-building)
The three patterns above originate in block-building. Other domains will yield more. Sketches:
- Attestation aggregator. A composite organism that folds TDX Measurements quotes from multiple attestation organisms across vendors or regions into a single attested membership set.
- Coordination-market organiser. A composite organism that runs an allocation auction where inputs come from several independent signal organisms and outputs drive several independent downstream members.
- Cross-DA committer. A composite organism that commits a combined availability proof over two or more DA shards.
Each is an OrganismConfig whose lattices slice may
be empty and whose organisms slice names the upstreams.
Checklist mirror
The commissioning checklist in topology-intro — Checklist for commissioning a new composite organism applies verbatim. This page is the reference; the topology-intro page is the forcing function when commissioning one.
Cross-references
- topology-intro — why this rung exists.
- basic-services — the three specified module shapes plus retirement markers.
- ticket-issuance — the optional coalition-scoped issuance root.
- architecture — where composite organisms sit in one example coalition.
- composition — the subscription graph that members and composite organisms share.
- atomicity — what composite organisms deliberately do not guarantee.
- threat-model — how a composite organism’s trust assumption composes with the spanned members’.
Composition — members and organisms in a coalition
audience: contributors
Architecture maps composite organisms and members onto one example coalition. Composite organisms specifies the composite-organism shape. Basic services specifies Atlas, Almanac, and Chronicle. This chapter shows the wiring: which public surface each composite organism subscribes to on each spanned member, how the subscription graph grows as composite organisms and modules are added, and what fails where when an upstream stalls.
The wiring is deliberately weak. No cross-Group
atomicity, no shared state across members, no global
scheduler. Members and organisms react to each other’s
public commits via mosaik’s when() DSL and Collection
/ Stream subscriptions. This is the composition model
at every rung.
Two keys: member id and clock event
Every commit in every block-building lattice is keyed by slot (see builder composition). Every commit in a standalone organism is keyed by that organism’s own clock event — a slot, a tick, a round, a sequence number. A coalition adds the member id as an outer key on every cross-member fact.
The member_id used as a key in cross-member commits is
the first 20 bytes of the member’s blake3 stable-id
fingerprint. The full 32-byte value lives in Atlas cards
and in evidence pointers. The 20-byte truncation gives a
compact key that matches the mental model readers bring
from other ecosystems; collision resistance remains more
than sufficient at this rung.
Concretely:
- Intra-member commits continue to key on their own clock alone (no change from the member’s own book).
- Composite-organism commits that fan-out to multiple
target members key on
(target_member_id, target_clock_event). - Composite-organism commits that fan-in from multiple
origin members key on
(origin_member_id, origin_clock_event). - An integrator joining commits across a composite
organism and the members the composite organism touches
keys on
(member_id, clock_event)everywhere. - When a coalition ships an Almanac the composite
organism has opted into, the composite organism may
additionally carry
almanac_tickas an alignment key for cross-member joins where the members’ native clocks are not commensurate.
The 20-byte member_id is stable — it never changes for
a given member deployment. A member retirement yields a
new stable id and is therefore a new member id for every
coalition that adopts it.
The subscription graph
Each arrow is a subscription. The downstream component watches the upstream’s public collection or stream and reacts in its own state machine. No arrow represents atomic cross-Group commit. Dashed boxes are composite organisms; the oracle box on the left is a standalone organism.
integrators
(wallets,
searchers)
│
├──► zipnet[L1]:Submit ────► Broadcasts[L1] ──► UnsealedPool[L1] ─┐
│ │
├──► zipnet[L2]:Submit ────► Broadcasts[L2] ──► UnsealedPool[L2] ─┤
│ │
└──► offer[L1]:Bid / offer[L2]:Bid │
│
price-feed.eur ──► Price[tick] │
│
almanac ──► Ticks[K] │
│ │
└──────────── referenced by composite organisms for alignment ──┐ │
▼ │
┌────────────────── ┘
▼
┌───────────────────────┐
│ intents (composite) │
│ reads UnsealedPool[*] │
│ + price-feed.eur │
│ commits RoutedIntents │
└───────────────────────┘
│
RoutedIntents[L1,S] / RoutedIntents[L2,S]
▼
offer[L1]:AuctionOutcome offer[L2]:AuctionOutcome
│ │
atelier[L1]:Candidates atelier[L2]:Candidates
│ │
relay[L1]:AcceptedHeaders relay[L2]:AcceptedHeaders
│ │
tally[L1]:Refunds tally[L2]:Refunds
│ │
└────────────┬──────────────┘
▼
┌──────────────────────────┐
│ ledger (composite) │
│ reads Refunds[*] │
│ commits SharedRefunds │
└──────────────────────────┘
│
▼
integrators
atlas ──► MemberCards (consumed by dashboards, not coalition pipeline)
chronicle ──► ChronicleEntries (consumed by auditors, not coalition pipeline)
Read top to bottom:
- Wallets submit to each lattice’s
zipnet::Submit; searchers submit to each lattice’soffer::Bid. Neither changes from builder. - Each lattice’s
zipnetandunsealdo their usual work independently. The oracle organismprice-feed.eurpublishes ticks on its own clock. The Almanac (if shipped) publishes its own tick stream. - The
intentscomposite organism subscribes to every spanned member’s relevant public surface — lattices’UnsealedPools and, in this example,price-feed.eur’sPricestream. It may additionally subscribe to the Almanac for alignment keys. It observes cross-member intents and commits routed-intents entries per target lattice. - Each lattice’s
offersubscribes to the composite organism’sRoutedIntentscollection filtered for its own member id. Routed intents are an additional input to the auction, along with the lattice’s ownUnsealedPool. - Each lattice’s
atelierandrelayproceed as in builder. - Each lattice’s
tallycommits independently. - The
ledgercomposite organism subscribes to every spanned lattice’stally::Refundsand commits the aggregatedSharedRefundscollection. - Integrators read
SharedRefundsand per-member surfaces depending on their use case. Dashboards read the Atlas. Auditors read the Chronicle.
Atlas and Chronicle are not on any composite organism’s critical path in this example; they are consumed by dashboards and auditors directly. Modules serve observability and provenance, not the coalition’s data flow.
Subscription code shape
A contributor implementing a composite organism writes a
role driver in that composite organism’s crate. The
driver is a mosaik event loop multiplexing subscriptions
across members and calling group.execute(...) on its
own Group. The pattern is identical to any organism
driver, fanned out across more member kinds.
// Inside intents::node::roles::committee_member.
//
// `lattices` and `organisms` are the ordered sets of
// member references this composite organism spans,
// sourced from self.config.lattices and
// self.config.organisms.
loop {
tokio::select! {
// One subscription per spanned lattice's UnsealedPool.
ev = pool_a.when().appended() => {
let round = pool_a.get(ev).expect("appended implies present");
let intents = extract_cross_chain_intents(&round);
self.group.execute(IntentsCmd::ObservePool {
member_id: lattice_a_id,
slot: round.slot,
intents,
}).await?;
}
ev = pool_b.when().appended() => {
// ... same shape
}
// One subscription per spanned standalone organism.
ev = price_feed_eur.when().appended() => {
let tick = price_feed_eur.get(ev).unwrap();
self.group.execute(IntentsCmd::ObservePrice {
member_id: eur_feed_id,
tick: tick.seq,
price: tick.value,
}).await?;
}
// Optional: align to a coalition's Almanac.
ev = almanac.when().appended() => {
let t = almanac.get(ev).unwrap();
self.group.execute(IntentsCmd::AdvanceAlmanacTick(t.seq)).await?;
}
_ = self.apply_clock.tick() => {
// Per-slot deadline: seal the routing decision.
self.group.execute(IntentsCmd::SealSlot).await?;
}
}
}
Every observed event carries enough evidence
((member_id, clock_event, commit_pointer)) that the
state machine can validate it against the member’s public
surface during replay.
Apply order across the graph
Within one organism’s Group, mosaik’s Raft variant
guarantees every committee member applies commands in the
same order. Across composite organisms, and across
members, no such guarantee exists. The coalition layer
relies on the same two properties the builder layer does,
scaled up:
- Monotonicity by key. Within any component, commits
for key
(C, K+1)are not applied before(C, K). The component’s state machine enforces this per- member in its apply handler. - Eventual consistency by subscription. A downstream component’s driver observes every upstream commit eventually, because mosaik collections are append-only and readers converge.
Together these are enough to reconstruct a consistent per-member per-clock-event view across the whole coalition without global atomicity. An integrator wanting “the canonical decision for member C, clock event K, across members and composite organisms” reads each component’s per-(C, K) commit independently and joins on the key.
When an upstream stalls
Failure propagation is a small matrix. Rows are the failing component; columns are downstream components’ observable behaviour.
| Upstream fails | Same-member downstreams | Composite organisms that read this member | Other members |
|---|---|---|---|
| lattice organism | see builder composition | degraded — partial evidence per spec | unaffected |
| standalone organism | see that organism’s own book | degraded — partial evidence per spec | unaffected |
| member stable id bump (retirement) | in-member consumers re-pin | composite organism must redeploy against new stable id | unaffected |
| member content hash bump | in-member consumers re-pin if they pinned | composite organisms pinning content redeploy; stable-id-only pinners are unaffected | unaffected |
| composite organism stalls | no effect (members don’t depend on composite organisms for their own pipeline) | downstream composite-organism consumers see no new commits | unaffected |
| module stalls | no effect (members don’t depend on modules) | composite organisms aligned to this module see delayed/degraded commits | unaffected |
| composite-organism committee crosses threshold | no effect | bad commits possible (integrity lost); on-chain settlement is the final arbiter | unaffected |
| coalition operator retires coalition | no technical effect (members continue) | modules under retired coalition emit retirement markers, then stop | unaffected |
Two properties fall out, mirroring builder’s:
- Upstream failures degrade downstream outputs; they do
not corrupt them. A missing
UnsealedPool[L1, S]narrows theintentscomposite organism’s commit for that slot; the commit itself remains well-formed. - The pipeline is drainable per member. Failures on one member do not block the coalition’s other members. Each member’s pipeline is local; each composite organism applies what it observes.
What the coalition composition contract guarantees
Given the full commit logs of every member and every composite organism the coalition references:
- Deterministic replay per (member_id, clock_event). Anyone can recompute each component’s per-(C, K) decision and cross-check composite-organism commits against the member inputs they folded in.
- Independent auditability. A composite organism’s commit carries evidence pointers to the member commits it depends on. A consumer that trusts the members can verify a composite organism’s commit without trusting the composite organism’s committee, as long as the evidence pointers resolve.
- No silent corruption across coalitions. A member referenced from multiple coalitions is still one member; its commit log is one log. Different coalitions reading the same member see the same facts. A composite organism referenced from multiple coalitions is still one composite organism; its commit log is one log.
What the contract does not guarantee
- Atomic all-or-nothing commits across members. Already refused. An integrator reading a composite organism’s commit and the spanned members’ commits must tolerate differing commit wall-clock times.
- Cross-coalition coordination. Coalitions coexist, they do not coordinate. If a cross-coalition commit is genuinely needed, the answer is a composite organism that spans the relevant members directly — which both coalitions may reference independently.
- Bounded end-to-end latency. As in builder: if a composite organism stalls, downstream consumers never see its next commit. No composite-organism-level timeout triggers a dummy commit; operators requiring bounded latency add per-slot deadlines at the composite-organism level.
Contributors implementing a new composite organism
Wiring checklist for a composite organism:
- Identify every spanned member’s public surface you
subscribe to. Record as ordered slices of member
references in your
Config—lattices,organisms, or both. - Decide whether your commits fan-in, fan-out, or both. Fan-in composite organisms aggregate per-origin-member facts; fan-out composite organisms distribute one fact to multiple target members; some composite organisms do both.
- Key every commit by
(member_id, clock_event). Never by one alone. Use the 20-byte truncated member id. If your state machine has a natural sub-clock- event cadence, commit at that cadence but carry the owning(member_id, clock_event)pair. If the composite organism opts into a coalition’s Almanac and needs cross-member alignment, also carryalmanac_tick. - Write one role driver per
Groupmember role. Keep it as atokio::select!over the upstream subscriptions (one per member) and your local timers. - Validate evidence on replay. The upstream-event
pointers carried in your
Observe*commands must be checkable against the member’s public surface during replay; a replay that sees an unresolved evidence pointer must reject the command. - Document your per-member-failure policy. What happens when one spanned member stalls, reorders, or bumps its stable id or content hash — all are operational realities.
- Declare dependency on modules. If you require an Almanac for alignment, or consume Chronicle entries, document it.
- Document the composition contract in your
composite organism’s
contributors/composition-hooks.md(per-organism documentation). Update architecture and this page’s subscription graph to include the new composite organism if the example coalition is the right place for it.
Cross-references
- Architecture — the coalition shape these subscriptions run on.
- Composite organisms — the organism the arrows land on.
- Basic services — Atlas, Almanac, Chronicle details.
- Atomicity — what the subscription graph deliberately does not buy you.
- Threat model — how trust assumptions compose across the subscription graph.
Atomicity boundary
audience: contributors
This chapter states what the coalition layer does and does not guarantee about atomicity, supplying one reference page for design reviews of new composite organisms or extensions to the coalition model.
The rules are inherited from zipnet and builder. The coalition layer introduces no new atomicity primitive; it makes the inherited boundary legible one rung higher.
What the coalition layer does not provide
The coalition layer does not provide:
- Cross-Group atomicity inside a member. Rejected by builder for lattices and by each organism’s own design for standalone organisms. Two organisms commit independently and subscribe to each other’s public surfaces.
- Cross-member atomicity inside a coalition. Rejected by this blueprint. Two members in the same coalition commit independently and a composite organism subscribes to both.
- Cross-coalition atomicity. Rejected by this blueprint. Two coalitions coexist on the shared universe and have no shared consensus unit.
- Multi-organism atomicity. Rejected by this blueprint. Two composite organisms referenced by the same coalition each commit to their own Group; integrators that need joint commits join by key.
The rejection is load-bearing at every rung. Admitting one atomicity primitive at any rung forces every rung below to carry it, collapsing the trust and operational boundaries the rungs were designed to isolate.
What the coalition layer does provide
The coalition layer provides, as a consequence of the composition discipline:
- Per-component atomicity. Every organism — standalone, composite, or module — commits atomically within its own Group. Mosaik’s Raft variant guarantees single-Group atomicity.
- Determinism of replay. Given the commit logs of all components the coalition references, each component’s per-key decision is reproducible. The evidence pointers composite organisms carry make cross-component replay legible.
- Independent auditability. A consumer verifying a composite organism’s commit need trust only the spanned members’ own commit logs (and the composite organism’s committee, to whatever its trust shape permits). They do not need a coalition-wide replay to audit one composite organism’s decision.
- Provenance (if Chronicle is shipped). Not
atomicity, but a record of coalition-level decisions
over time: which
CoalitionConfigs were published when, which composite organisms were referenced or unreferenced, which modules were added or retired. Audit trail, not atomicity.
What integrators and operators must design around
Three recurring realities.
Partial outcomes across members
An integrator placing paired bundles on two lattices, or correlating an oracle tick with a lattice auction outcome, must tolerate partial observation: member A commits, member B does not. The coalition layer surfaces this, it does not mitigate it. Every integrator driver spanning members carries reconciliation logic (post-bond collateral, on-chain HTLCs, searcher-level risk management, timestamp tolerance windows — whichever matches the domain).
Staggered commits through composite organisms
A composite organism’s commit for
(member_id, clock_event) lags the upstream members’ own
commits for that event by at least one Raft round inside
the composite organism’s committee. Consumers reading
both treat the member commit as ground truth and the
composite-organism commit as derived aggregation.
Member identity bumps
A member’s stable id changes on retirement; its content
hash bumps more often (ACL rotations, TDX Measurements bumps). A
coalition that references that member sees its modules
re-derive on stable-id bumps (because COALITION_ROOT
changes); composite organisms re-derive only when they
themselves span the bumped member. During the transition,
old and new deployments may coexist. If the coalition
ships a Chronicle, the next Chronicle entry records the
transition.
Promotion path if atomicity is genuinely required
If a concrete use case forces atomicity across components:
- If it’s one lattice, two organisms: design a lattice organism that owns both decisions. That is the same answer builder topology-intro gives.
- If it’s one coalition, two members: design a composite organism that owns both decisions, subscribing to the two members’ relevant public surfaces. The state machine will commit one atomic record per event-pair; the two members themselves still commit independently, but the composite organism’s commit is the authoritative joint fact. HTLC-style commit semantics live inside the composite organism’s state machine, not across members.
- If it’s two coalitions: the cross-coalition commit is a composite organism folding the relevant member references directly; both coalitions reference that composite organism independently. No cross-coalition consensus is needed because the composite organism is coalition-independent.
In every case the atomicity primitive lives inside one Group, not across Groups. This is the rule the whole ladder obeys.
Cross-references
- topology-intro — No cross-Group, cross-member, or cross-coalition atomicity
- Composition — What the contract does not guarantee
- builder — No cross-Group atomicity
Threat model
audience: contributors
This chapter states the trust assumptions the coalition
layer adds over the builder and zipnet trust models, and
describes how per-component trust composes when members
(lattices and standalone organisms), composite organisms,
and modules are referenced under one CoalitionConfig.
It does not re-derive per-organism trust shapes inside a lattice; those live in builder threat model. It does not re- derive trust shapes for standalone organisms; those live in each organism’s own book. The coalition layer inherits them unchanged. Primitive-level mechanics the trust arguments below lean on — Raft-based majority-honest agreement (mosaik — Raft consensus), peer bonds (mosaik — Bonds & Peer Connections), state-sync for catch-up (mosaik — State Sync & Replay), and deterministic hashing (mosaik — Determinism & Hashing) — are specified upstream and referenced inline where they bite.
Goals and non-goals at the coalition layer
Goals.
- Trust is strictly compositional. A property of a single member is not weakened by that member being referenced in a coalition. Referencing is ambient; it does not open new channels into the member.
- Composite-organism commits are independently auditable against the member commits they fold in. A consumer that trusts the spanned members can verify a composite organism’s commit without trusting the composite organism’s committee, up to the composite organism’s own majority-honest bound.
- Coalition identity is a naming convenience. Code
treating a
CoalitionConfigfingerprint as authority is misusing it. - Modules do not gate. Atlas, Almanac, and Chronicle are services a coalition offers; none is on any member’s critical path for admission or operation. A compromised module can mislead consumers but cannot compel a member.
Non-goals.
- Cross-coalition confidentiality. Two coalitions coexisting on the shared universe do not get any additional confidentiality over “two services on the shared universe” already get. Mosaik’s ACL and tickets are the only gates.
- Cross-member atomic integrity. Ruled out at the composition layer. See atomicity.
- Protection against a malicious coalition operator.
A coalition operator can publish a
CoalitionConfigreferencing any member whose stable id they know, including members whose operators have not consented to the reference. The reference has no technical consequence for the member’s integrity or confidentiality; it is a social or legal matter between operators. The blueprint surfaces the observability required to flag the misuse; it does not prevent it. - Protection against deferred-primitives drift. A future proposal promoting a deferred primitive (enforcement, taxation, judiciary) requires its own threat model. The current model assumes opt-in composition only.
The composite organism’s trust composition
Every composite organism’s trust shape is determined by two inputs:
- The composite organism’s own committee assumption. Usually majority-honest for integrity, possibly TDX-attested for confidentiality of the cleartext it processes.
- The worst-case assumption across the spanned
members’ public surfaces it reads. If the composite
organism reads cleartext from each spanned lattice’s
unseal::UnsealedPooland a signed feed from an oracle organism, it inherits thet-of-nthreshold of every spannedunsealcommittee and the signing-quorum assumption of the oracle organism.
The composed assumption is the conjunction: the composite organism’s guarantee holds while every component’s assumption holds simultaneously. Breaking any one component can at most degrade the composite organism’s output per the weakest component’s failure mode.
Crucially, the composite organism’s trust shape does
not include any coalition that references it. A
malicious coalition operator cannot weaken a composite
organism they merely reference; they can only stop
referencing it in their next CoalitionConfig.
Example: the intents composite organism
An intents composite organism reads cleartext from three
lattices’ UnsealedPools and commits a per-target-
lattice routed-intents commit under a TDX-attested,
majority-honest committee.
- Confidentiality of cross-chain intents to external
observers: holds while every spanned lattice’s
zipnetany-trust assumption andunsealt-of-nthreshold assumption hold and the composite organism’s TDX image is attested. - Integrity of the routed commit: holds while the composite organism’s majority-honest committee assumption holds.
- Availability of routing: holds while at least one
of the spanned lattices reaches
UnsealedPoolfor the target slot and a composite-organism majority commits.
Example: the shared-ledger composite organism
A ledger composite organism reads each spanned
lattice’s tally::Refunds and commits an aggregated
SharedRefunds under a majority-honest committee.
- Faithfulness of the aggregated attribution: holds
while every spanned lattice’s
tallymajority-honest assumption and the composite organism’s own majority-honest assumption hold. A malicious latticetallymajority can poison the aggregated commit; the on-chain settlement contract receivingSharedAttestationsis the final check. - Non-duplication of refunds: holds while the aggregation rule is implemented correctly and state- machine-deterministic.
Module trust shapes
Each of the five modules has its own trust shape, summarised here and specified in basic services.
Atlas trust
- Faithfulness of
MemberCardcontents: holds while the Atlas committee is majority-honest. A compromised Atlas can publish incorrect endpoint hints or stale TDX Measurements pins. Integrators are expected to cross-check with per-member operators’ own handshake pages; Atlas is a convenience, not a certificate. - Confidentiality: N/A; Atlas is public by design.
Almanac trust
- Monotonicity of ticks: holds while the Almanac committee is majority-honest. A compromised Almanac can skip ticks or delay them, but cannot un-commit previously committed ticks.
observed_attimestamp vectors are advisory. A compromised committee can publish ticks with implausible timestamps; consumers should treat the per-member vector as a correlation hint, not a cryptographic timestamp. The vector shape does let consumers compositionally detect single-member clock skew (outlier entries in an otherwise-clustered vector); this is an observability aid, not a security guarantee.
Chronicle trust
-
Tamper-evidence of past entries: holds while at least one of:
- (a) the on-chain anchor path is uncompromised —
the Chronicle committee periodically commits a
blake3 digest of the entry stream to the anchor
contract declared in
ChronicleConfig.content; or - (b) at least one honest ex-member’s signed
archive survives — every
ChronicleEntrycarries per-member signatures in addition to the quorum signature, so an honest ex-member’s archive is a cryptographic witness against forgery.
Retroactive rewriting requires compromising both paths.
- (a) the on-chain anchor path is uncompromised —
the Chronicle committee periodically commits a
blake3 digest of the entry stream to the anchor
contract declared in
-
Completeness of recent entries: majority-honest. A compromised committee can omit entries from being committed; it cannot forge them without being detected, but it can DoS provenance.
Compute trust
- Scheduling integrity. Holds while the Compute committee is majority-honest. A compromised committee can grant a request to a provider who never runs the image, grant to a wrong provider, or omit grants altogether. It cannot forge a provider’s usage attestation (those are provider-signed) nor steal a requester’s settlement evidence (settlements live off-protocol).
- Image-hash honesty. A grant commits a specific image post-hash; a TDX-gated grant additionally commits the expected TDX Measurements. The requester verifies the provider is actually running the committed image at workload startup; a provider running a different image fails attestation and the workload aborts.
- Non-collusion between scheduler and provider. Out of scope. The Compute module commits the match; if the scheduler and a malicious provider collude, the requester’s only recourse is observing that the workload’s outputs never appear and routing to a different provider next time. A reputation organism scoring provider delivery closes the loop.
Randomness trust
- Scheduling and commit integrity. Holds while the Randomness committee is majority-honest. A compromised committee can skip rounds, delay commits past their target tick, or grant a round to a provider whose card it should have rejected. It cannot forge a beacon value that verifies against an honest provider’s declared public key.
- Unbiasability inheritance. The beacon’s unbiasability is inherited from the provider’s declared scheme. A coalition admitting a weak scheme (a plain VRF alone) is offering randomness that a malicious provider can bias by withholding unfavourable draws. A coalition admitting only threshold-BLS (t-of-n ≥ 3-of-5) or TDX-attested schemes inherits those schemes’ unbiasability arguments.
- Challenge path. Suspected bias goes on Chronicle (a signed entry naming the round and the challenger’s evidence); consumers unpin the provider in their own validator. The module has no built-in challenge stream.
- Non-collusion between scheduler and provider. Out of scope, same as Compute. If the scheduler and a malicious beacon provider collude, the bias is detectable only by consumers’ own cross- verification. A reputation organism scoring provider honesty closes the loop.
Ticket issuance trust
- Issuance correctness: trust shape inherited from
mosaik’s
TicketValidatorcomposition. This blueprint introduces no new primitives. A component that recognises the coalition-scoped issuance root trusts the issuer’s ACL composition; a component that does not recognise it is unaffected.
Coalition operator responsibilities
Coalition operators carry a narrow set of responsibilities.
Must do:
- Publish the
CoalitionConfigstruct (and the derived fingerprint) as the handshake. - Publish every module’s and every coalition-run composite organism’s TDX Measurements if TDX-gated.
- Publish every coalition-commissioned standalone organism’s TDX Measurements that is TDX-gated. If the organism is operated by a different team, that team publishes its own TDX Measurements and the coalition operator re-publishes for convenience.
- Document the set of members and composite organisms referenced, including a pointer to each per-member operator’s and per-composite-organism operator’s handshake page.
- State explicitly which modules the coalition ships and which it does not. Silence is ambiguous.
- Notify integrators when a referenced member’s
stable id bumps and publish the updated
CoalitionConfigpromptly.
What a compromised coalition cannot do
Regardless of how many modules a coalition operator runs maliciously:
- Cannot change a referenced member’s or referenced composite organism’s commits. Each component’s commit log is authoritative in its own Groups. A compromised module cannot forge a commit belonging to another component.
- Cannot mint money. Same argument as builder: on- chain settlement contracts enforce the evidence carried in attestations.
- Cannot produce cross-member atomic outcomes. Atomicity is not a primitive; a compromised module cannot force two members to jointly commit something they did not independently commit.
- Cannot compel members. A compromised Atlas cannot force dashboards to trust it; a compromised Chronicle cannot rewrite what honest replayers and external anchors have already recorded.
What a compromised coalition can do
Conservatively:
- Poison module commits. A majority-compromised module can publish incorrect records. Integrators reading those commits observe the misbehaviour in public and can object, migrate, or appeal to on-chain settlement.
- Mislead Atlas consumers. A compromised Atlas can publish wrong endpoint hints, stale TDX Measurements pins, or fabricate membership. Dashboards relying on Atlas see degraded accuracy; the members themselves are unaffected.
- DoS the module tier. A committee that loses majority stops producing new commits. Referenced members and their own pipelines are unaffected.
- Publish a misleading
CoalitionConfig. A coalition operator can publish aCoalitionConfigthat references members or composite organisms the integrator did not expect. Integrators guard against this by compiling in theCoalitionConfigexplicitly and auditing its contents — a misleading fingerprint is a visible artefact. - Stop publishing Chronicle entries. The absence of an entry is observable; a coalition that goes silent loses trust even if it cannot rewrite the past.
Compositional table
| Property | Depends on |
|---|---|
| Per-lattice block-building properties | That lattice’s full builder-level assumption stack |
| Per-organism properties | That organism’s own assumption stack |
| Composite-organism commit integrity | Composite-organism committee majority-honest |
| Composite-organism confidentiality (if TDX) | Composite-organism TDX attestation + spanned members’ upstream confidentiality |
| Atlas accuracy | Atlas committee majority-honest + per-member operator correctness |
| Almanac monotonicity | Almanac committee majority-honest |
| Chronicle tamper-evidence | On-chain anchor path honest OR one honest ex-member’s signed archive survives |
| Chronicle completeness | Chronicle committee majority-honest |
| Compute scheduling integrity | Compute committee majority-honest |
| Compute workload attestation (TDX) | Provider TDX Measurements match the grant’s expected_mrtd at workload startup |
| Ticket-issuer recognition | Component’s own TicketValidator composition; coalition does not impose |
| Coalition observability | At least one honest replayer can read every component’s commit log |
| Accurate aggregated attribution | Every spanned upstream honest AND composite organism honest |
| Cross-member partial-outcome discipline | Integrator-side risk management (no protocol support) |
| Coalition liveness | Every referenced member’s liveness AND every referenced composite organism’s liveness |
The decomposition is the point. A coalition that misbehaves at one tier degrades the guarantee dependent on that tier; it does not collapse everything.
Operator responsibilities recap
Every operator running a committee member in any composite organism, module, or standalone organism is responsible for the same set of obligations a lattice-organism operator is (running the attested image, protecting committee-admission secrets, rotating on schedule, reporting anomalies).
Cross-member composite-organism operators add one responsibility:
- Cross-member dependency reporting. When a referenced member’s stable id or content hash bumps, the composite-organism operator files an advisory to any coalition operators referencing the composite organism and to integrators so updates propagate with a known cadence, not silently. If any referencing coalition ships a Chronicle, that advisory lands in the next Chronicle entry.
Cross-references
- builder threat model — per-lattice trust shapes this layer composes over.
- composite organisms — the organism the compositional trust statements above are about.
- basic services — trust shapes for Atlas, Almanac, Chronicle.
- ticket issuance — the optional issuance root.
- composition — the subscription graph these trust statements travel along.
- atomicity — the one thing that does not compose.
Deferred-primitives pressure
audience: contributors
The blueprint defers enforceable coalition-level primitives: no protocol-level fees, no in-protocol membership requirements, no admission filters the substrate itself imposes, no adjudication machinery. Topology-intro names this the deferred-primitives space. The CLAUDE.md conventions flag any drift toward it as a bug.
This page names the site on the blueprint’s surface where that drift is most likely to arrive: the web2 compute-bridge walkthrough. Compute and Randomness both have a market-for-supply structure, which is what makes the blueprint useful for the work the book is about, and also what makes them the obvious surfaces for regulatory pressure to attach to.
Why compute sits on the edge
Compute is the basic service that touches the outside world at the closest range. Atlas, Almanac, and Chronicle are internal to the coalition — a directory, a clock beacon, an audit log. Compute is not: it bridges to cloud providers and bare-metal hosts, and those two domains already carry regulation.
Export control on AI accelerators. AI-specific workload reporting — US EO 14110, EU AI Act Article 51 and onward, the UK regulator frameworks. GPU licensure. Jurisdictional cloud-residency rules. Whatever of these applies to a compute-bridge operator at their jurisdiction of incorporation applies whether or not the substrate knows about it.
Compute also carries settlement evidence. The requester hands the module an opaque hash; off- module that hash usually resolves to an on-chain payment, which brings money-transmitter frameworks, FATF travel-rule regimes, and per-session reporting thresholds into play once values cross a declared floor.
Compute hosts third-party workloads. Cloud providers
have been subpoenaed for workload records; a
compute-bridge operator served with a subpoena for
its ComputeLog stream cannot refuse on the grounds
that shuffle anonymisation hid the requester —
the log still names the provider, the window, and
the usage.
Reputation organisms that commit binding scores about named providers sit adjacent to defamation law and, depending on market share, competition law. A coalition that pins a reputation floor in its member validators is running a light-touch licensure regime in all but name.
Randomness inherits the same exposure through the same market-for-supply structure. Beacon providers often operate in already-regulated domains (lottery, gambling-adjacent randomness, public-sector randomness). The quirks are different from Compute’s, the shape of the creep is the same.
What the creep looks like
Each vector below usually arrives as a small, technical improvement. Stacked, they rebuild a regulator on top of the substrate.
- Requester due diligence. “A small allowlist on
ComputeRequestto prevent abuse.” The allowlist becomes protocol-level admission; providers end up compelled to enforce it whether or not their jurisdiction requires it. - Export control on workload images. “The scheduler refuses images whose manifests declare restricted scientific domains.” The scheduler committee becomes a content regulator; coalitions that do not carry the filter become de facto unavailable in regulated jurisdictions.
- Provider licensure. “Registration fee or certification attestation before a beacon provider’s card is accepted.” A certification body emerges adjacent to the scheduler; entry is gated.
- Settlement as money-transmission. “The module verifies settlement clears a jurisdictional floor before clearing the grant.” The module is now a transaction filter; the operator is a money-transmitter by proxy.
- Reputation defamation or antitrust. “The coalition pins a reputation floor; non-compliant providers stop receiving grants.” A de facto ban; the provider’s recourse is litigation against the coalition operator.
- Platform liability. “The bridge retains
ComputeLogs for N years under subpoena-friendly retention.” The log stream becomes a compliance artefact; the substrate is a records system. - Jurisdiction over the scheduler committee. “Committee members must all reside in one jurisdiction for serviceability.” Committee geography becomes a legal foothold; the voluntary-members property slips.
- Continuity-of-service. “Retirement markers require N-day notice; early retirement triggers operator liability.” The operator’s exit guarantee (see web2 sustainability — operator exit) degrades from unconditional to gated.
- Gambling and fair-draw frameworks. “Randomness logs every draw’s use case to satisfy audits.” The substrate acquires an audit surface; beacon consumers become auditable subjects.
Each item is implementable as a content-field change
to a module’s OrganismConfig or a TicketValidator
clause. The slope is gentle. The destination is
recognisable only after several steps.
How creep shows up in a proposal
A proposal that drifts into the deferred-primitives space usually does not name itself that way. It will read like a local optimisation with one of a few familiar framings. A temporary safeguard. Just a small content parameter. Optional by default. For the benefit of users. Because the regulator requires it.
None of the framings is wrong on its own. A temporary safeguard can be a reasonable ACL. A content-parameter change is how modules are configured in the first place. An opt-in flag empowers operators. User protection is obviously a goal. Regulators are real.
The question is where the filter is applied. An
opt-in flag on an operator’s own TicketValidator
is inside the blueprint. The same filter pinned in a
module’s content, propagating to every provider on
the substrate, is outside it.
How to tell
Four questions to run a proposal through. Failing any one means the proposal belongs on its own branch, with its own trust composition and its own audience.
- Is the filter opt-in at a
TicketValidator, or protocol-level in module content? - Who decides admission — the coalition operator, or the substrate?
- Is the sanction voluntary degradation (a reputation score drops, subscribers unbond, a validator refuses new tickets) or compulsion (a module refuses to commit a properly-formed request because of who the requester is)?
- Does the change re-introduce a supra-agent authority — a single party whose decisions the substrate is arranged to enforce?
A proposal that passes all four is a new
TicketValidator clause, a new reputation organism,
or a new module content field whose semantics are
observational, not exclusionary. A proposal that
fails any of them is a proposal for the
deferred-primitives space. The discipline is clear:
it lives on its own branch, rebuilds the trust
composition from first principles, and earns its
way.
What the stance provides
The stance this page resists is not “regulation is illegitimate”. It is “regulation is inevitable, so bake it into the substrate”. The blueprint rejects the second claim on engineering grounds. Buterin’s d/acc: one year later (2025) makes the closest kin argument for TEEs, zkproofs, and voluntary coordination rails as alternatives to substrate-level enforcement; the Legitimacy essay (2021) is the earlier version of why substrate-level enforcement forfeits the property that makes the infrastructure useful. Buterin’s On balance-of-power as a goal for the 21st century (2025) is the corresponding positive frame: once any sector’s natural limits recede, the remaining check is structural, and substrate-level enforcement removes a check rather than adding one. The deferred-primitives space is named because that is where substrate-level enforcement would land if it landed anywhere; the book defers it explicitly so the structural check stays.
The reasons here:
- Operator-boundary compliance composes. An operator
facing a jurisdictional obligation adds a
TicketValidatorclause that requires whatever the obligation calls for — KYC evidence, an export-control attestation, a money-transmitter licence root. Every bonded member sees the clause, admits it or does not, and the composition stays readable. - Substrate-level compliance does not. A filter pinned in module content propagates to every provider and requester, regardless of whether their jurisdiction would have imposed it. The module becomes a global regulator for a local concern.
- The operator’s exit is the substrate’s ultimate non-compulsion guarantee. A coalition operator facing unacceptable pressure retires the coalition; providers exit; requesters rebind elsewhere. Retirement markers (see sustainability) are the substrate’s answer to pressure on a named operator, not a substitute for the operator’s compliance posture.
Randomness
Randomness has the same structural exposure as Compute. Three quirks worth naming:
- Beacon providers in gambling or lottery jurisdictions are already licensed; a provider card admitting only licensed providers is the same admission slippage as Compute’s.
- Some jurisdictions require verifiable draws for regulated use cases (public lotteries, securities allocations). The module produces verifiable draws already; the slippage is when the module also enforces an audit-trail retention requirement.
- Beacon challenges by design go on Chronicle, not
a module-owned stream. A proposal to move them
into a dedicated compliance record — signed
committee verdicts retained indefinitely for
regulator consumption — is the same
substrate-becomes-records-system pattern as
Compute’s
ComputeLogretention.
The four questions above apply identically.
Cross-references
- Topology-intro — deferred-primitives space
- Basic services — Compute
- Basic services — Randomness
- Threat model — Compute trust
- Part II — web2 overview
- Web2 sustainability — operator exit
- Buterin, d/acc: one year later (2025) and Legitimacy (2021).
Roadmap
audience: contributors
This roadmap covers the coalition blueprint, not the v2 lists of any individual composite organism, module, or standalone organism. Each crate ships its own internal roadmap; the zipnet crate’s Roadmap to v2 is the template future crates follow.
Items below are ordered by external-impact visibility, not by engineering order; implementation order is determined by what the first production coalition requires.
v0.1 — Blueprint (this document)
Specification complete. No crates shipped. Audience: contributors who want to challenge the composition shape before composite-organism or module implementation starts.
v0.2 — Coalition meta-crate walking skeleton
Goal: one coalition meta-crate exists, its
CoalitionConfig type compiles against a fixed set of
example member references, and its coalition_id()
derivation is stable and testable.
Minimum content:
- Crate layout. One
coalitionmeta-crate owningCoalitionConfig<'a>,OrganismRef<'a>,OrganismConfig<'a>,TicketIssuerConfig<'a>, the derivation helpers, the module lookup helpers (atlas(),almanac(),chronicle()), and re-exports ofbuilder::{LatticeConfig, UNIVERSE}. No runtime yet. - Lifetime parameterisation. Every public struct is
#[non_exhaustive]and parameterised over'a.constinstances continue to compile under'staticinference; runtime construction is first-class. - Schema version byte.
SCHEMA_VERSION_U8 = 1folded as the first element of every identity preimage. - Stable-id / content-hash split. Both
LatticeConfigandOrganismRefexpose astable_id()accessor separate from their full fingerprint. - Derivation tests. Golden-vector tests ensuring a
fixed
CoalitionConfigproduces a fixed fingerprint, and that each included member’s fingerprint is unchanged by coalition membership. - Mixed-composition tests. A coalition with zero lattices and two standalone organisms derives correctly; a coalition with two lattices and zero organisms derives correctly; mixes derive correctly.
- Module-helper tests. Helpers return
Somewhen a module by the well-known name is present,Noneotherwise. - Book examples. Every
rust,ignoresnippet in this book that referencesCoalitionConfigtype-checks against the v0.2 meta-crate signature.
Non-goals for v0.2:
- Any composite-organism implementation. Composite organisms arrive piecemeal once the meta-crate is stable.
- Any module implementation. First module and the ticket issuer land in v0.3.
- Any standalone-organism implementation. Those live in their own crates; the meta-crate only references them.
- On-wire types. No new wire types are added at the coalition layer beyond what each organism (composite, module, or standalone) commissions for itself.
v0.3 — First module (Atlas) + ticket issuance
Goal: the first module ships end-to-end and validates the coalition’s civic-services pattern; the optional ticket-issuance root ships alongside because it is mechanically simpler than any module.
Atlas is chosen first because it has the narrowest trust shape and the shortest state machine. It exercises every part of the derivation and subscription path without introducing threshold cryptography or cross-chain auction semantics.
Minimum content:
coalition-atlascrate with:Configfingerprint folding the coalition root and the set of member references the Atlas catalogues.Atlas::<MemberCard>::readandAtlas::<MemberCard>::publishtyped constructors.- A small state machine that commits member cards (metadata, endpoint hints, ticket-issuance roots, TDX Measurements) per member reference, co-signed by the Atlas committee. The card format handles both lattices and standalone organisms.
- Ticket-issuance support in the
coalitionmeta-crate:TicketIssuerConfigplumbed intoCoalitionConfigwith derivation underCOALITION_ROOT.derive("tickets"). - Integration test: stand up two members (mocked — one
lattice, one organism), one Atlas module, optional
ticket issuer, and demonstrate an integrator binding
to all three through one
CoalitionConfig.
v0.4 — Almanac + Chronicle
Goal: two more modules ship.
coalition-almanaccrate with committee-driven tick commits. Per-memberobserved_atvector captured at commit time. Integration test: a correlator composite organism aligns events from two members to almanac ticks.coalition-chroniclecrate with append-only audit log. Per-member signatures on every entry; optional on-chain anchor path with configurable cadence. Integration test: coalition republishes aCoalitionConfigwith a new member; Chronicle records the transition and emits an anchor commit at the next cadence boundary.
These land together because they share infrastructure (monotonic committee-signed commits) and because both are strictly additive to v0.3.
v0.5 — First commissioned composite organism + retirement markers
Goal: the first composite organism whose state machine depends on cleartext order flow from multiple lattices.
Minimum content:
coalition-intentscrate following the intent-router pattern in composite organisms. Derives independently of any coalition; the crate ships an exampleOrganismConfigand example coalitions that reference it.- TDX admission on every committee member.
- Integration test: intents submitted on lattice A are
routed to lattice B’s
offerinput and a downstreamtallycommit reflects the cross-chain attribution. - Per-member stall policy documented in the crate’s
composition-hooks.md. - Retirement marker support across all shipped crates
(
coalition-atlas,coalition-almanac,coalition-chronicle,coalition-intents): every committee emits a terminalRetirementMarkerbefore shutting down; the Chronicle records it asOrganismRetiredorModuleRetired.
v0.6 — Shared attribution ledger + Compute
Goal: a second commissioned composite organism demonstrating fan-in attribution, plus the fourth module.
coalition-ledgercrate following the shared-ledger pattern in composite organisms.coalition-computecrate implementing the Compute module spec in basic services — Compute. Integration test: an agent organism submits aComputeRequestfor a TDX image, receives aComputeGrant, the provider starts the workload with matching TDX Measurements, the provider emits aComputeLogon completion.
(Passport is gone; ticket issuance is in v0.3.)
v1.0 — First production coalition
Goal: one coalition runs on mainnet references continuously for a month with no protocol-level incidents.
- Rolling upgrades of composite organisms and modules.
Until this point, “stop the service, bump the
CoalitionConfig, restart” is an acceptable release strategy; at v1.0 it is not. - Snapshot + state-sync for every composite organism’s and every module’s state machine.
- Full operator runbooks under operators/, graded by severity and audited externally.
- Stable
CoalitionConfigserialisation format.CoalitionConfig::from_hexis safe to use as the handshake after v1.0.
Longer-term items (no version assigned)
Versioning
Carrying the zipnet/builder policy into the coalition model with three adjustments.
- Per composite organism / module: lockstep at the organism level. Commissioned composite organisms ship and version on their own schedule independent of any coalition that references them — because composite organisms no longer derive under a coalition root, a composite-organism upgrade does not force every coalition referencing it to re-derive. Coalitions simply reference the new fingerprint when they wish.
- Per coalition: version-in-name for the coalition
identity. A coalition retirement is an operator-
level decision and produces a new instance name
(
ethereum.superchain-v2026q2). Individual modules inside a stable coalition name can still upgrade in lockstep without retiring the coalition. - Per member reference: stable-id pinning plus
optional content-hash pinning. A
CoalitionConfigreferences members by stable id. Composite organisms and modules choose per-component whether to also pin the content hash. Whether content-hash-pinning becomes a coalition-wide policy rather than a per-component choice is open for v0.3 decision.
Neither policy is load-bearing for v0.2 / v0.3. The first v1.0 release forces the decision.
Cross-coalition coordination
Out of scope for v0.1. A composite organism whose content folds the relevant members directly can be referenced independently by multiple coalitions; the cross- coalition commit is whatever that composite organism commits. No new primitive is needed. Research-complete, engineering-deferred.
TDX-attested modules
The v0.3 Atlas is a minimal, non-TDX module. A TDX- attested Atlas — where the committee commits cards only over attested images — is a v1+ refinement. Same for TDX-attested Almanac, Chronicle. The blueprint is unchanged; the refinement touches only the crates.
Optional cross-coalition directory
Not a core feature; same argument as the lattice
directory in builder. A shared
Map<CoalitionName, CoalitionCard> listing known
coalitions may ship as a devops convenience. If built,
it must:
- be documented as a convenience, not a binding path;
- be independently bindable — the coalition meta-crate never consults it;
- not become load-bearing for ACL or attestation.
Flag in-source as // CONVENIENCE: if it lands.
Byzantine liveness for every organism committee
Mosaik’s Raft variant is crash-fault tolerant. The zipnet liveness item applies to every committee. A future BFT variant in mosaik would be inherited by every component; until then, a deliberately compromised committee member can DoS liveness in its own committee.
Composite-organism-level confidentiality beyond TDX
Some composite-organism roles (cross-chain intent routing over many chains, cross-feed correlation of sensitive oracles) may want post-quantum confidentiality ahead of their upstream members themselves. Research-complete for several threshold schemes; engineering-deferred. The organism surface does not change; only the crypto inside the composite organism’s state machine does.
New mid-rung composition classes
Builder is the first fully-specified class of mid-rung composition (block-building lattices). Other classes may follow — attestation fabrics, oracle grids, identity substrates with their own collective shape — each with its own book and its own handshake. When one does:
- The new class’s book specifies its own
FooConfigand derivation discipline, mirroring builder. - The coalition meta-crate may add a new referenced slice
(
pub fabrics: &'a [FabricConfig<'a>], etc.) or may continue referencing those compositions via their root organisms. Either works; the tradeoff is ergonomic. - Composite organisms gain the ability to fold the new
class’s fingerprints into their
Configalongside lattices and organisms. - Atlas
MemberCardschemas are extended via#[non_exhaustive]field additions to carry metadata about the new kind.
Research-and-engineering-deferred. The coalition blueprint grows in lockstep with whichever class lands first.
Deferred-primitives space (research stance)
The blueprint explicitly refuses deferred-primitives: enforceable policies over members, taxation, judiciary, mandatory membership. The refusal is load-bearing for the current trust and composition stories.
A future proposal could make a case for one deferred primitive at a time, as a separate design with its own book branch. Any such proposal must:
- give a full trust composition for the new primitive showing what it does to the existing guarantees;
- specify a migration path for coalitions that ship the current opt-in shape;
- earn its way past the objection that it reintroduces supra-member authority the current blueprint does not provide.
No concrete deferred-primitives proposal is planned. The space is flagged so contributors know where the current scope ends and where fresh proposal work would begin.
What this roadmap does not include
- Specific crate-versioning schedules. Each crate owns its own version cadence.
- A list of composite organisms, organism categories, or lattice classes the blueprint wants shipped. Unlike builder’s six-organism commitment, the coalition blueprint stays open beyond the five basic services. The roadmap names three plausible first commissioned composite organisms; the catalogue grows as cross- member problems force new ones.
- Operator-onboarding contractual detail. Coalition operators run different organisations under different legal regimes; the book does not try to standardise that.
- Adoption strategy. The book specifies and documents; adoption is the operators’ concern.
Glossary
audience: all
Domain terms as used in this book. Where a term is inherited from mosaik, zipnet, or builder, the entry points at the authoritative source rather than re- deriving.
Almanac. A basic service: a shared clock / sequence beacon members may use for cross-member timing. See basic services.
Atlas. A basic service: a directory of members with operator-supplied metadata (endpoint hints, ticket- issuance roots, TDX Measurements pins). See basic services.
Basic service. A coalition-scoped module whose shape is specified once in the blueprint so every instance means the same thing across coalitions. Five are specified: Atlas, Almanac, Chronicle, Compute, Randomness. A coalition may ship any subset (zero through all five). Compute and Randomness additionally have a market-for-supply structure where the module is a scheduler-and-registry and separate providers compete to register.
Bridge organism. The builder book’s name for a
speculative cross-lattice organism. In this blueprint,
generalised to a composite organism — an organism
whose Config fingerprint folds two or more member
references. See
composite organisms.
Chronicle. A basic service: a tamper-evident audit log of coalition actions (publications, rotations, retirements). See basic services.
Compute. A basic service: a scheduler and registry
through which coalition members submit
ComputeRequests for workloads identified by image
pre-hash (crate source + min CPU / RAM / TDX) and
receive ComputeGrants matching them to registered
providers. The module commits the match; the actual
compute runs on a separate provider. See
basic services.
Randomness. A basic service: a scheduler
committing Stream<BeaconTick> of unbiasable
beacon values plus a
Collection<ProviderId, ProviderCard> of
registered providers. The module commits the
rounds; the actual randomness is produced by
separate providers (threshold-BLS committees,
dVRFs, drand-alike external beacons, TDX-attested
per-round derivations). Consumers derive targeted
draws locally by hashing the beacon value with a
domain tag. The coalition’s admitted scheme
families determine the unbiasability argument
consumers inherit. See
basic services.
Member. A lattice or organism referenced by a
coalition’s CoalitionConfig. “Referenced unit of the
coalition”.
MemberId. The 20-byte prefix of a member’s blake3
stable-id fingerprint, used as a compact key in cross-
member commits. The full 32-byte fingerprint lives in
Atlas entries and in evidence pointers. See
composition — Two keys.
Coalition. A fingerprint-addressed composition of
zero or more lattices and zero or more organisms
(standalone or composite), possibly shipping up to five
coalition-scoped modules (Atlas, Almanac, Chronicle,
Compute, Randomness) and an optional ticket-issuance
root. Identified by a CoalitionConfig.
Operator-scoped, not a consensus unit, not an ACL root.
An opt-in composition offering services to its members.
See topology-intro.
CoalitionConfig. The parent struct a coalition
operator publishes and an integrator compiles in. Contains
the coalition’s name, the ordered LatticeConfigs it
references, the ordered OrganismRefs it references
(including any composite organisms), and an optional
TicketIssuerConfig. See
topology-intro — Coalition identity.
COALITION_ROOT. The derived fingerprint used as the
root for each coalition-scoped module’s (Atlas, Almanac,
Chronicle, Compute, optional ticket issuer) identity
derivation. Commissioned composite organisms derive
independently and do NOT fold COALITION_ROOT. See
topology-intro — Membership-by-reference.
Composite organism. An organism whose Config
fingerprint folds two or more member references
(lattices, OrganismRefs, or a mix) and whose public
surface coordinates across the referenced members. Its
identity is independent of any coalition: one composite
organism may be referenced by many coalitions. See
composite organisms.
OrganismConfig. The parent struct for a composite
organism’s Config. Folds the organism’s role name,
ordered spanned lattices, ordered spanned standalone
organisms, content parameters, and ACL. Does not fold a
coalition root. See
composite organisms — the Config fingerprint.
Content + intent addressing. The discipline every
consensus-critical id in every organism, lattice, or
coalition obeys:
id = blake3(intent ‖ content ‖ acl). Inherited verbatim
from zipnet and builder.
Content hash. The portion of a member’s fingerprint that folds its ACL, TDX Measurements, and state-affecting parameters. Bumps on operational rotations; distinct from the stable id. See topology-intro — Member reference shape.
Costly signalling. A mechanism-design pattern in which a signal’s cost is lower for legitimate senders than for impostors, so the separating equilibrium distinguishes the two (Spence, Job Market Signalling, 1973). In this book, attestation fabrics are the costly-signalling rendering: the cost is a TDX quote, an ML-inference receipt, or a hardware-bound attestation. See emergent coordination — attestation fabrics.
Deployment. A single running instance of an organism,
lattice, or coalition. Identified by the relevant
Config fingerprint.
Evidence pointer. A reference from a composite organism’s commit back to the member commit it depends on. Resolved on replay to validate the organism’s state-machine transition.
Fan-in organism. A composite organism aggregating facts from multiple origin members (e.g. a shared-ledger organism, a cross-feed correlator).
Fan-out organism. A composite organism distributing a fact to multiple target members (e.g. an intent router).
Fingerprint. A synonym for the content + intent
addressed id of a Config (coalition, lattice, or
organism). Mismatched fingerprints are the ladder’s
debuggable failure mode at every rung.
Fixed shapes, open catalogs. The blueprint discipline
of specifying shapes (CoalitionConfig, OrganismConfig,
the five basic services, the ticket-issuance shape) once
and leaving the catalogs (which composite organisms,
which organism categories, which lattice classes, whether
a coalition ships any modules) open. See
introduction — Fixed shapes, open catalogs.
Deferred-primitives space. The speculative (and deferred) class of coalition-level primitives — enforceable policies over members, taxation, judiciary. Explicitly out of scope; see introduction — Fixed shapes, open catalogs.
Hypergame. A generalisation of non-cooperative game theory in which players hold different beliefs about the game being played (Bennett, 1977; see the 2025 survey). Cited in this book only to name the failure of common-knowledge-of-rationality for LLM agents; the book does not model agent behaviour as a hypergame, it just notes that classical equilibrium analyses of LLM populations do not compose.
Integrator. External developer consuming a coalition,
member, or composite organism. Never client (ambiguous;
the book uses PeerId for the peer-side identity).
Intent-router pattern. A composite organism that
reads cleartext from spanned lattices’ unseal::UnsealedPools
and commits a routed-intents collection per target
lattice. See
composite organisms — intent-router pattern.
Kreps–Milgrom reputation. A repeated-game mechanism (Kreps, Milgrom, Roberts, Wilson, Rational Cooperation in the Finitely Repeated Prisoner’s Dilemma, 1982) under which a long-lived observer commits a summary of a player’s history and downstream players use the summary to gate future interaction. The book’s reputation feedback pattern is a committee-committed rendering with consumer-side opt-in — consumers choose whether to consult the reputation organism’s scores.
Lattice. One fully-specified mid-rung composition of
organisms. Builder specifies the first
class of lattice: one end-to-end block-building
deployment for one EVM chain, identified by a
LatticeConfig fingerprint. Nothing in this blueprint
assumes a lattice is a block-building lattice; other
classes may follow their own proposals. Coalitions
reference lattices; they do not own them.
LatticeConfig. Builder’s parent struct for a block-
building lattice. Unchanged in this blueprint. See
builder glossary.
Mechanism design. The subfield of game theory concerned with designing the rules of a game so that self-interested participants produce a desired outcome. In this book, mechanism design enters wherever the operator picks a clearing rule, a scoring function, or a verification rule — the coordination-market, reputation-feedback, and attestation-fabric patterns all admit a mechanism-design reading. The book treats mechanism design as a lens on the operator’s chosen rules, not as a prediction of how agents will behave. See societies — Game theory as a lens, not a prediction.
Module. A coalition-scoped component whose identity
derives under COALITION_ROOT.derive("module").derive(name).
The five basic services (Atlas, Almanac, Chronicle,
Compute, Randomness) are modules. Commissioned composite
organisms are NOT modules — they derive independently.
TDX Measurements. Intel TDX measurement register binding a boot
image to the hardware root of trust. Pinned per TDX-gated
organism in that component’s Config. See
mosaik — Intel TDX.
Narrow public surface. The discipline of exposing one or two primitives per organism on the shared universe. Inherited from the zipnet design intro.
No-regret learning. An online-learning regime in which a player’s time-averaged payoff approaches the best fixed action’s payoff in hindsight. Classical game- theoretic convergence results assume no-regret play; Park et al. (2024) show that LLM-class agents are not no-regret in canonical repeated games. Cited in this book to flag that equilibrium analyses of LLM populations do not compose in the way the classical literature assumes.
Operator. Team running a lattice, standalone organism, composite organism, module, or coalition (or any combination). See introduction.
Organism. A mosaik-native service with a narrow public surface. The six builder organisms (zipnet, unseal, offer, atelier, relay, tally) inside each block- building lattice, every composite organism, every module, and every standalone organism a coalition references are organisms.
OrganismRef. The coalition’s reference type for an
organism: a role name plus the organism’s stable id and
optional content hash. The concrete Config type lives
in the organism’s own crate and is opaque to the
coalition meta-crate. See
topology-intro — Coalition identity.
PeerId. The mosaik-native peer identity used by
every node on the universe. Peers may rotate their
PeerId per submission (the shuffle’s anonymity property — a
fresh PeerId per sealed submission) or hold a stable
PeerId bonded into an organism’s TicketValidator ACL
(the ordinary integrator case). This book does not define
a coalition-scoped peer identity distinct from PeerId;
the rotating and stable cases are usage patterns of the
one type. See
mosaik — Identity & Networking
and
mosaik — Bonds & Peer Connections.
Retirement marker. A record a composite organism, module, or coalition commits to its own stream before its committee shuts down, declaring effective retirement time and an optional replacement pointer. See basic services — Retirement markers.
Separating equilibrium. In a costly-signalling game, the equilibrium in which senders of different types choose distinguishable signals because the cost of the signal is type-dependent. The book’s attestation fabrics rely on a separating structure: legitimate participants produce TDX or inference-receipt signals cheaply; impostors cannot.
Shared-ledger pattern. A composite organism that
aggregates per-lattice tally::Refunds into a
cross-origin-member attribution feed. See
composite organisms — shared-ledger pattern.
Shuffle. Abstract primitive that takes N sealed submissions from distinct senders and makes their cleartext available to downstream readers in a way that breaks the sender → submission link. Concrete shuffle constructions include threshold-decryption committees (as in zipnet), cMix-style mix networks, threshold-BLS decryption pools, and FHE- backed release. Every example in this book that mentions anonymous submission composes on top of a shuffle; zipnet is the specific implementation the upstream project ships and the one against which the book’s worked examples bond. See introduction — Shuffle.
Shared policy. The mechanism by which mosaik AI
agents self-organize and converge: each agent’s
TicketValidator admits the same fingerprint —
either the Config.content of a mediating organism
(reputation’s utility function, a market’s clearing
rule, an attestation fabric’s verification rule, a
stigmergic collection’s write-side contract) or, for
TDX deployments, a shared set of TDX Measurements
that binds the runtime policy itself. Every
emergent-coordination pattern in the book is an
instance of this mechanism; every bond remains
voluntary on both sides. See
ai/emergent-coordination.md
and, for the TDX arm,
ai/sustainability.md.
Stable id. The (instance_name, network_id) blake3
hash a member publishes as its durable identifier.
Changes only on retirement, not on operational rotations.
See
topology-intro — Member reference shape.
Standalone organism. An organism living directly on
the universe rather than inside a lattice. Oracles,
attestation fabrics, identity substrates, data-
availability shards, analytics pipelines, and the like —
all referenced by a coalition via OrganismRef.
StateMachine. Mosaik’s term for the deterministic
command processor inside a Group<M>. Every organism has
its own state machine. See
mosaik groups.
Stall policy. Per-composite-organism rule for behaviour when one spanned member is not producing inputs for the current clock event. Either commit with partial evidence (preserving liveness) or stall the event (preserving quality). Documented per composite organism.
TDX. Intel Trust Domain Extensions. The TEE technology mosaik ships first-class support for. Used by composite organisms and sensitive standalone organisms. See mosaik TDX.
TicketIssuer. An optional coalition-scoped mosaik
ticket issuer. Non-authoritative: no component is required
to accept tickets from this issuer; components opt in by
including the issuance root in their own
TicketValidator composition. See
ticket issuance.
Universe. The shared mosaik NetworkId
(builder::UNIVERSE = unique_id!("mosaik.universe"))
hosting every coalition, every lattice, and every
organism. See
mosaik — Identity & Networking.
VCG (Vickrey–Clarke–Groves). A family of truthful auction mechanisms (Vickrey 1961; Clarke 1971; Groves 1973) in which each bidder’s dominant strategy is to bid their true valuation. Cited in this book as one clearing-rule option for coordination markets; the book specifies the market surface but does not mandate a clearing rule. The operator picks.