Inference server

orangu-server loads a GGUF model and serves an OpenAI-compatible HTTP API — both the OpenAI-compatible endpoints (/v1/chat/completions, /v1/completions, /v1/embeddings, /v1/models) and its own native ones (/health, /props, /slots, /metrics, /completion, /tokenize, /detokenize, /embedding, /apply-template).

orangu-server is the inference engine: GGUF loading, tokenization, the transformer forward pass, sampling, and request scheduling are implemented directly in Rust, with no dependency on llama.cpp/ggml’s own compiled code. orangu-coordinator (see the Coordinator chapter) sits in front of it, starting and stopping an orangu-server process on demand for machines that only have the resources to keep one model resident at a time — this chapter covers orangu-server itself.

It’s also the machine’s GGUF inventory tool — the system/suggest/ list/show/download/delete subcommands (below) answer the questions that matter when getting, choosing, and cleaning up a model, before or after serving. Those six read (or write) GGUF files directly off disk and query the local machine, no model loaded and no HTTP listener bound; download talks to the Hugging Face Hub to fetch a model, and list talks to it too — before printing its table, to check whether a newer commit exists for each Hugging Face-backed model already on disk (see list and show below). If the Hub is unreachable, list still prints the table; it just skips the check silently rather than failing the command.

Quick start

orangu-server unsloth/gemma-4-E2B-it-GGUF

The model argument is resolved the same way show/download resolve one: an existing local .gguf path, an NR/MODEL label already under the configured models directory (see orangu-server list), or a <user>/<model>[:quant] Hugging Face repo — fetched into models first if it isn’t already cached there. No separate download step is needed.

Leave it off entirely and orangu-server lists every .gguf model under the configured models directory and prompts for one by NR, then — unless --all/--code/--review/--explorer/--embedding was passed — prompts for a role too (see below), TAB-completing over the five valid names (dropdown-style: an empty TAB press lists all five) and defaulting to all on an empty entry:

orangu-server
NR  MODEL                            QUANT   SIZE        SUPPORTED
 1  Qwen/Qwen2.5-0.5B-Instruct-GGUF  Q4_K_M  468.64 MiB  Yes (qwen2)
 2  unsloth/gemma-4-E2B-it-GGUF      Q4_K_M  2.89 GiB    Yes (gemma4)

Select a model (NR): 2
role [all]: 

When the directory holds exactly one model there is nothing to choose between, so the NR prompt is skipped — the table is still printed (it names the model and whether this build supports it), and the run goes straight on to the role prompt:

NR  MODEL                            QUANT   SIZE        SUPPORTED
 1  Qwen/Qwen2.5-0.5B-Instruct-GGUF  Q4_K_M  468.64 MiB  Yes (qwen2)

model: Qwen/Qwen2.5-0.5B-Instruct-GGUF:Q4_K_M
role [all]: 

On startup, orangu-server prints the same CPU/GPU report system does, followed by the model/UI/API/workspace summary:

CPU
  Model            : AMD Ryzen 7 4800H with Radeon Graphics
  ...

GPU
  [0] AMD Navi 14 [Radeon RX 5500/5500M / Pro 5300/5300M/5500M]
      ...

Model      unsloth/gemma-4-E2B-it-GGUF:Q4_K_M (llama arch, CPU/AVX2, 26 layers, 8192 ctx)
UI         disabled
API        http://0.0.0.0:8100
Workspace  /home/user/src/orangu

The model line names the model as MODEL:QUANT — the quantization the resolved file is actually stored at, the same value list’s QUANT column shows, appended unless the model was named with a :tag of its own already. Its second field names the backend the forward pass actually ran on: CPU/CPU/AVX2, or Vulkan/<adapter name>, CUDA/<device name>, OpenCL/<device name>, ROCm/<device name> when the matching GPU backend was used (see GPU backend below). The workspace line is the directory tree this server operates in (see Workspace below).

Every completed request logs a throughput line, orangu-server-style:

orangu-server: [slot 0] prompt 42 tokens in 0.18s (233.33 tok/s), generated 128 tokens in 4.31s (29.70 tok/s)

GGUF inventory

Six subcommands cover getting, choosing, and cleaning up a model, all sharing the same orangu-server.conf and its models directory (see Configuration below).

download fetches a model from Hugging Face into the configured models directory, laid out exactly the way llama.cpp’s own -hf/--hf-repo downloads into — models--<user>--<model>/{blobs,refs,snapshots}, content-addressed blobs with a relative symlink per file — so list/show already read what this writes, and llama.cpp itself recognizes it as already downloaded rather than fetching it again:

orangu-server download unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF:Q4_K_M
orangu-server download ggml-org/embeddinggemma-300M-GGUF   # no :quant -> prefers Q4_K_M, then Q8_0
Downloading Qwen3-Coder-30B-A3B-Instruct-Q4_K_M.gguf: 47% [1/1]

If the repository also ships a multimodal projector (mmproj-*.gguf, needed for vision/audio input), it’s fetched alongside the model too — the same best-matching one orangu-server’s own -hf would auto-fetch on first launch anyway, so LLAMA_CACHE=<models> already has it ready offline instead of needing a live fetch the first time a vision-capable model is launched. A multi-part model’s every shard (and a bundled mmproj) downloads concurrently rather than one at a time; an interrupted download resumes from where it left off next time. Set HF_TOKEN in the environment for a private or gated repository.

system detects the machine’s CPU and GPU(s) — the same report printed at the top of every attached orangu-server startup (see Quick start above):

orangu-server system
CPU
  Model            : AMD Ryzen 7 4800H with Radeon Graphics
  Vendor           : AuthenticAMD
  Architecture     : x86_64
  Physical cores   : 8
  Logical cores    : 16
  Frequency        : 4.29 GHz
  Memory total     : 62.19 GiB
  Memory available : 36.19 GiB

GPU
  [0] AMD Navi 14 [Radeon RX 5500/5500M / Pro 5300/5300M/5500M]
      Memory type  : Dedicated
      VRAM total   : 3.98 GiB
      VRAM used    : 3.71 GiB
      Driver       : amdgpu

GPU detection has no single cross-platform API, so it layers several best-effort sources: nvidia-smi for NVIDIA (Linux and Windows), Linux’s /sys/class/drm for everything else on Linux (AMD, Intel, and any other PCI display device), and native OS tools (system_profiler/PowerShell’s Win32_VideoController) on macOS and Windows. A machine where none of them finds anything gets no GPU section at all — the CPU inventory is the whole report — rather than a heading over a “none detected” line. Memory type tells apart a genuine dedicated card from an integrated GPU/APU sharing the CPU’s system RAM — a Shared GPU’s VRAM total is always reported as the machine’s total system RAM regardless of what its own platform query said, since that’s the real ceiling on how much it can actually draw on.

suggest estimates a GGUF model size (parameter count, not a specific model yet) likely to run comfortably on this machine, printed as a table — one row per context length, one column per quantization — sized against two budgets: dedicated GPU VRAM alone (its table is skipped entirely on a machine with no dedicated GPU at all, rather than printing a useless 0 B budget of nothing but -), and every GPU’s memory combined:

orangu-server suggest
Suggested model size (Dedicated)
  Estimated budget : 3.98 GiB

  Context  Suggestion (Q2_K)  Suggestion (Q4_K_M)  Suggestion (Q8_0)
  -------  -----------------  -------------------  -----------------
  1K       ~9B parameters     ~4B parameters       ~3B parameters
  ...

The memory-estimation formula mirrors Sam McLeod’s GGUF VRAM Estimator: model weight bytes scale as parameters × bits-per-weight ÷ 8, KV cache bytes scale with context length × layers × hidden size, plus a small fixed runtime overhead.

list recursively scans the configured models directory for .gguf files and prints one row per model (a multi-shard model collapses into a single row, with SIZE summed across shards):

orangu-server list
NR  MODEL                                        QUANT   SIZE        SUPPORTED
 1  unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF    Q4_K_M  17.28 GiB   Yes (qwen3)
 2  unsloth/Qwen3-Coder-480B-A35B-Instruct-GGUF  Q4_K_M  270.14 GiB  Yes (qwen3)
 3  ggml-org/gemma-4-12B-it-GGUF                 Q4_K_M  7.14 GiB    Yes (gemma4)
 4  unsloth/GLM-5.2-GGUF                         Q4_K_M  433.83 GiB  No (glm-dsa)

NR numbers models in the printed order, starting from 1 — a shorthand for show so you don’t have to retype a long MODEL string. When a file was downloaded by -hf/--hf-repo, MODEL is the repo id to hand back to -hf: <user>/<model>. The :quant tag is left off — QUANT shows it in the next column — so two quantizations of one repo print the same MODEL and are told apart by their QUANT cells. Both spellings resolve against what’s on disk, so unsloth/gemma-4-E2B-it-GGUF and unsloth/gemma-4-E2B-it-GGUF:Q4_K_M name the same local model; use the tagged form (or the row’s NR) to pick one particular quantization of a repo that has several, and to ask for one that isn’t downloaded yet. A multimodal projector (“mmproj”) sidecar file doesn’t count as its own model — it’s meant to be loaded alongside a base model, not to stand in as one.

SUPPORTED says whether this build can actually load the model’s architecture — Yes (<arch>) or No (<arch>), where <arch> is the GGUF general.architecture (e.g. qwen3, gemma4, glm-dsa). A No row (like the glm-dsa one above) is printed greyed rather than hidden: you can still select it, but loading it will fail with a clear “not yet supported” error, so the column tells you that up front. The greying is only emitted to a terminal — piped or redirected output stays plain text, so the shell completion scripts that read list by column keep working.

show prints a GGUF file’s full metadata — every key/value pair in the file, not just the well-known keys. Omit the argument entirely to pick one interactively (list’s own table, then an NR prompt):

orangu-server show 3                                     # NR from `list`
orangu-server show unsloth/Qwen3-Coder-Next-GGUF          # MODEL from `list`
orangu-server show Qwen3-Coder-30B-A3B-Instruct.gguf      # bare name under `models`
orangu-server show ./relative/or/absolute/path.gguf
orangu-server show 3 --tensors   # also list every tensor's shape/type/offset
orangu-server show 3 --full      # print full arrays instead of a preview
orangu-server show               # no argument: list, then pick an NR interactively

Array-valued metadata (e.g. tokenizer.ggml.tokens, which routinely holds well over 100,000 entries) is truncated to a short preview by default — --full disables that. Tensor data itself is never read, only the header, metadata, and tensor-info table, so list/show stay fast even against multi-gigabyte model files.

delete removes a model from disk, resolving its argument the same way show does (or, omitted, the same interactive list + NR prompt bare orangu-server uses to pick a model to serve — here picking one to remove instead), and always against every shard the model is made of, so a multi-shard model is deleted atomically rather than leaving orphans behind:

orangu-server delete 3                                     # NR from `list`
orangu-server delete unsloth/Qwen3-Coder-Next-GGUF          # MODEL from `list`
orangu-server delete                                        # no argument: interactive
Delete 'unsloth/Qwen3-Coder-Next-GGUF' (Q4_K_M, 4 files, 17.28 GiB) from /home/you/models? [y/N]: y
Deleted 'unsloth/Qwen3-Coder-Next-GGUF' (Q4_K_M, 4 files, 17.28 GiB)

Asks for confirmation first ([y/N], defaulting to No) unless -y/--yes is given. When a file lives under a Hugging Face hub cache, its target blob is reclaimed too — but only when no other snapshot left in that repo still references it — and any now-empty snapshots/<rev>/ or models--<user>--<model>/ directory left behind is cleaned up, never anything above the configured models directory itself.

Configuration

orangu-server.conf:

[orangu-server]
models = ~/models
model = unsloth/gemma-4-E2B-it-GGUF:Q4_K_M
host = all
port = 8100
slots = 1
web = 8101
backend = auto
role = all

-c/--config picks a config file explicitly; without it, ./orangu-server.conf then ~/.orangu/orangu-server.conf are tried, in that order — the same order every subcommand above resolves it in too, not just serving. -i/--init writes ~/.orangu/orangu-server.conf interactively — it also prompts for role (TAB-completing over the five valid names, defaulting to all), right after model, and only writes the role = line when a non-default value was chosen. A models directory that doesn’t exist yet is created, parents included, rather than refused. -d/--daemon detaches from the terminal and runs in the background (Unix-only) — it requires model to be set in the config, since there’s no attached terminal left to pass a CLI argument to or prompt on; the config and model are resolved, and both listeners bound, before detaching, so a bad config or a port already in use is still reported to the invoking terminal rather than silently lost. -h/--help and -V/--version are also available. -s/ --shell-completions prints a bash/zsh/fish completion script for the shell detected from $SHELL — covering every flag above, the six subcommand names, and the positional model argument plus show’s and delete’s own arguments, the latter three completed by shelling out to orangu-server list itself. -w/--workspace completes directories (only), and -c/--config any file, in all three shells.

Workspace

-w/--workspace sets the root directory orangu-server operates in — the same concept, spelled the same way, as orangu’s own -w/--workspace (see the Workspaces chapter):

orangu-server -w ~/src/orangu unsloth/gemma-4-E2B-it-GGUF
orangu-server --workspace ~/src/orangu unsloth/gemma-4-E2B-it-GGUF

It is a run-time parameter only — there is no orangu-server.conf key for it. Without the argument the current working directory is used. Either way the path is made absolute against the directory the server was started in and normalized (. and .. segments folded away, symlinks left alone), then checked to be an existing directory — a typo fails at startup, while there’s still a terminal to report it on, rather than at first use. With --daemon this all happens before detaching, so a relative path still means what it meant in the launching shell.

The resolved path is printed on the startup banner, reported as workspace by GET /props, and included in the web UI’s saved debug report. It is the root every workspace-scoped feature operates in: the file-lifecycle API (the five *_file and three *_directory endpoints — see Endpoint reference below) refuses any path that resolves outside it, and the features built on top of it later will do the same.

Roles

--all/--code/--review/--explorer/--embedding (mutually exclusive; --all is the default) hint at which of orangu-server’s own features matter for a given deployment. These mirror orangu’s conventional deployment roles (all/code/review/explorer/embeddings), but a single orangu-server process serves whatever model it’s given rather than picking one — so unlike a real orangu-server process per role, this only adjusts the handful of things that are actually role-specific in an engine that doesn’t have orangu-server’s --fit/--tools/--webui-mcp-proxy/ -sm/--cache-reuse/-ctk/-ctv equivalents at all:

code behaves identically to all today — no orangu-server feature is code-specific yet beyond what all already provides.

The role in effect is, in order: whichever CLI flag was passed; or, if none was and this is an attached run with no model given on the command line either, whatever’s typed at the interactive role [all]: prompt; or, in --daemon mode only (no attached terminal to prompt on), the config file’s own role key; or, failing all three, all.

GPU backend

orangu-server can run the forward pass on a GPU as well as on the CPU. Four GPU backends are available, chosen via backend in the config (or auto, the default — see Configuration above for the fallback order):

On macOS, backend = auto automatically detects the machine and runs on CPU, no configuration needed.

Naming a backend explicitly fails to start rather than silently falling back to the CPU, for when GPU inference was asked for specifically. Startup prints which backend actually ran the model (see Quick start above).

Web UI

Set web in the config (or at the web prompt in --init) and visit http://<host>:<web>/ for a small built-in chat UI: an input box, a scrolling transcript, a New Chat button, and a History button that lists previous chat sessions — sessions with no messages in them are left out, so History only ever shows conversations that actually happened. It’s a plain server-rendered HTML/CSS/JS page (no build step, no WASM) served by the same binary — a chat turn calls straight into the model in process, never making an HTTP hop to the API’s own port.

Each assistant reply is rendered from markdown to HTML server-side, including syntax-highlighted fenced code blocks.

While a reply is streaming in, the Send button becomes a Stop (×) button; clicking it cancels the request. Whatever text had already streamed in stays on screen, marked as stopped, but since the turn never reached completion it isn’t saved — a stopped reply won’t reappear if you reload or revisit it from History.

Chat sessions persist as one directory per session at ~/.orangu/server/sessions/<uuid>/chat.json, so History survives a restart.

Session management

orangu-server prune            # list sessions, pick one (or 'all') interactively
orangu-server prune all        # delete every non-active session
orangu-server prune <uuid>     # a specific session, by NR or full id

prune deletes chat sessions from ~/.orangu/server/sessions/. Needs no config file and loads no model. Every invocation, regardless of its own argument, first removes any non-active session with an empty chat history (a New Chat click that was never sent to) and any persisted slot KV-cache file (~/.orangu/server/<fingerprint>/slots/, written by the ?action=save endpoint) untouched for over 30 days, reporting the space reclaimed. Those slot files are a pure reprefill-avoidance cache, so an over-eager sweep only ever costs a one-time prefill; age is used rather than session-liveness because a slot file is named by the client’s session id, which the server can’t cross-reference. With no argument, it lists the rest as a numbered table, newest first, and prompts for an NR or all; all deletes every remaining session except active ones — sessions a currently-running orangu-server is still using, checked live against the process table each time prune runs, not a snapshot from startup. Naming an active session explicitly refuses rather than deleting it. -y/--yes skips the confirmation prompt, the same flag delete uses.

Shutting it down

Three equivalent ways: Ctrl+C, SIGINT (kill -INT <pid>), or POST /v1/shutdown (loopback-only — refused from a non-localhost peer, the same safety rule orangu-coordinator’s own shutdown endpoint uses). Both the API and (if enabled) the web UI listener stop together.

What a request cost

Every generation endpoint reports what the request cost, so a client never has to infer it from its own wall clock — which cannot separate prompt processing from generation, nor a cache hit from real work:

On a streaming response they ride on the final chunk (the one carrying finish_reason), immediately before [DONE]; on a non-streaming response they are top-level fields. orangu-bench --pp reads them to report prefill throughput, and the orangu client reads them for its status-line rates.

cache_prompt

/v1/chat/completions, /v1/completions, and /completion accept cache_prompt (llama.cpp’s field name, default true). It controls whether a request may reuse an already-computed KV cache for whatever prefix of its prompt one exists for — the cross-slot prefix pool, or a slot’s own retained cache. Leaving it at the default is what makes a growing conversation cheap: only the new suffix is processed.

Set it false to force the whole prompt through a real forward pass. That is what a prefill measurement needs, since a cached prompt is reported as processing thousands of tokens per second while doing almost nothing — usage.prompt_tokens_details.cached_tokens and prompt_progress.cache show exactly how much was skipped. The flag governs only what a request reads: the resulting cache is still stored for later requests either way.

Endpoint reference

Endpoint
GET /v1/models
POST /v1/chat/completions streaming (SSE) and non-streaming; requires the model to have a tokenizer.chat_template; disabled under --embedding
POST /v1/completions legacy OpenAI completion, no chat template needed; disabled under --embedding
POST /v1/embeddings pooled (mean or last-token, per the model’s own pooling_type) and L2-normalized
GET /health
GET /props model + server metadata, including the backend and device the model is running on
GET /slots per-slot busy/prompt/generated-token state
GET /metrics Prometheus text
POST /completion native, streaming; disabled under --embedding
POST /tokenize / POST /detokenize
POST /embedding native embeddings
POST /apply-template renders the chat template without generating
POST /v1/create_file file lifecycle: write a new file, with optional permissions
POST /v1/modify_file file lifecycle: replace named line ranges, returning a diff
POST /v1/move_file file lifecycle: rename a file, optionally re-setting permissions
POST /v1/delete_file file lifecycle: delete a file
POST /v1/show_file file lifecycle: return a file’s entire content
POST /v1/create_directory file lifecycle: create one directory, with optional permissions
POST /v1/move_directory file lifecycle: move an entire directory tree
POST /v1/delete_directory file lifecycle: delete an empty directory
POST /v1/shutdown not part of the standard API — orangu-server’s own

Those eight are orangu-server’s own JSON API for the whole life cycle of a file and the directories it lives in, and are confined to the workspace (see Workspace above): a path outside it is refused before anything is touched. delete_directory only removes an empty directory, and nothing in the API deletes a tree.

When the workspace is a Git repository, they are Git operations: a file is created, modified, moved and deleted with git add, git mv and git rm, so the change is staged, and each reply reports what reached the index (including the forge, when gh or glab is installed). Nothing is ever committed — that stays the user’s own decision. A request can pass "git": false for a plain filesystem change. They are documented field by field in the Inference server internals chapter, under File-lifecycle API.

The built-in Web UI (above) is served on its own web port, separate from the API’s port, and exposes a small /api/... surface of its own — used only by that page’s own JavaScript, not part of the OpenAI- compatible API above, and only reachable at all when web is configured:

Endpoint
GET /api/asset-version the served page’s own asset fingerprint — powers the Reload prompt shown when a newer build is running behind an already-open tab
GET /api/system-report plain-text hardware report (system’s own output) plus model/backend identity — what an error bubble’s Save button bundles into its downloadable debug report, alongside the visible conversation
POST /api/sessions creates a new, empty chat session, returning its id
GET /api/sessions lists every non-empty session, newest-updated first
GET /api/sessions/{id} one session’s full message history, each assistant reply already rendered to HTML
POST /api/sessions/{id}/messages sends one chat turn against that session; streaming (SSE) reply, the same shape /v1/chat/completions’ own stream uses

Scope

Text-in/text-out GGUF chat, completion, and embedding models, for six architecture families: Llama-style (general.architecture one of llama, qwen2, qwen3, mistral, and qwen3vl — Qwen3-VL’s text backbone, text-only input), Gemma4 (gemma/gemma2/gemma3/gemma4, dense and the gemma-4-26B-A4B routed-expert MoE — a dense shared MLP plus softmax top-k experts per MoE layer — plus the bidirectional-attention, embeddings-only gemma-embedding), Qwen3.5/3.6-MoE (qwen35moe), Qwen3.5 dense (qwen35 — the same hybrid full-attention/gated-DeltaNet layer shape as qwen35moe, plain SwiGLU FFN instead of MoE routing), and Phi-3 (phi3, covering Phi-3 and Phi-4-mini — Llama-style attention and SwiGLU, but with the query/key/value projections fused into one attn_qkv tensor, the FFN gate and up projections fused into one ffn_up tensor, and LongRoPE frequency factors on a partially-rotated head), and Mistral 3 (mistral3, e.g. Ministral-3 — llama’s block shape plus YaRN RoPE scaling, a head width read from attention.key_length rather than derived from n_embd / n_head, and an attention temperature scale) — using F32/F16/BF16/Q8_0/Q4_0/Q5_0/Q2_K/Q3_K/Q4_K/Q5_K/Q6_K and the IQ1_S/IQ1_M/IQ2_XXS/IQ2_XS/IQ2_S/IQ3_XXS/IQ3_S/IQ4_NL/IQ4_XS tensors. Weight matrices and embedding tables are read lazily from the memory-mapped file (dequantized one row at a time, on demand) rather than eagerly resident, so even large models fit in modest RAM. A model split across several files (<name>-00001-of-000NN.gguf …) is loaded from every shard — the shard count comes from the split.count metadata key, and each shard is mapped separately.

A quantization label names the file’s dominant type, not its only one. A K-quant block is 256 elements wide, so every tensor it covers needs a row length divisible by 256; where a model’s rows aren’t, upstream’s quantizer substitutes a narrower type row by row. unsloth/Qwen2.5-Coder-0.5B-Instruct-GGUF:Q2_K is the common case — its embedding_length is 896, which is 28 blocks of 32 but not a multiple of 256, so the file that download produces is mostly IQ4_NL and Q5_0, with Q3_K only on the 4864-wide ffn_down rows and Q8_0 on the embedding table. Every one of those types is read, so the model loads and runs; what the label predicts is the size, not a single tensor type.

Type coverage differs by backend. Only cpu reads every type listed above. vulkan covers all of them except IQ1_S, IQ1_M, and IQ2_XXS; cuda, opencl, and rocm cover the float types, the legacy quants, Q2_K/Q3_K/Q4_K/Q5_K/Q6_K, and IQ4_NL. What’s missing in each case is the IQ* types that index a lattice codebook the backend has no uploaded buffer for. A model carrying a type the selected backend lacks is refused at startup, naming each missing type, rather than failing partway through the first request.

Six further types load that upstream cannot read at all: Q4_0_4_4, Q4_0_4_8, Q4_0_8_8, and the IQ4_NL_4_4/_4_8/_8_8 equivalents. ggml retired those ids and llama.cpp refuses such a file outright (“TYPE_Q4_0_4_4 REMOVED, use Q4_0 with runtime repacking”). They are ARM-SIMD pre-repacked Q4_0/IQ4_NL: the packing interleaves 4 or 8 rows, and for the Q4_0 family also flips a bit per nibble. That is a lossless permutation, so orangu undoes it once when the model opens and serves the result as ordinary Q4_0/IQ4_NL. Quality is identical to a plain build of the same weights — bit-identical, not merely close — and no GPU backend needs a kernel for any of them. One consequence worth knowing: those tensors are held in memory rather than read from the mapped file, because interleaving rows leaves no row with a contiguous range to be lazy about.

Not yet built, and out of scope for now: multimodal input, /infill, /rerank, LoRA hot-swap, and slot save/restore.

See the Developer information chapter for how the GPU backends, request scheduler, model forward passes, and GGUF inventory tooling work internally.