Run huge mixture-of-experts models from a swarm of peers, with the colibri engine. Pure C, no dependencies.
One machine shares a model. Any other machine chats with it. Nothing is downloaded up front: the bytes an inference actually touches arrive from a peer on first use and stay in the shared CAS. With Segment available, the chatter keeps only tokenizer, embeddings, final transform/head and conversation state; whole layer ranges and their state remain resident on executor peers. Colibri's ordinary executables and local-inference behaviour are unchanged.
Any machine may join, GPU or not. The engine was built for CPU and SSD first; a GPU only makes it faster, never different, and the output is byte-for-byte the same either way. Networks that pool GPUs recruit from the few. lumabri recruits from everyone.
make ENGINE=/path/to/colibri/cOn the machine that has a model (any colibri model directory):
./lumabri serve --model /path/to/modelOn a machine that wants to chat:
./lumabri chat --tracker <server-ip>:7300That is all. The first answer is slower while the Edge working set crosses the
network. If no complete compatible Segment route exists, the same command
automatically falls back to the existing expert/CAS engine, then to local
execution as coverage permits; there is no separate segment_chat command for
an end user.
No model at hand? make fixture builds a tiny synthetic one so every step above
is real, just small.
lumabriNo arguments. It asks for the swarm address and, once, for the operator public
key, finds the engines itself, and remembers all of it in ~/.lumabri/config.
The second time it is Enter, Enter, and you are in. Flags still win when you give
them, so a script never inherits somebody's saved answers.
When you join it also asks how you want to take part — just chat, or lend your
machine too. disk receives complete rarest-first files up to the chosen GB
budget (transferred and verified in MiB blocks). compute takes the rarest
tracker-assigned Segment slice when enough spare RAM is available. It publishes
direct P2P when reachable and otherwise uses the signed outbound Segment relay;
the finer-grained expert donor remains the lower-memory fallback.
Both run at low priority and die with the TUI. Nothing to configure — Enter
picks "just chat".
lumabri machine shows the quick startup profile used for donation: CPU
model/ISA, physical and logical cores, NUMA, RAM/swap, visible GPU/VRAM, disk,
interfaces and optional tracker RTT. --json emits a stable schema for
automation. lumabri limits shows the current donation budget; lumabri pause
and lumabri resume control every local donor without killing the chat.
On kernels without /proc/meminfo's MemAvailable (notably WSL1), the same
conservative reclaimable-cache fallback is shared by doctor, Segment, Expert
and the governor; modern Linux continues to use its native value unchanged.
lumabri doctor --json is the versioned deployment preflight for required
binaries, CAS state, model readability, tracker reachability and the complete
serving port block. The reproducible local, sanitizer, multi-host and soak
release gates are documented in PRODUCTION.md.
Inside the chat, /swarm (or /hosts) shows stable human-readable machine
names, storage served, expert calls and live Segment ranges. /experts answers
how often each executor has actually been used; /model, /debug, /storage
and /help expose the other controls. Tab completes slash commands. The prompt
is a real line editor — arrow keys, Home/End, word and line kill, and Up/Down
through the session's history — so a typo is one keystroke back, not a retyped
line.
Generation streams as soon as decoded text is stable. During inference a small
dock remains fixed above the input and reports routing, prefill, decode,
checkpoint or failover without splicing diagnostics into the answer. The input
remains active: read-only menus open immediately and one next prompt or command
can be prepared while the current KV transition finishes. Ctrl-C interrupts
the active turn and exits immediately instead of waiting for it to finish;
Ctrl-Z restores the terminal before suspending and rebuilds the dock after
resume, while Ctrl-\\ follows the same immediate shutdown path through
SIGQUIT. Normal exit, SIGINT, SIGTERM, SIGHUP and SIGQUIT all restore
the original terminal mode. If a child is genuinely uninterruptible, a second
Ctrl-C forces the chatter out after the first has already restored the shell.
As on every Unix program, SIGKILL cannot run cleanup; reset remains the
recovery command after an external kill -9.
Sharing bytes. serve runs two small programs: a tracker, which is only an
index of who holds which files, and a maintainer, which answers byte-range reads
on the model directory. A maintainer can hold a slice of a model, and several
maintainers can share one.
Reading bytes. chat mounts the model through liblumabri.so, an
LD_PRELOAD shim that interposes the handful of libc calls an engine makes on a
model directory (open, fopen, opendir, pread). Files appear as sparse
local mirrors of the true size, so fstat, readdir and the page cache work
natively. A missing block is fetched from a peer, written to the mirror, and
then the engine's own pread proceeds. A warm read is a table lookup plus a
normal local read: no FUSE, no daemon on the read path. Every verified MiB is
also stored by sha256 in a local content-addressed store. The default CLI path,
~/.lumabri/cas, is shared by every checkpoint, so equal chunks are downloaded
once and can rebuild a different sparse mirror without a byte server.
One rule, inherited from colibri: the network may change where bytes come
from, never which bytes. Writing a model file returns EROFS. A block no peer
can serve is a loud EIO, never silent zeros. Byte identity is verified cold,
warm, and with every peer dead.
Layers run as stateful segments. serve reads model_type, layer count,
context, CPU count, available RAM and reachable network address, then starts a
small set of disjoint layer-aligned executors automatically. The origin ranges
are marked fallback. Compute donors ask only for a model; the tracker promises
the least-replicated exact range while they load it, and the asynchronous route
selector prefers their ordinary ranges over the matching origin ranges on the
next turn. Thus the original server begins with complete coverage and loses its
pipeline progressively without ever making the route incomplete. Every turn
uses one request per segment, with its model-specific KV/recurrent/conv state
kept in an isolated remote session.
The local Edge opens through liblumabri.so, so a user supplies neither a model
directory nor roots: the signed aggregate model identity comes from the tracker
and only blocks actually read by tokenizer/embedding/head enter the CAS. Four
origin ranges is the current latency/replacement compromise. Segment prefers
persistent direct TCP and falls back request-for-request to the exact peer's
signed tracker tunnel. A machine behind NAT therefore contributes without
publishing an unreachable address or opening a data port.
Discovery probes Segment endpoints on its control thread and publishes an
immutable completion estimate with each route. Selection minimizes the sum of
EWMA latency and advertised queue/inflight cost for the complete chain; origin
fallback status is only a tie-breaker. Adding a slower donor therefore does not
replace a faster known route. Expert replicas use the same EWMA model, open a
circuit only after repeated failures, and hedge automatically only after enough
samples show a real p95 tail. LUMABRI_HEDGE_MS remains an explicit
override: a positive value is the fixed delay, and -1 turns hedging off.
These are online estimates, not a speed claim: swarm_bench.py on distinct
hosts remains the authority for single-chat and aggregate throughput.
The TUI's temperature and top-p are applied to logits returned by Colibri Edge; temperature zero retains the exact greedy selector. When a compatible replica exists, a completed turn checkpoints every opaque remote state. If a peer dies, it opens an exact-range compatible replica, restores the common checkpoint, replays only the token delta and retries the interrupted batch with the same conversation.
Experts run on peers. For a mixture-of-experts model the chatter keeps only
the dense weights, the router and the KV cache, and sends the 4 KB activation to
the peer that holds each routed expert. Expert weights never reach the chatter.
Both sides are built from the engine's own source, so the local run and the
distributed run are one code path and produce identical tokens. A peer also
advertises its exact build (engine, source hash, ISA, compiler, quantization,
model root), and a chatter refuses a peer whose build differs before it sends a
single activation, because a -march=native rebuild can change the last bit and
that must never happen silently. The refusal names the field that diverged, and
the gate splits by what a mismatch means: engine, source hash, model and math
flags always refuse; the OpenMP version never does; compiler and ISA refuse by
default but LUMABRI_ALLOW_CODEGEN_SKEW=1 downgrades them to a warning and turns
spot-checking on, for a mixed-hardware swarm that accepts verified-but-approximate
results instead of bit-identical ones.
Peers are not trusted. Every maintainer computes a sha256 per MiB of what it
holds and sends it with its registration. The origin can sign that truth with an
ed25519 key it keeps offline; the tracker only carries the signature and cannot
mint one, so a chatter verifies every block against a key it holds itself. A
lying peer has its bytes rejected and refetched elsewhere. Remote compute is
checked the only way it can be: LUMABRI_VERIFY=N reruns N percent of expert
calls on a second replica and demands identical output. Two honest peers cannot
disagree, so a disagreement is proof of a lie and the run stops.
Prefill and target verification already arrive at the MoE as multiple rows.
lumabri keeps that union intact and sends one multi-row EXEC per selected
expert, including speculative-draft verification; it never serializes a batch
into row-sized requests. LUMABRI_HEDGE_MS=N optionally sends a duplicate to
the next replica when the nearest has not replied after N milliseconds and
uses the first valid deterministic result. The fixed delay is deliberately the
public mechanism, not an automatic SLA policy.
colibri ships several engines and they do not share a shape, so the expert side is per engine: a small patch that hooks the MoE function, and an expert-node binary built from that engine's own source. The engine is never touched, the patch is applied to a copy, and it is regenerated from source anchors so it fails loudly instead of applying in the wrong place.
| engine | model | chat | experts on peers |
|---|---|---|---|
olmoe |
OLMoE | yes | expert_node, proven by phase2_test.sh |
colibri |
GLM | yes | expert_node_glm, proven by phase2_glm_test.sh |
inkling |
Inkling | yes | expert_node_inkling, proven by phase2_inkling_test.sh |
kimi_k3 |
Kimi K3 | yes | expert_node_kimi, proven by phase2_kimi_test.sh |
deepseek |
DeepSeek V4 | yes | expert_node_deepseek, proven by phase2_deepseek_test.sh |
qwen36 |
Qwen3.6 | yes | expert_node_qwen36, proven by phase2_qwen36_test.sh |
"Proven" means the experiment, not the claim: the same engine and the same prompt, generated twice, once with the experts local and once with every one of them on a peer, and the tokens compared bit for bit. That test caught a real bug once. GLM computes an expert over all of its routed rows at once, so feeding a peer one row at a time gave different floats and the tokens drifted after four positions. Nothing but running it would have found that.
Build the peers with make engines, the patched chat engines with
make chatters, or both with make phase2-all ENGINE=/path/to/colibri/c, for
the engines your colibri checkout actually has.
The Segment path keeps whole contiguous layer ranges and their sequence state
resident on peers, reducing the network boundary from one request per
layer/expert to one request per segment. It is the preferred path of ordinary
lumabri chat when the matching Colibri ABI and a complete compatible route
exist. GLM, Inkling, Kimi K3, OLMoE, Qwen3.6 and DeepSeek V4 are all release
gates; OLMoE is not a special-case definition of complete. Build details,
relay/failover semantics and the remaining operational boundaries are in
SEGMENT_DIRECT.md.
A full server walkthrough (systemd, firewall, operator key, clients) is in DEPLOY.md. The short version:
make ENGINE=/path/to/colibri/c
make phase2-all ENGINE=/path/to/colibri/c # classic expert fallback
sudo make install # or PREFIX=$HOME/.localOn the server, lumabri serve --model /srv/model starts tracker, maintainer,
classic expert executor and the automatic Segment origin. TCP 7300 must be
reachable. A public IPv4 attached to the machine is detected automatically and
enables the fastest direct paths on 7301 onward; allow 7300:7309 when using up
to seven public Segment ranges. Without a reachable address, Segment, READ and
EXEC use signed outbound tracker tunnels, so no data port is required. Add
--key swarm.key to sign the model.
serve derives names such as host-gpu-box-7300-storage, -experts and
-segment-1; use --host-name gpu-box for an operator-chosen prefix. Its live
summary reports connected hosts, bytes served, expert calls and active Segment
runs, so successful swarm work is visible on both sides.
Automatic Segment is a real compute service. It starts only with at least 8 GiB
available by default (LUMABRI_SEGMENT_MIN_FREE_MB), gives each sequential
slice a full physical-core team, runs fallback work at low priority and keeps
4 GiB free before accepting a new session. LUMABRI_RAM_RESERVE_MB is the
common limit; LUMABRI_SEGMENT_RAM_RESERVE_MB and
LUMABRI_EXPERT_RAM_RESERVE_MB are per-role overrides. A relay-only/NAT
origin defaults to two sessions per slice; a direct server defaults to four.
Every executor runs the same hysteretic resource governor. ACTIVE publishes
capacity; PRESSURE and PAUSED advertise Segment draining or zero Expert
coverage and reject new work; RECOVERY waits three healthy samples before
publishing again. In-flight Segment work sees the cancellation callback and is
migrated through the existing checkpoint/replay path. Expert work already in
flight drains, while new calls fall back to another replica or the Segment's
local kernel. This pauses donor CPU and I/O immediately; resident RAM stays
allocated inside the donor process, protected by the reserve chosen before
loading, so recovery does not cold-load the model again.
Every transition names its cause and prints available RAM, the configured
reserve and process residency; a draining advert is therefore diagnosable
from the executor log instead of being a bare state bit.
On every other machine, pick a role:
| you want to | run |
|---|---|
| chat | lumabri chat --tracker SERVER:7300 |
| chat on the machine that holds the model | lumabri chat --local DIR |
| donate disk (hold bytes) | lumabri serve --model ./slice --join SERVER:7300 --model-name NAME --donate GB |
| donate compute | pick compute in the join menu; Segment range or experts are selected automatically |
A disk donor is told which complete files to hold, rarest first, by the tracker;
the GB budget is a hard placement input, not permission to fill the disk. A
compute donor needs no model: when Segment is active and a quarter-range fits
after the system reserve, it receives the least-replicated origin range. Direct
P2P is preferred; NAT donors use Segment relay automatically. If the range does
not fit, --hold auto sizes a strictly resident expert slice after preserving
the system RAM reserve (LUMABRI_EXPERT_RAM_RESERVE_MB, 4096 by default).
The tracker gives it what nobody else covers through direct EXEC or relay and
does not see the donor until every assigned weight is RAM-ready. The origin's
explicit --cache executor remains the labelled disk fallback. Both
load through the verified swarm mirror, so the whole model never lands on the
donor.
Automatic compute donation has one machine/user lease shared by chat and
serve --join. Opening the menu repeatedly therefore cannot start several
executors that each size themselves from the same available-RAM snapshot. A
second process prints the PID/model/tracker of the active owner and may still
donate storage. Stop the owning chat or joined server before replacing it; on
Linux, its executors also receive SIGTERM if their parent is killed.
Donors register under donor-<hostname>-… (pick one with --donor-name);
a name already owned by another peer key is retried with a numbered suffix
instead of being silently rejected forever. So several
compute donors split the model into disjoint slices automatically. (--hold N sets the count by hand; --stride 2:0 / --stride 2:1 or
--layers … split it explicitly if you want to size each machine yourself.)
The origin publishes four stable, layer-aligned fallback ranges by default
(LUMABRI_SEGMENT_CHUNKS=1..7 overrides it). Each range uses the full local
CPU team because decode traverses the chain serially. A resident Segment donor
then replaces one exact range; it advertises measured RSS only after its engine
has opened, and the server remains the fallback for every range not yet donated.
LUMABRI_SEGMENT_THREADS=N is the explicit per-range CPU override.
Within either origin or donor ranges, Segment Hybrid also delegates any fully
covered MoE layer to strict-RAM Expert donors. Selected experts are sent in
parallel; incomplete layers and failed donor calls execute locally. Thus even a
peer too small for a complete Segment range contributes useful resident expert
work, while the server remains the correctness fallback.
Files written by the running engine are deliberately not model content.
Lumabri excludes .coli_* state such as .coli_usage, KV/checkpoint state and
SSD metadata from storage manifests. These files remain local and mutable;
only checkpoint/model payloads enter signed CAS identity.
Concurrent chats are admitted FIFO at every Segment range. Queue depth and
inflight work are published to the predictive scheduler, the queue is bounded,
and a request that misses its admission deadline returns BUSY so an exact
replica can take over instead of waiting behind a 300-second socket timeout.
The four origin ranges form a pipeline, so different chats can occupy different
ranges concurrently. Lumabri deliberately does not fuse rows from unrelated
sessions: current Colibri adapters own opaque per-session state and can round a
cross-session batch differently. Calling that continuous batching before an
engine-neutral multi-session batch ABI exists would break the token oracle.
When two donors happen to hold the same expert, add LUMABRI_SPREAD=1 on the
chatter to balance the load between them too. Neither donor needs to know the
others exist. Expert requests can fail over to another replica. Stateful
Segment sessions with compatible replicas checkpoint at turn boundaries; on
failure the gateway restores an exact-range replica, replays tokens after the
common checkpoint and retries the interrupted batch. If no compatible replica
exists, it still fails loudly rather than inventing divergent state.
For a manual signing-key rotation, distribute a keyring containing one public
key per line. --pubkey keyring and LUMABRI_PUBKEY=keyring accept every key
in it (up to 16). First deploy old+new, then restart the origin signing with
the new secret, and only after clients and donors have moved remove the old
line. Put the newest key last: the tracker keeps the valid signature made by
the highest-priority (latest) key, so old donor heartbeats cannot roll it back.
Comma-separated public keys are accepted too; the low-level tracker and
maintainer commands also accept repeated --pubkey.
There is still one signature per object; the overlap belongs to the verifier,
so the wire format does not change during rotation.
Everything works with none of these set. Turn one on by putting it in front of
the command, e.g. LUMABRI_SPREAD=1 lumabri chat ….
| set | to |
|---|---|
LUMABRI_SPREAD=1 |
spread the load across peers that hold the same expert (default: the nearest one wins) |
LUMABRI_VERIFY=N |
re-run N% of expert calls on a second peer and demand the same answer — a lie stops the run |
LUMABRI_HEDGE_MS=N |
after N ms with no reply, ask a second peer too and take whichever comes first |
LUMABRI_HEDGE_MS=-1 |
never ask a second peer — the only way to get one request per call, which attribution and benchmarking need |
LUMABRI_ALLOW_CODEGEN_SKEW=1 |
let peers built with a different compiler or CPU join (results are then verified, not bit-identical) |
LUMABRI_ENCRYPT=1 |
encrypt the transport (see below) |
RAM_GB=N |
tell a --local run how much RAM it may use to keep experts resident |
Set LUMABRI_ENCRYPT=1 on every tracker, maintainer, expert node and chatter
to encrypt tokens, model blocks and activations with an authenticated
X25519/Ed25519 handshake and ChaCha20-Poly1305 frames. If a peer key cannot be
loaded or created, networking fails closed instead of falling back to
plaintext.
Each machine keeps its private endpoint identity in ~/.lumabri/peer.key and
prints the public half with lumabri peer-key. Outbound endpoints are recorded
in ~/.lumabri/known_hosts; a changed key is refused on later connections.
For first-contact MITM protection, distribute an operator-managed file before
connecting:
SERVER:7300 64_HEX_PEER_KEY
SERVER:7301 64_HEX_PEER_KEY
SERVER:7302 64_HEX_PEER_KEY
Then set LUMABRI_PEER_PINS=/path/to/peer-pins. Strict pin files must list
every endpoint the process may contact. LUMABRI_REQUIRE_PIN=1 applies the
same no-learning rule to a preseeded known_hosts. The endpoint key is not
the model-signing key: LUMABRI_PUBKEY authenticates model contents, while
peer pins authenticate network endpoints. For endpoint-key rotation, publish
two rows for the same address containing old and new keys, switch the server,
then remove the old row. Persistent TOFU instead requires an explicit
known_hosts update after verifying the replacement key out of band.
The tracker also persists the first key that owns each maintainer/executor name. A restart rebuilds placements from heartbeats but does not reopen names for takeover. Per-key and per-source live-name quotas limit table exhaustion; they are admission controls, not a claim to solve distributed Sybil attacks.
For the classic expert path, the server also runs an expert node on the whole model, so a fresh swarm works on day zero with the server executing everything, and donors that join later win the calls they are nearest for. The nearest replica sets the speed: an expert held at 2 ms and at 30 ms runs at 10.5 tok/s, not 1.4, because only your closest copy matters.
make testruns the core suites: byte identity, donor integrity, role parsing, security
(path escape, hostile frame lengths, aggregate receive memory, idle
connections, durable identities and admission quotas), protocol input
validation, cryptographic vectors, encrypted transport and prefetch policy.
Per-engine expert identity runs with fixtures
(make test-engines), and DeepSeek V4 against a real model
(make test-phase2-deepseek MODEL=<dir>). Assignment, concurrency and signing
have their own scripts (assign_test.sh, concurrency_test.sh,
sign_test.sh). The newer mechanisms have focused targets:
make test-cas test-key-rotation test-hedge test-relay-exec and
make test-segment-v2 test-segment-discovery test-segment-direct-real.
Segment discovery checks leases, route generations, replicas, draining,
compatibility and the asynchronous snapshot. The direct gate runs all six tiny
families through real TCP executors, matches independent Colibri token oracles,
drives sampled persistent TUI turns, overlaps sessions, and proves rarest-first
automatic range replacement. The same target also forces Segment through a
relay-only NAT topology, kills a selected executor to require checkpoint
restore/replay, and launches the ordinary serve + chat UX without a public
data address. Relay EXEC needs
an OLMoE engine source under ENGINE; its script reports SKIP explicitly
when that external checkout is absent. Every claim in this README has a script
behind it.
Peer-to-peer LLM inference exists; this combination does not. Petals and llama.cpp RPC split consecutive transformer layers across devices, which needs each slice to run fast, in practice a GPU. lumabri splits at expert granularity instead, which matches MoE sparsity: only 4 KB travels per expert, a peer is useful holding a single one, and a swarm with no GPU is a working swarm. The output is byte-identical by construction, because remote and local are the same code, which is also what makes spot-check verification of untrusted peers possible at all.
Linux, gcc, GNU make, and Python 3 (it applies the chatter hooks to the engine by anchor at build time, so a patch survives colibri moving the code around it; numpy is only needed for the synthetic test fixtures). A colibri build provides the engine binaries.
Working prototype, deployable. Open swarms verify bytes (sha256 per MiB and a
signed complete-model root, checked by the chatter against its own trust set)
and results (spot-check on a second replica). Private swarms add an invite token
everywhere with LUMABRI_TOKEN; LUMABRI_ENCRYPT=1 protects that token and
activations in transit, using persistent TOFU or strict endpoint pins.
Multi-row speculative verification, fixed-delay
hedging, a local cross-checkpoint CAS, manual old+new key rotation and NAT relay
for both READ and EXEC are implemented. Automatic SLA tuning, distributed/S3
CAS, KMS/HSM integration and automatic revocation are intentionally not part of
this dependency-free base. Expert execution is checked by replica agreement,
not by the operator signature.
Apache 2.0