Configuration
hal0’s runtime configuration is split across a few TOML files under
/etc/hal0/. Every write is atomic; every field is schema-validated;
a bad edit can never produce a half-written file.
| Path | What it holds |
|---|---|
/etc/hal0/hal0.toml | The main daemon configuration file. |
/etc/hal0/capabilities.toml | User-facing capability config (embed / voice / img / NPU rollups). |
/etc/hal0/slots/<name>.toml | Per-slot lower-layer config (provider, model, port, options). |
/etc/hal0/slots/<name>.env | Per-slot env file consumed by the systemd unit. |
/etc/hal0/hardware.json | Output of the hardware probe (see below). |
/etc/hal0/openwebui.env | OpenWebUI env, written by the installer. |
/etc/hal0/proxmox.json | Optional PVE API token + endpoint for the host-pressure segment in the memory bar. 0600, redacted on read. |
/etc/hal0/api.env | API env (auth toggles, secrets). Written by the installer. |
/etc/hal0/ is preserved across hal0 update. The installer never
overwrites a user-modified config file; it skips with a warning if
the file already exists.
If hal0 is running in an LXC on a Proxmox node, dropping a read-only
PVEAuditor token + endpoint into /etc/hal0/proxmox.json (Settings
→ Proxmox integration writes this for you) lights up the “Proxmox
host” segment in the dashboard’s unified-memory bar. Without it, the
panel stays quiet and the memory bar shows the LXC’s cgroup slice
only. The file is mode 0600; tokens are redacted in logs and on the
config-read API.
capabilities.toml is the user-facing config layer — embed / voice
/ img cards and the NPU backend rollup. It sits on top of the per-slot
slots/*.toml files; the capability orchestrator reconciles drift
between the two on every apply.
Editing the config
Section titled “Editing the config”Three supported workflows:
- Dashboard. The Settings view exposes most fields with a form for each section. Saves go through the atomic-write path.
- CLI.
Terminal window hal0 config edit # opens $EDITORhal0 config validate # schema check without writinghal0 config show # print merged viewhal0 config migrate # apply schema migrations to an older config - Direct edit. Open the file in any editor. On the next
hal0-apirestart (or ahal0 config validaterun), the schema enforces shape — a typo fails loudly, not silently.
Atomic writes
Section titled “Atomic writes”Every config write goes through:
NamedTemporaryFile(delete=False) → write → fsync → os.replace()If the process crashes mid-write, the prior file is fully intact;
os.replace() is atomic on POSIX filesystems. There’s no window in
which /etc/hal0/hal0.toml is half-written.
The same pattern applies to per-slot env files; a failed slot config update leaves the previous env in place.
Schema validation
Section titled “Schema validation”The config schema is Pydantic-defined in src/hal0/config/schema.py
and exported as JSON Schema for reference. Every field has:
- A type (Python type or JSON Schema primitive).
- A default value where reasonable.
- A constraint set (regex for slot names, range bounds for ports).
- Inline documentation that the dashboard surfaces as help text.
A failed validation surfaces as a structured config.invalid error
with details.path pointing at the offending field.
See Config schema reference for the full field list.
The hardware.json file
Section titled “The hardware.json file”/etc/hal0/hardware.json is probe output, not config. It’s
regenerated by hal0 probe and consumed by the slot loader to pick
sensible defaults and surface VRAM/RAM fit warnings inline.
Re-run the probe whenever the hardware changes (BIOS UMA carveout,
GPU swap, RAM upgrade, or changing the LXC’s dev0–dev3 passthrough
set):
hal0 probeThe output is structured: cpu_*, mem_*, gpu_*, npu_*, plus
provider availability flags.
Gotcha: [model] default in slot TOMLs is a seed
Section titled “Gotcha: [model] default in slot TOMLs is a seed”In each /etc/hal0/slots/<name>.toml, the [model] default field is
the install-time seed — the model the installer picks the first
time. It is NOT a live default. Once a slot is provisioned, model
swaps write the active selection to env + a runtime override; the TOML
file deliberately stays stale. If you edit default on a running box
and nothing changes, this is why. Use hal0 slot swap <name> --model <ref> (or the dashboard’s model picker) to swap.
Coming soon — outline
Section titled “Coming soon — outline”- Hot-reload of selected fields (changing an idle timeout without restarting the slot).
- Encrypted secrets storage for upstream API keys.
- Multi-file config (drop-in fragments under
/etc/hal0/conf.d/).