hal0 v1.0 Quick Start & Migration Guide New install Upgrade What's new Docs ↗

Get started with hal0 — the local AI inference appliance

hal0 turns a Linux box into a polished, OpenAI-compatible inference appliance. Every workload runs in its own podman container supervised by systemd; one control plane on :8080 serves the dashboard, routes /v1/* requests, and stewards the whole box through its built-in brain agent. This guide covers a fresh install for new operators, a clean upgrade from the 0.9.x beta line to v1.0 for existing boxes, and a map of how the pieces fit together.

1command to install
:8080dashboard + OpenAI API
:3001prewired OpenWebUI chat
Version

This guide targets the hal0 1.0 line (current build: v1.0.0-rc.3 on the preview channel). Full reference documentation lives at hal0.dev/docs — this page is the guided tour; links throughout point at the deep-dive pages.


OrientationThe shape of the platform

Four ideas explain almost everything in hal0: slots run things, models describe things, profiles tune things, and one control plane supervises it all.

Slot — a running seat

One podman container + one hal0-slot@<name>.service unit + one port. A slot owns its physical launch facts: device (gpu-vulkan, gpu-rocm, cpu, npu), runner image & binary, threads, NGL, autoload (start at boot?), pinned (exempt from eviction?), and eviction priority. → concepts/slots

Model — a logical asset

A row in the local registry pointing at weights on disk. Models own logical behavior: chat template, context length, tune defaults (extra args, parallel), and the typed capabilities — MTP, Thinking (auto/on/off), vision. Device-agnostic: the same model can serve from any slot. → guides/pull-and-register-models

Profile — a flag bundle

A bench-tuned llama-server flag template per backend (vulkan, rocm, rocm-moe, dedicated embed/rerank lanes, …). Picking one stamps defaults onto the slot — later edits belong to the slot, not the profile. Since 1.0 the profile rides the slot's model choice, per slot. → concepts/capabilities-and-profiles

Control plane — hal0-api

hal0-api on :8080 owns the slot state machines, routes OpenAI-compatible /v1/* calls to the right slot (use the slot name as the model id), serves the dashboard, and exposes the MCP mounts (/mcp/admin, /mcp/memory) that agents use. → concepts/architecture

Who owns which flag

At launch, hal0 layers three tiers into the final runner command. Knowing which tier owns a setting tells you where to edit it — and which migrator moves it (see migrations).

PROFILE template · stamped on apply · backend flag bundle · vulkan / rocm / moe / embed… · bench-tuned defaults edits after apply stay on the slot MODEL logical · device-agnostic · chat template · context · defaults: extra args · parallel · MTP · Thinking · vision migrate-flags · migrate-caps SLOT physical · one container · one port · device · image · binary · threads · NGL · port · autoload · pinned · priority migrator: migrate-hw stamps defaults → bound to slot → owns launch ↓ LAUNCH — layered left → right (later wins) 1 · profile flags + 2 · model defaults (tune) + 3 · slot hardware grid podman container · hal0-slot@<name>.service runner binary + resolved flags · one port · GPU shared via arbiter routed by hal0-api :8080 — /v1/* uses the slot name as the model id
Profiles stamp, models describe, slots run. The launch command is the layered result.

What's around the core

  • Seeded capability slots — a fresh install seeds agent (the capable default/fallback anchor), utility (cheap helper for background jobs), brain, coder, embed, rerank, tts, img, and the NPU-backed flm trio. Capabilities are on-demand — enable/disable from the dashboard. → guides/manage-slots
  • hal0-brain — the built-in platform steward behind the dashboard's Agent Chat button (POST /api/brain/chat). It reaches the whole 180-tool admin MCP catalog: create slots, pull models, run benchmarks, read health — with an operator-approval gate on destructive actions. → concepts/agents
  • Hermes agents — installable autonomous agents (hal0 agent install hermes) with personas, driven through the same MCP surface. → guides/run-agents
  • Hindsight memory — long-term memory service for agents and chat, exposed over the /mcp/memory mount (26 tools). → concepts/memory, guides/enable-memory
  • OpenWebUI — prewired chat UI on :3001, pointed at the local API out of the box. → getting-started/first-chat
hal0 dashboard overview — unified memory map, throughput, utilization, and slot list
The dashboard overview — unified-memory map per slot, live throughput/utilization, request telemetry, and the slot roster. One glance answers "what is my box doing right now".

PrerequisitesRequirements

hal0 runs on any systemd Linux on x86_64. The installer self-detects your package manager, container runtime, and GPU/NPU backend — there is no minimum-spec gate; backend selection degrades to CPU rather than refusing to run.

Host

  • Linux, x86_64 (amd64-only binaries; no ARM/macOS/Windows)
  • systemd (systemctl on PATH; not needed in --dev mode)
  • Python ≥ 3.12 — auto-resolved or auto-installed if the default is older
  • A container runtime — podman preferred (auto-installed if absent); docker accepted if already present
  • Disk for models — point pulls at a big volume with --models-dir
  • Free ports: 8080 (API + dashboard), 3001 (OpenWebUI), + the slot pool

Hardware

  • first-class AMD Strix Halo — Ryzen AI Max+ 395 (128 GB) and 385/390 (64 GB): iGPU + XDNA NPU + unified memory
  • supported AMD RX 7000-series discrete GPUs
  • experimental NVIDIA RTX 30/40/50 via CDI + NVIDIA Container Toolkit
  • fallback any x86_64 CPU-only host

Full detail: reference/hardware-matrix · concepts/strix-halo · getting-started/drivers

Inference backends

ROCm seeded, Vulkan faster

LLM slots name their device explicitly and the runner is pinned to it. ROCm is what hal0 seeds on AMD — for validation history and MTP tuning, not speed — and needs /dev/kfd (on Proxmox LXC add dev1: /dev/kfd). Vulkan needs only a render node, so it serves boxes where /dev/kfd was never forwarded, and on Strix Halo it now measures faster: +13.96% prefill, +20.45% decode. Switch with hal0 slot edit <slot> --hardware vulkan. The lane is gated on a Vulkan-validated runner image — the old ade07ba lineage emitted invalid tokens for every model on Vulkan and is refused by name — and every slot must then clear an output-sanity probe before it is marked ready.

ROCm · NPU · CPU

ROCm/HIP for discrete AMD, AMDXDNA NPU via FastFlowLM (STT/embed/small LLMs), and a fully-supported CPU path (incl. Moonshine CPU STT). Devices are picked per-slot; you can pin any of them.

Privilege model

The installer runs as root (re-execs under sudo if piped through plain bash). hal0-api runs as root so it can apply updates + manage units. A dedicated hal0 system user runs the non-root services (agents, hermes-gateway, hindsight-api). Model containers (podman) are the sandbox boundary. Auth & network posture: operate/auth · concepts/security.

Installing under Proxmox or WSL? Dedicated walkthroughs: Proxmox LXC (GPU/NPU passthrough) · bare metal Ubuntu · WSL (experimental).


New usersInstall hal0

The one-liner

# The bootstrap is the trust boundary: it fetches the signed release
# manifest, cosign-verifies the tarball, unpacks it, and hands off to
# the real installer (installer/install.sh).
curl -fsSL https://hal0.dev/install.sh | sudo bash

# Pick a release channel (default: stable)
HAL0_CHANNEL=preview curl -fsSL https://hal0.dev/install.sh | sudo bash

Common variations

# Point model pulls at a larger disk
curl -fsSL https://hal0.dev/install.sh | sudo bash -s -- --models-dir=/mnt/ai-models

# Set everything up but don't start the units yet
curl -fsSL https://hal0.dev/install.sh | sudo bash -s -- --no-start

# From a clone: local-only dev install under $PWD/.hal0ai (editable, no systemd)
bash installer/install.sh --dev

Environment overrides

VariableDefaultPurpose
HAL0_CHANNELstableRelease channel: stable · preview · nightly
HAL0_PREFIX/usr/lib/hal0Install root (versioned dir + current symlink)
HAL0_PORT8080API + dashboard port
HAL0_MODELS_DIR/var/lib/hal0/modelsWhere Hugging Face pulls land (same as --models-dir)
HAL0_PYTHONpython3Interpreter to build the venv from
HAL0_NONINTERACTIVE=1 forces flag/env values instead of prompting
HAL0_NO_PROBE=1 skips the hardware probe / first-run seeding
HAL0_SKIP_HINDSIGHT=1 skips installing the Hindsight memory service
HAL0_PY_AUTOINSTALL=1 lets the installer auto-install Python 3.12

What the installer does

Sixteen idempotent steps — safe to re-run after a partial failure, and existing config files are never clobbered. Condensed (full list: getting-started/install):

  1. Pre-flight — architecture, systemd, Python, container runtime, disk, free ports. Accurate diagnostics on failure (see troubleshooting).
  2. Layout + venv — code at /usr/lib/hal0/hal0-<version> behind a current symlink; the hal0 service user; config in /etc/hal0/; state in /var/lib/hal0/. Links /usr/local/bin/hal0. --dev lands everything under $PWD/.hal0ai/.
  3. Dashboard UI — release tarballs ship a prebuilt ui/dist; source checkouts build it (Node auto-provisioned).
  4. Config + units — writes hal0.toml, api.env, upstreams.toml, openwebui.env; installs + enables hal0-api and hal0-openwebui (unless --no-start).
  5. Slot seeds — copies the curated slot TOMLs (agent, brain, coder, utility, embed, rerank, tts, img, flm, …) into /etc/hal0/slots/, never overwriting operator edits.
  6. Hardware-anchored provisioning — probes CPU/RAM/GPU/NPU into /etc/hal0/hardware.json, seeds a hardware-recommended steward slot + profile, installs the FastFlowLM NPU runtime on AMDXDNA/apt hosts (fail-soft elsewhere), sets up the ComfyUI model share, writes the first-run bundle catalog, installs bundled agent skills, and starts the services.

New usersFirst run

There's no separate setup wizard — the install itself probes your hardware and provisions a coherent set of slots, models, and extensions in one pass. Your first run is a verification lap.

  1. Open the dashboard — browse to http://<host>:8080. The Overview page shows the unified-memory map, throughput, and the seeded slot roster. A first-run bundle picker offers curated, RAM-sized model collections if you'd rather start from a preset.
  2. Verify healthhal0 doctor all should report green across slots, memory, Hermes, services, and (new in 1.0) the MCP mounts; GET :8080/api/health returns 200.
  3. Look around — the Slots page (sidebar → Slots) is mission control: per-slot cards with model select, live tok/s / TTFT / ctx, device + profile pills, and lifecycle buttons.
# Sanity from the CLI
hal0 doctor all --json
hal0 slot list
hal0 status
curl -fsS http://127.0.0.1:8080/api/health
hal0 slots page — inference engine cards with model selects, throughput, and activity feed
The Slots page — every capability is a card: bound model, live metrics, device + profile pills, stop/restart/logs. The activity feed on the right narrates every state change.
hal0 slot drawer — auto-load and pinned toggles, typed hardware grid, model and profile selects
The slot drawer — the slot's whole contract on one panel: Auto-Load (start at boot) and Pinned (eviction exemption) in the header, the typed hardware grid (runner image/binary, threads, NGL), then the Model group with its per-slot Profile.

First model & first chat

Models live in a local registry — pull one from Hugging Face, bind it to a slot, talk to it. (Deep dive: first-model · first-chat · choose-models.)

# See what's already registered, pull a starter model
hal0 model list
hal0 model pull qwen3-4b

# Bind it to the agent slot and confirm
hal0 slot edit agent --model qwen3-4b
hal0 status

# Chat — the slot NAME is the model id on the OpenAI surface
curl http://localhost:8080/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"agent","messages":[{"role":"user","content":"hello!"}]}'

Prefer a UI? OpenWebUI is prewired on http://<host>:3001, already pointed at the local API. Or hit the dashboard's Agent Chat button and let the brain steward do the driving:

hal0 Agent Chat panel — the hal0-brain platform steward with suggested actions
Agent Chat — hal0-brain stewards the instance: "Help me create a new slot", "Download and set up a model", "Benchmark the model on a slot", "How's the hardware doing?". Destructive actions wait for your approval.
Remember the split

Models own logical behavior (chat template, tune defaults, MTP/Thinking/vision). Physical launch facts — device, image, binary, threads, NGL — belong to the slot. Profiles stamp starting points. See the ownership diagram.


Existing usersUpgrade from beta — land cleanly on 1.0

Upgrading a 0.9.x beta box is an idempotent, in-place operation — not a reinstall. The swap is a cosign-verified, atomic symlink flip of /usr/lib/hal0/current; your config (/etc/hal0) and state (/var/lib/hal0) are untouched by the swap itself. Full mechanics: guides/update-and-rollback.

Which path is yours?

You're onPath to 1.0Notes
0.9.8 hal0 update (or re-run the installer) The full R5 migration set applies — read Migrations first. The old 0.9.8 CLI reports a spurious error at the very end of a successful update; verify with hal0 --version + curl :8080/api/health.
older than 0.9.8 step through 0.9.8 first Then follow the 0.9.8 row.
1.0.0-rc.1 hal0 update --target 1.0.0 An rc.1 box can't see later releases as available (its version comparison predates the fix, #1663). --target bypasses the availability gate and pulls the release directly.
1.0.0-rc.2 / rc.3 hal0 update Plain update on the preview channel; no new migrations.
# Check what your channel offers, then apply
hal0 update --check
hal0 update            # stages, shows release notes + breaking/migration callouts, confirms, applies

# Switch channels first if needed (persists in hal0.toml, also runs a check)
hal0 update --channel stable

# Pin a specific version / escape the rc.1 visibility bug
hal0 update --target 1.0.0
Before your first v1.0 update — profiles.toml

The first hal0 update that crosses the v1.0 schema boundary wipes and reseeds /etc/hal0/profiles.toml (seed profiles now live in code; the file holds only your custom entries). hal0 backs the file up unconditionally to /var/lib/hal0/backups/profiles-<timestamp>.toml and asks for consent if custom profiles are present — but there is no restore command, and rollback does not undo it. If you hand-wrote profiles, copy the file aside first: sudo cp /etc/hal0/profiles.toml ~/profiles.toml.bak.

What the update does

Fetch manifest → download tarball + cosign signature → verify digest + OIDC identity (a failed verification aborts, nothing swapped) → extract + run forward config migrations → atomic current symlink swap → re-render every slot unit through the new code (running slots are not bounced; a "N slots need restart" banner appears — pass --restart-slots to bounce them) → record the prior tree for rollback.

Migrations — what's automatic, what's operator-run

v1.0 re-drew the ownership lines between slots, models, and profiles (see the diagram). One sweep runs automatically; the rest are deliberate, operator-run, dry-run-by-default one-shots for a maintenance window. Your box keeps working on the old shapes until you run them (see back-compat).

Automatic at first v1.0 boot

WhatDetail
enabled sweep SlotConfig.enabled is gone — a bound model is the activation signal. The boot sweep drops the key from slot TOMLs; a slot that was enabled = false with a bound model gets the model cleared so it stays off. Re-runnable on demand: hal0 slot migrate-enabled-removal (dry-run; --apply to write).
profiles.toml reseed One-time, during the update that crosses the v1.0 boundary — see the warning above.

Operator-run, at a window

All four share the same shape: bare command = dry-run preview, --apply writes after a timestamped backup under /var/lib/hal0/backups/, --yes skips the prompt, and --stop-services stops hal0-api + active hal0-slot@* units first (without it, --apply refuses while they're active). Full CLI reference: reference/cli.

CommandMoves what, where
hal0 slot migrate-flags Slot-era tunes → the bound model's defaults: extra_args, parallel, per-slot chat_template overrides (layered over profile flags). Refuses the whole run — writes nothing — if two slots would fold divergent tunes onto one shared model; resolve (pick one tune, or split the model row) and re-run.
hal0 slot migrate-caps Slot-era capability tri-states → the model: mtp, enable_thinking, vision. An existing curator-set model default always wins; conflicts between slots sharing a model are reported, not silently dropped.
hal0 slot migrate-hw Model/profile-era physical facts → the slot's typed hardware grid: NGL, runner binary, deliberate image pins. Clears the folded model hardware columns.
hal0 slot migrate-id-keying Optional. Flips every slot artefact from name-keyed (<name>.toml, hal0-slot@<name>) to stable id-keyed (<id>.toml, hal0-slot@<id>). The runtime reads both layouts — flip when you choose. Since rc.3, id-keyed boxes are first-class across every lane.
# The pattern, using migrate-flags as the example — same for -caps and -hw
sudo hal0 slot migrate-flags                 # 1. dry-run: read the per-slot plan
sudo hal0 slot migrate-flags --apply --yes --stop-services
# → "backup written to /var/lib/hal0/backups/<timestamp>.tar.gz"
sudo systemctl daemon-reload && sudo systemctl start hal0-api
hal0 doctor                                  # 3. verify: expect all-green

# Optional: flip to id-keyed slot artefacts
sudo hal0 slot migrate-id-keying             # dry-run plan (name → id)
sudo hal0 slot migrate-id-keying --apply --yes --stop-services
hal0 slot list && systemctl list-units 'hal0-slot@*'

Coming from much older boxes

SituationWhat to run
v0.1.x model store under /mnt/ai-models/ hal0 migrate model-layout — builds the canonical <recipe>/<capability>/ symlink tree under /var/lib/hal0/models/. Writes only symlinks; source files never move. Dry-run by default, --apply to write, verify with hal0 doctor migrations + hal0 doctor models.
Box that ran the Honcho memory engine Nothing. Honcho was removed outright; Hindsight is the only memory engine and starts fresh. There is no data carry-over path and no command to run.

Why your box keeps working before you migrate

Tolerant config

Legacy slot and model keys load without a boot crash — old fields are read (or ignored with a one-time deprecation warning, like the retired lru key) until you run the relevant migrator. Dry-run any of them to see exactly what will change.

Bilingual runtime

Name-keyed and id-keyed slot layouts are both fully supported. Update swaps code; the one-shot migrations stay operator-controlled.

Rollback

  • hal0 update --rollback swaps current back to the previous tree (recorded in /var/lib/hal0/hal0.previous). It never touches config — the profiles.toml reseed and applied slot migrations are not undone by a code rollback.
  • Release tarballs are immutable and cosign-signed — any prior tag can be re-installed from its GitHub release.
  • Rolling back past the v1.0 boundary needs the config backup taken before upgrading: pre-v1.0 code reads a missing enabled as true, so slots the sweep cleared come back model-less rather than re-enabled.
  • The slot migrators write timestamped backups under /var/lib/hal0/backups/ before changing anything — restoring one is the undo.

ReleaseWhat's new in 1.0

The 1.0 line is the sum of the R5 rework (rc.1), the feature-complete GA content (previewed by rc.2), and a 38-fix hardening pass (rc.3). The short version, by theme — the full story is in the CHANGELOG.

Ownership model finalized R5

  • A slot is (id, name, model, port, state) plus a typed hardware grid; models carry the materialized tune in defaults; profiles are per-slot templates that stamp, not bind. The migrators in Migrations move existing boxes across.
  • New slot lifecycle controls: autoload (binding a model no longer implies boot start) and eviction priority (0–100, default 50). The inert lru = true opt-in is retired — every non-pinned resident slot is now an eviction candidate under memory pressure; pinned is the only exemption.
  • Stopping a slot is POST /api/slots/{name}/unload (409 slot.pinned on pinned slots) — config writes no longer have lifecycle side effects.
  • On-demand capability slots: disabling a capability clears the slot's model (the pick survives in capabilities.toml); the retired vision lane and curated type-tag chips are gone in favour of typed model fields.

Agents & memory

  • Admin MCP catalog: 92 → 180 tools — services, ComfyUI, updater/doctor/health, hardware + request telemetry, slots/models long-tail, bench, activity, approvals, runner images, NPU load/unload. The brain steward reaches all of it through POST /api/brain/chat.
  • Memory MCP surface at feature parity with Hindsight 0.8.4: 26 tools (was 5) — reflect, curate/history, mental models, directives, async operations, bank introspection. The /mcp/memory mount dropped to CLIENT-tier: memory-only agents no longer need the platform-admin key.
  • Hermes bootstrap MCP wiring fixed end-to-end (auth token injection, --repair refresh after key rotation); hal0 doctor all gained live MCP-mount and Hermes-auth preflights.

Voice, image, dashboard

  • Moonshine reinstated as the CPU STT engine in its own toolbox image — voice.stt is a device-keyed switch: cpu → Moonshine, npu → whisper-v3:turbo (FLM trio), GPU → no STT engine (the old silent fall-through to a llama chat profile is fixed).
  • Image Gen pane: state-typed engine pill (stopped/starting/running/generating·%/error) and a real Stop that drives the GPU arbiter back to inference mode.
  • Slot drawer: runner image is a catalog dropdown (with a custom-ref escape hatch) that repopulates the binary dropdown; Auto-Load and Pinned pair in the header; profile rides the model choice.
  • GET /api/slots latency cut sharply on wide boxes (single-flight snapshot, TTL-cached image inspects, no inspects for stopped slots).

Hardening (rc.3)

  • The update path works end-to-end on real hosting: manifest fetch follows redirects, the privileged stage honours HAL0_RELEASES_URL, wrappers refresh on every activate.
  • Id-keyed boxes are first-class in every lane (capability toggles, NPU trio, config writes).
  • Memory surfaces tell the truth: real operations envelope, accurate bank-delete blast radius, per-agent stats scoping, ACL-aware pagination, extraction-slot changes actually reach the daemon.
  • Removed: the experimental standalone browser MCP server (never mounted; Hermes brings its own browser tooling).
  • [brain_chat] tool_model is wired for real: rc.1 deleted the key because nothing read it, and it came back with an implementation behind it. Tool rounds run on tool_model (default hal0/agent) while chat stays on the brain slot; set it to off, none or disabled to route tool turns nowhere.

OperateTroubleshooting

Always start here

hal0 doctor all --json reports health across slots, memory banks, Hermes, services, and the MCP mounts in one pass. For a permissions-specific audit, hal0 doctor perms; for pending model-layout links, hal0 doctor migrations. Logs live on the dashboard's Logs page and in journalctl -u hal0-api / -u 'hal0-slot@*' — see guides/logs-and-activity.

Known issues on the beta → 1.0 path

  • 0.9.8's CLI reports a spurious error at the end of a successful update — it polls the API it's restarting and treats the mid-restart connection refusal as fatal. Verify the real outcome: hal0 --version + curl http://127.0.0.1:8080/api/health.
  • The profile-catalog reset doesn't fire during the 0.9.8 → 1.0 update itself (#1585) — the commit phase runs inside the old daemon. Nothing is lost; the reset lands on the next update applied by v1.0 code.
  • rc.1 boxes see "nothing to update" (#1663) — use hal0 update --target <version> (see upgrade paths).
  • First-boot installs can lose the dpkg lock race to unattended-upgrades (#1584) — hermes provisioning degrades gracefully; re-run hal0 agent install hermes afterwards.

unprivileged LXC Install refuses at the container-runtime preflight

Symptom: podman run fails with crun: create keyring: Disk quota exceeded. Cause: the host kernel keyring byte-quota (kernel.keys.maxbytes) is exhausted — usually leaked keyrings from repeated failed healthchecks. hal0 correctly refuses (a real slot couldn't start either).

# Clear it, then re-run install
# reboot the container  — or —
keyctl clear @s
# or raise the quota on the Proxmox / host kernel
sysctl -w kernel.keys.maxbytes=2000000

GPU Slot runs but on CPU / GPU access denied

If /dev/dri/renderD128 is owned by a group that isn't your host's render group, older builds group-added the wrong GID. v1.0 derives the GID from the device node itself. Confirm your hal0 user is in the device's owner group:

stat -c '%G %g' /dev/dri/renderD128
id -nG hal0

Driver/firmware setup (incl. Proxmox passthrough): getting-started/drivers · getting-started/proxmox.

Hardened host: permissions look wrong after install

A CIS/STIG umask (0027/0077) leaking into the install can leave the tree 0700. The installer normalizes to 022 for its own body; if you see PermissionError reading /usr/lib/hal0 or /etc/hal0/slots, run hal0 doctor perms --fix.


ReferencePaths & commands

Filesystem

/usr/lib/hal0/currentactive code (atomic symlink)
/etc/hal0/config (hal0.toml, slots/, profiles.toml, api.env)
/etc/hal0/hardware.jsonprobe result (CPU/RAM/GPU/NPU)
/var/lib/hal0/modelsmodel store + canonical symlink tree
/var/lib/hal0/hal0.dbmodel registry + slot identity
/var/lib/hal0/backupsmigration + profiles.toml backups
/var/lib/hal0/slotsper-slot runtime state

Full map: reference/paths-and-files

Everyday commands

hal0 doctor allhealth across the platform
hal0 slot list / editmanage inference slots
hal0 model list / pullmanage the registry
hal0 statusbox summary
hal0 update [--check]atomic in-place upgrade
hal0 update --rollbackswap back to the previous tree
hal0 agent install hermesinstall the Hermes agent

Full surface: reference/cli · API: reference/api

Environment variables

The install-time variables are in the Install section. These are the runtime ones you'll actually reach for — the full table (60+ vars, grouped by subsystem) is at reference/env-vars.

VariableDefaultPurpose
HAL0_PORT / HAL0_BIND_HOST8080 / 0.0.0.0API port and bind host (also read by hal0 serve)
HAL0_API_URLhttp://127.0.0.1:8080Base URL the CLI uses to reach hal0-api — set it when driving a remote box
HAL0_REQUIRE_AUTHOverrides [security].require_auth; keys live in /etc/hal0/api.env (HAL0_ADMIN_KEY, HAL0_CLIENT_KEY — see hal0 auth)
HF_TOKEN / HUGGING_FACE_HUB_TOKENHugging Face auth for gated models (first-set wins; used by install, model routes, pull jobs)
HAL0_MODEL_STOREModel-store root override (env → [models].store/var/lib/hal0/models)
HAL0_FLM_MODELS_DIRNPU/FLM model-store override
HAL0_CONTAINER_RUNTIMEauto-detectOverride the podman/container runtime binary
HAL0_HINDSIGHT_URLhttp://127.0.0.1:9177Hindsight memory engine base URL
HAL0_RELEASES_URLofficial manifestPoint the updater at a self-hosted release manifest (redirects OK since rc.3)
HAL0_HOME— (FHS paths)Dev/test-only: relocate all root paths (etc, var_lib, …) under one directory
NO_COLOR / HAL0_PLAINDisable ANSI color / force ASCII-only CLI output
Units & ports

hal0-api.service serves the control plane + dashboard on :8080; hal0-openwebui.service serves chat on :3001. Slot units are hal0-slot@<name> (or hal0-slot@<id> after id-keying).

Agents, Hermes gateway, and Hindsight run as the non-root hal0 user. Slot lifecycle detail: reference/slot-lifecycle.

Full documentation

This guide is the tour — the complete reference lives at hal0.dev/docs: getting-started walkthroughs (Proxmox, bare metal, WSL), concepts, how-to guides, the CLI/API/config-schema references, and operations runbooks.