Skip to content

loom-serve

loom-serve serves source-defined models over HTTP. There is no subcommand and no built-in model. Devices are explicit process resources; model registrations have independent lifetimes.

loom-serve --device=URI [--model=path/model.json ...] [options]
loom-serve --device=task --pool_backing=fixed --listen=127.0.0.1:8080
loom-serve --flagfile=serve.flags
loom-serve --help
loom-serve --agents_md

The serving walkthrough reaches a first response without weights. Stream speech receives incremental audio and explains how voices share numerical batches while advancing independently. Audio transcription accepts recorded audio, and the client guide describes upload formats and Open WebUI dictation. Model documents specify programs, assets, placement and per-model capacities. Author model programs describes preparation, execution and the contracts for adding a model package. The operation and observation workflows describe lifecycle controls, pressure, counters and telemetry cursors.

Process options

Flag Default Meaning
--device=URI Required, repeatable HAL device URI; encounter order defines device indices.
--model=path None, repeatable One JSON deployment document per value; omission starts empty.
--listen=address 127.0.0.1:8080, repeatable Numeric IPv4 host:port, IPv6 [host]:port, or unix:path.
--workers=N 8 Shared CPU workers for JIT, model scheduling and media work.
--model_capacity=N 32 Registered names, including drained, failed and removing entries.
--connections=N 64 Simultaneous admitted HTTP connections across all listeners.
--held_requests=N -1 Closed-gate holding credit; -1 selects half the connection limit, 0 rejects rather than holds.
--request_body_bytes=N 8388608 Maximum HTTP body bytes per connection.
--heartbeat_ms=N 1000 Per-model stderr JSONL heartbeat interval; 0 disables periodic reporting, not cumulative counters.
--workspace_idle_ms=N 0 Trim reusable command-workspace backing after the device's last workspace allocation retires and stays idle for this interval; 0 disables expiry.
--parameter_idle_ms=N 0 Deactivate unpinned elastic model weights after this idle interval; 0 disables expiry. Sessions and KV/prefix history survive.
--pool_backing=elastic\|fixed elastic Shared demand-committed parameter/state/workspace slabs or eagerly backed retained storage.
--weight_slab_bytes=N 1073741824 Reusable elastic parameter and shared-workspace slab size in bytes (1 GiB); loading uses independent bounded read windows. 0 uses the allocator recommendation. Ignored for fixed backing.
--state_slab_bytes=N 67108864 Elastic mutable-state commitment/reclamation size in bytes (64 MiB); 0 uses the allocator recommendation. Ignored for fixed backing.
--memory_bytes=N 0 Shared serving-managed physical parameter/state/workspace limit; 0 imposes no serving limit.

Model, connection and body capacities must be positive. Holding credit must remain below connection capacity. Heartbeat/idle intervals, slab sizes and memory limits are nonnegative. A nonzero memory limit requires elastic backing and exactly one device: independent device pools cannot enforce a shared byte limit. Invocation input/output storage and command workspace share this limit with parameters and mutable model state. Host snapshots, other host allocations and driver overhead remain outside it; it is not a whole-process or whole-device memory cap.

--help shows serving options; --help=all also shows linked runtime options. --agents_md prints compact integration guidance without initializing devices. Unexpected positional arguments fail instead of being interpreted as models.

Devices and listeners

Repeated devices form one ordered group. Each model selects one group member through its top-level device index; omission is accepted only for a singleton group. A URI is resolved by its linked HAL driver. The server neither chooses an implicit device nor falls back to a different backend.

Device URI query parameters request immutable runtime services. feedback provisions device-to-host diagnostics used by authored kernel assertions and other UBSAN-style reports. asan and tsan provision address- and race- sanitizer state and start the report transport each requires. They are bare, additive parameters. --device=amdgpu:?feedback configures the default AMDGPU device, while --device=amdgpu://GPU-0e12865a3bf5b7ab?feedback&asan configures a specific device. ?feedback&asan&tsan is also valid; explicit feedback adds general authored diagnostics to the sanitizer services. A backend that cannot provide a requested service rejects the URI during device creation.

Models on one device share its memory budget and provisioned queues. Each loaded model holds a queue assignment until its last execution reference retires. New assignments choose the fewest live model executions in each selected queue family; removing and reloading a model reuses the available inventory. A single-queue device is supported, and models share queues when there are more live executions than queues.

For independent AMDGPU model submissions, provision extra queues at startup:

loom-serve --device='amdgpu://0?queue_count=2' \
  --model=models/chat/model.json --model=models/speech/model.json

Both model documents select the same device and share its storage and residency policy. queue_count defaults to one per selected GPU and remains fixed for the device lifetime. Separate queues allow independent submissions to overlap, but do not reserve compute or memory bandwidth and provide no latency guarantee. Assignment counts live executions; request batching and residency pinning remain separate controls. Vulkan uses its provisioned inventory, and task devices use the application's shared CPU workers.

The model's native source must compile for that device. task uses native x86 CPU execution. AMDGPU and Vulkan require the corresponding compiler target, HAL driver and supported hardware. XDNA packages use resident direct-dispatch programs rather than assuming a GPU command program also runs on the NPU. Device-group membership alone does not distribute a model or share its memory between members.

Elastic backing supports shared physical-memory budgets and reclamation of idle, unpinned parameters on task and AMDGPU. It requires virtual reservations, mapping-source allocations, and bind/unbind operations from the selected device. Task uses host virtual memory where available; Vulkan requires suitable sparse-memory capabilities. Fixed backing eagerly retains storage and does not support parameter deactivation or a serving physical-memory budget.

Elastic command workspace preserves its virtual ranges across model changes and physical trim. Logical queue allocations reuse those ranges; physical backing shares the model-storage pool rather than a separate scratch budget. Idle workspace is reclaimed before reloadable model data under pressure.

Elastic backing fails during device-group initialization when the required mapping capabilities are unavailable. Model-specific resource requirements are checked during preparation. Neither path silently changes the memory policy. Address-sanitized devices require fixed backing so their allocations can be published to the sanitizer shadow state.

All listeners share one catalog, worker pool and connection budget. A port of zero requests an ephemeral port. One JSON ready record is written to stderr for each bound address after every startup binding succeeds. An occupied Unix socket path is a startup error; successfully owned paths are removed on teardown.

loom-serve --device=task --pool_backing=fixed \
  --listen=127.0.0.1:8080 --listen=unix:/srv/run/loom-serve.sock
curl --unix-socket /srv/run/loom-serve.sock http://localhost/v1/status

The socket's parent directory must exist and permit creation. The same HTTP protocol runs over TCP and Unix sockets; the localhost origin in this curl command does not select another server over TCP.

Flagfiles and paths

An ordinary flagfile contains one literal flag per line:

--device=task
--pool_backing=fixed
--listen=127.0.0.1:8080
--model=/srv/models/vectors/model.json
--model=/srv/models/scout/model.json

Run loom-serve --flagfile=serve.flags. Scalar values use the last occurrence; repeatable flags accumulate in encounter order. There is no shell expansion. Relative flagfile and model arguments use the process working directory, including arguments read from a flagfile. References inside a model document instead use that document's directory or its explicit base_directory.

Readiness, errors and trust

/healthz and /readyz describe server availability. /v1/status reports every registration and its preparation or failure state. /v1/models lists prepared deployments and their capabilities. A model registration's HTTP 202 means accepted intent, not completed JIT or weight loading.

A bad source package remains inspectable while peers keep serving. An accepted native failure affecting shared resources stops admission and drains accepted work. SIGINT/SIGTERM likewise joins actual asynchronous work before destruction; there is no arbitrary deadline that makes in-flight device storage safe to free.

The server has no built-in authentication, authorization or TLS termination. Registration executes trusted source and accesses server-local assets; it is not a source sandbox. Loopback, socket access controls, tunnels or an external proxy establish the deployment's trust boundary.