pub trait MeshDaemon: Send + Sync {
// Required methods
fn name(&self) -> &str;
fn requirements(&self) -> CapabilityFilter;
fn process(
&mut self,
event: &CausalEvent,
) -> Result<Vec<Bytes>, DaemonError>;
// Provided methods
fn required_capabilities(&self) -> CapabilitySet { ... }
fn optional_capabilities(&self) -> CapabilitySet { ... }
fn snapshot(&self) -> Option<Bytes> { ... }
fn is_stateful(&self) -> bool { ... }
fn restore(&mut self, state: Bytes) -> Result<(), DaemonError> { ... }
fn health(&self) -> DaemonHealth { ... }
fn saturation(&self) -> f32 { ... }
fn on_control(&mut self, _event: DaemonControl) { ... }
}Expand description
A daemon that runs on the mesh.
Daemons consume inbound causal events via process() and return zero or
more output payloads. The runtime wraps outputs in CausalLinks
automatically — the daemon only produces raw payloads.
§Performance
process() must complete in microseconds. Heavy work should be deferred
to a background task and emitted as a later event.
§WASM compatibility
All methods are synchronous — no async. Input/output are Bytes — maps
cleanly to WASM linear memory. No generics or associated types.
Required Methods§
Sourcefn requirements(&self) -> CapabilityFilter
fn requirements(&self) -> CapabilityFilter
Capability requirements for placement.
The scheduler uses this to find nodes whose CapabilitySet matches.
Return CapabilityFilter::default() to run anywhere.
Sourcefn process(&mut self, event: &CausalEvent) -> Result<Vec<Bytes>, DaemonError>
fn process(&mut self, event: &CausalEvent) -> Result<Vec<Bytes>, DaemonError>
Process one inbound causal event, returning zero or more output payloads.
The output Bytes values become payloads in the daemon’s own causal
chain (the runtime wraps them in CausalLinks automatically).
Provided Methods§
Sourcefn required_capabilities(&self) -> CapabilitySet
fn required_capabilities(&self) -> CapabilitySet
Hard capability requirements for Phase F-aware placement.
Returns the set of tags + metadata the candidate node MUST
have for the daemon to run there. Tag-set inclusion is the
hard-constraint check (StandardPlacement returns None
when a required tag is absent — see
crate::adapter::net::behavior::placement).
Default: empty set. Daemons that care about specific hardware / software override:
fn required_capabilities(&self) -> CapabilitySet {
CapabilitySet::new().add_tag("hardware.gpu")
}Phase G slice 2 of CAPABILITY_SYSTEM_PLAN.md. Coexists
with the legacy requirements() method until the
mikoshi-placement-v2 feature flag flips: requirements()
drives the legacy CapabilityFilter-based path; this
method drives the Artifact::Daemon { required, .. }
payload that PlacementFilter impls consume.
Sourcefn optional_capabilities(&self) -> CapabilitySet
fn optional_capabilities(&self) -> CapabilitySet
Soft capability preferences for Phase F-aware placement.
Returns the set of tags + metadata the daemon prefers but
does NOT require. The scheduler factors satisfaction of
these into per-axis scoring; missing optional capabilities
don’t veto placement (unlike required_capabilities).
Default: empty set. Daemons with a strict required floor but additional preferences (e.g. “must have GPU; prefer 80GB+ VRAM”) populate this via per-tag adds.
Phase G slice 2 of CAPABILITY_SYSTEM_PLAN.md. Slice 5’s
per-axis scorers consume the optional set when scoring
candidates; slice 2’s stub axes return 1.0 regardless.
Sourcefn snapshot(&self) -> Option<Bytes>
fn snapshot(&self) -> Option<Bytes>
Serialize current state for migration/checkpoint.
Returns None for stateless daemons. Stateful daemons must return
opaque bytes that restore() can accept.
Sourcefn is_stateful(&self) -> bool
fn is_stateful(&self) -> bool
Whether this daemon carries persistent state that migration / restart paths must preserve.
The default restore previously accepted any bytes silently
for daemons that didn’t override it, including ones that
should have been stateful but forgot to provide a restore
impl. The new default restores correctly: it matches
is_stateful()’s answer. Stateless daemons leave
is_stateful at false (matches snapshot() = None);
stateful daemons override is_stateful to true AND
snapshot / restore.
The migration path can use this to refuse to migrate a stateful daemon’s snapshot bytes into a stateless target, surfacing the misconfiguration rather than silently dropping state.
Sourcefn restore(&mut self, state: Bytes) -> Result<(), DaemonError>
fn restore(&mut self, state: Bytes) -> Result<(), DaemonError>
Restore from a previous snapshot.
Called before any process() calls after migration.
The default implementation now refuses non-empty state on
stateless daemons (is_stateful() == false) — silently
discarding a stateful source’s snapshot into a stateless
target loses every byte of state with no signal. Stateful
daemons must override both is_stateful and restore. An
empty state is still accepted (it’s what
snapshot() -> None produces under the migration adapter),
so genuine stateless-to-stateless migrations
continue to work.
Sourcefn health(&self) -> DaemonHealth
fn health(&self) -> DaemonHealth
Self-reported health. Polled by the MeshOS supervisor on
each tick. Default Healthy.
Daemons with a real health surface (queue-depth probes, internal cache freshness, dependency readiness, etc.) override to return a richer value. The supervisor surfaces the latest sample on the behavior snapshot for Deck.
Must complete in microseconds — same constraint as
process(). Heavy probes belong in a side task whose
result the daemon caches.
Sourcefn saturation(&self) -> f32
fn saturation(&self) -> f32
Self-reported saturation, 0.0 (idle) to 1.0 (fully
loaded). Used by Phase D-1’s mesh scheduler to decide
whether a daemon’s host is a good candidate for new
work. Default 0.0.
Daemons without a meaningful saturation surface should leave the default. The value is informational under the current scheduler; a poor estimate doesn’t cause migrations to thrash.
Sourcefn on_control(&mut self, _event: DaemonControl)
fn on_control(&mut self, _event: DaemonControl)
Receive a control event from the supervisor. Default: no-op (the daemon proceeds as normal regardless of the control signal).
Daemons that participate in graceful shutdown / drain /
backpressure override to react. The dispatch is sync —
the supervisor calls this between process() events on
the daemon’s main task, so long-running work in
on_control blocks subsequent event processing.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".