Skip to content

Config schema reference

Every TOML file under /etc/hal0/ is validated against Pydantic v2 models at load time. A typo like device = "gpu-rcom" raises a ValidationError with the offending field path rather than failing later at dispatch.

When HAL0_HOME is unset, hal0 uses the standard layout. Setting HAL0_HOME=/some/path re-roots everything under that prefix (used for dev installs and tests).

FileFHS pathPurpose
hal0.toml/etc/hal0/hal0.tomlTop-level config.
slots/<name>.toml/etc/hal0/slots/<name>.tomlOne file per slot.
profiles.toml/etc/hal0/profiles.tomlProfile catalog (optional; seeds used if absent).
providers.toml/etc/hal0/providers.tomlExternal LLM providers.
upstreams.toml/etc/hal0/upstreams.tomlSlot + remote upstream catalog.
capabilities.toml/etc/hal0/capabilities.tomlCapability-slot selections.
agents/<name>.toml/etc/hal0/agents/<name>.tomlOne file per bundled/user agent.
stacks.toml/etc/hal0/stacks.tomlNamed slot+profile+model bundles (optional; see Stacks, below).
hardware.json/etc/hal0/hardware.jsonCached hardware probe (written by hal0 probe).
manifest.json/etc/hal0/manifest.jsonRelease manifest (pinned toolbox image digests).

State (registry, models, slot state, memory banks) lives under /var/lib/hal0/. Config and state are both preserved across updates.

SetValues
device (hardware preference)gpu-rocm, gpu-vulkan, gpu-cuda, cpu, npu
provider (slot engine label)llama-server, flm, moonshine, kokoro, qwen3tts, comfyui
slot type (dispatch routing)llm, embedding, reranking, transcription, tts, image
seed profilesrocm, rocm-dnse, rocm-moe, vulkan, cuda, embed, rerank, flm, tts, tts-qwen3, cpu-llm, comfyui

The top-level config is assembled from these sections, each with sane defaults (an empty file is valid).

KeyTypeDefaultNotes
schema_versionint (≥1)1Bumped by hal0 config migrate.
KeyTypeDefaultNotes
max_slotsint (≥0)0Max concurrent slots; 0 = unlimited.
port_range_startint8081First port in the auto-allocation pool for new slots.
port_range_endint8099Last port in the auto-allocation pool (inclusive); must be ≥ start. The pool stops below 8188 so a new slot never claims ComfyUI’s port — this only bounds auto-allocation, not an individual slot’s port field, which validates up to 8200 (see [slot].port below).
idle_timeout_sint (≥0)300Default idle-eviction TTL; 0 disables. Per-slot value overrides.
evict_pressure_mbint (≥0)8192Host free-RAM floor (MiB) for pressure-driven LRU eviction. When host MemAvailable drops below this, idle LRU-eligible slots are evicted in least-recently-used order until free RAM recovers; 0 disables pressure eviction.
publish_hoststr"127.0.0.1"Address slot containers publish their port on. 0.0.0.0 exposes every slot’s raw port directly on the LAN, bypassing the hal0-api/reverse-proxy front door; a specific interface IP binds just that address. Applies on the slot’s next (re)start; host-networked slots ignore it.
KeyTypeDefaultNotes
prefetch_timeout_sfloat (>0)8.0Cold-cache prefetch timeout.
prefetch_parallel_capint (≥1)4Max concurrent upstream prefetches.
KeyTypeDefaultNotes
enabledboolfalseOpt-in anonymous telemetry.
channel"stable" | "nightly""stable"Update channel.
KeyTypeDefaultNotes
rootslist[str]["/var/lib/hal0/models"]Absolute roots scanned for model files.
auto_scan_on_startbooltrueRun discovery scan at startup.
file_extensionslist[str][".gguf", ".safetensors"]Candidate file suffixes.
storestr""Single source of truth for where models are read/written. When set, the pull engine writes here and slot containers bind-mount it. HAL0_MODEL_STORE overrides.
KeyTypeDefaultNotes
enginestr"hindsight"Active memory engine: cognee | hindsight | mem0 | pgvector. hindsight is the current default.

[memory.embedding] — reranker knobs (Hindsight era)

Section titled “[memory.embedding] — reranker knobs (Hindsight era)”

Hindsight embeds server-side with its own bundled model, so this table no longer pins an embedding model — it only tunes the second-pass reranker hal0 runs over cross-bank recall results.

KeyTypeDefaultNotes
rerank_gateway_urlstr"http://127.0.0.1:8080"Base URL of the OpenAI-compatible gateway the reranker POSTs /v1/rerankings to. Defaults to hal0-api itself.
rerank_modelstr"builtin.jina-reranker-v1-tiny-en-q8"Rerank model id sent to the gateway; must resolve to a model the rerank slot serves.
rerank_connect_timeout_sfloat (0.05–10.0)1.0TCP connect timeout for the rerank call. Kept short so a wedged rerank slot can’t stall memory search.
rerank_read_timeout_sfloat (0.05–60.0)8.0Read budget for the rerank slot. Failures on either timeout fall through to fused vector ordering, never blocking recall.

[memory.graph] — graph extraction (ADR-0023)

Section titled “[memory.graph] — graph extraction (ADR-0023)”
KeyTypeDefaultNotes
enabledboolfalseOff by default. On the Hindsight engine this is a reporting gate — Hindsight builds its graph natively; vector recall works either way.
extraction_slotstr"utility"The local type=llm slot Hindsight uses for graph extraction. Propagated to hindsight-api as HINDSIGHT_API_LLM_MODEL=hal0/<slot> via a systemd drop-in. Validated against the live enabled-llm-slot set at set-time. Slot-name grammar (lowercase alnum/-/_, ≤32, leading alphanumeric).
llm_timeout_sint (30–3600)300Timeout for the Hindsight daemon’s LLM calls — extraction, consolidation, and reflect. Covers cold slot starts and long reflects. Propagated to hindsight-api as HINDSIGHT_API_LLM_TIMEOUT via the same systemd drop-in as extraction_slot; the daemon restarts to pick it up.
KeyTypeDefaultNotes
enabledbooltrueRecords every config-mutating action and system state change to a SQLite table (/var/lib/hal0/activity.db) that survives restarts.
retention_daysint (≥1)30Rows older than this are pruned. HAL0_ACTIVITY_RETENTION_DAYS overrides at the env layer.
max_rowsint (≥100) | null50000Row cap; null disables the cap (retention_days still applies).

The dashboard’s Settings → Advanced panel is schema-driven, not hand-copied: it reads GET /api/settings/schema (Pydantic field types/bounds/descriptions) and GET /api/settings/apply-plan (per-key apply_class: live / ⟳ restart a service / ⚠ manual restart) and renders a control per key, so the dashboard cannot drift out of sync with this page. It groups every key above — except [meta] and [models], which have their own dedicated General/Storage pages — into four panels:

  1. Slots runtime[slots]: max_slots, port_range_start, port_range_end, idle_timeout_s, evict_pressure_mb, publish_host.
  2. Dispatcher[dispatcher]: prefetch_timeout_s, prefetch_parallel_cap.
  3. Memory[memory] engine + reranker (engine, the four [memory.embedding] keys); a separate Memory graph extraction panel right below it drives [memory.graph] through its own GET/PUT /api/memory/graph endpoints instead of the generic settings PUT.
  4. Activity log[activity]: enabled, retention_days, max_rows.

A dirty manual-restart key gates Save behind a confirm dialog; Save batches every dirty key into one deep-merged PUT /api/settings. A Restart hal0-api control sits below the groups for service-restart/ manual-restart keys that need it.

A slot config has [slot], [model], and optional [server] / [npu] / [image] sections. Unknown keys round-trip (the model uses extra="allow").

KeyTypeDefaultNotes
namestrrequiredLowercase alphanumeric + -/_, starts alphanumeric, ≤32 chars.
portintrequiredHost port in range 8081–8200 (127.0.0.1 only).
typestrllmDispatch routing: llm | embedding | reranking | transcription | tts | image.
devicestrgpu-rocmgpu-rocm | gpu-vulkan | gpu-cuda | cpu | npu.
gpu_indexint | null (≥0)nullPins the slot to one GPU on multi-GPU hosts (HIP_VISIBLE_DEVICES/ROCR_VISIBLE_DEVICES on ROCm, GGML_VK_VISIBLE_DEVICES on Vulkan, CDI device mapping on CUDA). null = all GPUs. No dashboard control yet — TOML/CLI only.
providerstrllama-serverEngine label (round-trips for compatibility/UI).
profilestr | nullnullProfile name from profiles.toml (image + tuned flags).
rolestr | nullnullRole hint: primary, utility, npu. Derived from name when unset.
enabledbooltrueStart this slot on hal0 startup.
enable_thinkingbool | nullnullPer-slot reasoning default; overridable per request.
mtpbool | nullnullTri-state multi-token-prediction override: true forces on, false forces off, null (Auto) enables MTP only when the profile opts in (profile.mtp) and the model itself ships MTP heads (registry mtp tag, or a delimited mtp marker in the model id/filename, e.g. -MTP-/_mtp/.MTP).
chat_templatestr | nullnullChat-template id override (auto/null = GGUF-embedded).
visionbooltrueLoads the model’s mmproj sidecar (--mmproj) when present, so the slot accepts images. Set false to boot text-only and free the ~0.9 GB resident projector. No effect when the model has no sidecar.
workersint (≥1)1Parallel request workers.
idle_timeout_sint (≥0)300Idle TTL for this slot; 0 disables.
default_voicestr | nullnullTTS slots only. Voice id injected into /v1/audio/speech when the request omits voice. null = engine default. Set from Settings → Voice.
default_speedfloat | null (0.25–4.0)nullTTS slots only. Playback speed injected when the request omits speed. Engines clamp further (Kokoro: 0.5–2.0).
default_response_formatstr | nullnullTTS slots only. One of mp3 | wav | opus | flac | pcm, injected when the request omits response_format. null = engine default (mp3).
KeyTypeDefaultNotes
defaultstr""Default model id from the registry.
context_sizeint (≥128)null (derived)When unset, hal0 derives the context window from the model’s native size (capped) or a safe floor; never silently falls back to 4096.
n_gpu_layersint-1Layers offloaded to GPU; -1 = all.
rope_freq_basefloat (≥0)0.0Deprecated (accepted, ignored) — parsed and round-tripped but never emitted by the container launch path. Set --rope-freq-base <n> via [server].extra_args instead.
KeyTypeDefaultNotes
extra_argsstr | nullnullFreeform llama-server CLI passthrough; tokenised and merged with the profile/model flags — this segment wins last, so it overrides the same flag set anywhere else in the chain.
envdict[str, str] | nullnullExtra environment variables injected into the slot container (--env K=V), e.g. HSA_OVERRIDE_GFX_VERSION. Keys must match [A-Za-z_][A-Za-z0-9_]*; values must not contain newlines. Explicit env keys win over any GPU-visibility vars gpu_index derives.
KeyTypeDefaultNotes
asrboolfalseEnable ASR via FLM --asr 1.
embedboolfalseEnable embeddings via FLM --embed 1.
KeyTypeDefaultNotes
idle_restore_minutesint (≥0)60Idle minutes before the GPU arbiter restores stopped LLM GPU slots; 0 = never. Hot-reloadable — unlike most slot-TOML values, a change here takes effect without restarting the slot.
default_sizestr"1024x1024"Default output size (WxH).
default_stepsint (≥0)0Default sampler steps; 0 = model-class default.
[slot]
name = "chat"
port = 8081
device = "gpu-rocm"
profile = "rocm"
role = "primary"
[model]
default = "qwen3-4b-q4_k_m"
context_size = 32768
[server]
extra_args = "-fa on"

A profile is a reusable backend template: a container image plus a bench-tuned flag bundle. Slots reference a profile by name; the profile supplies the image and flags, the slot supplies the model, context size, and port.

KeyTypeNotes
imagestrContainer image ref (required).
flagsstrBench-tuned llama-server flags (no model/port/ctx args).
mtpboolProfile opt-in: when true, a slot in Auto mode enables MTP for models that are actually MTP-eligible. It does not unconditionally append the speculation bundle to every model.
device_classgpu | cpu | npu | imgDevice class the profile targets.
backendrocm | vulkan | cuda | nullGPU runtime (authoritative ROCm/Vulkan/CUDA choice); null for non-GPU profiles.
cloned_fromstr | nullProvenance: the profile this one was cloned from (set by the dashboard’s Clone / “Edit a copy” flow). Informational only.
intentstrHuman label shown in the dashboard.
quantstrWeight quant format shown as a chip — informational only, never read by the runtime.

Current seed profiles (12): rocm, rocm-dnse, rocm-moe, vulkan (GPU/ROCm and Vulkan chat profiles — rocm is the gpu-rocm default, MoE/agents, FP4, no MTP; rocm-dnse/rocm-moe opt into MTP), cuda (experimental NVIDIA, upstream llama.cpp CUDA image), embed and rerank (dedicated GPU lanes — these must run as separate slots, since combining --embedding and --reranking on one llama-server instance yields all-zero scores), flm (NPU), tts (CPU / Kokoro), tts-qwen3 (GPU / Qwen3-TTS, multilingual), cpu-llm (CPU-only chat, no MTP), comfyui (image generation).

A stack is a named, portable bundle of slot assignments — one [stack.<slug>] entry holding a list of slot rows (each with slot, model, profile, device, role, vision, the mtp tri-state, server_extra_args, and optional embed/rerank/stt/tts/vision capability child rows) plus the profile and model metadata those rows reference, embedded so the stack is self-contained. stacks.toml is optional; three seed stacks (saber, forge, pi) ship built in and are immutable like seed profiles — clone under a new name to customize one. Applying a stack writes each row through the same guarded slot-config pipeline as a manual edit (device/profile coherence, NPU exclusivity, default-uniqueness), then converges the runtime: it loads or swaps every slot the stack names and unloads any dispatchable slot the stack doesn’t mention — applying a stack is a declarative replace, not a merge. Stacks can be exported/imported as a portable .hal0stack.json envelope, and POST /api/stacks/snapshot can capture the live running configuration into a new draft stack.

  • Slot lifecycle — the slot state machine and state.json.
  • hal0 CLIhal0 config and hal0 slot commands.
  • Capabilities & profiles — the concept behind the schema.
  • Stacks — the concept behind stacks.toml: plan/converge, drift, and portable export/import.