Rust Core and its objects
Muxiva is reliable because Rust Runtime Core alone defines how data flows, work stops, and errors propagate. Algorithm Nodes may use different languages, but they cannot invent independent queues, lifecycle rules, or message formats.
The six essential objects
flowchart LR
G["Graph<br/>complete topology"] --> N["Node<br/>processing logic"]
N --> OP["Output Port<br/>named and typed"]
OP --> E["Edge<br/>routing and bounded queue"]
E --> IP["Input Port<br/>named and typed"]
IP --> N2["Node<br/>downstream logic"]
F["Frame<br/>immutable data unit"] -.moves through.-> E
R["Runtime<br/>lifecycle and scheduling"] --> G
Frame: the only data unit
A Frame is the only value transported between Nodes. It contains a Header and a Payload:
Frame
├── Header
│ ├── frame_id / stream_id / trace_id
│ ├── timestamp + clock_domain
│ ├── sequence_id
│ ├── metadata / extensions
│ └── lineage
└── Payload
├── Audio
├── Video
├── Text
├── Byte
├── Signal
└── Event
Frames are immutable after construction. Branches can safely share the underlying Buffer. A Transform derives a new Frame and records lineage instead of mutating its input. This makes concurrency, tracing, and fault diagnosis predictable.
Audio and Video are not unstructured bytes. They include validated sample
rate, channels, sample format, pixel format, planes, and dimensions. Two
audio Ports may still require different media formats. Port schemas describe
that detail, and a Resample or Codec Node must perform an explicit conversion.
Implementation: muxiva-types.
Node: one focused responsibility
A Node is a processing component with typed Ports and one lifecycle. Its graph role is one of:
| Kind | Input and output | Examples |
|---|---|---|
| Source | Produces Frames | microphone, timer, file reader |
| Transform | Consumes and produces Frames | ASR, LLM, TTS, resampler |
| Sink | Consumes Frames | speaker, stdout, storage |
Every language follows the same lifecycle:
on_prepare
↓
on_process ← may run many times
↓
on_finish ← normal completion
on_abort ← failure, cancellation, or forced stop
on_process does not need to return output. A Node uses its Context to make
each action explicit:
def on_process(self, frame, ctx):
ctx.emit("text_out", output_frame)
ctx.emit_signal("muxiva.turn.interrupt", {"reason": "barge-in"})
ctx.publish_notification("app.transcript.ready", {"text": frame.text})
One callback can emit zero, one, or many Frames, or only publish control data.
Implementation: muxiva-core::node.
Port: a typed Node socket
A Port has a name, direction, and exact Frame Type:
The Graph never guesses a Port from a Node name and has no any type. A
connection spells out microphone.audio_out -> asr.audio_in, and both Frame
Types must match exactly.
Official or project Nodes can add a detailed schema such as PCM S16LE, 16 kHz, mono, and 20 ms. Studio displays this contract directly.
Edge: a bounded conveyor
An Edge is more than a line on a canvas. It defines:
- the exact output and input Ports;
- the single transported Frame Type;
- queue capacity;
- overflow behavior when the queue is full; and
- Edge metrics and lineage attribution.
flowchart LR
A["ASR.text_out"] -->|"text · capacity 8 · block"| B["LLM.text_in"]
Capacity is always bounded. An unbounded real-time queue turns a brief service stall into uncontrolled memory use and stale responses seconds or minutes later.
Implementation: muxiva-core::edge, queue, and flow.
Graph: a declaration, not a running object
A Graph Definition stores Nodes, Edges, configuration, and topology. It does not store running threads, sockets, model clients, or Node instances. The same Graph can be validated by the CLI, edited by Studio, compiled by Runtime, and checked deterministically by tests.
Graph v1 is currently a static directed acyclic graph. Build-time validation rejects duplicate IDs, missing Ports, wrong directions, type mismatches, zero-capacity queues, and cycles.
Implementation: muxiva-core::graph and muxiva-graph-json.
Registry and Factory: resolve declarations to code
The Graph declares which implementation it needs. The Registry owns executable Factories. Their exact identity is:
For example, qwen.asr_realtime + python + 1.0.0. Runtime does not
guess a version or silently switch languages. After validation, a Factory
creates an independent runtime instance for each Graph Node ID.
Implementation: muxiva-core::registry and foreign_registry.
Runtime: bring the Graph to life safely
Runtime:
- creates Node workers in topology order;
- calls
on_prepare; - schedules Sources and Edge queues;
- delivers each Frame to the correct Node and input Port;
- collects emissions, Signals, Events, and metrics;
- finishes on success or aborts after failure or cancellation; and
- waits within a bound for every worker and external domain to close.
Business Nodes neither need nor receive permission to implement this scheduler.
Implementation: muxiva-core::runner, concurrent, and registered_runtime.
Rust crate responsibilities
| Crate | Responsibility |
|---|---|
muxiva-types |
Frames, Buffers, time, IDs, schemas, lineage, and errors |
muxiva-core |
Nodes, Ports, Edges, Graph, Registry, Runtime, and control plane |
muxiva-graph-json |
Graph v1 JSON, built-in Registry, and compilation |
muxiva-ffi |
Stable C ABI and C++ Node Pack loading |
muxiva-testkit |
Deterministic tests, probes, clocks, and fault injection |
Next, read Graph and typed Ports and real-time flow and control.