This document is the canonical operator reference for Kiln's typed server
configuration. It describes the configuration accepted by the current
KilnConfig and RequestLogConfig implementations, including current defaults,
validation, mechanically derived environment overrides, and runtime provenance.
The machine-readable contract is
contracts/kiln-config-v1.schema.json.
The documentation website renders its complete field reference directly from
that schema. python3 scripts/check_config_schema.py --self-test verifies that
the schema, these tables, and kiln.example.toml agree.
Use kiln config --file kiln.toml --json for the complete hardware-free
effective startup object. A running server publishes its immutable startup
snapshot in GET /v1/config under effective_configuration, beside the
backend-derived and live capacity diagnostics that can only be resolved after
hardware selection.
Kiln's intended public environment-variable naming rule is mechanical:
KILN_<SECTION>_<FIELD>
Both the section and field are converted to uppercase snake case. For example,
server.host maps to the canonical target KILN_SERVER_HOST, and
request_log.max_file_bytes maps to
KILN_REQUEST_LOG_MAX_FILE_BYTES.
Every fixed field with an environment override implements its canonical name.
The "Alternate env spelling(s)" column is deliberately none for every field:
- implemented means the mechanically derived canonical name works;
- none means there is no supported environment override for that field;
- target only; not implemented means setting the mechanically derived name currently has no effect because the field is intentionally config-file-only.
There are no environment aliases. Retired non-canonical names are ignored, so they cannot silently override the typed configuration. The complete migration index maps every retired public spelling to its canonical replacement.
Do not assume that an arbitrary KILN_* name is public configuration. The
repository contains internal diagnostics, qualification switches, kernel
experiments, and build/toolchain inputs. Only the canonical names listed here
are supported public field overrides.
The generated Runtime Environment Inventory catalogs every direct environment read and mutation in crate-owned source, classifies its owner boundary, and exposes the remaining typed-config migration queue. It is an engineering inventory, not a second list of supported settings.
Resolution and startup
Config file selection
Kiln selects at most one TOML file, in this order:
- The explicit path supplied by the command, such as
kiln --config /path/kiln.toml serve. - The path in
KILN_CONFIG. ./kiln.toml, if it exists in the process working directory.- No file; built-in defaults are used.
An explicitly selected file that cannot be read or parsed is a startup error.
KILN_CONFIG selects the file; it is not an override for a TOML field and is
not included in the field counts below.
Value precedence
Effective startup values resolve in this order, highest priority first:
- Typed CLI overrides applied after environment resolution
(
serve --served-model-idandserve --eval-mode). - The mechanically derived canonical environment name listed here.
- The selected TOML file.
- The built-in default.
The -v/-vv and --quiet logging flags override logging.level for the
running command. RUST_LOG, when present, takes precedence over that resolved
level when the tracing filter is built.
Environment resolution happens once at startup. Restart the server after changing a file or environment value. Model, training, and request execution receive resolved policy rather than re-reading public configuration from the process environment.
Strict failure behavior
The top-level document and every typed section reject unknown fields. This
includes [request_log], [eval], [agent], [teachers], and each dynamic
teacher credential. A misspelled key does not fall back to a default. The one
intentional open subtree is agent.self_improve, whose structured request body
is validated later by the self-improvement subsystem.
TOML type errors, invalid enum values, malformed URLs, out-of-range values, and semantically invalid combinations stop startup. Present centralized environment overrides must be valid UTF-8 and must parse successfully; malformed values stop startup and the diagnostic names the variable and raw value. The centralized loader's boolean overrides accept, case-insensitively and with surrounding whitespace ignored:
true: true, 1, yes, on
false: false, 0, no, off
Optional TOML values are represented by omitting the field; TOML has no null
literal. Environment-specific clearing syntax is documented per field.
Validate without starting the server:
kiln config --file kiln.toml
kiln config --file kiln.toml --backend rocm
This command uses the same typed loader and environment precedence as serving,
but its pretty output is a summary rather than a complete effective-config
dump. The optional --backend cpu|cuda|rocm|metal|vulkan selector resolves that
target's static scheduling capabilities and applies the same actor-prefill
startup validator as kiln serve. It does not enumerate devices, probe memory,
open an accelerator, or load model weights.
Coverage summary
The accepted TOML surface contains 16 top-level sections and 112 fixed leaf
fields. Dynamic teachers.credentials.<id> entries add two leaf fields per
credential. Of the 112 fixed fields:
- 107 implement the canonical mechanical environment name;
- 5 are config-file-only and have no environment override;
- no field has an alternate environment spelling.
The tables below cover all 112 fixed fields and both dynamic credential fields.
The migration index separately tracks all 82 former public spellings; entries
marked removed are inert and intentionally have no replacement field.
Unknown TOML fields are rejected, including the removed
speculative.enabled and streaming_prefill.enabled toggles. Their canonical
replacement fields are documented below.
[server]
| TOML field | Type and exact default | Canonical env target | Alternate env spelling(s) | Validation and effective semantics |
|---|---|---|---|---|
server.serving_profile |
string enum; "stable" |
KILN_SERVER_SERVING_PROFILE (implemented) |
none | stable, experimental, or maintenance, case-insensitive. Process-lifetime policy; restart required. |
server.deterministic |
boolean; false |
KILN_SERVER_DETERMINISTIC (implemented) |
none | Enables deterministic tensor behavior and forces the effective concurrent decode width to one. |
server.host |
string; "127.0.0.1" |
KILN_SERVER_HOST (implemented) |
none | Must be non-empty. Binding beyond loopback exposes an unauthenticated inference and training API; use a trusted network or authenticated reverse proxy. |
server.port |
unsigned 16-bit integer; 8420 |
KILN_SERVER_PORT (implemented) |
none | 1..=65535. |
server.request_timeout_secs |
unsigned integer; 600 |
KILN_SERVER_REQUEST_TIMEOUT_SECS (implemented) |
none | Must be greater than zero. Bounds a request, including model work and cleanup settlement. |
server.terminal_access |
string enum; "loopback_only" |
KILN_SERVER_TERMINAL_ACCESS (implemented) |
none | loopback_only, enabled, or disabled. This capability can execute arbitrary code; changing it requires restart. |
server.http_send_buffer_bytes |
optional unsigned integer; omitted (None) |
KILN_SERVER_HTTP_SEND_BUFFER_BYTES (implemented) |
none | When set, 1024..=16777216. Applied to accepted sockets. Startup preflights the listener and rejects an OS read-back smaller than requested. |
server.stream_stall_grace_ms |
unsigned integer; 2000 |
KILN_SERVER_STREAM_STALL_GRACE_MS (implemented) |
none | 10..=2000. A request retaining KV state with no streaming delivery progress is selected for cancellation after this grace. |
server.max_batch_tokens |
unsigned integer; 512 |
KILN_SERVER_MAX_BATCH_TOKENS (implemented) |
none | 2..=65536. Combined decode-plus-prefill token budget for one batching-actor cycle. |
server.max_prefill_tokens_per_cycle |
unsigned integer; 256 |
KILN_SERVER_MAX_PREFILL_TOKENS_PER_CYCLE (implemented) |
none | 1..=65536. Independent new-prompt-token ceiling within the combined actor budget. ROCm actor serving requires equality with the effective streaming tile, tiled streaming-prefill dispatch no later than that boundary, and server.max_batch_tokens >= tile + effective max_decode_batch; unsafe combinations fail startup. |
server.max_prefill_layers_per_cycle |
unsigned integer; 4 |
KILN_SERVER_MAX_PREFILL_LAYERS_PER_CYCLE (implemented) |
none | 1..=1024. Number of transformer layers an in-flight prefill chunk may execute before yielding to decode. |
server.max_decode_batch |
"auto" or unsigned integer; "auto" |
KILN_SERVER_MAX_DECODE_BATCH (implemented) |
none | auto, backend, and backend_policy all delegate to backend policy; an integer must be 1..=65536. Deterministic mode and max_batch_tokens may lower the final width. Explicit values require backend-specific correctness, memory, and latency qualification; qualification receipts never mutate this field. |
server.eval_mode |
boolean; false |
KILN_SERVER_EVAL_MODE (implemented) |
none | Enables deterministic eval-serving defaults, headers, adapter warnings, and transient-cache cleanup behavior. serve --eval-mode applies a typed override after environment resolution and wins without mutating process environment. |
server.debug_model_state |
boolean; false |
KILN_SERVER_DEBUG_MODEL_STATE (implemented) |
none | Enables trusted GET /v1/debug/model-state diagnostics without changing inference, cache, or eval semantics. server.eval_mode=true also enables the endpoint. The response contains model/configuration/runtime state but no prompt or user-message contents. |
server.default_thinking_enabled |
optional boolean; omitted (None) |
KILN_SERVER_DEFAULT_THINKING_ENABLED (implemented) |
none | None preserves the model template default. Requests may override with chat_template_kwargs.enable_thinking. The canonical environment override accepts strict booleans; there is no environment value that restores None. |
server.default_thinking_budget_tokens |
optional unsigned integer; omitted (None) |
KILN_SERVER_DEFAULT_THINKING_BUDGET_TOKENS (implemented) |
none | Integer values include 0, which closes thinking immediately. Case-insensitive unlimited clears a TOML limit back to None. Requests may inherit, replace, or explicitly disable the limit. |
server.default_thinking_budget_ms |
optional unsigned integer; omitted (None) |
KILN_SERVER_DEFAULT_THINKING_BUDGET_MS (implemented) |
none | Integer values include 0. unlimited clears a TOML limit. The clock starts at the first decode candidate, after queueing and prefill. The first token or time limit reached forces the model's closing </think> sequence. |
server.fold_reasoning_into_content |
boolean; false |
KILN_SERVER_FOLD_REASONING_INTO_CONTENT (implemented) |
none | Copies separated reasoning into content for compatibility clients. A request can override it. |
server.chat_performance_metadata |
boolean; false |
KILN_SERVER_CHAT_PERFORMANCE_METADATA (implemented) |
none | Default for chat response performance metadata; requests can override with include_performance. |
server.chat_config_hash_metadata |
boolean; false |
KILN_SERVER_CHAT_CONFIG_HASH_METADATA (implemented) |
none | Default for chat response config hashes; requests can override with include_config_hashes. |
server.slow_request_warn_secs |
unsigned integer; 30 |
KILN_SERVER_SLOW_REQUEST_WARN_SECS (implemented) |
none | 0 disables slow-request warnings; otherwise a request at least this old emits a structured warning. |
server.shutdown_timeout_secs |
unsigned integer; 5 |
KILN_SERVER_SHUTDOWN_TIMEOUT_SECS (implemented) |
none | Must be greater than zero. Hard ceiling for graceful drain before forced exit. |
Serving profiles
The profile owns GPU mutation and admission policy; individual requests cannot override it.
| Profile | Inference | Training GPU ownership | Adapter weight transitions | Dynamic KV resize / allocator reclaim | Live graph capture | Exclusive behavior |
|---|---|---|---|---|---|---|
stable |
admitted | allowed | allowed | enabled | enabled | writer priority |
experimental |
admitted | allowed | allowed | enabled | enabled | writer priority |
maintenance |
not admitted | allowed | allowed | enabled | disabled | drain, then exclusive |
The default stable profile is the normal full product: inference, training,
adapter transitions, memory management, and guarded graph capture do not need
a special opt-in. experimental is reserved for backend routes under an
explicit correctness quarantine; it is not a faster user mode.
The only profile-gated configuration is an offline forced KV resize:
| Field | Values requiring the profile | Required profile |
|---|---|---|
memory.kv_force_blocks |
every positive integer | maintenance plus memory.kv_autoscale = true |
server.debug_model_state is not an execution experiment: it only exposes the
trusted diagnostics route and does not alter inference, cache, training, or
evaluation semantics. It is therefore source-tracked and restart-bound but not
profile-gated. Logging level debug is likewise observability, not an
execution selector.
[accelerator]
This section owns process-lifetime accelerator execution behavior that must be
fixed before the primary device context or model runner is created. The
resolved object uses schema kiln.accelerator-runtime-policy.v16. Startup,
kiln config, GET /v1/config, /health, trusted debug state, and the
dashboard all report the same configured/effective/source values, plus the
compiled Vulkan kernel-policy schema ID; lower model, tensor, and kernel paths
do not re-read these public environment names.
| TOML field | Type and exact default | Canonical env target | Alternate env spelling(s) | Validation and effective semantics |
|---|---|---|---|---|
accelerator.kt_api_mode |
string enum; "auto" |
KILN_ACCELERATOR_KT_API_MODE (implemented) |
none | auto, all, or disabled, case-insensitive. auto enables qualified routes, all enables every adapter route, and disabled forces legacy fallbacks. Restart required. |
accelerator.full_attention_score_budget_mib |
unsigned integer MiB; 2048 |
KILN_ACCELERATOR_FULL_ATTENTION_SCORE_BUDGET_MIB (implemented) |
none | 64..=2048. Immutable ceiling for exact full-attention materialized score and scratch geometry across CPU, CUDA, ROCm, Metal, and Vulkan model routes. ROCm online attention derives min(value, 1024) MiB while retaining fixed qualified 2048-query/4096-key tiles. Runtime memory observations remain fail-closed admission and reservation checks; they never resize the geometry or switch to smaller tiles during a request. Restart required. |
accelerator.vulkan_device_index |
"auto" or unsigned integer; "auto" |
KILN_ACCELERATOR_VULKAN_DEVICE_INDEX (implemented) |
none | auto preserves automatic discrete-GPU preference and otherwise chooses the first enumerated Vulkan physical device. An integer strictly selects that zero-based Vulkan enumeration index. An unavailable index fails logical-device startup; it is never ignored or replaced with another device. The immutable selection is installed before Vulkan device creation and reported with source attribution. Restart required. |
accelerator.vulkan_validation |
boolean; false |
KILN_ACCELERATOR_VULKAN_VALIDATION (implemented) |
none | true enables VK_LAYER_KHRONOS_validation at startup and fails if the layer is unavailable. Restart required. |
accelerator.cuda_kernel_profile |
string enum; "native_default" |
KILN_ACCELERATOR_CUDA_KERNEL_PROFILE (implemented) |
none | native_default enables the device-neutral subset of twenty-four CUDA model/backend routes and declines the GDN full-chunk multiblock route whose performance evidence covers only one GPU configuration. portable_fallback declines every owned route. The complete twenty-five-route set is installed before CUDA backend construction, immutable for the process lifetime, and reported with source attribution. Restart required. |
accelerator.cuda_marlin_profile |
string enum; "disabled" |
KILN_ACCELERATOR_CUDA_MARLIN_PROFILE (implemented) |
none | disabled preserves BF16 projections; attention_mlp and attention_mlp_gdn select immutable Marlin W4A16 layouts. Restart required. |
accelerator.cuda_flash_backward_mode |
string enum; "fast" |
KILN_ACCELERATOR_CUDA_FLASH_BACKWARD_MODE (implemented) |
none | fast or deterministic, case-insensitive. fast preserves the established CUDA FlashAttention backward accumulation. deterministic selects split accumulation for exact replay and diagnosis. The mode is installed before model construction and cannot change between training jobs. Restart required. |
accelerator.metal_kernel_profile |
string enum; "native_default" |
KILN_ACCELERATOR_METAL_KERNEL_PROFILE (implemented) |
none | native_default or portable_fallback, case-insensitive. native_default preserves forty-five of the forty-six Metal backend routes active before consolidation; custom LM-head argmax remains disabled by default. portable_fallback declines every owned route. The complete route set is installed before Metal backend construction, immutable for the process lifetime, and reported with source attribution. Restart required. |
accelerator.rocm_synchronization_mode |
string enum; "legacy_host_barriers" |
KILN_ACCELERATOR_ROCM_SYNCHRONIZATION_MODE (implemented) |
none | legacy_host_barriers or stream_ordered, case-insensitive. Restart required. |
accelerator.rocm_strided_batched_matmul_mode |
string enum; "disabled" |
KILN_ACCELERATOR_ROCM_STRIDED_BATCHED_MATMUL_MODE (implemented) |
none | disabled uses one operation per logical row; enabled selects strided batching. The retired auto value is rejected. Restart required. |
accelerator.rocm_bf16_matmul_output_mode |
string enum; "f32_then_cast" |
KILN_ACCELERATOR_ROCM_BF16_MATMUL_OUTPUT_MODE (implemented) |
none | f32_then_cast is the portable default; native_bf16 explicitly requests native BF16 output. Restart required. |
accelerator.rocm_kernel_profile |
string enum; "native_default" |
KILN_ACCELERATOR_ROCM_KERNEL_PROFILE (implemented) |
none | native_default enables native single-row and batched dynamic-length paged attention. portable_fallback is the explicit diagnostic route. The retired qualified and experimental_multiblock values fail startup. Restart required. |
accelerator.rocm_graph_mode |
string enum; "profile" |
KILN_ACCELERATOR_ROCM_GRAPH_MODE (implemented) |
none | profile selects guarded lazy capture during serving and eager execution during maintenance. Explicit modes are startup-immutable. Restart required. |
accelerator.rocm_graph_cache_entries |
unsigned integer; 8 |
KILN_ACCELERATOR_ROCM_GRAPH_CACHE_ENTRIES (implemented) |
none | 1..=64. Bounds retained native graph entries in every product and embedding constructor. At saturation, admission reclaims idle owners first and then the minimum fair-LRU active entries while preserving one graph per active owner after the incoming candidate. Zero or unbounded capacities are rejected. Restart required. |
accelerator.rocm_graph_cache_max_bytes |
unsigned integer bytes; 1073741824 (1 GiB) |
KILN_ACCELERATOR_ROCM_GRAPH_CACHE_MAX_BYTES (implemented) |
none | 67108864..=17179869184 (64 MiB through 16 GiB). Independently bounds requested physical bytes retained by graph-owned stable tensors, capture arenas, private-stream hipBLASLt workspaces, and owner slot state. Opaque HIP graph/exec/stream/event overhead is counted as objects and remains subject to live driver-pressure policy. Restart required. |
accelerator.kt_api_mode replaces the former KILN_USE_KT_API_*,
KILN_DISABLE_KT_API_*, and KILN_USE_KT_PAGED_KV_* debugging switches.
Those per-operation names are not compatibility aliases: they created
order-dependent route combinations that could not be represented, validated,
or reported as one startup policy. Use the typed field or its mechanically
derived canonical environment name instead.
accelerator.cuda_kernel_profile owns these twenty-five CUDA model/backend decisions:
| Policy leaf | native_default |
portable_fallback |
|---|---|---|
full_attn_qkv_in_proj |
on | off |
gdn_ab_in_proj |
on | off |
gdn_prefill_ab_in_proj |
on | off |
gdn_prefill_gates |
on | off |
gdn |
on | off |
gdn_gates |
on | off |
gdn_gated_rms_norm |
on | off |
gdn_decode_fused |
on | off |
gdn_decode_unexpanded_qk |
on | off |
gdn_decode_qk_norm_recurrent |
on | off |
gdn_decode_qk_norm_recurrent_rmsnorm |
on | off |
fused_conv1d |
on | off |
lora_decode_add |
on | off |
gdn_full_chunk_forward_multiblock |
off | off |
fused_paged_decode |
on | off |
fused_rotary_qk |
on | off |
attn_decode_qkv_prep |
on | off |
fused_mlp_silu_mul |
on | off |
fused_mlp_gate_up_prefill |
on | off |
fused_attn_sigmoid_mul |
on | off |
fused_rmsnorm |
on | off |
rmsnorm_backward |
on | off |
fused_l2_qk_norm |
on | off |
paged_decode_dyn_seqlen_batch |
on | off |
gdn_chunk_pre_permute |
on | off |
The CUDA-specific variables KILN_DISABLE_CUDA_FULL_ATTN_QKV_IN_PROJ,
KILN_DISABLE_CUDA_GDN_AB_IN_PROJ,
KILN_DISABLE_CUDA_GDN_PREFILL_AB_IN_PROJ,
KILN_DISABLE_CUDA_GDN_PREFILL_GATES,
KILN_DISABLE_FUSED_GDN_DECODE,
KILN_DISABLE_GDN_DECODE_UNEXPANDED_QK,
KILN_DISABLE_CUDA_GDN_DECODE_QK_NORM_RECURRENT,
KILN_DISABLE_CUDA_GDN_DECODE_QK_NORM_RECURRENT_RMSNORM,
KILN_DISABLE_CUDA_LORA_DECODE_ADD, and
KILN_DISABLE_GDN_FULL_CHUNK_FORWARD_MULTIBLOCK no longer control CUDA and
are not aliases. The same is true of the former CUDA/generic switches for
direct paged decode, rotary QK, decode QKV preparation, MLP fusion, attention
sigmoid fusion, RMSNorm forward/backward, L2 QK normalization, dynamic-length
paged decode, GDN pre-permute, training MLP chunking, and split Q/gate
training. Use the complete profile; individual route combinations are not a
supported product configuration.
accelerator.cuda_marlin_profile owns the complete CUDA Marlin weight-layout
choice:
| Profile | Full-attention Q | MLP gate/up/down | GDN output | Packing |
|---|---|---|---|---|
disabled |
BF16 | BF16 | BF16 | none |
attention_mlp |
W4A16 | W4A16 | BF16 | parallel |
attention_mlp_gdn |
W4A16 | W4A16 | W4A16 | parallel |
The former KILN_W4A16 and KILN_W4A16_GDN_OUT_PROJ switches are removed,
not aliases. KILN_DISABLE_PARALLEL_PACK is also removed: production packing
always uses the established parallel path, while serial comparisons belong in
an explicit benchmark harness. Marlin remains CUDA-only; selecting a profile
does not itself claim model-quality, correctness, memory, or performance
qualification for a particular NVIDIA system.
accelerator.cuda_flash_backward_mode is the sole CUDA FlashAttention
backward accumulation authority. fast is the historical default;
deterministic selects split accumulation. The former
KILN_FLASH_ATTN_BWD_DETERMINISTIC spelling is removed rather than retained as
an alias. This setting concerns CUDA training backward only and does not imply
that server.deterministic makes every accelerator kernel bitwise
deterministic.
Two unused or unsafe-to-retune training-kernel controls are deleted without
replacement. KILN_DISABLE_OPD_LOSS_KERNEL had no live caller.
KILN_FLCE_ACTIVE_ROW_TILE is fixed at the established bounded 4,096 active
rows; unsupported shapes continue through the existing backend fallback.
accelerator.metal_kernel_profile owns these forty-six Metal backend decisions:
| Policy leaf | native_default |
portable_fallback |
|---|---|---|
sdpa |
on | off |
sdpa_full |
on | off |
conv1d_prefill |
on | off |
conv1d_update |
on | off |
gdn_forward_substitution |
on | off |
gdn_recurrent |
on | off |
gdn_gates |
on | off |
gated_rms_norm |
on | off |
gdn_in_proj |
on | off |
gdn_qk_norm |
on | off |
gdn_qkv_conv_norm |
on | off |
gdn_prefill_qkv_conv_split |
on | off |
gdn_in_proj_row_pair |
on | off |
gdn_in_proj_row_quad |
on | off |
gdn_in_proj_row_triple |
on | off |
gdn_in_proj_serial_vector_load |
on | off |
gdn_in_proj_serial_x2_load |
on | off |
gdn_prefill_decay_recurrent |
on | off |
gdn_prefill_ab_in_proj |
on | off |
gdn_decode_gates_recurrent |
on | off |
gdn_decode_gates_recurrent_rmsnorm |
on | off |
rms_norm |
on | off |
mlp_gate_up_fusion |
on | off |
mlp_gate_up_row_pair |
on | off |
mlp_gate_up_row_quad |
on | off |
mlp_gate_up_row_triple |
on | off |
mlp_gate_up_row_quad_vector_load |
on | off |
mlp_gate_up_serial_vector_load |
on | off |
mlp_gate_up_serial_dedicated |
on | off |
mlp_silu_mul |
on | off |
attn_gate_fusion |
on | off |
fused_qkv_proj |
on | off |
lora_delta_decode |
on | off |
lm_head_argmax |
off | off |
lm_head_argmax_rows |
on | off |
lm_head_argmax_gpu_reduce |
on | off |
lm_head_sample |
on | off |
paged_attn_decode_contiguous |
on | off |
paged_kv_write_token_major |
on | off |
transposed_coop_gemv |
on | off |
transposed_coop_gemv_tile8 |
on | off |
transposed_coop_gemv_tile16 |
on | off |
transposed_coop_gemv_row_pair |
on | off |
transposed_coop_gemv_row_quad |
on | off |
transposed_coop_gemv_row_quad_tile8 |
on | off |
transposed_coop_gemv_row_triple_tile8 |
on | off |
The former Metal switches are removed, not accepted as aliases. They were:
KILN_DISABLE_METAL_SDPA, KILN_DISABLE_METAL_SDPA_FULL,
KILN_DISABLE_METAL_CONV1D_PREFILL, KILN_DISABLE_FUSED_CONV1D,
KILN_DISABLE_METAL_FUSED_CONV1D, KILN_DISABLE_GDN_KERNEL,
KILN_DISABLE_FUSED_GDN_GATES, KILN_DISABLE_METAL_GDN_GATES,
KILN_DISABLE_METAL_GDN_FORWARD_SUBSTITUTION,
KILN_DISABLE_METAL_GDN_RECURRENT,
KILN_DISABLE_METAL_GDN_DECODE_GATES_RECURRENT,
KILN_DISABLE_METAL_GDN_DECODE_GATES_RECURRENT_RMSNORM,
KILN_DISABLE_METAL_GATED_RMSNORM, KILN_DISABLE_METAL_GDN_QK_NORM,
KILN_DISABLE_METAL_GDN_QKV_CONV_NORM,
KILN_DISABLE_METAL_GDN_PREFILL_QKV_CONV_SPLIT,
KILN_DISABLE_METAL_GDN_PREFILL_DECAY_RECURRENT,
KILN_DISABLE_METAL_GDN_PREFILL_AB_IN_PROJ,
KILN_DISABLE_RMSNORM_KERNEL, KILN_DISABLE_METAL_RMSNORM,
KILN_DISABLE_METAL_MLP_GATE_UP_FUSION,
KILN_DISABLE_METAL_MLP_GATE_UP_ROW_PAIR,
KILN_DISABLE_METAL_MLP_GATE_UP_ROW_QUAD,
KILN_DISABLE_METAL_MLP_GATE_UP_ROW_TRIPLE,
KILN_DISABLE_METAL_MLP_GATE_UP_ROW_QUAD_VECTOR_LOAD,
KILN_DISABLE_METAL_MLP_GATE_UP_SERIAL_VECTOR_LOAD,
KILN_DISABLE_METAL_MLP_GATE_UP_SERIAL_DEDICATED,
KILN_DISABLE_METAL_MLP_SILU_MUL, KILN_DISABLE_METAL_ATTN_GATE_FUSION,
KILN_DISABLE_METAL_FUSED_QKV_PROJ,
KILN_DISABLE_METAL_LORA_DELTA_DECODE,
KILN_DISABLE_METAL_GDN_IN_PROJ_FUSION,
KILN_DISABLE_METAL_GDN_IN_PROJ_ROW_PAIR,
KILN_DISABLE_METAL_GDN_IN_PROJ_ROW_QUAD,
KILN_DISABLE_METAL_GDN_IN_PROJ_ROW_TRIPLE,
KILN_DISABLE_METAL_GDN_IN_PROJ_SERIAL_VECTOR_LOAD,
KILN_DISABLE_METAL_GDN_IN_PROJ_SERIAL_X2_LOAD,
KILN_ENABLE_METAL_LM_HEAD_ARGMAX, KILN_DISABLE_METAL_LM_HEAD_ARGMAX,
KILN_DISABLE_METAL_LM_HEAD_ARGMAX_ROWS,
KILN_DISABLE_METAL_LM_HEAD_ARGMAX_GPU_REDUCE,
KILN_DISABLE_METAL_LM_HEAD_SAMPLE,
KILN_DISABLE_METAL_PAGED_ATTN_DECODE_CONTIGUOUS,
KILN_DISABLE_METAL_PAGED_KV_WRITE_TOKEN_MAJOR,
KILN_DISABLE_METAL_TRANSPOSED_COOP_GEMV,
KILN_DISABLE_METAL_TRANSPOSED_COOP_GEMV_TILE8,
KILN_DISABLE_METAL_TRANSPOSED_COOP_GEMV_TILE16,
KILN_DISABLE_METAL_TRANSPOSED_COOP_GEMV_ROW_PAIR,
KILN_DISABLE_METAL_TRANSPOSED_COOP_GEMV_ROW_QUAD,
KILN_DISABLE_METAL_TRANSPOSED_COOP_GEMV_ROW_QUAD_TILE8, and
KILN_DISABLE_METAL_TRANSPOSED_COOP_GEMV_ROW_TRIPLE_TILE8.
The profile is intentionally closed: use a whole-profile comparison plus route
telemetry and a focused reproduction rather than reconstructing arbitrary
per-kernel combinations.
Fixed model, loader, and fallback policy
The following former unsectioned switches are removed without aliases. They were debug or rollback controls, not stable product configuration, and allowed behavior to change after typed startup validation. Their replacement behavior is fixed or owned by the typed backend profile shown above.
| Policy family | Retired names | Product behavior |
|---|---|---|
| Decode route and fallback | KILN_DISABLE_CUDA_DIRECT_PAGED_DECODE, KILN_ROCM_PAGED_DECODE, KILN_DECODE_HOT_PATH_DEBUG_FALLBACK, KILN_METAL_DECODE_BATCH_GENERIC_FALLBACK, KILN_VULKAN_DECODE_BATCH_GENERIC_FALLBACK, KILN_ROCM_DECODE_BATCH_GENERIC_FALLBACK, KILN_VULKAN_DECODE_BATCH_ROWWISE_RETRY |
CUDA and ROCm direct paged decode follow their installed kernel profiles. Vulkan retains its qualified native route and LoRA-specific counted portable path. Other unsupported decode fallbacks fail closed instead of changing route from process state. |
| CUDA model routes | KILN_DISABLE_FUSED_PAGED_DECODE, KILN_DISABLE_FUSED_CUDA_ROTARY_QK, KILN_DISABLE_CUDA_ATTN_DECODE_QKV_PREP, KILN_DISABLE_FUSED_CUDA_MLP_SILU_MUL, KILN_DISABLE_FUSED_MLP_GATE_UP_PREFILL, KILN_DISABLE_FUSED_CUDA_ATTN_SIGMOID_MUL, KILN_DISABLE_RMSNORM_KERNEL, KILN_DISABLE_RMSNORM_BACKWARD, KILN_DISABLE_FUSED_L2_QK_NORM, KILN_DISABLE_FUSED_PAGED_DECODE_DYN_SEQLEN_BATCH, KILN_FORCE_FUSED_PAGED_DECODE_DYN_SEQLEN_BATCH, KILN_DISABLE_GDN_CHUNK_PRE_PERMUTE |
Every listed CUDA decision is a leaf of accelerator.cuda_kernel_profile; no hot path reads process environment. |
| Training geometry | KILN_DISABLE_CUDA_TRAINING_MLP_CHUNKING, KILN_DISABLE_GPU_TRAINING_MLP_CHUNKING, KILN_CUDA_TRAINING_MLP_CHUNK_TOKENS, KILN_GPU_TRAINING_MLP_CHUNK_TOKENS, KILN_DISABLE_SPLIT_Q_GATE_TRAINING, KILN_DISABLE_CUDA_SPLIT_Q_GATE_TRAINING, KILN_DISABLE_VULKAN_SPLIT_Q_GATE_TRAINING, KILN_SPLIT_Q_GATE_OUTPUT_CHUNK_FEATURES |
ROCm uses its complete typed policy. CUDA uses enabled 1,024-token MLP chunks and an unsplit Q/gate output. Vulkan uses enabled split Q/gate output with at most 1,024 features per slice. |
| Projection residency and loading | KILN_KEEP_PROJECTION_ORIGINALS, KILN_DROP_PROJECTION_ORIGINALS, KILN_KEEP_PROJECTION_TRANSPOSES, KILN_DISABLE_PARALLEL_PROJECTION_LOAD, KILN_DISABLE_PARALLEL_AUX_LOAD, KILN_VK_NATIVE_TRAINING |
CUDA and Metal drop redundant original projection tensors after cached transposes are ready; CPU, ROCm, and Vulkan retain originals. Every backend retains cached transposes. Metal parallel projection and auxiliary upload remain enabled. Vulkan training capability is backend-owned, not inferred from environment. |
| State and precision | KILN_DISABLE_FAST_BATCHED_LINEAR_STATE_SCATTER, KILN_DISABLE_CUDA_BF16_INFERENCE_STATE, KILN_DISABLE_ROCM_BF16_INFERENCE_STATE, KILN_DISABLE_VULKAN_BF16_INFERENCE_STATE, KILN_ALLOW_FP8_ON_METAL |
Qualified device-resident state scatter remains enabled with its replacement fallback. CUDA, ROCm, Metal, and Vulkan advertise native-with-constraints BF16/F16 recurrent state. Metal FP8 KV storage remains declined because its CPU round trip is not a qualified product route. |
| Fixed optimized paths | KILN_DISABLE_WEIGHTED_LM_HEAD_PREP, KILN_DISABLE_MARLIN_BF16_DROP, KILN_DISABLE_CUDA_GDN_BATCHED_DECODE_ROW_LOOP, KILN_ENABLE_CUDA_GDN_BATCHED_DECODE_ROW_LOOP, KILN_ENABLE_METAL_GDN_STREAMING_FASTPATHS |
Weighted LM-head preparation and redundant Marlin transpose release remain enabled. CUDA GDN uses row-wise execution only for genuinely noncontiguous rows. The unqualified Metal streaming-GDN experiment remains disabled. |
| Diagnostics and legacy routing | KILN_ARENA_FORCE_ZERO, KILN_CUDA_NATIVE_TRAINING |
Capture arenas zero only buffers whose allocation contract requests zero initialization. Server training uses the authoritative shared tensor tape; the obsolete legacy CUDA-native selector remains unavailable. |
| Metal graph execution | KILN_METAL_GRAPHS, KILN_FORCE_EAGER_DECODE, KILN_METAL_GRAPH_STABLE_PAGED_METADATA |
The owning runtime options select graph eligibility before ModelRunner construction. Eligible Metal runners use stable paged metadata; ineligible runners remain eager. Process state cannot change either decision during decode. |
| Tape saved-tensor residency | KILN_TAPE_GDN_OFFLOAD_SAVED_TENSORS, KILN_TAPE_OFFLOAD_MATMUL_A, KILN_TAPE_OFFLOAD_MIN_BYTES |
GDN recurrence and matmul saved tensors remain device-resident. The unsupported host-offload experiment is unavailable until a typed training plan owns and qualifies its transfer and memory policy. |
| Metal SDPA and command cadence | KILN_SDPA_SPLIT, KILN_SDPA_PREFILL_MIN, CANDLE_METAL_COMPUTE_PER_BUFFER |
Split-K width follows the shape and occupancy heuristic, matrix-core prefill begins at 16 query tokens, and command buffers commit after 50 compute encodes. These fixed correctness/performance choices cannot change after startup. |
server.deterministic remains the public deterministic control, with
KILN_SERVER_DETERMINISTIC as its mechanically derived environment target and
no alternate spelling. Standalone kiln-tensor consumers do not read process
environment for this policy; without an owning application calling the typed
configuration hook, deterministic execution defaults to false.
accelerator.rocm_kernel_profile replaces the model-layer ROCm controls
KILN_DISABLE_ROCM_ATTN_DECODE_QKV_PREP,
KILN_ENABLE_ROCM_GDN_STREAMING_FASTPATHS,
KILN_DISABLE_ROCM_LONG_FLASH_ATTN,
KILN_ROCM_FLASH_NATIVE_RECTANGULAR_CAUSAL,
KILN_DISABLE_ROCM_TRAINING_MLP_CHUNKING,
KILN_ROCM_TRAINING_MLP_CHUNK_TOKENS,
KILN_DISABLE_ROCM_W8_SAMPLED_LM_HEAD,
KILN_DISABLE_ROCM_SPLIT_Q_GATE_TRAINING,
KILN_ROCM_SPLIT_Q_GATE_ROW_TILE_TOKENS,
KILN_DISABLE_ROCM_SPLIT_Q_GATE_F32_OUTPUT,
KILN_DISABLE_ROCM_GQA_SDPA_F32,
KILN_ROCM_TAPE_FLASH_MATERIALIZED, KILN_ROCM_W8A16,
KILN_ROCM_W8A8, KILN_ROCM_W8A8_SAMPLED_LM_HEAD, and
KILN_DISABLE_ROCM_W8_SWIGLU, plus the lower-level tensor spellings
KILN_DISABLE_ROCM_SPLIT_PAGED_ATTN,
KILN_ROCM_PAGED_ATTN_SPLIT_TOKENS,
KILN_ROCM_PAGED_ATTN_MAX_SPLITS,
KILN_DISABLE_ROCM_GQA_PAGED_ATTN,
KILN_DISABLE_ROCM_GQA_D128_PARALLEL,
KILN_DISABLE_ROCM_GQA_D256_PARALLEL,
KILN_DISABLE_ROCM_CONCAT_SAFE_ROW_ASSEMBLY,
KILN_ROCM_CONCAT_AXIS0_ROW_COPY,
KILN_ROCM_IS_FINITE_LARGE_HOST_SCAN,
KILN_ROCM_IS_FINITE_HOST_SCAN_ELEMENTS, and
KILN_ROCM_RMSNORM_ROW_TILE_ROWS. None is an alias. The two default-off
investigation switches for streaming GDN and materialized tape flash have no
profile leaf because no qualified product uses them. The default-off axis-zero
concat experiment and its dead vectorized kernel were also deleted rather than
promoted.
The context-owned flash-attention subsection replaces or deletes all 50 former
flash build/runtime spellings: KILN_ROCM_ATTENTION_COOPERATIVE_YIELD,
KILN_ROCM_ATTENTION_YIELD_MS, KILN_ROCM_DISABLE_CK_FMHA,
KILN_ROCM_ENABLE_CK_FMHA, KILN_ROCM_ENABLE_CK_FMHA_FWD,
KILN_ROCM_F32_MATMUL_INNER_TILE,
KILN_ROCM_FLASH_BWD_PRECOMPUTE_DELTA,
KILN_ROCM_FLASH_BWD_PRECOMPUTE_DELTA_MAX_SEQ, KILN_ROCM_FLASH_CK,
KILN_ROCM_FLASH_COLLAPSED_GQA_BWD,
KILN_ROCM_FLASH_DISABLE_CK_BWD_COLLAPSED_GQA,
KILN_ROCM_FLASH_DISABLE_WMMA_GQA_QBLOCK,
KILN_ROCM_FLASH_DISABLE_WMMA_GQA_R64K16,
KILN_ROCM_FLASH_DISABLE_WMMA_GQA_R64K32,
KILN_ROCM_FLASH_DISABLE_WMMA_GQA_R64K32_LOG2,
KILN_ROCM_FLASH_MATMUL_BWD, KILN_ROCM_FLASH_NATIVE_BWD,
KILN_ROCM_FLASH_NATIVE_BWD_FORCE,
KILN_ROCM_FLASH_NATIVE_BWD_LONG_MIN_SEQ,
KILN_ROCM_FLASH_NATIVE_BWD_MAX_SEQ,
KILN_ROCM_FLASH_NATIVE_DIRECT_COLLAPSED_GQA_BWD,
KILN_ROCM_FLASH_NATIVE_DIRECT_COLLAPSED_GQA_QPAR,
KILN_ROCM_FLASH_NATIVE_FFI_SYNC, KILN_ROCM_FLASH_NATIVE_GQA_QBLOCK,
KILN_ROCM_FLASH_NATIVE_GQA_QBLOCK_MIN_SEQ,
KILN_ROCM_FLASH_NATIVE_KEYSPLIT,
KILN_ROCM_FLASH_NATIVE_KEYSPLIT_MIN_SEQ,
KILN_ROCM_FLASH_NATIVE_KEY_TILE, KILN_ROCM_FLASH_NATIVE_MAX_SEQ,
KILN_ROCM_FLASH_NATIVE_QUERY_TILE,
KILN_ROCM_FLASH_NATIVE_RECTANGULAR_CAUSAL,
KILN_ROCM_FLASH_NATIVE_SCALAR, KILN_ROCM_FLASH_NATIVE_SCALAR_FORCE,
KILN_ROCM_FLASH_NATIVE_SINGLE_MAX_SEQ,
KILN_ROCM_FLASH_NATIVE_STREAMING,
KILN_ROCM_FLASH_NATIVE_STREAMING_FORCE,
KILN_ROCM_FLASH_NATIVE_STREAMING_MIN_SEQ,
KILN_ROCM_FLASH_NATIVE_TILED, KILN_ROCM_FLASH_NATIVE_TILED_FORCE,
KILN_ROCM_FLASH_NATIVE_WMMA_QBLOCK,
KILN_ROCM_FLASH_NATIVE_WMMA_QBLOCK_MIN_SEQ, KILN_ROCM_FLASH_ONLINE,
KILN_ROCM_FLASH_ONLINE_BWD,
KILN_ROCM_FLASH_ONLINE_MATMUL_BATCH_GROUP,
KILN_ROCM_FLASH_USE_WMMA_GQA_R64K16,
KILN_ROCM_FLASH_USE_WMMA_GQA_R64K32,
KILN_ROCM_FLASH_USE_WMMA_GQA_R64K32_LOG2,
KILN_ROCM_FLASH_WMMA_GQA_R64K16_MIN_SEQ,
KILN_ROCM_FLASH_WMMA_GQA_R64K32_LOG2_MIN_SEQ, and
KILN_ROCM_FLASH_WMMA_GQA_R64K32_MIN_SEQ. None is accepted as an alias.
Positive/negative/force combinations collapse into the closed profile;
cooperative sleeps and forced FFI synchronization are deleted; the unused
key-split/WMMA branches and numerically incorrect CK backward route are removed
rather than exposed as policy.
The generic GPU training and fused-route comparison switches in the fixed policy table above are no longer migration inputs for any backend. Their ROCm decisions remain leaves of the complete typed policy.
accelerator.full_attention_score_budget_mib replaces the undocumented
KILN_FULL_ATTN_SCORE_BUDGET_MB, KILN_ROCM_FLASH_SCORE_BUDGET_MB,
KILN_FULL_ATTN_SCORE_TILE_MAX_ELEMENTS,
KILN_ROCM_FULL_ATTN_SCORE_ELEMENT_CAP,
KILN_ROCM_FLASH_SCORE_TILE_MAX_ELEMENTS,
KILN_ROCM_FLASH_ONLINE_SCORE_BUDGET_MB,
KILN_ROCM_FLASH_ONLINE_QUERY_TILE, and
KILN_ROCM_FLASH_ONLINE_KEY_TILE controls. Those names are intentionally not
aliases. Previously, model and ROCm flash paths parsed different permissive
values during execution and recomputed score budgets from changing free-memory
snapshots, permitting route geometry to change between layers or requests.
Policy v16 fixes one bounded ceiling before execution; the ROCm allocator
governor may still reject a planned operation when its exact working set is no
longer admissible, but it cannot silently shrink or expand that plan.
Vulkan device policy
kiln.vulkan-device-policy.v1 is the model/kernel boundary installed from the
two typed fields above before the first logical Vulkan device is created. A
same-value reinstall is idempotent; a conflicting late owner fails closed. The
selected VulkanDevice retains its physical enumeration index for diagnostics.
The removed GGML_VK_VISIBLE_DEVICES compatibility behavior is not a Vulkan
loader contract and is not accepted as a Kiln alias. Use the typed field or its
mechanically derived canonical environment name. External loader/driver
selectors such as MESA_VK_DEVICE_SELECT, DRI_PRIME, and Vulkan ICD selectors
remain identity remaps and cause device-scoped memory-probe validation to fail
closed rather than claim the wrong physical device.
Vulkan kernel policy
Vulkan kernel selection is an immutable implementation contract, not a public
configuration surface. Product execution uses
kiln.vulkan-kernel-policy.v6, derived once from the selected physical
device's reported Vulkan limits and memory types before model routes are
projected. There is no TOML, CLI, request, environment, device-name, vendor-ID,
device-ID, driver-name, or PCI-ID override for its leaves. Device identity and
machine qualification data do not alter product dispatch.
Kiln negotiates the instance API exposed by the Vulkan loader, capped at 1.2. The common shader set targets Vulkan 1.0. Three tiled attention shaders use subgroup basic/arithmetic operations and target Vulkan 1.1; they are selected only when the physical device reports compute-stage support for both operations, otherwise the Vulkan 1.0 untiled shader remains active.
Policy derivation checks each shader family's local workgroup geometry,
invocation count, shared-memory requirement, storage-buffer binding count, and
push-constant size against VkPhysicalDeviceLimits. Workload-dependent
dispatch-grid and buffer-range checks remain at dispatch. A coherent
host-visible recurrent-state route additionally requires a host-visible,
device-local Vulkan memory type; cached staging memory remains a separate
choice. A device that cannot create the complete route set skips full prewarm
and lazily creates only compatible selected pipelines.
Changing a requirement or workload crossover requires a reviewed source change, a new policy version, backend/oracle parity, performance evidence, and cross-device qualification.
The capability policy owns these decisions:
| Family | Capability-derived selection |
|---|---|
| Model route availability | GDN, linear and batched argmax, full-attention QKV, SDPA prefill, paged decode with GPU gather, fused MLP, packed-weight projections, resident decode, and final-state readback elision are admitted only when every shader requirement for that route fits. |
| Kernel scheduling | Row grouping, single-submit, chained dispatch/transfer, parallel reduction, fused recurrence, and batched transfer/upload routes are independently limited by their workgroup, shared-memory, binding, and push-constant requirements. |
| Memory topology | Recurrent zero-copy host visibility requires a coherent host-visible device-local memory type. Discrete-only memory keeps recurrent state device-local. Prompt recurrent-state residency remains disabled. |
| Explicit fallback | VulkanKernelPolicy::portable_fallback() is the pre-device and device-unavailable baseline. Unsupported optional routes retain their narrow established fallback instead of disabling unrelated Vulkan routes. |
| Dispatch safety | Vulkan linear submissions are capped at exactly 20,000,000,000 estimated FLOP and oversized work is sub-chunked. The former floating-point environment parser and its zero-means-unbounded escape are removed. |
| Bounded operator tiling | Flash attention uses a 2048-row tile and a 10,000,000-element row-work budget. Frozen-BF16-weight matmul uses 128-row tiles. Generic elementwise work uses 1,048,576 elements per dispatch and exponentiation uses 65,536. All are positive immutable policy leaves. |
| Profiling and references | Kernel-stage and resident-decode profiling are disabled. GDN and normalization CPU-reference functions remain available for parity tests and offline diagnosis, but process environment cannot change live route selection. |
Receipts for earlier policy versions describe those historical binaries, not
the current product policy, and do not by themselves qualify v6.
The former variables represented by this table, including the applicable
KILN_DISABLE_VULKAN_*, KILN_ENABLE_VULKAN_*, kernel-threshold, split-K,
kernel-stage profiling, model-route, packed-weight, recurrence-residency, and
resident-decode controls, were deleted without aliases or replacement fields.
They permitted route mixtures and permissive fallback below the typed startup
boundary, and the model duplicated a different copy of several thresholds.
Historical optimization documents may name those variables as experiment
evidence; they do not describe current runtime controls. The research
microbenchmark remains a separate executable surface and must not be treated as
product configuration.
The serving library and product kernel paths no longer read residual
KILN_VK_* tiling or CPU-fallback switches. The separate
vulkan_decode_microbench research executable also has no KILN_* input: its
complete experiment policy is a typed, fail-fast command line documented
below. It is not server configuration, and invoking it does not create a
product qualification receipt. Non-Vulkan internal runtime controls are tracked
separately in the environment inventory.
Standalone benchmark configuration
kiln-bench loads the same typed KilnConfig as the server. --config selects
the TOML file; in its absence normal config discovery applies. In particular,
the [speculative] section supplies the method, draft proposal count, and draft
depth. The three --spec-* arguments are explicit per-invocation overrides for
controlled A/B work. The executable has no direct KILN_BENCH_*,
KILN_SPEC_*, or qualification environment reads.
| Argument | Type and exact default | Validation and effect |
|---|---|---|
--config <path> |
path; normal discovery | Loads typed startup configuration before device selection. |
--model-path <path> |
path; required | Local model and tokenizer directory. |
--max-output-tokens <n> |
positive integer; 128 |
Maximum generated tokens per request. |
--prompt-tokens <n> |
positive integer; 512 |
Approximate generated benchmark prompt length. |
--training-steps <n> |
unsigned integer; 10 |
SFT steps when training is not skipped. |
--skip-training |
flag; false | Omits the SFT benchmark. |
--paged |
flag; false | Uses the production paged-KV latency path. |
--latency-only |
flag; false | Stops after latency and emits empty throughput/training results. |
--latency-warmup-runs <n> |
unsigned integer; 0 |
Runs unmeasured complete latency passes first. |
--seed <u64> |
integer; 42 |
Selects prompt and deterministic sampler trajectory. |
--chat-template |
flag; false | Applies Qwen ChatML framing to the MTP arm. |
--prompt-subset <name> |
all, gsm8k, humaneval, or c4; all |
Selects the MTP prompt pool. Unknown values are fatal. |
--temperature <f32> |
finite non-negative number; 0.0 |
Sampling temperature for every benchmark arm. |
--spec-method <method> |
off, skip_layer, or mtp; typed [speculative] effective method |
Overrides only this benchmark invocation. Unknown values are fatal. |
--spec-num-tokens <n> |
integer; typed speculative.num_speculative_tokens |
Must pass the model speculative window validation, currently 1..=4. |
--spec-draft-layers <n> |
integer; typed speculative.draft_layers |
Must be positive and less than model layer count. |
--force-mtp |
flag; false | Bypasses benchmark shape routing; it does not enable serving. |
--log-tokens |
flag; false | Emits generated token IDs for the paged non-speculative arm. |
--log-itl |
flag; false | Emits each measured ITL for the paged non-speculative arm. |
--allow-experimental-speculative |
flag; false | Required for a non-off method. Acknowledges unsupported research behavior; it does not make the run qualification evidence. |
-v, --verbose, -vv |
count; 0 |
Selects info or trace diagnostics. |
-q, --quiet |
flag; false | Selects warning diagnostics and wins over verbosity. |
The speculative benchmark opt-in is deliberately not named qualification.
Only a declared workload executed by scripts/qualification/run.py and a
strictly checked retained receipt constitute qualification evidence. A direct
benchmark command, including one using the experimental opt-in, does not.
vulkan_decode_microbench is an offline kernel research tool. It parses all
arguments before opening a Vulkan device. Unknown arguments/cases, empty list
items, malformed integers, and zero numeric values are fatal. Its complete base
and geometry surface is:
| Argument | Type and exact default | Effect |
|---|---|---|
--only <case,...> |
validated CSV; all 16 cases | Runs a subset of full_attn_qkv, mlp_bf16_gu_f32_d, mlp_bf16w, linear_decode, causal_conv1d_update, gdn_gated_norm, qwen_rmsnorm, gdn_gates, gdn_in_proj, gdn_block_resident_batched, full_step_resident, full_step_resident_batched, full_token_resident_batched, full_token_resident_mixed_batched, full_token_resident_mixed_paged, and full_token_resident_paged. |
--batches <n,...> |
positive-integer CSV; 1,4,8,16,32,64 |
Batch sweep. |
--warmup-iters <n> |
positive integer; 10 |
Untimed iterations per result. |
--timed-iters <n> |
positive integer; 30 |
Iterations in each timed block. |
--repeats <n> |
positive integer; 5 |
Timed blocks; the minimum block mean is reported. |
--attention-history <n> |
positive integer; 256 |
Contiguous attention history for the mixed resident case. |
--paged-history <n> |
positive integer; 256 |
Paged-attention history. |
--paged-block-size <n> |
positive integer; 16 |
Paged KV block size. |
The microbenchmark kernel-policy arguments are explicit research A/B controls; they never modify product policy:
| Argument | Exact default/effect |
|---|---|
--mlp-rows8-min-batch <n> |
256 |
--mlp-gate-up-rows4-min-batch <n> |
8 |
--mlp-down-rows4-min-batch <n> |
16 |
--linear-rows8-min-batch <n> |
64 |
--linear-rows4-min-batch <n> |
16 |
--gdn-in-proj-rows8-min-batch <n> |
64 |
--gdn-in-proj-rows4-min-batch <n> |
16 |
--full-attn-qkv-rows8-min-batch <n> |
64 |
--full-attn-qkv-rows4-min-batch <n> |
2 |
--disable-linear-rows4, --disable-linear-rows8 |
Both routes default enabled. |
--disable-mlp-rows8, --disable-mlp-gate-up-rows4, --disable-mlp-down-rows4 |
All three routes default enabled. |
--disable-full-attn-qkv-rows4, --disable-full-attn-qkv-rows8 |
Both routes default enabled. |
--disable-gdn-in-proj-pair-qkv-z, --disable-gdn-in-proj-row-pair, --disable-gdn-in-proj-row-quad |
All three routes default enabled. |
--enable-gdn-in-proj-row-octet |
Eight-row grouping defaults disabled. |
--enable-gdn-in-proj-conv-split-fusion |
Projection/conv fusion defaults disabled. |
--disable-gdn-qk-norm-recurrent-fusion |
Q/K-normalization recurrence fusion defaults enabled. |
ROCm synchronization semantics
legacy_host_barriers is the portable default. It preserves the conservative
device-wide barriers around large hipBLASLt results and BF16/F32 cast
boundaries, the historical active-stream waits after eager tensor operations,
and a device-wide external-yield drain before generated progress is published.
Choosing it retains ordering safety without relying on device identity.
stream_ordered is an explicit local-qualification mode. It omits only
barriers whose call site asserts that producer and consumer are FIFO-ordered on
the same HIP stream. It does not omit host readback, host-buffer lifetime,
in-place mutation, allocator reclaim, graph transition, error recovery, or
global-state drains. External yield waits for the primary producer stream
rather than the whole device. A replayed graph records completion on its
capture stream and makes the primary stream wait on that event before the
external-yield stream wait, so replay work is included.
ROCm matmul route semantics
The portable defaults are disabled strided batching and f32_then_cast
output. They select per-row GEMMs and F32 output followed by an on-device BF16
cast without inspecting the device model or ROCm version. enabled and
native_bf16 are explicit diagnostic comparison routes.
The retired machine-shaped auto values fail parsing. The effective values
are reported with source attribution by kiln config, /v1/config, health,
and trusted debug state. Former force/disable and trace variables are ignored;
no matmul path reads process environment during execution.
ROCm token-only LM-head qualification fixture
The default native_default profile disables the W8 token-only LM-head routes,
as does portable_fallback; both retain the
ordinary BF16 LM head. Historical W8/W8A8 route
attribution is available only in the explicit hardware-qualification example
build; it is not a server profile or environment-selectable product path.
See Local Hardware Qualification for fixture behavior,
telemetry, and receipt interpretation.
ROCm synchronization telemetry and quarantine
The primary ROCm context stores the immutable policy. A second caller asking for a different policy on the same device receives a startup error naming the already-installed and requested policies. This prevents two model/runtime owners from silently mixing synchronization disciplines.
Synchronization telemetry has 23 fixed reason values. /health reports device
wait count, stream wait count, waited nanoseconds, and skipped count for every
reason under decode_runtime.rocm_synchronization. The same object exposes
cleanup_quarantined: when true, a fatal execution or synchronization failure
made device state unsafe. The flag is shared by every context for that device
ordinal and is process-lifetime sticky: a later recovery drain may collect
diagnostics, but cannot re-enable execution or cleanup. New ROCm execution is
rejected, possibly in-flight HIP resources are retained instead of being
destroyed unsafely, backend admission fails closed, and the process must be
restarted. Active ROCm telemetry becoming unavailable is treated as the same
fail-closed health condition rather than as a false quarantine value. The
central server health gate observes and latches this state before adapter,
training, import, or other backend mutation admission, so those paths cannot
slip through before the model runner notices the fault. This is live state, so it is
reported by health and trusted debug rather than /v1/config; the latter remains
the immutable policy authority. /metrics exports the same
fixed dimensions as kiln_rocm_synchronizations_total,
kiln_rocm_synchronization_wait_seconds_total, and
kiln_rocm_synchronization_skipped_total, plus policy, availability, and
kiln_rocm_cleanup_quarantined gauges. Treat the quarantine gauge as unknown
unless kiln_rocm_synchronization_telemetry_available is 1.
Reading these surfaces loads atomics only; it never synchronizes the device or
probes the driver.
capture_rollback and error_recovery are deliberately different reasons.
After a native capture error, capture_rollback may settle the device while
execution admission remains open; eager continuation is allowed only after the
runner also proves that its logical recurrent state was restored. A settlement
failure, a logical-rollback failure, or an armed/unclassified capture guard
leaving scope publishes the process-lifetime STOP state first, then uses
error_recovery only as a diagnostic drain. That fatal path remains
cleanup-quarantined even if the later drain succeeds and always requires a
process restart.
Stream-ordered mode is not promoted by configuration alone. Qualify legacy and stream-ordered runs on the same source tree using token/logit parity, throughput at concurrency 1/8/16/32/64, p50/p95/p99/max inter-token latency, reasoned synchronization time, and stable memory plateaus before changing the default.
ROCm graph lifecycle
disabledbypasses graph-shaped warmup, capture, and replay.warmup_then_eagerruns one graph-shaped eager warmup, never captures, and remains eager. It exists for controlled graph-state-machine comparisons.lazy_capture_replaywarms eagerly and may capture/replay eligible decode shapes while serving. Capture/fallback/replay state remains visible in/health.profileis the recommended default: stable and development serving select guarded lazy capture/replay, while drained maintenance stays eager.
Entry count and retained bytes are independent hard limits. Byte accounting deduplicates physical ROCm allocations by device pointer, counts graph-stable I/O, freeze-pointer capture arenas, each private stream's actual hipBLASLt workspace, and persistent recurrent/conv slot state once per owner. Health, trusted debug, and Prometheus split those categories and report peak bytes, evictions, admission rejections, and the number of opaque HIP graph, exec, stream, and event objects. The byte budget deliberately does not pretend that HIP exposes the allocator overhead of those opaque objects; live driver memory pressure remains a separate complementary signal.
Before native capture, the runner reclaims eligible idle owners at entry/byte saturation. If those cannot make room, it computes a deterministic fair-LRU order across active owners. The incoming candidate counts toward its owner's projected share; each step selects the most represented owner, then its oldest exact geometry with stable owner/geometry tie-breakers. Admission retires only the minimum entries needed and preserves at least one graph per active owner after the candidate, plus every live recurrent-state slot, row assignment, and decode-continuity timeline. No active graph is retired while unused global entry and byte headroom remains. The runner then performs one settled warm Record pass, measures the candidate's exact queryable allocation identities, rechecks matching-device pressure, and atomically reserves global governor headroom. Native capture begins only after that sequence admits it. A governor device-selector mismatch fails closed rather than consuming another accelerator's headroom. The Record pass necessarily allocates the candidate before its exact size is knowable. Phase telemetry independent of the model and graph-runner locks plus last/peak transient-candidate bytes make that residual exposure observable. Before any capture-parity snapshot allocation, a separate matching-device reservation covers two GDN state snapshots, the eager hidden copy, all current K/V rows, one current-row gather, and the largest exact U8 comparison mask. The later exact candidate reservation overlaps it through native capture, so the transient high-water mark includes both working sets. A candidate that alone exceeds the byte budget or cannot be accounted exactly makes its geometry non-capture-safe for this runner. Aggregate byte-budget suppression clears after ownership or budget relief; global-reservation denial retries after the matching device reports enough cached headroom. A selector mismatch remains fail-closed rather than consuming another accelerator's budget. None repeats a full warm pass on every token.
Ordinary budget eviction is deterministic least-recently-used eviction of
idle owners as a unit, including every graph for the owner and its retained
slot state. Those owners are always considered before fair active relief. At
actual saturation, boundary pre_capture_active_fair_share settles and retires
the selected active graph entries in one narrow transaction. A cache hit is
never an admission candidate, and the algorithm never removes an active
owner's last projected graph merely to grow another owner's share.
Every completed transaction emits rocm_graph_cache_eviction with its
boundary, typed reason, removed graph/slot counts, released requested bytes,
and active_graph_only_owner_count. A nonzero active count identifies the
settled prior-geometry retirement path rather than an idle-owner eviction.
Moderate pressure permits retained replay but blocks cache growth. Tight
pressure additionally reclaims eligible idle owners while preserving an active
cache hit. Critical or unavailable pressure disables replay,
reclaims all graphs only after device settlement, and uses eager execution only
if both pre-drop and post-drop settlement prove cleanup safe. A destructor,
async-free, or settlement failure activates the process-lifetime device
quarantine; no reclaimed-byte success is reported and no eager retry follows.
ROCm graph observability contract
GET /v1/config and trusted GET /v1/debug/model-state expose two independent
live values and a reason beside each one:
rocm_graphsis the nonblocking full cache/counter snapshot, withrocm_graphs_unavailable_reason.rocm_graph_telemetryis the current/completed phase and transient-candidate snapshot, independent of the model and graph-runner locks, withrocm_graph_telemetry_unavailable_reason.
Each value is either an object with a null reason or null with exactly one of
backend_without_graph_runner, model_runner_busy,
model_runner_lock_poisoned, graph_runner_busy, or
graph_runner_lock_poisoned. The full snapshot can use any of those five. The
phase handle is stored outside both runner locks, so a real backend retains live
phase telemetry through model-runner and graph-runner contention or poison;
currently only backend_without_graph_runner makes that value null. The phase
reason family nevertheless uses the same closed schema. Do not interpret any
null value as an empty cache or zero activity.
Health flattens both authorities into decode_runtime.rocm_graphs for an
operational view. Its state is enabled or disabled when full statistics
are present, busy only for model_runner_busy or graph_runner_busy, and
unavailable for the no-runner and poisoned-lock reasons. unavailable_reason
belongs to the full statistics. phase_telemetry_available and
phase_telemetry_unavailable_reason independently govern current_phase,
current_phase_elapsed_micros, six phase summary objects, and last/peak
transient candidate bytes. Every unavailable field is serialized as null;
the server never fabricates a zero snapshot.
For a coherent point-in-time full snapshot, rocm_graphs also serializes the
six completed phase summaries and last/peak transient bytes. The separate
rocm_graph_telemetry object is the authoritative current-phase source and
continues advancing when full statistics cannot acquire either runner lock.
Health sources its phase and transient fields from that separate channel.
The phase names are exactly pre_candidate_headroom, candidate_warm,
pre_native_reservation, native_capture, native_replay, and
rejected_candidate_cleanup. Each completed phase object contains calls,
slow, total_duration_micros, and max_duration_micros; slow means at
least 100 ms. current_phase_elapsed_micros uses a monotonic clock while a
phase is active. native_capture remains active through capture, the settled
first launch, defensive cache admission/publication, and the blocking committed
governor debit. rejected_candidate_cleanup begins only when an unretained
candidate enters destruction and settlement. last_transient_candidate_bytes and
peak_transient_candidate_bytes measure the peak matching-device reservation
for the exact deduplicated pre-admission candidate plus the capture-parity
snapshot/gather/mask working set. Already-owned recurrent slot state and opaque
native objects remain excluded. These values are not retained-cache bytes; only
the candidate subset is committed when admission retains the graph.
native_replay covers per-replay device input updates, the default-stream to
capture-stream dependency, and native launch submission. It does not include
the external-yield settlement that makes the result safe to publish; that wait
is reported separately as request synchronization_ms. Direct and batched ROCm
serving snapshot phase totals while holding the graph-runner lock for exactly
one invocation, so their request graph_capture_ms and graph_replay_ms fields
cannot absorb another concurrent request's work. A zero value means the phase
ran below microsecond resolution; null means that route did not run the phase.
For batched decode, the same invocation envelope is attached only to the ready requests whose rows participated. It is intentionally a per-request overlap candidate, so summing requests can duplicate shared work by the decode width; process-work totals remain authoritative in the six lifetime phase summaries. ROCm mixed-load qualification rejects request totals above lifetime phase time times maximum observed decode width, which also catches contamination from prefilling or backpressured active slots.
Native ROCm HIP-graph capture supports both single-row decode and the contiguous
BF16 multi-row route. Batched graphs are keyed by row count and bucketed
attention geometry. They retain graph-stable token IDs, positions, RoPE tables,
block tables, sequence lengths, KV slots, per-layer attention scratch, output
hidden state, and any GDN recurrent state. Final normalization, LM head, and
sampling remain eager after the graph. A width-four graph therefore reports one
active graph slot across changing request cohorts; it is not an idle single-row
owner. multi_row_batch_unsupported remains in the closed schema so historical
receipts stay valid, but a supported current batched route must leave it zero
and show real capture/replay activity instead.
Before a new batched graph becomes replayable, its first launch is compared
exactly with the already-required eager warm pass. The comparison covers hidden
output, every recurrent and convolution state tensor, and the current K/V rows
for every full-attention layer. Native same-dtype equality produces one bounded
U8 mask at a time and reads back only the reduced scalar. Structured event
rocm_graph_capture_parity_check reports passed, failed, or error, whether
comparison completed, compared bytes, duration, hidden equality and the first
recurrent, convolution, K, and V layer mismatch, or the comparison error.
Comparison failure follows the capture rollback/settlement contract, counts as
capture_failure, disables further graph execution for the runner, and reaches
eager only after state restoration and containment succeed.
Health makes the admission proof durable with process-lifetime
batched_capture_attempts, batched_capture_successes,
batched_capture_deferrals, batched_capture_failures,
capture_parity_checks, capture_parity_passes,
capture_parity_failures, capture_parity_errors,
capture_parity_compared_bytes for completed equality operations, and
capture_parity_duration_micros. Batched attempts and parity checks each
reconcile to their closed outcome sets. Every
successful batched capture has a prior passed check, so cumulative successes
cannot exceed cumulative passes. Equality is required for a clean qualification
window; a passed check followed by a later cache-admission error is retained as
a pass plus capture failure rather than falsified into a successful admission.
The eager-fallback reasons are exactly multi_row_batch_unsupported,
cold_cache_host_round_trip,
persistent_host_round_trip, shape_dependent_attention,
graph_cache_capacity, graph_cache_byte_budget,
graph_accounting_incomplete, moderate_memory_pressure,
tight_memory_pressure, critical_memory_pressure,
memory_reservation_denied, memory_governor_selector_mismatch,
capture_failure, and replay_failure. The full snapshot reports one counter
per reason plus total, slow, total-duration, and maximum-duration values.
Prometheus always emits two availability gauges and two closed one-hot reason
families. A zero kiln_rocm_graph_telemetry_available is explained by
kiln_rocm_graph_snapshot_unavailable{reason} and omits only the full
cache/counter families. A zero
kiln_rocm_graph_phase_telemetry_available is explained by
kiln_rocm_graph_phase_telemetry_unavailable{reason} and omits only current
phase, phase latency, and transient-candidate families. Both reason labels use
the same five-value set above. Phase availability remains one for a real backend
while full snapshot availability is zero during either runner-lock contention
or poison. Full
families cover state; cache, slot, owner, retained-byte and opaque-object
gauges; admissions, evictions and their four causes; three post-capture
rejection reasons; five pre-capture skip reasons; capture/replay outcomes;
batched capture attempts/outcomes; first-launch parity checks/outcomes, logical
bytes, and duration; and all 14 fallback reasons and latency. The
fixed-cardinality families are
kiln_rocm_graph_batched_capture_attempts_total,
kiln_rocm_graph_batched_capture_outcomes_total{outcome="success|deferred|failure"},
kiln_rocm_graph_capture_parity_checks_total,
kiln_rocm_graph_capture_parity_outcomes_total{outcome="passed|failed|error"},
kiln_rocm_graph_capture_parity_compared_bytes_total, and
kiln_rocm_graph_capture_parity_duration_seconds_total. Live families cover
the one-hot current phase, active elapsed seconds, calls/slow/total/max duration
for all six phases, and last/peak transient bytes. Every label set is closed;
request, shape, allocation, and configured-byte values never become labels.
Graph-stable paged metadata is a correctness invariant rather than a knob.
The runtime no longer reads KILN_ROCM_GRAPH_STABLE_PAGED_METADATA, graph
cache/capture flags, matmul synchronization thresholds, or full-attention
handoff flags inside decode. The three historical graph variables listed in
the table are parsed once by the typed startup loader. Setting both historical
graph-mode aliases is rejected even when their booleans happen to agree; use
the canonical enum to state one unambiguous lifecycle.
[batching]
These values are resolved once, after backend selection and after
server.deterministic, server.max_decode_batch, and
server.max_batch_tokens determine the effective decode width. Every change
requires a process restart; none is a live tuning control.
| TOML field | Type and exact default | Canonical env target | Alternate env spelling(s) | Validation and effective semantics |
|---|---|---|---|---|
batching.rowwise_decode |
boolean; false |
KILN_BATCHING_ROWWISE_DECODE (implemented) |
none | false sends each ready cohort through one true batched forward. true issues one forward per row while retaining actor ownership; it is an emergency correctness comparison, normally reduces throughput, and does not increase the effective decode width. Restart required. |
batching.prefix_aware_admission |
boolean; true |
KILN_BATCHING_PREFIX_AWARE_ADMISSION (implemented) |
none | When true, a queued same-adapter strict descendant waits while its active shorter prefix can become reusable; independent rows may still be admitted. Disable only for a controlled admission A/B. Restart required. |
batching.prefill_admission_quantum |
"auto" or unsigned integer; "auto" |
KILN_BATCHING_PREFILL_ADMISSION_QUANTUM (implemented) |
none | An integer must be 1..=65536 and caps how many queued prompts the actor admits in one cycle before returning to decode. auto is case-insensitive and uses the backend policy below. The selected value is then clamped to 1..=effective max_decode_batch; the diagnostics name effective_decode_width as final authority when it performs that clamp. With non-burst admission, total active capacity is effective decode width plus this staging quantum, capped internally at four staging slots. Restart required. |
batching.actor_cycle_idle_ms |
unsigned integer milliseconds; 0 |
KILN_BATCHING_ACTOR_CYCLE_IDLE_MS (implemented) |
none | 0..=60000. Zero preserves the unpaced actor. A nonzero value inserts one intentional cooperative wait after an actor cycle that advanced prefill or decode, only after synchronous accelerator work has returned. The actor polls control commands at intervals no longer than 5 ms, so shutdown remains responsive, and the independent response-delivery worker and HTTP process remain live. This deliberately trades request throughput and inter-token latency for a lower sustained accelerator duty cycle; it is not a temperature controller and never changes itself from a live sensor. Config, health, debug, Prometheus, and serving-benchmark receipts expose the policy and observed waits. Restart required. |
Every real backend uses the batching actor. There is no activation switch and no second direct-stream decode scheduler. This invariant gives cancellation, backpressure, admission, adapter barriers, KV ownership, and shutdown one state machine. Mock mode keeps the deterministic scheduler-backed test engine and does not construct a production actor.
Backend-owned auto policy
auto preserves backend qualification rather than imposing one cross-device
default. The matrix is evaluated against the final effective decode width, not
the unconstrained backend maximum.
| Backend | Backend decode width before server constraints | prefill_admission_quantum = "auto" |
burst_prefill_admission diagnostic |
actor_prefill_tile_alignment_required diagnostic |
|---|---|---|---|---|
| CUDA | 8 | effective decode width | true | false |
| ROCm | 8 | 4, clamped to effective width | false | true |
| Vulkan | 64 | effective decode width | false | false |
| Metal | 8 | 4, clamped to effective width | false | false |
| CPU/other | 8 | 4, clamped to effective width | false | false |
burst_prefill_admission is backend-owned and intentionally has no TOML or
public environment field. On CUDA it lets admission refill the decode width in
one actor turn. It is reported with the four primary-actor settings so an observed
CUDA/Vulkan/ROCm difference is not mistaken for a hidden runtime override.
actor_prefill_tile_alignment_required is also backend-owned. ROCm sets it
because local deterministic parity proved that changing a prompt partition can
change greedy output. Startup therefore requires actor prompt chunks and the
qualified streaming-prefill tile policy to preserve one numerical partition.
Effective policy and provenance
GET /v1/config reports the exact startup result at
batching.configuration and whether an actor was actually constructed at
batching.actor_active. A typical ROCm default is:
{
"batching": {
"configuration": {
"rowwise_decode": { "enabled": false, "source": "default" },
"prefix_aware_admission": { "enabled": true, "source": "default" },
"prefill_admission_quantum": {
"configured": null,
"configured_source": "default",
"backend_policy": 4,
"effective": 4,
"effective_source": "backend_policy"
},
"actor_cycle_idle": {
"milliseconds": 0,
"source": "default",
"enabled": false,
"command_poll_milliseconds": 5
},
"burst_prefill_admission": false,
"actor_prefill_tile_alignment_required": true
},
"actor_active": true
}
}
For explicit values, the configured source is config_file or environment.
The complete effective-source enum is default, backend_policy,
config_file, environment, or effective_decode_width. The admission quantum uses
effective_decode_width when the final decode width lowers the selected value.
A nonzero actor-cycle idle has no backend-derived effective value: its exact
configured milliseconds and source are immutable for the process. The actor
applies it only after a cycle performed model work, not while idle, queued, or
waiting for a request. Because the delay begins only after synchronous
accelerator return, it does not suspend outstanding device work. It is
reported so qualification can measure its throughput and ITL cost. A configured
quantum is retained even when clamped, so intent and execution cannot be
confused.
GET /health repeats the same immutable object at
decode_runtime.batching_configuration beside the optional live
decode_runtime.batching_engine snapshot. The trusted debug response keeps the
batching_engine.enabled actor-activity flag and the immutable object at
batching_engine.configuration. A real backend always reports the actor live;
mock mode reports no production actor snapshot.
When the actor exists, the live health/debug snapshot reports
actor_cycle_idle_ms, actor_cycle_idle_source, actor_cycle_idle_active,
actor_cycle_idle_count, total_actor_cycle_idle_ms, and
max_actor_cycle_idle_ms. The same snapshot reports
actor_barrier_adapter_active and actor_barrier_resize_active while an
ordered mutation is waiting for the active batch to drain or executing at the
between-requests boundary. Prometheus exports the same process-lifetime state as
kiln_batching_engine_actor_cycle_idle_configured_seconds,
kiln_batching_engine_actor_cycle_idle_active,
kiln_batching_engine_actor_cycle_idles_total,
kiln_batching_engine_actor_cycle_idle_seconds_total, and
kiln_batching_engine_actor_cycle_idle_max_seconds, plus the live gauges
kiln_batching_engine_actor_barrier_adapter_active and
kiln_batching_engine_actor_barrier_resize_active. These counters make an
intentional duty-cycle delay distinguishable from an unexplained inference
stall, while the barrier gauges distinguish an intentional model/KV mutation
from ordinary actor work without adding a control-plane wait. They do not
replace request-local adapter_ms or resize_ms. Serving benchmark driver v19 records the actor as the only request
route, snapshots an idle boundary outside each
measured request window and fails its actor_cycle_idle_accounted gate when the
source, count, elapsed time, maximum, or final active state contradicts the
configured policy.
kiln config --file <path> validates and prints all four [batching] startup
values: rowwise decode, prefix-aware admission, prefill quantum, and
actor-cycle idle. It also prints the combined actor-cycle budget, prompt-token and layer
ceilings, configured decode-width ceiling, streaming mode, threshold, base,
tape, and detached full-attention tiles with source provenance. It does not
construct an accelerator. Add --backend rocm (or another target) to resolve
the alignment requirement, decode width, streaming
dispatch, and tiles from the same backend policies used at serve startup. The
command applies the real actor-prefill contract and exits nonzero before any
hardware access when the combination is invalid. Without --backend, it names
those values as a serve-startup contract instead of guessing a target. Inspect
/v1/config after restart for actual selected-device and actor state.
[model]
| TOML field | Type and exact default | Canonical env target | Alternate env spelling(s) | Validation and effective semantics |
|---|---|---|---|---|
model.path |
optional string; omitted (None) |
KILN_MODEL_PATH (implemented) |
none | Must be non-empty when set. Omitted starts the server in mock mode; a real model path enables real inference. |
model.model_id |
string; "Qwen/Qwen3.5-4B" |
KILN_MODEL_MODEL_ID (implemented) |
none | Must be non-empty. Used for model/tokenizer identity and as the source of the default served id. Kiln still applies its built-in Qwen3.5-4B runtime profile. |
model.tokenizer_path |
optional string; omitted (None) |
KILN_MODEL_TOKENIZER_PATH (implemented) |
none | Must be non-empty when set. |
model.adapter_dir |
optional string; omitted (None) |
KILN_MODEL_ADAPTER_DIR (implemented) |
none | Must be non-empty when set. For the Qwen3.5-4B profile, omission resolves to <model.path>/adapters. |
model.snapshot_dir |
optional string; omitted (None) |
KILN_MODEL_SNAPSHOT_DIR (implemented) |
none | Must be non-empty when set. An empty or whitespace-only canonical environment value clears a TOML value. Without a value, Kiln tries a location beside the model and then the system temporary directory. |
model.checkpoint_read_mib_per_second |
optional unsigned integer MiB/s; omitted (None) |
KILN_MODEL_CHECKPOINT_READ_MIB_PER_SECOND (implemented) |
none | 1..=16384 when set. Independently bounds the private snapshot copy, initial full content verification, and post-upload full verification. Reflinked bytes are not charged as reads. Shutdown is checked between bounded chunks and at most every 25 ms during waits. Omission removes rate limiting but preserves cancellation. Applies to real-model startup on every backend, requires restart, and is never active during inference. GET /v1/config.model_startup.checkpoint_read reports all three phase observations. |
model.accelerator_weight_upload_mib_per_second |
optional unsigned integer MiB/s; omitted (None) |
KILN_MODEL_ACCELERATOR_WEIGHT_UPLOAD_MIB_PER_SECOND (implemented) |
none | 1..=16384 when set. Reserves the cumulative eager base-model source-byte schedule before the base group and each layer, then checks it again after the unit. The base group adds shutdown boundaries after embedding upload, transpose, pack, final norm, and rotary initialization. Transforms can add device work, so this is not a bus-throughput cap. The current backend operation is not interruptible; reservation waits poll cancellation every 25 ms. Omission removes rate limiting but preserves boundary cancellation. Inapplicable to mock and CPU-only execution. Startup-only, restart required, and never active during inference. GET /v1/config.model_startup.accelerator_weight_upload reports reserved/completed bytes and layers. |
model.vulkan_decode_weight_prewarm |
boolean; true |
KILN_MODEL_VULKAN_DECODE_WEIGHT_PREWARM (implemented) |
none | Populates backend-private Vulkan decode-weight caches during startup. Disable only to trade first-request latency for lower startup work. Restart required. |
model.vulkan_decode_weight_prewarm_mib_per_second |
unsigned integer MiB/s; 256 |
KILN_MODEL_VULKAN_DECODE_WEIGHT_PREWARM_MIB_PER_SECOND (implemented) |
none | 1..=16384. Bounds the average Vulkan decode-weight cache materialization rate. Pacing checks shutdown at least every 25 ms between uploads. Restart required. |
model.served_model_id |
optional string; omitted (None) |
KILN_MODEL_SERVED_MODEL_ID (implemented) |
none | Must be non-empty when set. Otherwise the effective id is the final slash-separated component of model.model_id (Qwen3.5-4B by default). serve --served-model-id applies a typed, validated override after environment resolution. |
[paths]
This section owns process-lifetime filesystem locations shared across backend crates. Resolution happens before model loading or accelerator construction, so inference never changes cache location in response to process environment.
| TOML field | Type and exact default | Canonical env target | Alternate env spelling(s) | Validation and effective semantics |
|---|---|---|---|---|
paths.cache_root |
optional path string; omitted (platform account cache directory) | KILN_PATHS_CACHE_ROOT (implemented) |
none | Must be a non-empty path when set. Relative paths are made absolute against the startup working directory. The resolved root is installed before cache consumers and cannot change during the process lifetime. GET /v1/config.paths reports the absolute effective path and source. |
When omitted, paths.cache_root resolves from the operating-system account
database to ~/.cache/kiln on Linux and other Unix hosts or
~/Library/Caches/kiln on macOS. Kiln does not consult HOME or
XDG_CACHE_HOME; use the typed field or its mechanical environment spelling
instead. If the account database has no home, Kiln uses the system temporary
directory. The root owns BLAS/rocBLAS autotune data, Vulkan pipeline caches,
and transposed model weights. kiln config prints the same resolved path.
[memory]
| TOML field | Type and exact default | Canonical env target | Alternate env spelling(s) | Validation and effective semantics |
|---|---|---|---|---|
memory.num_blocks |
optional unsigned integer; omitted (None) |
KILN_MEMORY_NUM_BLOCKS (implemented) |
none | Must be greater than zero when set. Omission invokes backend-aware automatic KV-block sizing. |
memory.gpu_memory_gb |
optional finite number; omitted (None) |
KILN_MEMORY_GPU_MEMORY_GB (implemented) |
none | Must be finite, greater than zero, and representable as bytes. Units are GiB. This is a capacity cap, not a hardware override: it may reduce the detected safe capacity but never expands physical VRAM, host-backed unified memory, or a cgroup-bounded capacity. A request above the safe detected capacity is clamped down. |
memory.inference_memory_fraction |
finite number; 0.7 |
KILN_MEMORY_INFERENCE_MEMORY_FRACTION (implemented) |
none | Loader validation accepts 0.0..=1.0; real-state construction clamps the configured value to 0.1..=1.0 before KV sizing. The remainder is available to the training budget. |
memory.training_memory_gb |
optional finite number; omitted (None) |
KILN_MEMORY_TRAINING_MEMORY_GB (implemented) |
none | Must be finite, greater than zero, and representable as bytes when set. Optional training-budget cap in GiB; it can reduce but never expand the capacity remaining after resident model and KV allocations. |
memory.vulkan_buffer_pool_gb |
finite number; 3.0 |
KILN_MEMORY_VULKAN_BUFFER_POOL_GB (implemented) |
none | Vulkan-only process-wide cap, in GiB, on idle scratch buffers retained for reuse. Must be finite, non-negative, and representable as bytes; 0 disables retention. Active operations may allocate beyond the cap, but overflow buffers are freed when their final caller drops. A new cache entry evicts the oldest idle buffers before admission, and pressure reclaim releases idle entries under exclusive GPU coordination. /v1/config, /health, and Prometheus expose the cap, retained/free/borrowed bytes, hits/misses by allocation route, evictions, and uncached overflow. Health also exposes one bounded last-miss record with requested and bucket bytes plus the source callsite. |
memory.floor_gb |
finite number; 1.0 |
KILN_MEMORY_FLOOR_GB (implemented) |
none | Must be finite, non-negative, representable as bytes, and strictly smaller than the selected accelerator's effective capacity after memory.gpu_memory_gb is applied. Units are GiB. Accelerator startup rejects an equal or larger floor before model upload and reports both configured and effective byte values. The process-wide governor subtracts this additional floor, then outstanding soft reservations, from live free memory when computing allocation headroom. On unified-memory devices it is separate from the physical-memory reserve applied during safe-capacity detection. |
memory.probe_ms |
unsigned integer; 500 |
KILN_MEMORY_PROBE_MS (implemented) |
none | Must be greater than zero. Sets the background memory-sampler cadence. Request, inference, health, and metrics paths read only the published sample and never run a driver/OS probe synchronously. Cached admission fails closed when the sample is older than max(5000 ms, 4 * probe_ms), the latest probe failed, or a required sampler is not running. An explicit refresh after a material allocation or release bypasses the cadence. |
memory.reclaim_mode |
string enum; "off" |
KILN_MEMORY_RECLAIM_MODE (implemented) |
none | Exactly off, on-demand, or automatic, case-insensitive with surrounding whitespace ignored. off prevents execution of registered allocator reclaim hooks; on-demand permits explicit pressure and allocation-retry reclaim calls; automatic also permits the background pressure monitor. The immutable serving profile remains authoritative: a profile with allocator reclaim disabled keeps the effective mode off and does not start the monitor. |
memory.kv_autoscale |
boolean; true |
KILN_MEMORY_KV_AUTOSCALE (implemented) |
none | Requests the pressure-driven physical KV-cache control loop. Backends without device-resident KV pressure report the request as unavailable rather than silently enabling mutation. /health, /v1/config, and the trusted debug state expose the request, effective state, bounded reason, and source. |
memory.kv_force_blocks |
unsigned integer; 0 (disabled) |
KILN_MEMORY_KV_FORCE_BLOCKS (implemented) |
none | A positive value requests one exact startup resize before the normal autoscaler loop. It requires memory.kv_autoscale=true and server.serving_profile="maintenance"; every other combination fails configuration validation. Zero disables the one-shot operation. The resize still uses full replacement-pool reservation, exclusive GPU ownership, graph invalidation, transactional publication, and typed forced_configuration attribution. This is an offline maintenance/qualification control, not a per-request tuning knob. |
memory.kv_cache_fp8 |
boolean; false |
KILN_MEMORY_KV_CACHE_FP8 (implemented) |
none | Requests E4M3FN KV storage. Backend storage policy may reject or disable the request when unsupported. |
memory.cuda_graphs |
boolean; true |
KILN_MEMORY_CUDA_GRAPHS (implemented) |
none | CUDA-only request. Non-CUDA backends ignore it, and a serving profile with live graph capture disabled selects eager-only execution regardless of this value. |
memory.cuda_graph_cache_entries |
unsigned integer; 8 |
KILN_MEMORY_CUDA_GRAPH_CACHE_ENTRIES (implemented) |
none | 1..=64. Bounds retained single-row CUDA decode graphs and their graph-stable device buffers. Resolved once before device selection; decode never re-reads process environment. The unqualified batched CUDA graph route remains unavailable. |
Capacity detection is device-scoped. Discrete accelerators use the selected device's driver-reported VRAM and never count GTT as device-local capacity. Linux DRM topology keeps the primary VRAM heap and a separately admissible host-backed GTT tier distinct. Any nonzero VRAM heap remains the primary pool, even when GTT is larger, because that is also a common discrete-AMD shape.
The host-backed tier is independently bounded by GTT free bytes,
MemAvailable, the most restrictive finite memory.max and memory.high
headroom across the visible cgroup hierarchy, and the unified-memory reserve.
Kiln's current Vulkan paged KV cache and recurrent prefix state are
host-resident, so startup requires them to fit both the primary accelerator
budget and this host-backed budget. Prefix state is reserved first; automatic
KV sizing uses the configured inference fraction of the remaining host-backed
headroom. Missing or exhausted host-tier evidence yields a startup error before
the zero-filled Rust allocation is attempted. CUDA and ROCm KV pools remain
device-resident and are not capped by this separate tier.
Only a driver reporting no local VRAM and a nonzero GTT heap is automatically
treated as fully host-shared. A host-shared primary pool retains
max(6 GiB, 25% of backing capacity) for the OS and CPU workloads. Apple
Silicon applies the same reserve to its unified pool and samples live host
pressure. The optional memory.gpu_memory_gb cap is applied only after safe
physical capacity is established.
The Vulkan scratch recycler is a cache, not an allocation entitlement. Its
memory.vulkan_buffer_pool_gb cap is applied to Vulkan's exact bound memory
requirements, including alignment, across device-local and host-visible
routes. Borrowed buffers count against the cap and are never evicted while a
caller owns them. When there is insufficient idle capacity, Kiln either evicts
the least-recently-used idle entries or returns an uncached buffer that is
destroyed normally. The memory governor can trim only idle entries and only
when the serving profile permits allocator reclaim; changing the cap requires
a restart. Recycler misses are counted separately for device-local and
host-visible allocation routes. GET /health retains only the most recent miss,
including its process-lifetime sequence, requested size, rounded bucket, route,
and Rust caller file and line; it reports null before any miss. This diagnostic
record has constant memory cost and is not a per-allocation log.
Device-local scratch lookup requires the exact rounded bucket. Host-visible staging lookup checks its exact bucket first, then selects the smallest sufficient idle larger bucket for the same Vulkan device and memory type, with oldest-use order breaking ties. This is sound because every host staging operation retains its logical copy/read extent; it prevents arbitrary prompt-tail shapes from allocating a new staging buffer while a larger compatible one is idle. Undersized and borrowed buffers are never candidates, and cross-device or cross-memory-type reuse is prohibited.
The paged KV block manager also favors residency locality: a completed request's block run returns to the front of the free list in its original logical order. The next compatible request reuses those already-touched pages before walking untouched sparse-zero capacity. On host-resident Vulkan KV pools, this bounds delayed anonymous/transparent-huge-page first touch without prefaulting the full configured cache; logical block ownership, prefix-cache leases, shrink retirement, and physical-resize safety are unchanged.
Physical-device identity remains fail-closed where backend enumeration and OS
memory probes expose unrelated logical ordinals. Typed
accelerator.vulkan_device_index now selects and reports the same Vulkan index
through kernel, model, and server code, but the subsequent memory-probe gate
still accepts it only when ordinal zero is the sole relevant DRM candidate.
This means an available nonzero Vulkan index is selected faithfully and then
rejected before model upload rather than being budgeted against another GPU.
CUDA and ROCm have the same single-candidate/ordinal-zero restriction.
Multi-device hosts, failed candidate enumeration, and driver-level visibility
or remapping controls such as CUDA_VISIBLE_DEVICES,
ROCR_VISIBLE_DEVICES, HIP_VISIBLE_DEVICES, MESA_VK_DEVICE_SELECT, or
DRI_PRIME are rejected. The canonical KILN_ACCELERATOR_VULKAN_DEVICE_INDEX
override is typed application configuration, not a driver remap; the retired
KILN_VULKAN_DEVICE and GGML_VK_VISIBLE_DEVICES names are ignored.
Automatic memory probing remains diagnostic-only;
CPU performs no accelerator probe, and Apple Silicon uses its single unified
physical memory pool. Multi-device startup remains unavailable until backend
selection and probing share a typed PCI address or UUID.
External accelerator environment safety
Driver visibility and ordinal-remapping variables are not Kiln configuration,
do not have TOML or KILN_* aliases, and cannot be changed through the API.
Kiln snapshots the presence of this closed set at the first accelerator memory-
probe validation, before model weights are loaded, and reuses that immutable
snapshot for the lifetime of the process:
| Driver family | Presence-only safety inputs |
|---|---|
| NVIDIA | CUDA_VISIBLE_DEVICES, NVIDIA_VISIBLE_DEVICES, CUDA_DEVICE_ORDER |
| ROCm | ROCR_VISIBLE_DEVICES, HIP_VISIBLE_DEVICES, CUDA_VISIBLE_DEVICES, GPU_DEVICE_ORDINAL |
| Intel | ZE_AFFINITY_MASK, ONEAPI_DEVICE_SELECTOR, SYCL_DEVICE_FILTER |
| Vulkan | MESA_VK_DEVICE_SELECT, DRI_PRIME, VK_ICD_FILENAMES, VK_DRIVER_FILES |
If any variable relevant to the selected family is present, device/probe
identity fails closed rather than interpreting its value or potentially
budgeting one physical device from another device's memory counters. Unset the
driver remap. Vulkan exposes the typed
accelerator.vulkan_device_index selector, subject to the single-device
identity restriction above; CUDA and ROCm do not yet expose a product
multi-device selector. Multi-device support requires a shared PCI-address or
UUID identity and cannot be enabled by adding another environment spelling.
[training]
| TOML field | Type and exact default | Canonical env target | Alternate env spelling(s) | Validation and effective semantics |
|---|---|---|---|---|
training.grad_checkpoint_segments |
optional unsigned integer; omitted (None) |
KILN_TRAINING_GRAD_CHECKPOINT_SEGMENTS (implemented) |
none | Must be greater than zero when set. When present, selects an explicit process-lifetime gradient-checkpoint segment count for native training; omission leaves workload- and capacity-aware automatic planning enabled. |
training.no_grad_checkpoint |
boolean; false |
KILN_TRAINING_NO_GRAD_CHECKPOINT (implemented) |
none | Disables gradient checkpoint execution for native training. The disabled state and any explicit segment count are retained together in the immutable training policy and exact-resume identity. Disabling checkpointing can materially increase training memory. |
training.recompute_checkpoint_boundaries |
string enum; "auto" |
KILN_TRAINING_RECOMPUTE_CHECKPOINT_BOUNDARIES (implemented) |
none | auto, enabled, or disabled, case-insensitive with surrounding whitespace ignored. auto replays sparse SFT boundaries when sequence length is at least recompute_boundary_threshold_tokens; enabled always replays them and disabled always retains them. Every other TOML type, TOML value, or environment value fails startup. |
training.recompute_boundary_threshold_tokens |
positive unsigned integer; 8192 |
KILN_TRAINING_RECOMPUTE_BOUNDARY_THRESHOLD_TOKENS (implemented) |
none | Inclusive sequence-length threshold used only by automatic SFT boundary replay. Zero, negative, overflowing, malformed, and non-UTF-8 environment values stop startup. |
training.checkpoint_boundary_anchor_stride |
"auto" or positive unsigned integer; "auto" |
KILN_TRAINING_CHECKPOINT_BOUNDARY_ANCHOR_STRIDE (implemented) |
none | When sparse SFT replay is active, a concrete value retains every Nth segment boundary as an anchor. auto derives a shape-specific positive stride from sequence length, segment count, hidden width, boundary dtype, and the cache target. Zero and strings other than auto fail startup. |
training.checkpoint_boundary_cache_gb |
positive floating-point GiB value; 6.0 |
KILN_TRAINING_CHECKPOINT_BOUNDARY_CACHE_GB (implemented) |
none | Automatic anchor-stride memory target. Despite the historical _gb spelling, the unit is GiB (2^30 bytes). The value must be finite, positive, convert to at least one byte, and remain below the u64 byte limit. Startup converts it once to integral bytes using the historical truncating conversion. |
training.checkpoint_interval |
optional unsigned integer; omitted (None) |
KILN_TRAINING_CHECKPOINT_INTERVAL (implemented) |
none | Must be greater than zero when set. Number of committed optimizer steps between checkpoints; per-job configuration overrides it. Omission disables periodic checkpoints. |
training.webhook_url |
optional string; omitted (None) |
KILN_TRAINING_WEBHOOK_URL (implemented) |
none | Must be a non-empty valid HTTP(S) URL. An exactly empty environment value clears a TOML URL; whitespace is not a clearing value and fails validation. Delivery is fire-and-forget with a five-second timeout after terminal state is recorded. |
training.logit_cache_dir |
optional path string; omitted (beside the effective adapter directory) | KILN_TRAINING_LOGIT_CACHE_DIR (implemented) |
none | Must be a non-empty path when set. Resolved once at startup; request handlers never reread the environment. |
training.max_queued_jobs |
unsigned integer; 32 |
KILN_TRAINING_MAX_QUEUED_JOBS (implemented) |
none | Must be greater than zero. At capacity, submissions return HTTP 503 with Retry-After: 30. |
training.max_tracked_jobs |
unsigned integer; 1024 |
KILN_TRAINING_MAX_TRACKED_JOBS (implemented) |
none | Must be greater than zero and at least max_queued_jobs. Counts queued, running, completed, and failed entries. |
training.tracked_job_ttl_secs |
unsigned integer; 604800 |
KILN_TRAINING_TRACKED_JOB_TTL_SECS (implemented) |
none | Must be greater than zero. Terminal entries older than the TTL are removed; active jobs are never age-evicted. |
Training GPU work is also governed by server.serving_profile; the default
stable profile grants coordinated training GPU ownership through the same
writer-priority protocol used for adapter transitions and physical memory
changes. maintenance is only required when inference must be fully drained.
Optimizer support is a resident capability, not configuration
There is intentionally no startup or request switch for optimizer fallback or
rounding. Product SFT, GRPO, OPD, the distinct DistillRefresh workload, and
OPD-backed distillation use immutable round-to-nearest. Stochastic rounding
remains available only to explicit Rust optimizer-library callers; it is not a
server product mode. Consequently, the
mechanical KILN_<SECTION>_<FIELD> rule produces no optimizer-policy
environment variable.
The following old process-global inputs were removed without aliases:
KILN_BF16_STOCHASTIC_ROUNDKILN_TRAINING_HOT_PATH_DEBUG_FALLBACKKILN_CUDA_TRAINING_OPTIMIZER_FALLBACKKILN_ROCM_TRAINING_OPTIMIZER_FALLBACKKILN_METAL_TRAINING_OPTIMIZER_FALLBACKKILN_VULKAN_TRAINING_OPTIMIZER_FALLBACK
Delete them from service definitions. There is no replacement field: silent host fallback during product training would change performance, precision, residency, and checkpoint identity. Unknown environment variables are not a supported way to select behavior.
GET /v1/config exposes the resident contract at
training.optimizer_support. A real runner returns schema ID
kiln.training-optimizer-support and version 1; a mock runner or a runner
whose snapshot cannot be read returns null. immutable_after_startup=true
means this is a process-lifetime capability snapshot, not mutable
configuration. The object has this complete shape (the arrays always enumerate
all four workloads and all three optimizer kinds):
{
"schema": {"id": "kiln.training-optimizer-support", "version": 1},
"backend": "rocm",
"device": "rocm:0",
"base_weight_dtype": "bf16",
"resolved_lora_parameter_dtype": "bf16",
"immutable_after_startup": true,
"rounding_modes": ["round_to_nearest"],
"backend_implementation_rounding_modes": ["round_to_nearest"],
"optimizer_tuple_kinds": ["muon", "adam_w", "sgd"],
"workloads": [
{
"workload": "sft",
"supported": true,
"unavailable_reason": null,
"allowed_optimizer_kinds": ["muon", "adam_w", "sgd"]
},
{
"workload": "grpo",
"supported": true,
"unavailable_reason": null,
"allowed_optimizer_kinds": ["muon", "adam_w", "sgd"]
},
{
"workload": "opd",
"supported": true,
"unavailable_reason": null,
"allowed_optimizer_kinds": ["muon", "adam_w", "sgd"]
},
{
"workload": "distill_refresh",
"supported": false,
"unavailable_reason": "distill_refresh is unavailable until admission pins separate exact SFT and OPD phase plans, prepares the exact SFT rows, and reserves the maximum sequential working set",
"allowed_optimizer_kinds": []
}
],
"optimizers": [
{
"kind": "muon",
"backend_implementation": {
"supported": true,
"route": "native_device_hook",
"native_device_hook": true,
"parameter_dtypes": ["f32", "bf16"]
},
"optimizer_tuple": {
"supported": true,
"unavailable_reason": null,
"lora_rank": {
"minimum": 2,
"maximum": 48,
"backend_maximum": 48,
"model_maximum": 1024,
"live_memory_admission_required": true
}
}
},
{
"kind": "adam_w",
"backend_implementation": {
"supported": true,
"route": "native_device_hook",
"native_device_hook": true,
"parameter_dtypes": ["f32", "bf16"]
},
"optimizer_tuple": {
"supported": true,
"unavailable_reason": null,
"lora_rank": {
"minimum": 1,
"maximum": 1024,
"backend_maximum": null,
"model_maximum": 1024,
"live_memory_admission_required": true
}
}
},
{
"kind": "sgd",
"backend_implementation": {
"supported": true,
"route": "native_device_hook",
"native_device_hook": true,
"parameter_dtypes": ["f32", "bf16"]
},
"optimizer_tuple": {
"supported": true,
"unavailable_reason": null,
"lora_rank": {
"minimum": 1,
"maximum": 1024,
"backend_maximum": null,
"model_maximum": 1024,
"live_memory_admission_required": true
}
}
}
]
}
Read the response as four distinct gates:
backend_implementationreports whether the optimizer library contains a raw executable update implementation, itsportable_referenceornative_device_hookroute, whether that route is an accelerator-native hook, and its parameter dtypes. It does not claim that resident server weights can execute a training workload. CPU therefore reportsportable_referencewithnative_device_hook=false. An unavailable raw implementation reportssupported=false, routeunavailable, andnative_device_hook=false;parameter_dtypesremains the backend's advertised kind-specific dtype set.optimizer_tuplecombines that implementation with the exact resident backend/device identity, base-weight dtype, resolved LoRA dtype, immutable product rounding rule, optimizer kind, and static LoRA-rank range. Withinlora_rank,backend_maximumis the optimizer backend's optional ceiling,model_maximumis derived from the smallest dimension among every trained projection, andmaximumis their effective minimum. A nullbackend_maximummeans the backend adds no ceiling; it never makes the effectivemaximumnull because the resident model still supplies one.optimizer_tuple_kindsis the summary of kinds whose resident tuple is supported. A supported tuple hasunavailable_reason: null; an unsupported tuple retains its concrete reason next to the kind.- Each member of
workloadsindependently reports whether the complete server substrate forsft,grpo,opd, ordistill_refreshis executable. Itsallowed_optimizer_kindsis the intersection of that workload gate andoptimizer_tuple_kinds; it is empty whenever the workload is unavailable, and that entry carries a concreteunavailable_reason. This per-workload array, not a raw hook or tuple, is the static HTTP and dashboard admission authority. live_memory_admission_required=trueis deliberately outside the static promise. A supported tuple and workload can still be rejected when the exact request shape does not fit the current memory budget. Admission rejects the request; it never lowers rank, changes optimizer, or switches execution route.
rounding_modes is the server-product policy and currently contains only
round_to_nearest. backend_implementation_rounding_modes describes what the
resident backend optimizer implementation reports. Those fields are separate
so a future implementation capability cannot silently become a product mode.
resolved_lora_parameter_dtype: null means the resident base dtype cannot be
resolved under the backend precision policy; the per-kind tuple reasons carry
the failure rather than treating the dtype as unknown.
The sibling training.native_training_supported and
native_training_unavailable_reason fields are a coarse compatibility summary.
They do not replace workloads: a true summary does not promise that all four
workloads are available, and clients selecting SFT, GRPO, OPD, or
DistillRefresh must inspect the matching workload member.
For canonical Qwen3.5-4B, whose trained-projection model ceiling is 1024, the resident optimizer-tuple matrix before workload and live-memory admission is:
| Backend | Base -> LoRA dtype | SGD | AdamW | Muon |
|---|---|---|---|---|
| CPU portable reference | F32 -> F32 | rank 1..=1024 (backend unbounded) | rank 1..=1024 (backend unbounded) | rank 2..=1024 (backend unbounded) |
| CUDA | F32 -> F32; BF16 -> BF16 | rank 1..=1024 (backend unbounded) | rank 1..=1024 (backend unbounded) | rank 2..=48 |
| ROCm | F32 -> F32; BF16 -> BF16 | rank 1..=1024 (backend unbounded) | rank 1..=1024 (backend unbounded) | rank 2..=48 |
| Metal | BF16 -> BF16 | unsupported | rank 1..=1024 (backend unbounded) | rank 2..=32 |
| Vulkan tuple | F32/BF16 -> F32 | rank 1..=1024 (backend unbounded) | rank 1..=1024 (backend unbounded) | rank 2..=32 |
This table is not a server-execution matrix. Current CPU processes expose the
portable F32 optimizer tuples for diagnostics and direct library testing, while
their sft, grpo, opd, and distill_refresh workload entries remain
unsupported. A Vulkan
process can likewise expose native hooks and resident optimizer tuples while a
workload fails closed. In the usual hybrid Vulkan server, model weights are
CPU-hosted, so exact native backend/device identity and resident-weight checks
reject every workload even though raw Vulkan hooks exist.
Static workload admission requires all of the following: a real readable
runner; a serving profile that grants training GPU ownership; agreement between
configured and resident weight devices; a training runtime that resolves those
weights; exact native backend and device identity; no Marlin-packed model
projection; and the authoritative kt_tape_authoritative forward/backward
route. SFT additionally rejects effective multi-segment checkpointing with a
full_logits loss route. OPD additionally requires both its loss route and
phase-B backward route. GRPO uses the common authoritative-tape gate. The
specific failed condition appears in workloads[].unavailable_reason.
DistillRefresh is not an OPD alias for admission. It is a sequential composite
with an SFT knowledge phase and an OPD behavior-recovery phase. The
distill_refresh row is unconditionally fail-closed with this stable reason:
distill_refresh is unavailable until admission pins separate exact SFT and OPD phase plans, prepares the exact SFT rows, and reserves the maximum sequential working set. Enabling it requires one admission artifact that binds both exact
phase plans, the precise SFT rows that phase one will consume, and a reservation
for the larger of the two sequential working sets. Adding the phases' estimates
or admitting only the OPD-shaped request is not equivalent.
F16 is inference-only on CUDA/ROCm. maximum is the effective static ceiling,
computed as min(backend_maximum, model_maximum) while treating a null backend
maximum as unbounded. Live memory may impose a lower request-time ceiling but
does not rewrite these static fields. The server validates
the cheap workload gate, optimizer kind, hyperparameters, base/LoRA dtype,
rounding, and rank before checkpoint loading or corpus scanning across dedicated
training endpoints, the intent-tagged front door, recipes, judge/self-improve,
DistillRefresh, and OPD-backed distillation. Checkpoint loading and corpus
preparation happen only after those checks. The worker
revalidates the checkpoint and the workload/tuple before memory reservation and
residency.
Invalid kind, rank, or hyperparameters use structured
training_invalid_request; an unsupported base dtype, backend/device identity,
or workload substrate uses training_backend_unsupported.
Cheap teacher-alias validation and metadata pinning retain their established request-error ordering and may precede the workload guard. Remote/local teacher materialization, checkpoint loading, corpus scanning, memory preflight, and GPU reservation do not.
For a queued resume, admission fully validates the manifest and every declared artifact hash, then retains a compact checkpoint-ID/manifest-digest identity plus the effective seed. The manifest digest covers its artifact hash entries. Before memory reservation at dequeue, the worker fully reloads the checkpoint and requires both the recomputed identity and effective seed to match. This is not an external-file snapshot: Kiln does not copy or pin checkpoint files in the queue, and a mutation after the reload remains a filesystem race. Keep the checkpoint directory immutable for its entire use.
GET /v1/recipes applies the same static checks to every built-in recipe step
and returns admission: {supported, unavailable_reason} on each descriptor. A
false descriptor identifies the first unsupported workload or optimizer/rank
tuple. A true descriptor is not a memory reservation: recipe submission repeats
the full preflight before any step is prepared, and live-memory admission still
occurs for each queued job.
Tape scope is internal execution authority, not configuration
The kt autograd tape is a required workload substrate. Kiln opens its thread-local scope internally around the forward/backward region that must record gradients and closes it when that region completes. SFT, GRPO, and OPD admission first require an authoritative tape route; a request cannot open a scope, suppress one recorder, or choose a partially tape-backed execution. There is intentionally no TOML field, API member, CLI flag, or mechanically derived environment name for tape activation.
Scope presence is also the complete inference boundary. Ordinary inference does not open a training tape scope and therefore retains forward-only fast paths. In particular, GDN chunkwise recurrence and CUDA's weight-aware embedding lookup defer to their tape-aware alternatives only while a scope is actually active. They do not consult a cached process-global tape setting. This prevents a default-on global flag from changing inference routing when no gradient graph exists.
The following former correctness switches were removed without compatibility aliases or replacement fields:
KILN_USE_TAPE_FORWARDKILN_USE_TAPE_FLASH_ATTNKILN_USE_TAPE_SDPAKILN_USE_TAPE_LORA_ADDKILN_USE_TAPE_GDNKILN_USE_TAPE_GDN_CONVKILN_USE_TAPE_GDN_QK_NORMKILN_USE_TAPE_GDN_GATED_NORM
Delete these names from service definitions instead of translating them. A
debug or performance control may select an implementation only when the active
scope still records the required analytic backward and preserves the graph. It
must not disable the tape, bypass an individual recorder, or fall through to a
forward-only kernel. If no graph-preserving route exists, the workload fails
closed through training.optimizer_support.workloads[] rather than accepting a
correctness opt-out.
This contract proves static ownership and route isolation; it does not by
itself qualify numerical correctness, latency, memory use, or stability on a
particular accelerator. Those claims require the platform-specific
qualification workload and committed evidence described in
NATIVE_SFT_PROFILE.md.
Frozen parameters are constants, not optimizer leaves
Native SFT, GRPO, and OPD train only LoRA A/B tensors. Embedding tables, base projection matrices, RMSNorm and GDN gated-RMSNorm weights, GDN gate parameters, MTP projection weights, and loss-head transposes are saved constants. Their tape nodes record only differentiable activations and LoRA leaves. Backward therefore returns only required activation and LoRA gradients; it does not allocate, retain, or deposit frozen-weight gradients, and frozen projection paths do not execute a dWeight matrix multiplication.
The split Q/gate projection keeps the original full LoRA A/B tensor IDs on both recorded chunks. Each chunk pads its B contribution to the full shape before the tape combines them, and tape-aware reshapes preserve the activation chain. Sliced base matrices and temporary B slices are never trainable leaves. This is an execution invariant with no TOML, request, CLI, debug, or environment override. It reduces frozen-gradient memory and compute by construction, but does not by itself qualify backend throughput.
The optimizer boundary independently requires an exact LoRA gradient set. The observed tensor IDs must equal the configured trainable leaves; shape, backward-compute dtype, master device, and finite values must match before any parameter, optimizer state, or step counter is changed. Missing or unknown entries reject the step, while a valid all-zero gradient is accepted. Checkpointed execution applies the same identity and metadata contract to the exact leaves in each layer range. The tape bridge reduces distinct recorded input contributions to one accumulated entry per leaf, but rejects the result if any registered differentiable input is absent. A connected clone therefore cannot hide a disconnected use of the same leaf. Split output-projection chunks assemble zero-padded contributions under the original full leaf ID rather than temporary slice IDs. A checkpoint range with no configured LoRA leaves accepts only an empty gradient set, and the merge rejects duplicate leaf IDs across disjoint segments. Token-level GRPO accumulation validates identity and metadata for each source but defers its finite-value reduction to the single final optimizer boundary, avoiding a per-completion device synchronization multiplier. None of these checks has a configuration or environment bypass. CUDA, ROCm, and Vulkan use backend finite reducers. Metal performs a synchronized full-gradient host scan at the same boundary until a native Metal reducer is qualified; this is a correctness fallback, not an advertised throughput path.
Backend-owned SFT loss route is not configuration
There is intentionally no [training] field for the native SFT loss route.
The resident backend reports one typed capability: CUDA and ROCm report
kt_tape_flce, Vulkan reports vulkan_active_rows, and Metal reports
full_logits. These values are capability and artifact names, not accepted
TOML enums, request fields, CLI flags, or /v1/config controls. Because no
configuration field exists, the mechanical naming rule does not produce an
environment variable for this choice.
The old KILN_USE_FLCE input has been removed. It is not a deprecated alias,
the typed loader does not consume it, and setting it has no effect on current
SFT loss selection. Operators should remove it from service definitions rather
than translating it to a new name. Backend loss routing is not an A/B switch.
SFT admission resolves the route from the resident model runner and applies a
route-specific, saturating memory upper bound. CUDA/ROCm account for kt-tape
FLCE buffers and any F32 head promotion; Vulkan accounts for its maximum legal
active-row chunk and F32 workspace; full_logits accounts for dense [T, V]
logits and cross-entropy forward/backward residency. Overflow saturates toward
rejection. An over-budget request returns HTTP 413 with estimated and available
capacity and a breakdown containing loss workspace ... (route=<route>).
The admitted enum is stored with the queued SFT job. The worker revalidates it
against the resident runner before memory reservation or reclamation, and the
trainer revalidates it against its execution backend before resident or
trainable allocations. The pinned value drives each forward/backward step,
appears in SFT receipts as runtime.sft_loss_route, and participates in
the SFT exact-resume planning identity. full_logits is not compatible with a
multi-segment checkpoint plan; that combination returns
training_invalid_request before queue publication and is checked again by the
trainer. These are immutable execution contracts, not omitted configuration
knobs.
SFT checkpoint-boundary policy
These four fields control activation boundaries inside gradient-checkpointed
native SFT. They do not enable or disable gradient checkpointing; that remains
the job of no_grad_checkpoint and the resolved segment plan. When replay is
inactive, SFT retains every segment input. When replay is active, it retains a
sparse set of anchors and recomputes intervening segment inputs during the
backward pass.
For checkpoint_boundary_anchor_stride = "auto", Kiln computes the bytes in
one boundary as sequence length * hidden size * bytes per element, determines
how many anchors fit in checkpoint_boundary_cache_gb, reserves one slot for
replay, and spreads the remaining anchors across the planned segments. The
automatically selected result is always at least one, and auto mode selects
stride one for a one-segment plan. An explicit stride wins even for a
one-segment plan and bypasses only this shape calculation. It does not override
the recompute mode.
Startup resolves all four values into one immutable
CheckpointBoundaryPolicy. The typed loader retains default, config_file,
or environment source attribution for each configured value. Admission and
execution receive the same copyable policy and call the same pure threshold and
shape functions, so a request cannot be admitted under one boundary-memory
estimate and execute another. Trainer and preflight code do not re-read any of
the four environment names. Changing any value requires restarting the server;
queued and running jobs retain the policy installed at startup.
Sparse checkpoint-boundary replay is currently SFT-only. Native GRPO and OPD
retain all num_segments + 1 boundaries and do not use these fields to choose
their live boundary layout. The common training runtime still records the
resolved policy in exact-resume planning identity. GRPO and OPD use
kiln.training-checkpoint-planning.v3. SFT extends the same object to v4 with
its pinned backend loss route. A changed boundary value, including one that is
execution-inert for GRPO or OPD today, is therefore exact-resume drift. An SFT
v3 identity also cannot authorize continuation under v4 because it cannot
prove the admitted loss implementation. See Native Training
Checkpoints.
The resolved object has this stable JSON shape:
{
"recompute_mode": "auto",
"recompute_threshold_tokens": 8192,
"anchor_stride": null,
"cache_target_bytes": 6442450944
}
GET /v1/config exposes it at training.checkpoint_boundary_policy alongside
the gradient-checkpoint plan. GET /health and its /v1/health alias expose it
at training.checkpoint_boundary_policy; trusted
GET /v1/debug/model-state exposes the same object at
training.checkpoint_boundary_policy. The dashboard's Runtime Config training
group renders mode, threshold, explicit-or-auto stride, cache target, and the
restart requirement. These are observations of immutable application state,
not live controls or fresh environment reads.
[openenv]
This section governs server-owned OpenEnv runs launched from the dashboard or
/v1/openenv/*. The kiln openenv CLI uses the same protocol client and
artifacts but is not disabled or origin-restricted by this server control-plane
policy.
| TOML field | Type and exact default | Canonical env target | Alternate env spelling(s) | Validation and effective semantics |
|---|---|---|---|---|
openenv.enabled |
boolean; true |
KILN_OPENENV_ENABLED (implemented) |
none | Enables protocol discovery, bounded Task API catalogs, and asynchronous run lifecycle routes. Disabling it does not remove the local CLI. |
openenv.max_active_runs |
unsigned integer; 4 |
KILN_OPENENV_MAX_ACTIVE_RUNS (implemented) |
none | Must be greater than zero and no greater than max_tracked_runs. Bounds admitted complete workflows across collection, queued or running GRPO, static post-evaluation, and paired held-out environment evaluation. Additional accepted runs wait in a cancellable FIFO; underlying executors retain their own bounds. |
openenv.max_tracked_runs |
unsigned integer; 128 |
KILN_OPENENV_MAX_TRACKED_RUNS (implemented) |
none | Must be greater than zero and at least max_active_runs. This is the hard admission bound for active plus FIFO-queued work and retained terminal history. A retained record also owns its optional idempotency-key binding. |
openenv.tracked_run_ttl_secs |
unsigned integer; 604800 |
KILN_OPENENV_TRACKED_RUN_TTL_SECS (implemented) |
none | Must be greater than zero. Terminal status and idempotency bindings age out after this window; content-addressed rollout and paired-evaluation artifacts remain under <adapter_dir>/.openenv/runs/. |
openenv.allow_remote_environments |
boolean; false |
KILN_OPENENV_ALLOW_REMOTE_ENVIRONMENTS (implemented) |
none | When false, server-launched discovery and runs reject non-loopback origins before network access. Enable only for trusted operators and origins; Kiln's HTTP API is unauthenticated unless protected by your deployment. |
openenv.credentials.<id> |
map of origin-scoped credential objects; empty | none | none | Config-file-only handles. IDs use 1..=64 ASCII letters, digits, _ or -, except that - alone is reserved for a public CLI/dashboard slot; each object requires an exact canonical origin and bearer_token_env. Remote origins require HTTPS. The named secret must be set and non-empty at startup; its value and variable name are redacted from effective configuration. |
Protected environments use server-owned, exact-origin credentials:
[openenv]
allow_remote_environments = true
[openenv.credentials.production-arcade]
origin = "https://arcade.example.com"
bearer_token_env = "ARCADE_OPENENV_TOKEN"
POST /v1/openenv/inspect, POST /v1/openenv/tasks, and POST /v1/openenv/runs accept
"credential_ids":["production-arcade"], aligned positionally with
environment_urls. Use null for an unauthenticated slot in a mixed list.
Kiln resolves the handle only after URL and origin validation, applies the
bearer header to HTTP discovery, Task API requests, and the WebSocket upgrade, and never
places the token in typed config, run status, logs, metrics, summaries, replay
manifests, or receipts.
Each active run uses the selected resident policy through Kiln's authoritative
in-process chat handler, so normal inference admission, adapter identity,
metrics, and limits apply. A train run then enters the same bounded native
GRPO queue as POST /v1/train/grpo; it does not create a second trainer. The
OpenEnv run remains the workflow-level owner, projects the trainer and linked
post-evaluation state, forwards cancellation to those authoritative executors,
and becomes terminal only when the complete requested workflow does. New
failed runs retain kiln.openenv-run-failure.v1 with a closed stage and code,
retryability, a bounded detail, an actionable hint, and exact protocol/HTTP
evidence when available. Alert on the fixed-cardinality
kiln_openenv_run_failures_total{stage,retryable} metric; its labels never
contain endpoints, run IDs, or peer messages.
[logging]
| TOML field | Type and exact default | Canonical env target | Alternate env spelling(s) | Validation and effective semantics |
|---|---|---|---|---|
logging.level |
string; "info" |
KILN_LOGGING_LEVEL (implemented) |
none | One of trace, debug, info, warn, error, or a valid tracing_subscriber::EnvFilter directive such as kiln=debug,tower_http=warn. RUST_LOG overrides the effective filter but does not make an invalid typed value valid. |
logging.format |
string; "auto" |
KILN_LOGGING_FORMAT (implemented) |
none | Exactly auto, json, pretty, text, or human. auto is pretty on a stderr TTY and JSON otherwise; text and human select pretty output. |
Logging is bootstrapped before the full file is validated so parse failures can
be reported through the requested renderer. The authoritative loader then
validates the complete file and stops startup if it differs or is invalid.
Malformed or non-UTF-8 RUST_LOG is fatal.
[prefix_cache]
| TOML field | Type and exact default | Canonical env target | Alternate env spelling(s) | Validation and effective semantics |
|---|---|---|---|---|
prefix_cache.enabled |
boolean; true |
KILN_PREFIX_CACHE_ENABLED (implemented) |
none | Requests reuse of KV blocks and recurrent-state snapshots for shared prompt prefixes. CPU, CUDA, ROCm, and Metal honor the request. Vulkan currently forces the effective capability off because repeated production-model runs proved semantic corruption after cross-request restoration. This is a source-level correctness quarantine, not a second setting. |
prefix_cache.max_blocks |
optional unsigned integer; omitted (None) |
KILN_PREFIX_CACHE_MAX_BLOCKS (implemented) |
none | Must be greater than zero when set. On an admitted backend, None resolves to half of the allocated KV block pool. It has no runtime allocation effect while the effective capability is off. |
prefix_cache.max_entries |
optional unsigned integer; omitted (None) |
KILN_PREFIX_CACHE_MAX_ENTRIES (implemented) |
none | Must be greater than zero when set. On an admitted backend, None resolves from the relevant safe allocation tier and per-entry recurrent-state bytes, with at least one entry. It has no runtime allocation effect while the effective capability is off; quarantined Vulkan reserves no host-backed prefix state. |
The TOML object records operator intent. GET /v1/config reports that object at
prefix_cache.configuration and reports the backend-qualified result beside it:
effective_enabled, effective_reason, effective_max_blocks,
effective_max_entries, and effective_max_state_bytes. Reasons are active,
configuration, vulkan_correctness_quarantine, or backend_unavailable.
GET /health and GET /v1/health expose the live capability both as
prefix_cache.enabled and, when the batching actor exists,
decode_runtime.batching_engine.prefix_cache_enabled. Trusted debug state
publishes the same two views. Prometheus publishes
kiln_batching_engine_prefix_cache_enabled for the actor capability plus the
existing kiln_prefix_cache_* activity and residency series.
For batching-actor requests, enabled changes storage and reuse only. Cache
admission does not change the canonical block-aligned final prefill boundary:
an enabled cache miss and a disabled-cache fresh prefill execute the same token
and layer quanta. With the cache disabled, Kiln skips lookup, recurrent-state
snapshotting, prompt registration, rolling snapshots, retained blocks, and
leases; it does not select a numerically different prompt partition. This
invariant matters for hybrid GDN models because each resumable chunk boundary
materializes recurrent state at the configured precision. Qualification must
compare tokens, recurrent state, and the following decode token before treating
the cache-off arm as a storage-only diagnostic.
While Vulkan is quarantined, all prefix-cache lookup, hit, miss, retained-block, retained-entry, recurrent-state, lease, and pending-release values must remain zero. Requests use fresh generic prefill, including exact repeats. There is no request override or alternate environment flag that bypasses the quarantine. Re-enablement requires a source change and production-model semantic parity across first use, exact repeats, strict descendants, changing concurrency, cancellation, and repeated process history; cache mechanics tests alone are not sufficient.
[speculative]
| TOML field | Type and exact default | Canonical env target | Alternate env spelling(s) | Validation and effective semantics |
|---|---|---|---|---|
speculative.method |
string enum; "off" |
KILN_SPECULATIVE_METHOD (implemented) |
none | off, skip_layer, or mtp, case-insensitive with surrounding whitespace ignored. method is the single authority: off disables speculative decoding and either non-off value requests that qualification method. Non-off serving remains fail-closed until its accelerator lifecycle contract is qualified. |
speculative.num_speculative_tokens |
unsigned integer; 4 |
KILN_SPECULATIVE_NUM_SPECULATIVE_TOKENS (implemented) |
none | Draft proposal bound K. Must be in 1..=4; out-of-range values stop startup before accelerator allocation. This conservative ceiling matches the planned local K=1/2/4 qualification matrix and cannot be raised without new accelerator evidence. |
speculative.draft_layers |
unsigned integer; 8 |
KILN_SPECULATIVE_DRAFT_LAYERS (implemented) |
none | Must be greater than zero. When method is not off, model-dependent startup validation also requires this value to be less than the selected model transformer-layer count. Invalid geometry stops startup; it does not fall back at request time. |
The loaded SpeculativeDecodingConfig is the sole serving authority. TOML and
the canonical environment overrides are resolved and validated once during
typed startup, then the immutable result is passed to serving state. Request
dispatch does not re-read speculative environment variables. Restart the
server to apply a change.
Current fail-closed status: off is the only serving method available.
Every enabled method, including skip_layer and mtp, stops startup until its
cancellation, owner-settlement, EOS, context-capacity, and burst-admission
contracts pass local accelerator qualification. The fields remain part of the
typed configuration so their intended contract is explicit and can be qualified
without introducing a second configuration path. kiln config --file ...
applies the same availability gate as serve, native MTP weights remain
deferred (load_mtp=false), request dispatch contains no speculative branch,
and Desktop always launches with speculative serving off. Benchmark-only
speculative paths require the explicit
--allow-experimental-speculative acknowledgment. That flag permits research
benchmarks only; it does not qualify a serving route.
The former KILN_MTP_DEBUG, KILN_MTP_DUMP_*,
KILN_MTP_SWAP_*, and KILN_MTP_*FP32* experiment controls are retired and
are not configuration inputs. They have no typed replacements because they
selected completed diagnostic branches rather than supported runtime policy.
Current source retains one canonical MTP execution path; historical commands
and conclusions remain labeled as such in PROFILING.md.
[streaming_prefill]
| TOML field | Type and exact default | Canonical env target | Alternate env spelling(s) | Validation and effective semantics |
|---|---|---|---|---|
streaming_prefill.mode |
string enum; "auto" |
KILN_STREAMING_PREFILL_MODE (implemented) |
none | auto, enabled, or disabled, case-insensitive with surrounding whitespace ignored. auto delegates dispatch to backend policy, enabled selects every non-empty prompt, and disabled selects none. ROCm requires dispatch to cover the first effective actor tile, so disabled is rejected for that backend. Every other TOML type, TOML value, or environment value fails startup. |
streaming_prefill.threshold_tokens |
"auto" or positive unsigned integer; "auto" |
KILN_STREAMING_PREFILL_THRESHOLD_TOKENS (implemented) |
none | In auto mode, an integer replaces the backend crossover only when that backend already has a threshold-based automatic policy. It does not make CPU or Vulkan auto-dispatch streaming. With the ROCm batching actor effective, the crossover cannot be later than the effective tile. 0, negative values, and strings other than auto fail startup. enabled and disabled modes ignore this crossover for dispatch while retaining it in diagnostics. |
streaming_prefill.tile_tokens |
"auto" or positive unsigned integer; "auto" |
KILN_STREAMING_PREFILL_TILE_TOKENS (implemented) |
none | Base tile for ordinary tiled prefill and non-tape GDN segment execution. Concrete values must be positive multiples of 64. With the ROCm batching actor effective, this tile must equal server.max_prefill_tokens_per_cycle and fit beside effective decode width in server.max_batch_tokens. When this field is concrete and either specialized tile below is auto, that specialized route inherits this base value rather than its backend default. |
streaming_prefill.tape_tile_tokens |
"auto" or positive unsigned integer; "auto" |
KILN_STREAMING_PREFILL_TAPE_TILE_TOKENS (implemented) |
none | Tile used by tape-authoritative training forward paths. Concrete values must be positive multiples of 64. auto inherits an explicit tile_tokens; when both are auto, backend policy owns the value. |
streaming_prefill.detached_full_attn_tile_tokens |
"auto" or positive unsigned integer; "auto" |
KILN_STREAMING_PREFILL_DETACHED_FULL_ATTN_TILE_TOKENS (implemented) |
none | Tile for detached materialized full-attention training work. A concrete value also controls its derived boundary-forward and tape-replay variants. auto inherits an explicit tile_tokens; when both are auto, each variant keeps its backend default. Every concrete value must be a positive multiple of 64. |
streaming_prefill.last_token_lm_head |
boolean; true |
KILN_STREAMING_PREFILL_LAST_TOKEN_LM_HEAD (implemented) |
none | When true, the final inference streaming tile computes the LM head only for its last row. All centralized strict boolean spellings, including on and off, work identically. |
streaming_prefill.mode is the single mode authority. The removed TOML
enabled toggle and non-canonical environment spellings are not alternate
paths into this policy: the TOML field is rejected and the environment names
are ignored.
The selected backend supplies the following auto policy. Dispatch thresholds
are inclusive. Tile counts are tokens:
| Backend | Automatic dispatch | Base | Tape | Detached full attention | Detached boundary | Detached tape replay |
|---|---|---|---|---|---|---|
| CPU | never | 8192 | 8192 | 8192 | 8192 | 8192 |
| CUDA | prompt tokens >= 2048 | 1024 | 1024 | 8192 | 65536 | 65536 |
| ROCm | prompt tokens >= 256 | 256 | 256 | 8192 | 8192 | 8192 |
| Metal | prompt tokens >= 2048 | 2048 | 2048 | 8192 | 8192 | 8192 |
| Vulkan | never | 2048 | 2048 | 8192 | 8192 | 8192 |
mode = "enabled" can deliberately force non-empty CPU or Vulkan inputs onto
the streaming path; this is an operator override, not a claim that the route is
qualified or faster on that backend. Conversely, mode = "disabled" is the
clean isolation control for a monolithic-prefill A/B on backends that admit
it; ROCm rejects this setting. A threshold override only adjusts an existing
CUDA, ROCm, or Metal automatic crossover. Dispatch eligibility and physical
splitting are distinct: an eligible route creates multiple tiles only when
its sequence is longer than the effective tile for that route.
Startup resolves this section once after backend selection and injects the same immutable execution policy into ordinary generation, prompt-logprob scoring, native SFT/GRPO/OPD admission and training forwards, local OPD teachers, MTP alignment, checkpoint planning, and the benchmark harness. Server-owned training and teacher construction fail closed if that startup policy is missing. No production model or trainer path re-reads these public environment names. Every change requires a restart; an existing job or request cannot observe a mid-process change.
Vulkan resumable-prompt GDN state residency is intentionally absent from this configuration section because the production route is correctness-quarantined. There is no TOML field, canonical environment override, alternate spelling, or internal enable variable that can activate it. The typed Vulkan runtime policy sets prompt residency to false. Ordinary actor chunking therefore materializes each layer's recurrent state at the completed token-chunk boundary, including the BF16 dtype boundary, before a request can yield and resume. Layer-group yields inside one token chunk retain their existing in-progress state and do not add an extra numerical boundary.
The lower-level registry, stable (serving row ID, linear-attention layer index) ownership, TensorId alias transfer, device-side BF16 boundary, exact
owner eviction, and observability remain compiled and test-covered so the fault
can be investigated without reconstructing the experiment. Production cannot
enter those prompt scopes. Re-enabling them requires a source change, the
focused real-device suite, a clean full-model semantic pass with prompt
residency enabled and decode residency disabled, the cancellation/drain probe,
and a checked soak. A micro-kernel or small-state parity result alone is not a
release gate. The source-bound failure and rollback receipts belong in
Local Hardware Qualification; they do not define a
machine-specific product default.
Prompt recurrent-state residency remains disabled by
kiln.vulkan-kernel-policy.v6; resident decode is enabled only when the
selected device satisfies the complete resident shader limit set. Their former
enable and disable variables were deleted without aliases, so process
environment cannot compose an unreported route mixture. Changing either
decision requires a reviewed source policy version and the full evidence
sequence above.
Trusted GET /v1/debug/model-state exposes current ownership as
caches.resident_recurrent_state.entry_count, buffer_bytes, and
allocation_bytes. /metrics publishes the same state as
kiln_gdn_recurrent_state_resident_entries and
kiln_gdn_recurrent_state_resident_bytes{kind="buffer|allocation"}. A drained
server must report zero for all three values. While prompt residency is
quarantined, production also expects zero throughout prompt execution; a
nonzero value is an invalid route activation or ownership defect. Their wire
types are generated from contracts/kiln-observability-v1.schema.json; no
copied environment variable or undocumented toggle controls them.
Kiln prompt-logprob teacher identity uses
kiln.prompt-logprobs.inference-config.v2 and hashes the complete resolved
execution policy: mode, threshold, every base/tape/detached tile variant, and
last-token LM-head behavior. Changing any of these fields therefore changes
inference_config_sha256, the canonical teacher content revision, and every
identity-bound logit-cache key. A deployment must re-register the teacher and
must not resume an OPD checkpoint pinned to the previous revision.
Prompt-logprob selection has no environment variable or runtime tuning field.
The runtime chooses either compact_device or bounded_host_fallback from the
backend implementation, and fixed-cardinality Prometheus counters report the
resolved route. The HTTP API Contract
defines scoring behavior and the Latency Observability
guide defines its operational evidence.
GET /v1/config exposes the complete resolved object at
streaming_prefill. Health repeats it at
prefill_runtime.streaming_prefill, and trusted debug exposes it at top-level
streaming_prefill. The object separates:
- configured mode/source, backend dispatch rule, effective dispatch rule, and effective authority;
- configured/backend/effective threshold, including whether an override actually changed a threshold-based backend policy;
- configured/backend/effective values and sources for base, tape, detached, detached-boundary, and detached-replay tiles;
- last-token LM-head configured/effective state and source; and
immutable_after_startupplusrestart_required_to_change.
An inherited specialized tile reports a closed source such as
inherited_from_tile_tokens_config_file; an untouched automatic value reports
backend_policy. There is intentionally no single effective_enabled boolean:
in automatic mode dispatch depends on the current prompt length.
Examples:
# Keep backend dispatch and tile policy (recommended default).
[streaming_prefill]
mode = "auto"
threshold_tokens = "auto"
tile_tokens = "auto"
tape_tile_tokens = "auto"
detached_full_attn_tile_tokens = "auto"
last_token_lm_head = true
# On non-ROCm backends, isolate a suspected tiled-prefill pause while keeping
# actor ownership.
[streaming_prefill]
mode = "disabled"
# ROCm diagnostic: lower the actor and streaming tile boundaries together.
[server]
max_batch_tokens = 256
max_prefill_tokens_per_cycle = 128
[streaming_prefill]
mode = "enabled"
threshold_tokens = 128
tile_tokens = 128
tape_tile_tokens = "auto"
detached_full_attn_tile_tokens = "auto"
[adapters]
| TOML field | Type and exact default | Canonical env target | Alternate env spelling(s) | Validation and effective semantics |
|---|---|---|---|---|
adapters.library_url |
string URL; "https://library.kiln.run" |
KILN_ADAPTERS_LIBRARY_URL (implemented) |
none | Must be a non-empty valid HTTP(S) URL. Resolved once at startup. |
adapters.max_disk_bytes |
optional unsigned integer; 107374182400 (100 GiB) |
KILN_ADAPTERS_MAX_DISK_BYTES (implemented) |
none | Caps finalized adapter bytes under adapter_dir, excluding upload staging and the composed cache. For the canonical environment override, empty or 0 means None and disables the cap. TOML 0 is accepted as a literal zero cap, not as None. |
adapters.composed_cache_max_bytes |
optional unsigned integer; 10737418240 (10 GiB) |
KILN_ADAPTERS_COMPOSED_CACHE_MAX_BYTES (implemented) |
none | LRU byte cap for .composed. Environment empty or 0 disables this dimension; TOML 0 remains a zero cap. |
adapters.composed_cache_max_entries |
optional unsigned integer; 64 |
KILN_ADAPTERS_COMPOSED_CACHE_MAX_ENTRIES (implemented) |
none | LRU entry-count cap for .composed. Environment empty or 0 disables this dimension; TOML 0 remains a zero cap. |
Because all three typed defaults are Some(...) and TOML has no null value,
the supported way to opt out is the canonical environment override with 0
or an empty value.
[teachers]
teachers.credentials is a dynamic map of server-owned credential handles.
There is no field-level environment override for the map. Each credential
points to a separately named secret environment variable; that secret is not
stored in TOML, AppState, API responses, logs, receipts, or caches. One narrow
credential-provider adapter performs every process-environment secret lookup;
model, training, request-handler, and configuration code cannot read it
directly.
[teachers.credentials.primary-vllm]
origin = "https://vllm.example.com:8443"
api_key_env = "VLLM_TEACHER_API_KEY"
| TOML field template | Type and default | Canonical env target | Alternate env spelling(s) | Validation and effective semantics |
|---|---|---|---|---|
teachers.credentials.<id>.origin |
required string for each entry; no entries by default | none; structured trust policy is TOML-only | none | Must be the exact canonical scheme://host[:port] origin, with no path, query, fragment, or embedded credentials. HTTPS is required unless the host is loopback. |
teachers.credentials.<id>.api_key_env |
required string for each entry | none; this value names the secret variable | none | Must match [A-Za-z_][A-Za-z0-9_]*, length 1..=128. The named variable must exist and contain a non-whitespace value at startup. |
Credential ids must be 1..=64 ASCII letters, digits, _, or -. A handle is
accepted only for its exact configured origin. Non-loopback teachers require a
configured credential handle; credential-free teachers are restricted to
loopback. Startup validates every configured secret before device or model
initialization. Availability is checked again when a handle is resolved, and
the provider reads the bearer value immediately before each outbound request;
missing, non-Unicode, or whitespace-only values fail closed without exposing
the configured variable name or remote response body. Operators should still
treat secret changes as restart-scoped configuration because configuration
validation and registered-teacher identity are startup-owned.
[eval]
The section is optional. When absent, the runtime uses the same queue defaults
shown below and roots eval data at <adapter_dir>/.eval. It creates suites,
datasets, and judgments below that root.
| TOML field | Type and exact default | Canonical env target | Alternate env spelling(s) | Validation and effective semantics |
|---|---|---|---|---|
eval.eval_dir |
optional path string; omitted (None) |
KILN_EVAL_EVAL_DIR (target only; not implemented) |
none | Must be non-empty when set. Despite the historical field name, runtime treats it as the shared eval root and creates the three registry subdirectories below it. |
eval.max_queued_jobs |
unsigned integer; 32 |
KILN_EVAL_MAX_QUEUED_JOBS (target only; not implemented) |
none | Must be greater than zero. |
eval.max_tracked_jobs |
unsigned integer; 1024 |
KILN_EVAL_MAX_TRACKED_JOBS (target only; not implemented) |
none | Must be greater than zero and at least max_queued_jobs. |
eval.webhook_url |
optional string; omitted (None) |
KILN_EVAL_WEBHOOK_URL (target only; not implemented) |
none | Must be a non-empty valid HTTP(S) URL. Terminal eval notifications are fire-and-forget. |
Names such as eval.root, eval.max_tracked_eval_jobs, and an
[eval.generation] table are not accepted by the current typed schema.
[request_log]
Request logging is enabled by default. It records inference request and response JSON on a dedicated bounded writer thread; overload drops log rows instead of blocking inference. Rotation and retention bound disk use.
| TOML field | Type and exact default | Canonical env target | Alternate env spelling(s) | Validation and effective semantics |
|---|---|---|---|---|
request_log.enabled |
boolean; true |
KILN_REQUEST_LOG_ENABLED (implemented) |
none | Master switch. Initialization failure logs a warning and disables logging rather than aborting an otherwise valid server startup. |
request_log.dir |
optional path string; omitted (None) |
KILN_REQUEST_LOG_DIR (implemented) |
none | Must be non-empty when set. None resolves to <adapter_dir>/.requests. The canonical environment override cannot clear a TOML directory; an empty value is fatal. |
request_log.max_file_bytes |
unsigned integer; 67108864 (64 MiB) |
KILN_REQUEST_LOG_MAX_FILE_BYTES (implemented) |
none | Must be at least 4096. The active JSONL file rotates after reaching the threshold. |
request_log.max_total_bytes |
unsigned integer; 2147483648 (2 GiB) |
KILN_REQUEST_LOG_MAX_TOTAL_BYTES (implemented) |
none | Must be greater than zero. Oldest rotated files are removed until retained bytes fit. There is no validation requiring this value to exceed max_file_bytes. |
request_log.compress |
boolean; true |
KILN_REQUEST_LOG_COMPRESS (implemented) |
none | Gzip rotated files when true. |
request_log.max_capture_bytes |
unsigned integer; 4194304 (4 MiB) |
KILN_REQUEST_LOG_MAX_CAPTURE_BYTES (implemented) |
none | Must be greater than zero. Per-request and per-response storage cap; truncation affects the log only, never the wire response. |
The default is intentionally data-bearing. Review log-directory permissions, retention, and the captured request content before exposing the service to untrusted traffic.
[agent]
The section is optional. Its absence disables the scheduled self-improvement loop, while the embedded run engine still receives the default concurrency and timeout.
| TOML field | Type and exact default | Canonical env target | Alternate env spelling(s) | Validation and effective semantics |
|---|---|---|---|---|
agent.self_improve_interval_hours |
optional unsigned integer; omitted (None) |
KILN_AGENT_SELF_IMPROVE_INTERVAL_HOURS (implemented) |
none | Omission disables scheduling. 0 is accepted and also results in no scheduler. The first run occurs one full interval after startup; cadence is persisted under the adapter directory. |
agent.self_improve |
optional structured value; omitted (None) |
KILN_AGENT_SELF_IMPROVE (target only; not implemented) |
none | Request template submitted to the same self-improvement path as the API. This value is intentionally open structured data; its inner request contract is validated by that subsystem rather than by KilnConfig. |
agent.max_concurrent_runs |
unsigned integer; 2 |
KILN_AGENT_MAX_CONCURRENT_RUNS (implemented) |
none | Must be greater than zero. Embedded pi runs above the limit queue FIFO. |
agent.run_timeout_secs |
unsigned integer; 900 |
KILN_AGENT_RUN_TIMEOUT_SECS (implemented) |
none | Must be at least 10. A per-run timeout can override the server default. |
agent.runs_access |
string enum; "loopback_only" |
KILN_AGENT_RUNS_ACCESS (implemented) |
none | loopback_only, enabled, or disabled. Embedded runs can execute arbitrary code; changing this requires restart. |
agent.pi_bin |
optional path string; omitted (search startup PATH) | KILN_AGENT_PI_BIN (implemented) |
none | Must name a non-empty existing file when explicitly configured. The resolved executable is immutable for the process lifetime. |
agent.pi_sessions_dir |
optional path string; omitted (OS account .pi/agent/sessions) |
KILN_AGENT_PI_SESSIONS_DIR (implemented) |
none | Must be a non-empty path when set. Relative paths and the operating-system account fallback are resolved once at startup without consulting HOME. |
Terminal and embedded-run access default to loopback_only. The host decision,
the pi executable, session root, adapter-library URL, and teacher-logit cache
root are resolved once during startup and published under operational in
GET /v1/config. Request handlers use that immutable snapshot; changing TOML,
PATH or a canonical configuration input requires a restart.
Effective values and provenance
Library runtime boundaries
Applications embedding kiln-model directly must initialize accelerator
memory governance as an explicit startup step. Call
InferenceMemoryRuntime::initialize(device, governor_config) before building
the runner, then pass the returned binding to
ModelRunner::new_with_initialized_runtime. Initialization validates the
backend/probe physical-device identity, detects safe capacity, treats
GovernorConfig::capacity_limit_bytes as a cap, publishes a live sample, and
starts the background sampler. The fallible runner constructor verifies the
binding against the model-weight device and installed process policy without
probing again. ModelRunner::new, new_with_options, and
new_with_runtime_options remain non-probing compatibility constructors for
owners such as kiln-server that install the same process-wide policy before
model construction.
Accelerator training has the same explicit identity rule. Construct
TrainingRuntimeContext::new_for_device(device, effective_vram, policy) and
use the *_with_runtime SFT, GRPO, streamed-GRPO, or OPD entry point. A context
without a device binding cannot authorize accelerator-backed weights. Weight
storage and native training execution must currently name the same device.
Vulkan serving uses CPU-host weight handles, but its full-model resident upload
path is not production-qualified and is therefore rejected before queue or
dataset admission with training_backend_unsupported; there is no environment
escape hatch. Vulkan-device training fixtures remain valid when their weights
are genuinely Vulkan-resident. Use the HF/TRL export/import workflow for
production training while serving through the hybrid Vulkan backend.
Kiln exposes complementary startup-input and runtime-derived views:
kiln config --file <path>performs authoritative parsing and validation and prints a concise human-oriented summary.kiln config --file <path> --jsonemitskiln.config-check.v1: the complete source-aware startup object, resolved accelerator policy, application paths, checkpoint-boundary policy, and optional backend preview. It does not probe hardware or load weights. Adding--backend <target>resolves hardware-independent scheduling capabilities and rejects an invalid actor-prefill contract, but deliberately does not claim device availability or live route state.GET /v1/configreports runtime diagnostics for serving profile, the complete immutableeffective_configurationstartup snapshot, the versioned accelerator runtime policy, effective decode width, speculative configuration and availability, VRAM/KV state, native-training runtime/weight devices and support reason, the versioned implementation/resident-tuple/per-workload optimizer contract, gradient-checkpoint segmentation, the immutable SFT checkpoint-boundary policy, the absolute shared cache root and source, memory budgets, and generation defaults. Itstraining.checkpoint_boundary_policyobject reports resolved recompute mode, inclusive automatic threshold, optional explicit stride, and integral cache target bytes. Itsspeculativeobject distinguishesconfigured_methodandconfigured_effective_methodfrom the actualserving_effective_method(off), reportsserving_routable=false, the stableserving_unavailable_reason, the K ceiling, and immutable backend MTP support facts. It does not expose live routing, admission, or weight-readiness fields because those are not serving authorities. A running process cannot have a non-off configured method through the supported startup path.training.native_training_supported=falseis accompanied bytraining.native_training_unavailable_reasonand matches the admission error without scanning a corpus.training.optimizer_supportseparately exposes backend implementations, exact resident optimizer tuples, and per-workload executable kinds. Consumers must useworkloads[].supportedandworkloads[].allowed_optimizer_kinds, not infer product support frombackend_implementationoroptimizer_tuple_kinds. When checkpoint execution is disabled,training.checkpoint_segmentsis0; an optional segment count retained intraining.checkpoint_policyis provenance, not an active execution plan. Theeffective_configurationis the complete input object; sibling fields are the authoritative backend-derived, hardware-derived, and live results.GET /healthand/v1/healthrepeat the accelerator policy and reasoned ROCm synchronization counters underdecode_runtime, and repeat the resolved boundary policy undertraining.checkpoint_boundary_policy; trustedGET /v1/debug/model-statereports the identical object at the same path. The dashboard reads/v1/configand renders the same process-lifetime values. None of these surfaces parses configuration or rereads process environment.GET /v1/configalso reports cached-sample age, maximum age, staleness, sampler requirement/liveness/health, cgroupmemory.high, and the separately boundedvram.live.raw_observations.host_backedtier./healthexposes the same liveness decision, while/metricsexports fixed-cardinality gauges for alerting. A stale or failed sample remains visible diagnostically but contributes zero allocation headroom./healthand/v1/debug/model-stateexpose config hashes and other runtime identity data. Trusted debug additionally exposes the current and process-lifetime batched recurrent-state cache lifecycle atcaches.batched_recurrent_state, plus the separate direct prompt/scoped-decode GDN registry atcaches.resident_recurrent_state;/metricspublishes the same fixed-cardinality ownership, reuse, rejection, concurrency, and eviction counters. The complete field and interpretation contracts are in resumable prefill residency telemetry and batched recurrent-state cache telemetry.- Startup logs record serving-profile provenance and configured/backend/final decode-width sources.
The versioned kiln.effective-configuration.v1 object is a deterministic flat
map keyed by canonical TOML paths. It always contains all 112 fixed typed
leaves, including materialized defaults for optional [eval] and [agent]
sections, plus two dynamic leaves for every configured teacher credential:
teachers.credentials.<id>.origin and
teachers.credentials.<id>.api_key_env. Every entry contains:
effective_value: the post-precedence typed JSON value, ornullwhen redacted;source: exactlydefault,config_file,environment, orcommand_line;canonical_environment: the mechanically derived supported environment name, or no name for config-file-only/dynamic fields;compatibility_environment: retained in schema v1 and always empty, making the absence of alternate spellings machine-readable;redacted: whether the value is deliberately withheld; andrestart_required_to_change: alwaystruefor this startup snapshot.
The object also reports its schema/version, fixed and dynamic field counts, the typed effective-config hash, and the invariant that every represented value requires restart. Field keys are lexicographically ordered. The loader parses the selected TOML document once, validates the typed object, records which leaves were explicit, applies centralized environment overrides, then applies the two supported serve CLI overrides. Unknown TOML fields and invalid values still fail before the dump can be produced.
Secrets and request-bearing values are never serialized into this diagnostic.
agent.self_improve, eval.webhook_url, training.webhook_url, and every
teachers.credentials.<id>.api_key_env entry are present with their real
source but redacted=true and effective_value=null. The named bearer secret
itself is never part of KilnConfig, the effective dump, application state, or
the config hash.
The effective_config_hash binds only the serialized effective typed
configuration and is repeated in the human-readable dump. Execution provenance
separately hashes the redacted set of present KILN_* environment inputs, so
ambient process state cannot silently change the meaning of the configuration
digest. Backend-derived adjustments are intentionally not rewritten into the
startup map: use --backend for a hardware-free scheduling preview and the
sibling /v1/config objects for the actual selected backend, capacity,
availability, and live state.
Configuration migration
The canonical-only environment contract is a breaking cleanup. The former
public spellings below are ignored rather than accepted as aliases. Replace
them before upgrading; kiln config --json exposes the final source of every
effective field so deployment checks can prove the replacement took effect.
| Retired environment name | Canonical replacement |
|---|---|
KILN_ADAPTER_DIR |
KILN_MODEL_ADAPTER_DIR |
KILN_ADAPTER_LIBRARY_URL |
KILN_ADAPTERS_LIBRARY_URL |
KILN_AGENT_RUNS |
KILN_AGENT_RUNS_ACCESS |
KILN_BATCHING_DIRECT_DECODE_RENDEZVOUS_MAX_BATCH |
removed; the direct worker no longer exists |
KILN_BATCHING_DIRECT_DECODE_RENDEZVOUS_MIXED_SEQ_LENS |
removed; the direct worker no longer exists |
KILN_BATCHING_DIRECT_DECODE_RENDEZVOUS_MODE |
removed; the direct worker no longer exists |
KILN_BATCHING_DIRECT_DECODE_RENDEZVOUS_WAIT_US |
removed; the direct worker no longer exists |
KILN_BATCHING_ENGINE |
removed; every real backend uses the actor |
KILN_BATCHING_MODE |
removed; every real backend uses the actor |
KILN_BATCH_DECODE_ROWWISE |
KILN_BATCHING_ROWWISE_DECODE |
KILN_BATCH_PREFILL_ADMISSION_QUANTUM |
KILN_BATCHING_PREFILL_ADMISSION_QUANTUM |
KILN_BATCH_PREFIX_AWARE_ADMISSION |
KILN_BATCHING_PREFIX_AWARE_ADMISSION |
KILN_CHAT_CONFIG_HASH_METADATA |
KILN_SERVER_CHAT_CONFIG_HASH_METADATA |
KILN_CHAT_PERFORMANCE_METADATA |
KILN_SERVER_CHAT_PERFORMANCE_METADATA |
KILN_CHECKPOINT_BOUNDARY_ANCHOR_STRIDE |
KILN_TRAINING_CHECKPOINT_BOUNDARY_ANCHOR_STRIDE |
KILN_CHECKPOINT_BOUNDARY_CACHE_GB |
KILN_TRAINING_CHECKPOINT_BOUNDARY_CACHE_GB |
KILN_CHECKPOINT_INTERVAL |
KILN_TRAINING_CHECKPOINT_INTERVAL |
KILN_CUDA_GRAPHS |
KILN_MEMORY_CUDA_GRAPHS |
KILN_DECODE_BATCHER |
removed; the direct worker no longer exists |
KILN_DECODE_BATCH_MAX |
removed; the direct worker no longer exists |
KILN_DECODE_BATCH_MIXED_SEQ |
removed; the direct worker no longer exists |
KILN_DECODE_BATCH_WAIT_US |
removed; the direct worker no longer exists |
KILN_DEFAULT_NO_THINK |
KILN_SERVER_DEFAULT_THINKING_ENABLED |
KILN_DEFAULT_THINKING_BUDGET_MS |
KILN_SERVER_DEFAULT_THINKING_BUDGET_MS |
KILN_DEFAULT_THINKING_BUDGET_TOKENS |
KILN_SERVER_DEFAULT_THINKING_BUDGET_TOKENS |
KILN_DEFAULT_THINKING_ENABLED |
KILN_SERVER_DEFAULT_THINKING_ENABLED |
KILN_DETACHED_FULL_ATTN_TILE_TOKENS |
KILN_STREAMING_PREFILL_DETACHED_FULL_ATTN_TILE_TOKENS |
KILN_DETERMINISTIC |
KILN_SERVER_DETERMINISTIC |
KILN_DISABLE_ROCM_BF16_MATMUL_F32_OUTPUT |
KILN_ACCELERATOR_ROCM_BF16_MATMUL_OUTPUT_MODE |
KILN_DISABLE_ROCM_STRIDED_BATCHED_MATMUL |
KILN_ACCELERATOR_ROCM_STRIDED_BATCHED_MATMUL_MODE |
KILN_EVAL_MODE |
KILN_SERVER_EVAL_MODE |
KILN_FOLD_REASONING_INTO_CONTENT |
KILN_SERVER_FOLD_REASONING_INTO_CONTENT |
KILN_FORCE_ROCM_BF16_MATMUL_F32_OUTPUT |
KILN_ACCELERATOR_ROCM_BF16_MATMUL_OUTPUT_MODE |
KILN_FORCE_ROCM_STRIDED_BATCHED_MATMUL |
KILN_ACCELERATOR_ROCM_STRIDED_BATCHED_MATMUL_MODE |
KILN_GPU_MEMORY_GB |
KILN_MEMORY_GPU_MEMORY_GB |
KILN_GRAD_CHECKPOINT_SEGMENTS |
KILN_TRAINING_GRAD_CHECKPOINT_SEGMENTS |
KILN_HOST |
KILN_SERVER_HOST |
KILN_HTTP_SEND_BUFFER_BYTES |
KILN_SERVER_HTTP_SEND_BUFFER_BYTES |
KILN_INFERENCE_MEMORY_FRACTION |
KILN_MEMORY_INFERENCE_MEMORY_FRACTION |
KILN_KV_AUTOSCALE |
KILN_MEMORY_KV_AUTOSCALE |
KILN_KV_CACHE_FP8 |
KILN_MEMORY_KV_CACHE_FP8 |
KILN_KV_FORCE_BLOCKS |
KILN_MEMORY_KV_FORCE_BLOCKS |
KILN_LOGIT_CACHE_DIR |
KILN_TRAINING_LOGIT_CACHE_DIR |
KILN_LOG_FORMAT |
KILN_LOGGING_FORMAT |
KILN_LOG_LEVEL |
KILN_LOGGING_LEVEL |
KILN_MAX_BATCH_TOKENS |
KILN_SERVER_MAX_BATCH_TOKENS |
KILN_MAX_DECODE_BATCH |
KILN_SERVER_MAX_DECODE_BATCH |
KILN_MAX_PREFILL_LAYERS_PER_CYCLE |
KILN_SERVER_MAX_PREFILL_LAYERS_PER_CYCLE |
KILN_MAX_PREFILL_TOKENS_PER_CYCLE |
KILN_SERVER_MAX_PREFILL_TOKENS_PER_CYCLE |
KILN_MODEL_ID |
KILN_MODEL_MODEL_ID |
KILN_NO_GRAD_CHECKPOINT |
KILN_TRAINING_NO_GRAD_CHECKPOINT |
KILN_NUM_BLOCKS |
KILN_MEMORY_NUM_BLOCKS |
KILN_PI_BIN |
KILN_AGENT_PI_BIN |
KILN_PI_SESSIONS_DIR |
KILN_AGENT_PI_SESSIONS_DIR |
KILN_PORT |
KILN_SERVER_PORT |
KILN_RECOMPUTE_BOUNDARY_THRESHOLD_TOKENS |
KILN_TRAINING_RECOMPUTE_BOUNDARY_THRESHOLD_TOKENS |
KILN_RECOMPUTE_CHECKPOINT_BOUNDARIES |
KILN_TRAINING_RECOMPUTE_CHECKPOINT_BOUNDARIES |
KILN_REQUEST_TIMEOUT_SECS |
KILN_SERVER_REQUEST_TIMEOUT_SECS |
KILN_ROCM_GRAPHS |
KILN_ACCELERATOR_ROCM_GRAPH_MODE |
KILN_ROCM_GRAPH_CACHE_MAX |
KILN_ACCELERATOR_ROCM_GRAPH_CACHE_ENTRIES |
KILN_ROCM_GRAPH_CAPTURE |
KILN_ACCELERATOR_ROCM_GRAPH_MODE |
KILN_SERVED_MODEL_ID |
KILN_MODEL_SERVED_MODEL_ID |
KILN_SERVING_PROFILE |
KILN_SERVER_SERVING_PROFILE |
KILN_SHUTDOWN_TIMEOUT_SECS |
KILN_SERVER_SHUTDOWN_TIMEOUT_SECS |
KILN_SLOW_REQUEST_WARN_SECS |
KILN_SERVER_SLOW_REQUEST_WARN_SECS |
KILN_SPECULATIVE_ENABLED |
KILN_SPECULATIVE_METHOD |
KILN_SPEC_DRAFT_LAYERS |
KILN_SPECULATIVE_DRAFT_LAYERS |
KILN_SPEC_ENABLED |
KILN_SPECULATIVE_METHOD |
KILN_SPEC_METHOD |
KILN_SPECULATIVE_METHOD |
KILN_SPEC_NUM_TOKENS |
KILN_SPECULATIVE_NUM_SPECULATIVE_TOKENS |
KILN_STREAMING_LAST_TOKEN_LM_HEAD |
KILN_STREAMING_PREFILL_LAST_TOKEN_LM_HEAD |
KILN_STREAMING_PREFILL |
KILN_STREAMING_PREFILL_MODE |
KILN_STREAMING_PREFILL_ENABLED |
KILN_STREAMING_PREFILL_MODE |
KILN_STREAMING_TILE_TOKENS |
KILN_STREAMING_PREFILL_TILE_TOKENS |
KILN_STREAM_STALL_GRACE_MS |
KILN_SERVER_STREAM_STALL_GRACE_MS |
KILN_TAPE_STREAMING_TILE_TOKENS |
KILN_STREAMING_PREFILL_TAPE_TILE_TOKENS |
KILN_TERMINAL |
KILN_SERVER_TERMINAL_ACCESS |
KILN_TOKENIZER_PATH |
KILN_MODEL_TOKENIZER_PATH |
KILN_TRAINING_MEMORY_GB |
KILN_MEMORY_TRAINING_MEMORY_GB |
KILN_VULKAN_BUFFER_POOL_GB |
KILN_MEMORY_VULKAN_BUFFER_POOL_GB |
KILN_VULKAN_DEVICE |
KILN_ACCELERATOR_VULKAN_DEVICE_INDEX |
KILN_VULKAN_VALIDATION |
KILN_ACCELERATOR_VULKAN_VALIDATION |
For ordinary aliases, preserve the old value under the replacement name. The former boolean-to-mode and force/disable controls require an explicit value:
KILN_DEFAULT_NO_THINKbecomesKILN_SERVER_DEFAULT_THINKING_ENABLED=false.KILN_TERMINALandKILN_AGENT_RUNSmap false todisabledand true toenabledon their replacement access fields.KILN_BATCHING_ENGINE,KILN_DECODE_BATCHER,KILN_STREAMING_PREFILL,KILN_STREAMING_PREFILL_ENABLED, andKILN_RECOMPUTE_CHECKPOINT_BOUNDARIESmap false todisabledand true toenabledon their replacement mode fields.KILN_ROCM_GRAPHSmaps false todisabledand true toprofile.KILN_ROCM_GRAPH_CAPTUREmaps false towarmup_then_eagerand true toprofile.- For the two retired ROCm matmul force/disable pairs,
trueforce-strided maps toenabled,truedisable-strided maps todisabled,trueforce-F32-output maps tof32_then_cast, andtruedisable-F32-output maps tonative_bf16. A formerfalsevalue delegated to the removed machine-shapedautopolicy and therefore has no exact replacement. Choose the portable defaults (disabledandf32_then_cast) or explicitly qualify the corresponding experimental route. KILN_SPECULATIVE_ENABLEDandKILN_SPEC_ENABLEDmap false tooffand true toskip_layeronKILN_SPECULATIVE_METHOD. Non-off serving remains fail-closed. The method override now accepts onlyoff,skip_layer, andmtp; historical synonyms must be replaced with those exact enum values.
TOML also has two removed fields: replace speculative.enabled with
speculative.method, using the boolean mapping above, and replace
streaming_prefill.enabled with streaming_prefill.mode, mapping false to
disabled and true to enabled. Unknown fields are fatal, so stale files fail
at startup instead of becoming inert.
Every public runtime field now resolves exactly once and is passed as immutable typed configuration to its owner; the environment contract is generated mechanically, and repository policy rejects direct production environment reads outside the closed driver-remap and credential-provider adapters. Internal experiment and qualification flags remain separate from this public API rather than being promoted by documentation.
Repository policy also scans executable and operational source under
.github/, scripts/, capabilities/, and desktop/ against the complete
retirement index. A retired public name in those surfaces fails
scripts/check_config_schema.py; current launchers, training recipes, generated
corpus examples, and workflow code must use the canonical name and value
semantics above. Exact-revision material under an archive/ directory is
historical evidence rather than a current command. The only non-archive source
exceptions are two smoke checks that assert retirement behavior and one
historical benchmark receipt generator that records the command originally
measured. Those exceptions may mention a retired spelling, but may not use it
as current runtime configuration.