Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
skippy-server
Production stage service and embeddable staged runtime crate.
skippy-server owns stage config, readiness, transport, runtime calls, and
non-blocking telemetry emission. The CLI commands are wrappers around Rust
entry points so mesh can host the same runtime in-process.
Architecture Role
Each embedded server or server process owns one contiguous layer range. Mesh
plans peers and layer ranges, sends LoadStage downstream-to-upstream, waits
for readiness, and then publishes the stage-0 route. OpenAI clients talk to
mesh/openai-frontend; diagnostic and benchmark clients may connect directly to
the first stage.
The full request/reply path is tip-to-tip: token IDs enter at the driver-facing tip, and activations flow through the stage chain. Generation 7 introduced direct prediction return from the final/readout tip to the driver-facing stage. Generation 8 retains that path and adds mandatory canonical stage-admission descriptors with exact participant echo before topology publication. Middle-out is the prefill optimization inside that path, where internal boundary activations are handed downstream while local compute advances.
flowchart LR
C["OpenAI client"] --> Mesh["mesh-llm<br/>openai-frontend + coordinator"]
Mesh --> D["stage-0 route<br/>token IDs"]
D --> S0["stage-0<br/>layers 0..10"]
S0 -->|activation frames| S1["stage-1<br/>layers 10..20"]
S1 -->|activation frames| S2["..."]
S2 -->|activation frames| SF["final tip<br/>output/readout"]
SF -->|PredictedToken / PredictedTokens<br/>direct return| S0
S0 -->|PredictedToken / ACK| D
D --> Mesh
Mesh --> C
SF -.->|control ACK / stats<br/>cold path| S2
S2 -.->|control ACK / stats<br/>cold path| S1
S1 -.->|control ACK / stats<br/>cold path| S0
P["layer package<br/>model-package.json + GGUF parts"] --> S0
P --> S1
Stage configs bind stage_id, stage_index, layer_start, layer_end,
model_path, checkpoint_quantization, upstream, downstream, optional K/V
cache type settings, and runtime settings into one loaded stage. Model execution flows through
skippy-runtime and the staged llama.cpp ABI.
For a direct Hugging Face checkpoint, point model_path at the local checkpoint
directory and optionally select load-time quantization:
The supported values are preserve (the default), F32, F16, BF16,
and every quantization advertised by the pinned llama.cpp llama-quantize
tool: Q1_0, Q2_0, Q4_0, Q4_1, Q5_0, Q5_1, IQ2_XXS, IQ2_XS,
IQ2_S, IQ2_M, IQ1_S, IQ1_M, TQ1_0, TQ2_0, Q2_K, Q2_K_S,
IQ3_XS, IQ3_XXS, IQ3_S, IQ3_M, Q3_K_S, Q3_K_M, Q3_K_L,
IQ4_NL, IQ4_XS, Q4_K_S, Q4_K_M, Q5_K_S, Q5_K_M, Q6_K,
Q8_0, and MXFP4_MOE. Importance-aware formats require
checkpoint_imatrix. The checkpoint must contain config.json, tokenizer
metadata, and a single or indexed set of SafeTensors shards. Quantization
happens as each stage-owned tensor loads; no intermediate model-sized GGUF is
written.
Commands
Embedding API
Mesh should use the embedded module instead of shelling out to the CLI:
SkippyRuntimeHandle::load(...)loads a stage runtime from Rust-ownedStageConfig/StageTopologyvalues and exposes status, telemetry, session stats, and explicit shutdown.start_stage_http(...),start_binary_stage(...), andstart_embedded_openai(...)start managed servers and returnEmbeddedServerHandlevalues with status and graceful shutdown.StageHttpOptions,BinaryStageOptions, andEmbeddedOpenAiArgsare the host-friendly equivalents of the old CLI argument structs. CLI commands now convert into these options and call the same serving functions.
The intended mesh ownership model is: mesh resolves models, chooses devices and topology, builds the stage configs, loads/starts handles, watches readiness and status, withdraws routes before shutdown, and then calls handle shutdown during unload or replan.
In-process tokenizer capability
SkippyRuntimeHandle::tokenizer_capability() returns a model-bound
skippy_tokenizer::Tokenizer backed by the already-loaded stage-zero runtime.
Consumers can call tokenize_batch for bounded, ordered results without an HTTP
round trip or a second model load. Every request supplies the expected
TokenizerIdentity; mismatches are returned as per-item errors. The identity
includes the model, source digest, tokenizer id, stage, and serving profile.
The capability also exposes a bounded structured encode operation for ordinary byte runs and opaque native control descriptors. Mesh does not interpret Rosetta vocabulary or control identities. The loaded backend accepts only lossless inputs it can preserve; unsupported controls, invalid UTF-8, interior NULs, identity mismatches, and limit violations return explicit errors rather than being decoded with replacement semantics. Native-serving plugins receive the same capability and inventory during activation and must prepare outside the proposal deadline.
The /v1/tokenize route is retained only as an explicit compatibility and
out-of-band adapter. It accepts the legacy add_special field as well as the
facade's special_tokens policy and is not part of generation or proposal
deadline handling.
Notes
serve-binaryis the tuned binary stage-to-stage path.serve-binaryparticipates in the breaking generation-8 stage protocol. Stage compatibility requires the completestage-generation-8control, status-list, strict-content-identity, and stage-admission bundle. Older peers, including generation 7 peers, are rejected during split planning rather than being mixed into a generation-8 topology.serve-binaryaccepts upstream protocol connections concurrently. Model execution remains serialized by the per-process runtime lock, but readiness, abandoned, or broken connections do not monopolize the listener and block the next OpenAI-driven request from reaching the downstream chain.- Non-final
serve-binarystages prefer the OS-selected route for downstream sockets, then validate that the local socket address matches the non-unspecified IP inbind_addr. If that route-selected path fails, the server falls back through explicit source/interface binding, including the macOS interface-scoped socket option. In a multi-NIC lab, setbind_addrto the private LAN address, such as192.168.0.x:19031, so both inbound serving and outbound stage-to-stage traffic are pinned to that interface. serve-openaiexposes/v1/models,/v1/chat/completions, and/v1/completionsusing the sharedopenai-frontendcrate for a local final/single-stage config with no downstream peer. Split serving uses embedded stage-0 OpenAI serving fromserve-binary --openai-bind-addrbecause generation-7 prediction returns flow directly from the final stage to stage 0. The older standaloneserve-openai --first-stage-addradapter is no longer supported.--model-idis the exact served model id to advertise and accept, for exampleorg/repo:Q4_K_M; it is not parsed as stage topology.--generation-concurrencycontrols how many chat generation requests may run at once and defaults to the config's KV-derivedlane_count.--generation-queue-capacityindependently bounds additional waiting requests (defaultclamp(8 * lanes, 16, 256)), while--generation-admission-timeout-secscan bound predicted and actual queue wait; the default0waits until client cancellation so capacity pressure drains through the bounded queue instead of rejecting accepted work. KV restore and prefill-record work runs on a separate prompt-scaled deadline: admission timeout plus about one minute per 4,000 prompt tokens, clamped to at least 60 seconds and at most 30 minutes. A legitimate prompt-sized prefill is therefore not killed by the queue-wait bound; when the work deadline does expire the request fails with atimeouterror frame in the stream, not an empty response. Embedded serving exposes the same controls with the--openai-prefix. Keep all three explicit in benchmark reports because they determine active execution, overload behavior, and tail latency.serve-openaiand embedded stage-0 OpenAI serving emit OpenAI-surface telemetry when--metrics-otlp-grpcand--telemetry-level debugare set. The spans account for the full request path visible to the backend: HTTP request, request summary, chat template or prompt preparation, generation admission, tokenization, downstream connection, prefill, decode, detokenization/text emission, generation summary, and response assembly. Embedded stage-0 spans also break prefill/decode into local stage-0 compute, downstream write, and downstream wait so benchmark reports can reconcile OpenAI request latency with the binary stage spans. Decode also emits per-tokenstage.openai_decode_tokenspans with acold,warmup, orsteadytoken phase so reports can separate first-token effects from steady TPOT. Runtime scheduling attributes on OpenAI and binary spans includeruntime_lock_wait_ms,runtime_lock_hold_ms,runtime_lock_acquires, and session-pool counts before/after execution so concurrent-depth runs can separate useful compute, model-lock wait, and non-runtime overhead.- Stage configs accept
cache_type_kandcache_type_v, defaulting tof16. Mesh carries runtime-supported cache types such asf16andq8_0; the experimental TCQ/TurboQuant cache lane is documented as benchmark evidence but is not built into this tree. - Embedded stage-0 OpenAI serving preconnects a persistent downstream lane pool
sized to
--openai-generation-concurrency. Each request leases one live stage0-to-stage1 stream for its full prefill/decode/stop sequence, then returns it to the pool; non-final binary stages keep their matching downstream streams open for the lifetime of that lane.Stopresets the logical session on a lane and leaves the TCP stream open. A failed lane is retired and replaced. - Set
SKIPPY_BINARY_WARM_PRECONNECT=1to establish one downstream binary connection while a stage runtime loads and replenish it after use. This is opt-in and leaves the normal on-demand connection path unchanged. - Set
SKIPPY_ITERATION_SCHEDULER_SAFE_MODE=1for an operator-controlled degraded mode that keeps the iteration scheduler as the sole serving path while serializing active sequences, prefills, and direct iteration batches. This is a restart-time containment control for production incidents; it does not restore or retain the removed decode batchers. Scheduler startup telemetry recordsskippy.scheduler.safe_modeand the bounded command-queue capacity so operators can verify the effective mode. --openai-prefill-chunk-policyselects fixed, scheduled, or adaptive stage0 prefill chunking without changing the default fixed--openai-prefill-chunk-size. Passing--openai-prefill-chunk-schedulekeeps the legacy schedule behavior, for example128,256,384uses128for the first prefill chunk,256for the second, and repeats384afterward.adaptive-rampstarts at--openai-prefill-adaptive-start, grows by--openai-prefill-adaptive-stepup to--openai-prefill-adaptive-maxwhen downstream transport is hidden under the slowest measured stage, and backs off when transport is exposed. Each stage folds its maximum prefill compute sample into the deferred ACK statistics; stage0 combines those samples with its own compute/write/wait timing, updates a lane-pool EWMA, and seeds the next request from that calibrated bottleneck. The measured slowest-stage token rate derives a chunk ceiling for--openai-prefill-adaptive-target-ms(100 ms by default), rounded down to an adaptive step. The configured start is the minimum feasible chunk andadaptive_maxremains the hard starvation ceiling, so calibration cannot weaken the scheduler's bounded-prefill decode-progress guarantee. Prefill and calibration spans record the selected policy, schedule/adaptive knobs, min/max observed chunk sizes, bottleneck stage, bottleneck duration, and transport-to-compute ratios.- Embedded stage-0 OpenAI serving can run neural draft speculative decoding with
--openai-draft-model-path,--openai-speculative-window, and--openai-adaptive-speculative-window. The draft model runs locally in the stage0 process as a complete model without stage tensor filtering, and proposal windows are verified through the existing stagedVerifyWindowbinary request. Rejected suffixes are resolved by the next message's absolute position, so acceptance, rejection, position rewind, draft-propose, and stale work are visible on OpenAI-path spans. The draft runner is single-session guarded; use this first as a depth-1 measurement knob before promoting it for concurrent serving. - Benchy usage lives in
docs/skippy/LLAMA_BENCHY.md. - The local OpenAI smoke harness is
scripts/openai-smoke.sh. serve-binaryforwards eligible non-final prefill activation frames on a bounded background writer by default. Use--no-async-prefill-forwardonly when comparing against the synchronous prefill path.runtime-sliceloads a full model and filters tensors at runtime.artifact-sliceloads GGUF slice artifacts written byskippy-model-packagewithfilter_tensors_on_load=true.layer-packageloads a localmodel-package.jsondirectory, validates the manifest and selected part files, then opens those GGUF parts directly through the stage ABI.- Package selection validates manifest schema, ABI version, selected part sizes, duplicate layers, and required layer presence before runtime load.
- If a layer package declares
projectorswithkind: "mmproj", package-backed loading uses the first projector unless the stage config supplies an explicitprojector_path. layer-packagealso acceptshf://namespace/repo[:revision]and caches the downloaded package underSKIPPY_HF_PACKAGE_CACHEor the default user cache directory.- Direct package loads are intentionally sparse: non-first stages omit embeddings, non-final stages omit output tensors, and all stages omit non-owned layers.
- Stage telemetry must not block model execution or protocol handling.
- Model execution flows through
skippy-runtimeand the C ABI shim.
Middle-Out Prefill
During prefill, activation frames are much larger than token/control traffic.
--prefill-chunk-size is chosen by the driver, while serve-binary enforces
bounded downstream credit with --max-inflight and --reply-credit-limit.
When --async-prefill-forward is enabled, eligible non-final prefill activation
writes run on a bounded background writer so compute for the next chunk can
overlap with transfer of the previous chunk. This is the middle-out path:
boundary activations leave one layer range while the stage keeps computing the
next chunk.
sequenceDiagram
participant U as upstream
participant S as stage server
participant W as async writer
participant D as downstream
U->>S: PrefillEmbd chunk i
S->>S: compute local layer range
S-->>U: early ACK within credit window
S-->>W: queue activation frame i
W-->>D: write frame i
U->>S: PrefillEmbd chunk i+1
S->>S: compute while frame i drains
This is topology dependent; use --no-async-prefill-forward to benchmark the
synchronous baseline on a target link. Activation frames use raw little-endian
f32; compression is not selected per family or split.
Debug telemetry includes middle-out timing spans:
stage.binary_llama_decodeis the local compute window for a binary message.stage.binary_downstream_writeis the actual downstream activation write window. In async mode this span is emitted by the background writer, not by the enqueueing request thread.stage.binary_message_timingcovers the full message lifecycle and includes compute, downstream write, downstream wait, upstream reply, credit, and deferred-reply timestamps. It also carries runtime lock wait and session counts for the executable message. Activation conversion is reported withinput_activation_decode_msfor wire materialization andactivation_encode_msfor f32 wire framing so transfer cost can be separated from compute and socket write time.stage.binary_session_stoprecords logical session reset timing when a persistent lane receivesStop; the TCP stream remains open after the reset.- Stage-to-stage
TcpStreams setTCP_NODELAYon accepted upstream sockets and downstream connections. Binary writes callwrite_alldirectly on the stream rather than a buffered writer, so per-token decode is not intentionally waiting on user-space flush batching.
Use these spans to compare stage0, stage1, and stage2 timelines directly. The middle-out health check is whether stage2 prefill compute begins while stage1 is still computing later prefill chunks, and whether downstream write/wait tail stays small after upstream compute ends.
Persistent OpenAI Stage Lanes
Embedded stage-0 OpenAI serving keeps stage-chain TCP streams connected before
customer requests arrive. The pool size is the OpenAI generation concurrency, so
a depth-N benchmark can lease up to N independent stage-chain lanes without
paying downstream TCP setup on the request hot path.
sequenceDiagram
participant O as OpenAI request
participant P as stage0 lane pool
participant S0 as stage0 runtime
participant S1 as stage1 connection handler
participant S2 as stage2 connection handler
P->>S1: preconnect lane 0..N-1
S1->>S2: preconnect matching downstream lane
O->>P: checkout lane
O->>S0: stage0 prefill/decode
S0->>S1: PrefillEmbd / DecodeEmbd over checked-out lane
S1->>S2: forward over persistent downstream lane
S2-->>S1: ACK for control/prefill
S2-->>S0: PredictedToken direct return
O->>S1: Stop logical session, keep TCP lane
S1->>S2: Stop logical session, keep TCP lane
O->>P: return healthy lane
Telemetry keeps the old stage.openai_downstream_connect span name for
per-request lane checkout timing, and adds pool/lane lifecycle spans:
stage.openai_downstream_persistent_connectstage.openai_downstream_pool_readystage.openai_downstream_lane_replacedstage.openai_downstream_lane_replace_failed