Author a model package for loom-serve¶
A serving package combines a model's numerical programs with its input, parameter and state contracts. The server supplies shared workers, JIT, device queues, memory ownership, request scheduling and HTTP encoding. Adding a model that fits an existing modality changes the package, not the server's C code or executable.
The first-output walkthrough runs a complete arithmetic package before weights or neural accuracy enter the picture. That is a useful starting point for a port: changing its math preserves a working path through registration, execution, output and retirement.
Select the execution contract¶
The important distinction is the shape of state and output, not the model name:
| Contract | Source responsibilities | Starting package |
|---|---|---|
| Retained text | Token framing, paged state geometry, mixed prompt/decode math, progress, sampling and chat policy. | Tiny text model |
| Staged image | Prompt preparation, parameter domains, numerical stages, invocation continuation and final RGBA8. | Image model |
| Finite embeddings | Input preparation, cohort cost/compatibility, pooling/projection and final vectors. | Embedding model |
| Finite decisions | Structured question framing and compact normalized answer distributions. | Decision model |
| Streaming speech | Voice conditioning, independent request state, compatible next-work batches and continuous waveform blocks. | Speech model |
| Continuing recognition | Independent input clocks, compatible next-work batches and revisable transcript segments. | Recognition model |
These packages use actual source VM programs, native kernels and production HTTP services, not canned native replies. They establish the serving contract, not learned quality or competitive neural performance. Each learned port needs its own numerical oracle and representative workload.
Image-conditioned text composes retained text with an optional finite image projector, described below. Audio input or an arbitrary workflow graph needs its own input/output ownership contract beyond these HTTP profiles, not an embedding vector with overloaded fields. The HTTP reference defines the existing boundary.
Keep the package complete and relocatable¶
A typical package contains:
model.json deployment, source roles, assets and capacities
prepare.loom cold declarations and parameter interpretation
control.loom warm request and execution policy
config.loom model/target specialization inputs
kernel.loom numerical providers and reusable helpers
tokenizer.json tokenizer asset, when needed
weights.safetensors checkpoint selected by preparation policy
These filenames are conventions, not hardcoded server paths. The model document names the actual files. GGUF and safetensors inputs follow the selected preparation policy; a file extension or model name does not convert an arbitrary checkpoint. Its keys, encodings and layouts must agree with the authored source.
All program roles and numerical providers accept .loom or .loombc.
Bytecode is portable IR and still JITs for the selected device. References in a
file document resolve from its directory, including references to shared motif
libraries elsewhere. JSON-only HTTP registration supplies its absolute
server-local base. A multipart source package instead carries programs and
metadata in a separate logical namespace while parameter files stay server-local.
The live development workflow
shows upload, native selection and retained-state comparisons.
definition.sources supplies shared VM and native providers. Roots and
referenced symbols determine dependency closure through the
normal Loom linker. Reusable helpers take SSA values or template arguments;
model-specific configuration belongs at program/kernel boundaries. This keeps
a motif usable without importing another model's global configuration namespace.
Preparation and control VM files each link against that catalog as primary inputs. Ordinary function declarations and template applications resolve to exported library definitions; library-private helpers stay private. This lets preparation, control and numerical commands share layout calculations without duplicating them across files.
Explicit func.decl import("module") declarations remain capability imports,
bound to native modules when the VM program loads. The cold program names
numerical roots; the warm program invokes the resulting prepared stages.
Shared source helpers do not turn device kernels into direct VM calls.
Reuse Unicode properties¶
Host text programs can use the string module's codepoint.* operations
instead of embedding Unicode tables in each model. They are available in
loom-serve, loom-test, and loom-benchmark VM execution. Each operation
accepts one Unicode codepoint; full case mapping handles expansions such as
ß → SS:
func.decl import("string", "codepoint.to_upper") @unicode.to_upper(%codepoint: i32) -> (i32, i32, i32, i32)
func.def public @uppercase(%codepoint: i32) -> (i32, i32, i32, i32) {
%count, %first, %second, %third = func.call @unicode.to_upper(%codepoint) : (i32) -> (i32, i32, i32, i32)
func.return %count, %first, %second, %third : i32, i32, i32, i32
}
codepoint.to_upper returns a count and three codepoint slots;
codepoint.to_lower returns a count and two slots. Unused slots are zero.
Both use locale-independent Unicode 15.1 mappings, preserve unmapped input,
and allocate no buffers. codepoint.is_decimal, codepoint.is_digit, and
codepoint.is_whitespace each take one i32 codepoint and return i32 zero or
one. Digits include decimal digits and characters such as ²; whitespace means
Unicode White_Space. Model-specific spacing, punctuation, and capitalization
policies remain in the authored program.
Separate preparation from execution¶
The cold prepare VM program receives modality inputs and the source-owned
options object. It validates architecture constraints and declares stages,
configuration and checkpoint domains. Shared preparation capabilities include:
Import in module prepare |
Meaning |
|---|---|
stage(root, tag) |
Declare a command-program root and a source-defined selection tag. |
dispatch(root, tag) |
Declare a buffer-only native kernel root with its compiled launch configuration. |
config(stage, key, value) |
Bind a public Loom configuration value in textual syntax. |
config_i64(stage, key, value) |
Bind a signed integer configuration value. |
workspace_limit(stage, bytes) |
Bound command workspace, including compatible live replacements. |
memory_forecast(root) |
Select a finite component's host control entry for complete-request memory estimates. |
source(directory, path) |
Declare the first shard of a checkpoint and return its source ordinal. |
source_append(source, directory, path) |
Append a shard to that checkpoint's ordered index. |
source_scope(scope) |
Select a model card's named, typed parameter files as one shared checkpoint source. |
parameter(stage, binding, input, source, policy) |
Bind a checkpoint to one policy-local input of a reflected fixed parameter binding. |
A split checkpoint uses source for its first file and source_append for
each additional shard. The files populate one index in declaration order.
The same source can supply several resident bindings or stages without repeating
the file list. Sources identify bytes, independently of resident placement or
preparation policy; a source declaration by itself loads no parameter payload.
Cold preparation opens each declared source once and shares its index and
imported-file cache across consuming bindings. Request choices retain the cold
prefix and index new sources on the preparation worker; warm execution does not
reopen checkpoint paths. A missing or invalid checkpoint fails preparation
before its parameter placement or activation.
Each fixed binding declares its policy inputs once, densely from zero. A policy
can combine independent checkpoints containing the same keys: its weights
imports use those local input ordinals, not model-wide source ordinals. Stages
naming the same ordered file lists and policy share a resident domain. The
loader accepts explicit GGUF, safetensors, and other supported parameter files
without inferring filenames.
Weight policies can combine checkpoint ranges with values computed during
preparation. The import
weights.input(source, key, key_offset, key_length, offset, length, alignment)
captures a checkpoint range; weights.input_buffer(data, alignment) captures an
immutable copy of a nonempty readable VM buffer. Both append bytes to the
current tensor's input recipe and return their aligned offset within it.
Computed bytes survive policy teardown and are reused if device parameters
are reactivated; they do not create a file
or another checkpoint visible through weights.count or weights.parameter.
A policy that declares inputs without a preparation command loads those bytes directly into the final tensor. Its ranges must cover the complete tensor contiguously, with no alignment gaps, and the policy returns the tensor's reflected byte length. This supports checkpoint slices, concatenated ranges from multiple sources, and computed host data without a staging buffer or a copy kernel. A policy declaring neither inputs nor a command returns zero and loads the canonical key from source zero.
When the policy declares a preparation command, input offsets address its staging buffer, and alignment gaps are allowed. The command receives the final tensor followed by staging, and the policy returns the tensor's reflected byte length. Without captured inputs, a command transforms the canonical source-zero bytes in place. Only commands with captured inputs contribute to staging capacity.
Both weights.parameter(source, key, key_offset, key_length) and weights.input
resolve the named byte range of key during the call. A policy can build names
in reusable scratch storage and pass only the used range. The captured entry
and returned metadata refer to the retained checkpoint index; subsequent writes
to the key buffer cannot change them.
Request preparation can declare additional sources after the immutable cold source prefix, or bind that prefix to new stages. It cannot append shards to a cold source. Each request choice owns its declarations independently; selecting another choice does not change the checkpoint identity of accepted work.
The exact signatures and ownership are in the preparation contract. Declarations copy their strings; opaque returned state must own its storage or retain its inputs. Preparation is not a place to submit device work.
The server resolves these declarations, compiles through its shared compiler task queue, and retains the selected stages for the model. Configuration can specialize stage shapes or layouts without giving every session its own program. Compatible requests share the prepared code and parameters. Warm work does not invoke a compiler subprocess or redo unchanged model preparation.
The warm control VM imports the runner-local runner.execute_N and
runner.feedback capabilities. execute_N submits a prepared stage with its
buffers; feedback transfers a bounded final result into a registered host slot.
Both enqueue work without waiting. The native model owner schedules completion
on work/feedback timelines and preserves buffers until their actual last use.
The runner-module contract
defines arity, buffer types and lifetime. This is a coarse serving capability,
not a source program's ownership of the entire device or process scheduler.
Independent work can use explicit dependencies. runner.fence(work) returns a
hal.fence for a previously accepted work value. It captures that producer,
not later submissions or the separate feedback branch. runner.join(ready)
orders subsequent model work after the supplied fence without waiting on the
CPU or synchronizing other models. A null fence represents no external work.
Completion describes readiness; storage ownership still extends through the
last accepted consumer, including when a dependency fails.
Measure device work¶
Control programs can bracket prepared stages with queue-clock captures:
(frequency_hz, valid_bits) = runner.timestamp_clock()
runner.timestamp(feedback_buffer, begin_byte_offset)
runner.execute_N(stage, ...)
finished = runner.timestamp(feedback_buffer, end_byte_offset)
runner.feedback(slot, feedback_buffer, byte_offset, byte_length)
Each capture writes a raw 64-bit tick to an 8-byte-aligned, transfer-writable destination. Its return value is an accepted work timepoint, not the captured tick. Captures follow preceding model work, and subsequent work follows the capture. They enqueue without a host wait or a device-wide barrier. Returning the samples in the existing feedback transfer needs no separate readback.
timestamp_clock reports the dispatch queue family's clock. A zero frequency
or width means that no timestamp clock is advertised; unsupported captures
return an error. Within that family, subtract samples modulo 2^valid_bits
and divide by frequency_hz to obtain elapsed seconds. A captured zero is
valid, and successful completion establishes that the sample was written.
Each queued epoch owns separate sample slots until its readers retire; a later
capture must not overwrite feedback that is still in flight.
Read checkpoint bytes on demand¶
Large lookup tables and paged experts can remain in checkpoint files instead
of occupying a resident parameter binding. The warm parameters capability
reads demanded byte ranges from the same sources declared during preparation:
source is the selected invocation's source ordinal, and key is a host byte
buffer naming an entry in that checkpoint. Independent sources may use the
same key. descriptors and target are hal.buffer references. Starting at
descriptor_offset, each 24-byte record contains three little-endian u64
values: the entry-relative byte offset, destination-buffer byte offset, and
byte length. Destination ranges are disjoint; zero-length records require no
payload transfer. Hashing, deduplication, packing, and cache placement remain
model-program decisions, not tensor interpretations in the server.
A control program can enqueue independent reads before joining either one:
producer = runner.execute_N(descriptor_stage, ...)
produced = runner.fence(producer)
first = parameters.gather(source_a, key_a, produced, ranges_a, 0, count_a, target_a)
second = parameters.gather(source_b, key_b, produced, ranges_b, 0, count_b, target_b)
runner.execute_N(independent_stage, ...)
runner.join(first)
runner.execute_N(first_consumer, ...)
runner.join(second)
runner.execute_N(second_consumer, ...)
The supplied fence covers descriptor production and destination availability, including any earlier readers of reused storage. The returned fence orders payload consumers and descriptor reuse. An empty gather preserves its incoming dependency without touching storage. Changing a request's source choice or removing its model does not redirect or release accepted reads: each read retains its original provider and buffer captures until actual retirement. Failed readiness is not permission to recycle those buffers.
This implementation asynchronously snapshots the descriptors to host memory, then submits the ranges through the parameter provider and HAL file queues. The VM call never waits for completion or synchronizes unrelated models. It requires queue download and deferred host-call support. Checkpoint opening uses the configured parameter-file mode; direct I/O requires appropriately aligned file ranges and destinations and does not silently fall back to buffered reads. A snapshot costs 24 bytes per descriptor plus one copied key; checkpoint payloads are not materialized in a separate model-owned host array.
This is host-VM-initiated asynchronous I/O, not a persistent GPU request service. A kernel that requests data while continuing other work needs a device-side progress and credit protocol beyond this call. The shared source identity and byte-range contract do not impose a model-wide barrier on that separate execution mechanism.
Tokenize request inputs¶
Request preparation can use the input capability to encode text and decode
token spans with the deployment's tokenizer. encode(text, flags, capacity)
returns a zero-padded little-endian I32 ID buffer and live token count; it can
stop at the requested capacity. decode(ids, flags, byte_capacity) consumes
the complete ID buffer and returns a zero-padded UTF-8 buffer and live byte
length. An insufficient decoding capacity fails instead of returning partial
text. Pass only live IDs, excluding encoding padding. Each call starts fresh
tokenizer state, including leading-space handling. Encoding flags are
ADD_SPECIAL_TOKENS = 4 and NO_SPECIAL_TOKEN_MATCHING = 8; decoding supports
SKIP_SPECIAL_TOKENS = 1, with zero retaining special tokens. The source owns
text normalization, sentence boundaries, and capacity admission.
Trace one finite request end to end¶
The embedding package is the smallest complete example. Its cold entry is
prepare(asset_root, options). It returns a batch-unit limit, upload/output/
result capacities, an optional tokenizer asset, a source name and opaque state.
Its control program exports:
prepare_request(state, input) -> (request_state, units, compatibility_tag)
prepare_batch(state, stage_tags, batch: ptr<finite.batch>)
-> (stage_index, upload_payload, result_plan)
run(state, stage_index, input_buffer, output_buffer, batch: ptr<finite.batch>)
collect_batch(state, batch: ptr<finite.batch>)
The HTTP parser provides indexed protocol records, not a source-private JSON
guess. prepare_request performs model framing and validation. units is a
positive additive bound on real work/storage; it need not mean tokens. Equal
compatibility tags mean requests can share a cohort. Each request retains its
source buffer across epochs; the model shares one serialized control instance.
Returned buffers retain any aliased input.
The native scheduler starts with the oldest prepared request and fills the
cohort from compatible waiting requests. It does not wait for hypothetical
arrivals. The finite capability exposes the entire selected cohort to one
preparation or collection call:
| Import | Contract |
|---|---|
batch_count(batch) -> i64 |
Number of selected members. |
batch_state(batch, ordinal) -> buffer |
Retained request state at its original cohort ordinal. |
batch_pack(batch) -> (ranges, packed) |
Explicitly copy states into an upload directory and payload. |
batch_origin(batch, ordinal) -> i64 |
Reserved cohort origin in source-defined storage units. |
batch_buffer(batch, ordinal, root) -> hal.buffer |
Stable device root whose capture protects the cohort until queue retirement. Submission only. |
batch_release(batch, ordinal) |
Relinquish a completed cohort's storage during collection while its logical request continues. |
batch_offer(batch, ordinal, units, tag) |
Publish the next work offer during successful collection. Zero units finishes the request. |
batch_finish(batch) |
Finish every member of a one-shot cohort during collection. |
The borrowed batch is valid only during that call. Cancellation preserves its
original ordinals until collection retires. batch_pack produces request-order
[offset, length] I64 ranges; the packed buffer contains the same directory
followed by the states. A one-shot program can upload it directly. A continuing
program can instead read each state and construct a compact control packet.
Batch preparation selects a stage and maps physical output back to requests.
After the accepted device frontier succeeds, collect_batch commits progress
and publishes each member's next offer. It never runs for failed readiness.
Unfinished members rejoin behind new arrivals, so compatible late requests can
join the next epoch. Each member can publish an ordered prefix of its remaining
result rows. Collection finishes a member exactly when that prefix exhausts its
remaining rows. Earlier rows retain their independent output storage while the
source releases and reuses numerical cohort scratch. Empty output alone does
not indicate completion. A one-shot source
calls finite.batch_finish from collection and uses this same lifecycle.
Request-state buffers are host control storage. Device intermediates need an
explicit producer-owned lifetime across epochs: native generators own that
storage and its retirement. Compiler workspace inside a source run invocation
is scoped to that invocation.
Finite prepare_batch can also declare stages with the prepare capability.
It uses the same stage, dispatch, config, config_i64, and
workspace_limit imports as cold preparation. Returned ordinals follow the
cold stages and are valid for that invocation. This lets a package specialize
an actual image geometry or cohort extent without enumerating a size catalog
at registration. A request can also declare sources and parameter bindings;
omitting parameter declarations preserves the cold layout. New source ordinals
follow the immutable cold prefix and belong to that exact request choice.
The server reuses an exact declaration set within its selected source generation
or compiles it asynchronously before parameter admission. Other models keep
running on the shared workers. Cancellation joins accepted compilation before
releasing its source and invocation, and cached choices are bounded by the
deployment's specialization_cache. Neither specialization
nor image-to-text composition requires downloading hidden features to the host.
The result plan describes physical output bytes separately from the live result prefix, then each request's rows and each row's offset/width. Results retain their device storage independently of the producing model. A logical request spanning cohorts keeps its rows in the original buffers and publishes one final result in input order. Device consumers import the producer's readiness and read those rows without a consolidation copy or host roundtrip. HTTP consumers explicitly download and retain compact snapshots until final encoding; device padding and activation storage need not be downloaded. Projection and normalization happen in the numerical program. Decision encoding similarly consumes final probabilities, not hidden activations.
The example deliberately reverses physical output rows. Correct client indices therefore prove that result mapping works rather than merely agreeing with a convenient device layout. Its independent arithmetic oracle also makes ragged packing and cohort association observable. See the finite-source contract for exact record layouts and ownership.
Retained text and staged images¶
Text uses one prepared model and cached stage set. Sessions are rows and storage references, not independent VM processes. Its source declares page/recurrent geometry and consumes packed spans that can mix prompt tokens, decode anchors and speculative verifier work. Token capacity and independently advancing span capacity are separate. The source reports completed progress; native ownership commits it after readiness.
Resident capacity grows independently of those epoch shapes. Source control
exports resize_state(control_state, resident_capacity), returning replacement
control state followed by the same five storage records used at preparation.
Existing private views, recurrent slots, and KV planes retain their byte offsets;
only the resident directory, its tables, and append-only storage grow. The native
owner joins accepted model work before growth. A task evaluates source layout
and allocates host session records, then the server owner submits native growth
and publishes the replacement after its queue frontier completes. Other models
remain schedulable throughout preparation and the asynchronous device wait.
Programs and weights remain loaded. Virtual backing
remaps the same physical slabs; fixed backing copies retained bytes at this cold
boundary and temporarily requires both allocations. Unused virtual capacity does
not acquire physical memory until request admission needs it.
Shared prefixes and explicit checkpoints keep immutable endpoint references. A branch needs a private recurrent writer without copying the entire KV prefix. The tiny text package exercises a partial-page frontier, an unconsumed pending token, fork/rewind, cancellation and full-replay equivalence. Those boundaries matter more than getting one unretained prompt to emit plausible text. The text service links the storage, epoch and chat-policy declarations beside their owners.
Cold image preparation selects stages and parameter domains for default geometry.
Warm source receives the requested height and width alongside prompt, seed, and
decoded adapter ID/scale records. It resolves IDs against its registrations,
validates geometry, and returns opaque request bytes with work and compatibility
facts. Compatible requests form one cohort; source batch preparation selects a
cold stage or declares stages through the same invocation-only prepare
capability as finite cohorts. Exact declaration sets reuse code within the
selected source generation; misses compile before parameter admission. Explicit
checkpoint declarations select retained banks or prepare independent banks on
demand; omitted declarations preserve the cold parameter layout. Stages within
one cohort share a parameter binding map.
Image control then drives command parts to final RGBA8. It returns a continuation cursor; another invocation occurs only after the previous accepted frontiers retire. Compiler-reflected workspace remains live across barrier-aligned parts. RGBA8 output and compiler-aligned workspace have separate cohort-sized pool allocations. Final feedback retains the output after workspace retirement. Each request keeps a stable output slice even if a peer is cancelled. Neither storage nor pixel geometry belongs to the executable cache. Final output is row-major RGBA8: four bytes per pixel in R, G, B, A order. Models perform their final quantization on device; native PNG encoding preserves those bytes, including alpha, using each request's dimensions. The image source contract defines entry signatures, alignment and cancellation.
Declare reasoning support¶
The text control program exports text_chat_reasoning_v1(), returning three
I32 values: whether reasoning is supported, a bitmap of selectable efforts, and
the effort ordinal used when a request omits controls. Preparation calls this
once and validates the declaration before publishing the model. The server
copies the resulting facts into discovery; it does not use them to interpret
requests or modify sampling.
Effort bits and ordinals are none=0, minimal=1, low=2, medium=3,
high=4, xhigh=5, and max=6. Source advertises the model's distinct policies,
not every accepted alias. A selectable ladder contains at least one reasoning
level, and its default must be in the bitmap. Non-reasoning models return
(0, 0, 0); reasoning models without an effort selector return (1, 0, 0).
For example, (1, 45, 0) advertises none/low/medium/xhigh with reasoning off by
default. The HTTP profile describes the discovery fields.
Tool-call translation¶
Text policy owns the generated grammar and canonical history. Its
parse_tools(schemas: buffer, response: buffer, truncated: i64) -> buffer root
returns function records with a name and an opaque argument string; generic
chat handling assigns IDs and encodes the same records for HTTP and SSE. The
server and model policy do not execute tools, enforce tool permissions, validate
executable arguments, or repair calls. Those operations belong to the harness.
Native admission passes model-specific request fields through without imposing
a tool-choice or template-option vocabulary. Source policy consumes the fields
needed for its own prompt, sampling, and output representation.
render_tool must preserve the call data when formatting the next turn, and
complete_text can authorize retained state reuse only when its canonical
bytes match the generated history.
truncated is one when generation reaches its token limit without EOS, and zero
after EOS. A truncated response can retain complete calls while omitting an
unfinished final call; its finish reason remains length, not tool_calls.
The original response reaches complete_text, including any omitted suffix,
so canonical history cannot authorize reuse of different generated bytes.
A source program can import
tools.parse_xml(schemas: buffer, text: buffer, truncated: i64) -> buffer for the
<tool_call><function=NAME><parameter=NAME>VALUE</parameter>…</function></tool_call>
grammar. This is an optional codec, not a model-wide protocol requirement.
It validates framing and UTF-8, preserves duplicate parameter members in order,
and uses property schemas only to distinguish representations:
| Hint | Argument representation |
|---|---|
| String, including string-capable unions | Literal text, even when it looks like a number or JSON. |
Explicit nullable hint with null text |
JSON null. |
| Non-string hint with a complete JSON value | Original JSON spelling, without numeric conversion or type enforcement. |
| Unknown property/tool, repeated tool name, opaque schema, or non-JSON text | Literal string. |
Hints cover direct types, nullable type arrays, and anyOf/oneOf branches;
they are not a JSON Schema evaluator or reference resolver. One framing newline
on each side of a parameter is removed; other string whitespace, JSON-looking
text, and XML entities remain literal. With truncated=1, an unfinished grammar
prefix at the end is omitted, and preceding complete calls are retained. No
closing syntax or argument data is invented. Malformed framing still fails the
complete call list without publishing a prefix; with truncated=0, unfinished
framing fails too. Missing required arguments, unknown names,
and schema-invalid values are representable calls for the harness to handle.
Other grammars can return argument strings directly, including malformed JSON,
provided their source history formatter can retain those strings faithfully.
Known-token stages¶
A sequence deployment uses retained rows, packed epochs, block pools, and
checkpoints without the generative chat contract. It consumes only supplied
known IDs and publishes source-defined opaque output. It can implement an
encoder or another retained stage; a source may also run a head and include its
result bytes explicitly, without asking the server to sample or feed them back.
Preparation retains the text model's nine-result ABI. The terminal-token marker
may be null. Control exports epoch, encode_epoch, publish_epoch,
encode_state, resize_state, bind_request, request_defaults, prepare_request, and
capture_epoch. Isolated step, tokenizer/chat roots, and drafting are not
required. Every submitted span has selection/proposal flags zero, and completed
progress contains no native output-token selection.
prepare_request(defaults, request, nonce, tokens) validates one complete
sequence request before row reservation or response streaming. tokens is a
read-only, reference-counted buffer of parsed little-endian nonnegative i32 IDs;
its byte length is four times the token count. The source checks vocabulary and
other model-specific input constraints here and returns its options buffer.
An input error rejects only this request with its diagnostic; retained histories
and other requests remain available. Validation covers the complete append,
including tokens beyond the first scheduled epoch. This call receives no row
state and must leave retained execution state unchanged. Source may retain the
token buffer in its returned options. Generative text's request_options
retains its three-argument contract; its source produces tokens in prepare_input.
Text and sequence plans are compact arrays of nine little-endian u32 fields
per span. The first epoch's records occupy [0, first_count); optional
continuation records immediately follow at first_count. A record's resident
state ID is independent of its plan ordinal. The continuation-flags argument to
publish_epoch is a buffer of little-endian u32 flags indexed by
first-plan ordinal, not a bitmask indexed by state ID. Source programs size
their tables and results from the requested resident and cohort capacities;
neither coordinate has a built-in sixteen-entry limit.
publish_epoch receives the retained control-state buffer as its first
argument, followed by the plan and completed feedback. It runs only after
successful epoch completion and can update source-owned history for subsequent
epochs, such as measured execution costs. The source owns this history's
layout and carries it through control-state growth. Submitted device work uses
its already-captured inputs; publication does not change those inputs or the
completed feedback banks.
encode_epoch receives the selected first-epoch and continuation token
capacities as first_packet_capacity and next_packet_capacity. These are
the prepared shapes, independent of live token counts and whether the inputs
contain media. The continuation capacity is zero when no continuation is
submitted. Source can use these values to lay out packets and associate
captured state with the prepared programs that consume it.
encode_epoch writes metadata and input packets, then returns
(output_count, transfer_plan, byte_offset, byte_length). The plan view contains
little-endian u64 records
{source_binding, source_offset, target_binding, target_offset, length}.
The source and target tables each bind metadata at ordinal zero and input at
ordinal one. Source and destination offsets are independent: compact host data
can populate a sparse device layout without transferring its holes.
Only listed bytes are uploaded:
preparing capacity for a large packed epoch does not make a one-token epoch
transfer that entire capacity. Source initializes all bytes its numerical
stages read. Nonempty records are ordered by target binding and offset, with
no overlapping targets. Repeated source ranges are permitted. Records describe
independent placements, not an ordered sequence of copies.
The plan names logical storage, not pointers, registrations, or completion handles. The execution owner binds physical resources and establishes readiness. The plan can reuse retained control state and is consumed during submission; packet bytes stay immutable until accepted transfers retire, including failure. Source reuse, destination visibility, and destination reuse after consumption are separate ownership boundaries. See the byte-placement contract for the encoding and validation rules. The same contract applies to generative text and media epochs. See epoch uploads for local HAL binding and payload ownership.
capture_epoch(control_state, shape_index, span_count, plan) returns a buffer
of little-endian i64 triples: [span_ordinal, residual_byte_offset, byte_length].
Ranges are grouped in submitted span order, with at least one nonempty range
per span. Multiple ranges concatenate in source order. The plan is checked and
copied before row mutation; output bytes are copied after the producer and
before the next epoch can overwrite the shared residual. See
capture ownership
for device views, readiness, and explicit host materialization.
Captured output owns its pooled storage and execution domain independently of the model, its weights, and retained rows. A downstream device consumer imports readiness and retains its view through queue retirement. HTTP uses a compact host snapshot and the sequence profile. Row IDs, request-relative input offsets, and packed activation offsets are different coordinates: the source must derive capture ranges from its actual packed layout, not treat a row or input offset as a physical output address.
Stream speech with independent requests¶
A speech package can share weights and numerical execution among clients while retaining each request's voice, cache history, RNG progression and playback position. Start with the speech walkthrough for a complete HTTP caller and a package whose output is independently checkable.
Cold preparation declares numerical stages and parameter domains, plus resident request capacity, additive batch capacity, input/state strides, conditioning storage, bounded output/feedback storage and waveform geometry. Those declarations separate persistent request storage from temporary batch geometry. A larger model can change its vocoder, diffusion schedule, cache layout or block size without teaching the HTTP service its architecture.
The warm source exports these operations:
| Operation | Source-owned result |
|---|---|
prepare_request |
Validate text, voice, instructions, seed and speed; return retained CPU state and immutable request bytes. |
prepare_work |
Describe one request's next operation with compact work bytes, positive additive units and a compatibility tag, without advancing it. |
prepare_batch |
Pack a compatible cohort and retain its plan, using explicit resident-row and byte-range records. |
generate |
Execute the plan through the prepared runner stages, optionally requesting bounded feedback. |
complete |
Interpret retired feedback for one original batch ordinal; publish playback position, sample range, frame count and EOF. |
The model declaration
owns the exact signatures, scalar widths and buffer layouts. prepare_batch
receives the prepared stage-tag catalog separately from the packed request work;
the source chooses its numerical stage and packing representation.
Speech ABI 2 adds reusable uploaded voices. speech_prepare_v2 appends
voice_capacity and voice_audio_capacity to the eleven scalar preparation
results, followed by the existing four metadata buffers. The latter capacity
bounds decoded original F32 audio bytes. Initial conditioning can populate a
prefix of the declared conditioning buffer; the service copies it once.
speech_prepare_voice_v2(model, slot, samples, rate, channels) runs on a CPU
worker with interleaved F32 audio at its original rate and channel count.
The shared decoder has checked complete frames and finite normalized samples.
The program owns model-specific mixing, resampling, trimming, and resource
limits. It returns an opaque voice buffer, retained upload state, and immutable
request bytes. Learned encoding then uses the ordinary prepare_work,
prepare_batch, generate, and complete lifecycle. Upload completion publishes
no audio; EOF publishes the voice only after accepted work retires.
speech_prepare_request_v2 receives that opaque voice buffer in place of a
voice-ID string. The native service maps IDs to slots and captures each voice
at admission, including queued requests. Removing an ID hides it immediately
but preserves conditioning for captured readers. A slot has one preparation
writer and is reused only after that writer and every reader retire. Programs
need neither a name table nor a second readiness protocol. The other roots use
the same speech_*_v2 suffix. Speech ABI 1 retains its source-defined voices and
rejects uploads.
Consider a request A already decoding when B arrives with another voice and a longer prefix. B first runs its required conditioning and prefix work. At a retired boundary, the service queries ready requests again. If A and B offer equal compatibility tags and their total work fits, they can share the next batch while retaining distinct cache positions. If their current phases need different numerical work, they advance in separate cohorts. Compatibility is a fact established by the package's kernels; the service cannot infer it from two opaque generation calls or from matching output formats.
Five dynamic roots give numerical programs compact batch work, stable request rows, shared conditioning, stable stream rows and packed output. Changing batch membership changes the small work description and row mapping; it does not move entire request histories. Compiler-private workspace belongs to the current command. Persistent convolution tails, recurrent state, KV caches and solver history belong to the request's stream row or explicitly owned conditioning.
One accepted batch retains its original row mapping through execution and
collection, even if a client cancels. complete runs for every original ordinal,
including phases with no audio or readback. A zero-frame result is independent
of EOF. Native serving checks the published range, converts samples to the wire
format and copies each result into that request's bounded output storage before
releasing shared feedback. A stalled client then prevents only its own next
operation from becoming eligible.
Shared conditioning has a publication boundary too. A voice entry becomes reusable only after its producer retires, and its storage remains valid while accepted readers use it. Per-request RNG state must produce the same sequence regardless of neighboring requests or their scheduling. The model owns these numerical invariants; the service owns admission, output credit and retirement.
Qualify a port with staggered requests of different lengths and voices, changing batch membership, a stalled reader, cancellation during an accepted batch and reuse of the released row. Compare each surviving stream with isolated execution and compare the model's numerical stages with an independent reference. Batch occupancy alone establishes neither a throughput improvement nor a playback deadline.
Image-conditioned text¶
A text definition's optional image component implements the finite contract. It shares the deployment's device and numerical provider catalog, while owning separate preparation and parameter residency. Ordinary text and exact retained image-prefix hits do not prepare the projector. Explicit component warmup follows the same preparation boundary. Its parameter pin policy is independent of the primary language model's policy; deactivation does not discard retained text state.
The text control program declares image limits and receives ordered content records plus a message-local frame table. Each media part names a contiguous frame range; each frame supplies display geometry and a presentation timestamp. An ordinary image has one frame with timestamp zero. The source chooses projection groups within each part, renders their model framing, and returns an explicit group count, marker ranges, projected row counts, and opaque preprocessing metadata. Native code validates complete, ordered coverage of the inspected frames before committing the plan. Input preparation then maps those projections into logical input spans. The ordered-media contract defines these records and retained identity.
On a media-prefix miss, codecs realize packed RGB8/RGBA8 pixels without resizing or normalizing them. The projector receives an image request packet containing a plane directory, encoded/display geometry, orientation, source metadata, and pixels for every frame in the group. Its device program owns preprocessing and projection. Compatible images from the same request or different requests share finite cohorts; source work units and compatibility tags govern packing, not a native assumption of one image per invocation.
Projection identity includes every frame's compressed content and timestamp, its part placement and detail, the selected grouping, and source preprocessing metadata. Retained reuse compares the identity established when the plan was accepted. For example, a model that pads an odd final frame by using it twice must recompute that last projection when a second frame is appended. Earlier complete pairs remain eligible for prefix reuse when their preprocessing and prompt placement are unchanged.
Projected rows remain on the device. The language epoch imports producer
readiness and gathers only the rows its current spans need. Source
encode_epoch maps those rows and ordinary tokens into its input packet and
owns the position information consumed by its numerical stages. The
media epoch contract
defines the host control records separately from device features. Projector
weights and completed features have independent lifetimes; live requests retain
features only until their language consumers finish.
With a finite serving memory limit, the projector's cold preparation selects a
control entry with prepare.memory_forecast(root). The selected function has
this signature:
The three inputs are buffers. The range table uses little-endian i64 offset/length pairs for descriptors containing image headers and source metadata, without decoded pixel planes. The three results are nonnegative i64 byte estimates for the complete logical request: the producer's private peak (parameters, activation staging, input and command workspace), all retained output roots, and gathered output rows with 16-byte row alignment. Retained output is excluded from the private peak and includes padded/shared roots; gather storage includes separate copies of aliased rows.
A logical text request can join one projector cohort shared with peers. Its other cohorts contain only its own projections. The retained-output estimate can therefore include private projection output plus one maximum cohort root, instead of multiplying every projection by the maximum peer count. Compatible frame pairs within a video continue to batch across the request's private cohorts.
These trusted source estimates let the server reject a request that cannot fit alone before pixel decoding or weight activation. It checks producer and language-consumer phases separately. The forecast does not reserve future capacity against concurrent requests; each phase still passes ordinary admission.
Recognize continuing audio¶
A recognition package accepts a continuing sequence of normalized F32 PCM frames
and explicit end-of-input. Input packet boundaries do not pad audio or finalize
an utterance. Each request retains its own sample clock, convolution history,
encoder state, decoder cache and transcript revisions as batch membership changes.
A source can also publish speech activity probabilities, either alone or together
with transcripts. Native callers explicitly select supported output types.
The recognition deployment role requires transcript support and exposes HTTP
transcription. The activity role requires activity support and serves native
streams without an HTTP inference endpoint. Both use the same preparation,
batching, input credit, and retirement contracts; compound sources can share
their weights and execution across different output selections.
The recognition model declaration owns entry signatures and binary layouts. Cold preparation declares stages, parameter domains, sample geometry, bounded input/event storage, recording limits, resident rows and additive batch capacity. Warm source operations are:
| Operation | Source-owned result |
|---|---|
prepare_request |
Validate language, prompt and temperature; receive the selected output types and retain independent request state and immutable conditioning. |
prepare_work |
Inspect a bounded PCM snapshot with its absolute sample position and EOF flag; offer compatible numerical work or zero units while awaiting input. |
prepare_batch |
Pack ready work using explicit resident-row and byte-range records, retaining original cohort order. |
generate |
Submit one source-selected numerical phase without waiting for device completion. |
complete |
Acknowledge consumed input and publish a bounded ordered packet of typed events, independently of request completion. |
Acknowledgement returns input credit only after actual execution retirement.
Source code owns any PCM needed beyond prepare_work; the snapshot itself is
borrowed only during that call. Every accepted cohort member is collected,
including cancelled requests, before shared feedback or request rows can be
reused. A stalled event consumer excludes only its own request from new
work. Source-defined compatibility permits requests at different sample or token
positions to share a batch when their next operations support it.
Cold preparation declares supported output types, maximum packet bytes, and maximum events per completion. A request selects a nonempty subset; an unrequested event is a source error. The completion buffer and its produced byte extent are separate, allowing the source to reuse output capacity across different counts. Native collection copies the packet into reusable request-owned storage before another source call can overwrite it. Events remain independently observable, even when several revise the same transcript segment. Consuming the entire packet returns that request's output credit. Final events can outlive model removal.
An activity event covers a positive interval of actual input and supplies a finite
speech probability in [0,1]. When activity is requested, each completion's
observations partition its acknowledged input prefix in order, without gaps or
overlap. Source programs retain future context as unconsumed input until its
observation is established; intermediate numerical phases can acknowledge zero
frames. The declared input window includes that lookahead. This lets callers
retain bounded pre-roll while the source chooses its own numerical work.
Coverage is not an exact onset, offset, or word boundary. Turn thresholds and
hangover belong to the caller's policy; source code owns numerical state and
EOF handling.
Each transcript segment has a stable request-local identity, increasing revision, covered sample interval and replacement UTF-8 text. Finalizing a segment makes its text and metadata immutable. Request completion requires every published segment to be finalized. A source can additionally provide speaker labels and word alignment; an input-coverage interval alone does not establish where words were spoken. Consumers preserve these distinctions instead of converting a revisable hypothesis into an append-only text delta.
The finite HTTP adapter decodes enabled WAV, MP3, and FLAC containers into the same bounded F32 input used by raw PCM. Encoded input supports channel conversion and filtered resampling on shared CPU workers. Raw PCM also supports filtered resampling without an audio codec dependency, with matching channel counts and an exact rational sample clock; model feature extraction, numerical stages, and transcript policy remain source responsibilities. Each upload owns its codec history independently of source batch membership, and accepted decode work retains that state until retirement. Packet and worker boundaries preserve filter history. Explicit input EOF flushes lookahead without extending the recording's duration.
The adapter selects transcript output, consumes revisions, and returns the completed document. Typed consumers can apply revisions as they arrive and independently supply more PCM. Qualify a model with isolated reference transcripts, staggered arrivals, different recording lengths, a stalled reader, accepted-work cancellation and row reuse. Compound-output sources also preserve event ordering and earlier revisions within a single packet. Compare text and sample clocks across changing cohorts, including a final partial model frame.
Make parameters and temporaries visible¶
Command stages declare fixed checkpoint domains and preparation policies. Stages sharing a weight bank must agree on reflected placement. Preparation indexes checkpoint metadata; activation streams and transforms weight payloads into final storage. Warm requests reuse those plans. Deactivation can release reloadable backing without discarding compiled code or retained session state.
The embedding package's weighted variant and policy demonstrate adding a checkpoint-backed head without native model code. Comparing the checkpoint's actual shapes/types with the numerical oracle is part of the port; current key/extent checks do not establish model identity.
Private command workspace comes from compiler reflection and queue-ordered allocation. It is not a permanently resident per-session tensor arena. Under elastic backing it draws from the same physical pool and serving budget as parameters and model state. Stable workspace addresses can survive physical trim without retaining the pages. Prepared working-set peaks drive admission; the physical slab size determines the minimum commitment, not each small logical allocation's size. Escaping output remains live through its final device or transfer consumer; copied host feedback survives CPU encoding. A slow network reader receives copied response storage rather than retaining device workspace.
Finite direct-dispatch stages instead take input/output buffers and own their device-local working storage. The resident XDNA example uses this path. These direct stages have no checkpoint-domain binding in the current source contract; weighted direct programs need an explicit source-owned parameter-placement contract, not a guess from native argument reflection. The ordinary weighted command example and unweighted resident example prove different boundaries.
Establish correctness before throughput¶
Start with the selected package's deterministic output and replace one numerical stage with the intended model operation. Checks can compare functions directly with independent VM oracles; kernel checks specify an appropriate oracle rather than copying candidate output into a golden. Correctness workflows cover functions, cases and scenarios.
A complete port then establishes final outputs through the same server binary using an external package directory. The useful cases include ragged inputs, different request sizes, cancellation during accepted device work, a failed request followed by successful reuse, and unregister/re-register. Retained text also compares append/fork/rewind against full replay. A compilation-only success does not establish these ownership or numerical contracts.
Agent-driven kernel development and compile reports provide the optimization loop once correctness is measurable. Real model shapes, memory traffic and independent error bounds guide layout, traversal, fusion and specialization. Microkernel speed is one input; server observations and end-to-end useful throughput determine whether the change helps the workload.