hal0 installs from a single command. The bootstrap script is the trust
boundary: it fetches the release manifest, verifies the tarball, unpacks
it, and hands off to the real installer (installer/install.sh).
curl -fsSL https://hal0.dev/install.sh | sudo bash
Channels
By default the bootstrap fetches the latest stable release manifest.
Pick a different channel with HAL0_CHANNEL:
HAL0_CHANNEL=preview curl -fsSL https://hal0.dev/install.sh | sudo bash
Accepted values: stable (default), preview, nightly.
Requirements
- curl and ca-certificates — the one-liner needs them to fetch the
bootstrap at all. Minimal cloud/LXC images, including a stock Ubuntu 24.04
Proxmox container, ship without curl:
apt-get update && apt-get install -y curl ca-certificates(or the
equivalent for your distro). The bootstrap then checks fortar,
sha256sum,jqandpython3, installs any that are missing with the
system package manager, and fetches its own pinnedcosign. - Linux, x86_64 — hal0 ships amd64-only binaries (the FastFlowLM
.deband the runner container images). ARM and macOS/Windows are not
supported. - systemd —
systemctlmust be onPATH(outside--devmode). - Python 3.12 to 3.14 — hal0 requires
>=3.12and is tested on 3.12, 3.13 and 3.14. If the defaultpython3is older, the installer usespython3.14,python3.13orpython3.12when one is already onPATH, and otherwise tries to installpython3.12through apt or dnf. If none can be found or installed it stops with a remediation hint (HAL0_PYTHON=python3.12). - Python for the memory engine — the Hindsight memory engine builds its own venv and accepts Python 3.11 to 3.14. The installer picks one (installing it when it can) before it does anything else, so a host with none finds out up front. If none is usable, the memory engine is skipped for that run and the rest of the install continues; point
HAL0_HINDSIGHT_PYTHONat a 3.11-3.14 interpreter and re-run to add it. - Network for the first Hermes build — the bundled Hermes agent builds on its own Python 3.14, never on hal0’s interpreter. It uses a uv-managed CPython kept under
/var/lib/hal0/hermes/python/, or a suitable system interpreter. The first build downloads Hermes’s dependencies (and the interpreter, when uv-managed), so the host needs internet access when Hermes is provisioned. - A container runtime — every inference slot runs in a container.
The installer prefers podman (auto-installed if neither podman nor
docker is found); docker is accepted if already present. - Node.js — only needed to build the dashboard UI from a source/git
checkout. Signed release tarballs ship a prebuiltui/distand skip
this requirement entirely; the installer auto-provisions Node when it’s
needed and can’t find a suitable version.
What the installer does
The bootstrap hands off to installer/install.sh, which runs 15 steps,
in order:
- Pre-flight checks — architecture, systemd, Python, container
runtime, disk space, free ports. - System user — creates the
hal0service account. - Filesystem layout — creates the FHS directory tree (or the
--dev
tree under$PWD/.hal0ai). - Python environment — builds the shared venv and
pip installs
hal0 into it. - Node.js toolchain — provisions Node only if this tree ships the
dashboard’s npm project. - Dashboard UI — builds
ui/dist(or reuses a release’s prebuilt
copy). - Configuration — writes
/etc/hal0/hal0.toml,api.env,
upstreams.toml,openwebui.env— never overwriting existing files. - Systemd units — writes and enables
hal0-api.serviceand
hal0-openwebui.service(unless--no-start). - Container slot seeds — copies default slot TOMLs into
/etc/hal0/slots/(never overwriting operator edits). - Hardware probe — detects CPU/RAM/GPU/NPU and writes
/etc/hal0/hardware.json. - Steward + agent models — seeds a hardware-recommended slot and
profile, then offers the optional agent model and a starter image
model (see Starter image model). - NPU prerequisites — installs the FastFlowLM runtime on
AMDXDNA/apt hosts (fail-soft elsewhere). - Bundle picker manifests — writes the dashboard’s first-run bundle
catalog. - Bundled agent skills — installs the shipped agent skill set.
- Service start — starts
hal0-apiandhal0-openwebui(unless
--no-start), waits up to 60 s for/api/healthto answer before the post-install checks run, stands up the Hindsight memory engine, then provisions the bundled Hermes agent (skip withHAL0_SKIP_HERMES=1; install later withhal0 agent install hermes). Hermes provisioning builds a release and can take a few minutes.
The installer is idempotent — safe to re-run after a partial failure,
or just to pick up new configuration defaults. Existing config files are
never clobbered, and a unit you disabled or masked (for example
hermes-gateway.service) is left off on re-run; the installer prints the
systemctl command to turn it back on.
Starter image model
On a box that can run the ComfyUI image engine (it needs a ROCm lane: /dev/kfd
and a render node), step 11 also offers a starter image model. Other boxes are
not asked, and the installer says why. The menu lists the image models the API
can render, each with the GB still to download and the time per image, and marks
the one that suits the box’s memory as [recommended]: Stable Diffusion 1.5
below 16 GB, SDXL Lightning from 16 GB, Qwen-Image Lightning from 96 GB. The
memory counted is the RAM the system sees (MemTotal, which inside an LXC guest
is the guest’s limit), or the container’s memory cap when that is lower, because
the image engine loads the weights into memory the guest is charged for.
Answer with menu numbers, catalog ids or recommended, separated by commas or
spaces, or press Enter to download nothing. A bad answer is asked again. The
first model that finishes downloading becomes the img capability’s model,
and the installer starts the image slot with it, which downloads the ComfyUI
runtime on first start and can take several minutes. Open WebUI’s environment
is re-rendered to match: a running Open WebUI restarts to pick it up, and one
you skipped or stopped stays down. If an image model is already selected it
stays selected, and the installer starts nothing. --no-start skips the step,
since it starts the image slot, and the installer prints how to do it later. A
failed download is reported and the install carries on; install a model later
with hal0 comfyui models install <id> or from the dashboard.
An unattended install (no terminal, or HAL0_NONINTERACTIVE=1) downloads
nothing unless HAL0_IMAGE_MODELS is set. Set it to recommended or a list of
ids to opt in, and to none to skip even on a terminal; see
Install-time overrides.
Flags and environment variables
curl -fsSL https://hal0.dev/install.sh | sudo bash -s -- --no-start --models-dir=/mnt/ai-models
| Flag | Effect |
|---|---|
--dev |
Local-only editable install under $PWD/.hal0ai — no systemd, no host package changes |
--no-start |
Set everything up but do not enable/start the units |
--models-dir=PATH |
Absolute path where Hugging Face pulls land (same as HAL0_MODELS_DIR) |
--summary-json=PATH |
Write a versioned, machine-readable install summary to PATH once the install finishes (see below) |
--no-owui |
Skip Open WebUI (same as HAL0_SKIP_OPENWEBUI=1) |
--no-comfyui |
Skip the starter image models (same as HAL0_IMAGE_MODELS=none); the img slot still exists, parked. Left on, the installer offers the starter image-model menu, whose default is none, so Enter downloads nothing |
--no-hermes |
Skip the Hermes agent and the Operator Board that goes with it (same as HAL0_SKIP_HERMES=1) |
--no-pi |
Skip the Pi agent (same as HAL0_SKIP_PI=1) |
--no-agents |
Skip both agents; same as --no-hermes --no-pi |
--no-memory |
Skip the Hindsight memory service (same as HAL0_SKIP_HINDSIGHT=1) |
--no-brain-model |
Skip the brain model pull (same as HAL0_SKIP_BRAIN_MODEL=1) |
--bare, --bare-inference |
Synonyms: turn every optional component above off. On a terminal a bare install still asks for the models dir, the Hugging Face token and the optional agent model [y/N]; set HAL0_PULL_AGENT_MODEL=0 and HAL0_NONINTERACTIVE=1 for a prompt-free bare install |
| Variable | Default | Purpose |
|---|---|---|
HAL0_PREFIX |
/usr/lib/hal0 |
Installation root (versioned dir + current symlink) |
HAL0_PORT |
8080 |
API bind port |
HAL0_PYTHON |
python3 |
Python interpreter to build the venv from |
HAL0_MODELS_DIR |
/var/lib/hal0/models |
Where Hugging Face pulls land |
HAL0_NONINTERACTIVE |
(unset) | Set to 1 to force flag/env values everywhere instead of prompting on a terminal |
HAL0_NO_PROBE |
(unset) | Set to 1 to skip the hardware probe / first-run seeding |
HAL0_SKIP_HINDSIGHT |
(unset) | Set to 1 to skip installing the Hindsight memory service |
HAL0_PY_AUTOINSTALL |
(unset) | The installer already sets this itself when the default Python is below 3.12, so you rarely need it; it allows installing python3.12 via apt or dnf when no 3.12-3.14 is on PATH. Other distros need HAL0_PYTHON pointed at a newer interpreter |
HAL0_HINDSIGHT_PYTHON |
(auto) | Interpreter (Python 3.11-3.14) for the Hindsight memory engine venv; use it when the installer reports none usable |
HAL0_SKIP_HERMES |
(unset) | Set to 1 to skip provisioning the bundled Hermes agent; install it later with hal0 agent install hermes |
HAL0_INSTALL_PI |
(unset) | Set to 1 to install the Pi agent unattended; the checklist sets it when the Pi row is on |
HAL0_IMAGE_MODELS |
(unset) | Starter image models to download without a prompt: recommended or a list of ids; none skips the step |
Choosing components
On an interactive fresh install the installer shows a checklist of the six
optional components before it installs them:
- Open WebUI: on
- ComfyUI (starter image models): on (the starter image-model menu is offered; its default is none, so Enter downloads nothing)
- Hermes agent: on
- Pi agent: off
- Hindsight memory: on
- Brain model: on
Flags and the checklist apply at install time only. They never remove a
component that is already installed.
Pick a preset: a keeps the defaults, b is bare inference (everything off),
p lets you pick row by row. Enter alone is a. A row whose precondition
fails on this machine is shown greyed with the reason and cannot be turned on.
The answer on screen wins over the environment: a row toggled on overrides an env
knob that would have skipped it (the installer unsets the matching
HAL0_SKIP_<X>, or HAL0_IMAGE_MODELS=none for ComfyUI). HAL0_SKIP_SETUP=1 is
not a per-row knob: it skips the brain and image-model steps whatever those rows
say, so the checklist shows the Brain model and ComfyUI rows greyed as unavailable
(HAL0_SKIP_SETUP=1) and they cannot be ticked on. The chosen set is written to the install log as one line.
The checklist does not appear on an upgrade, with --dev or --no-start,
without a terminal, with HAL0_NONINTERACTIVE=1, or when you pass any
component flag; those installs use the flags and variables above.
Like every other installer prompt, the checklist needs stdin to be a terminal.
curl … | sudo bash never shows it, even when typed at a terminal: stdin is
the pipe, so the install takes the defaults. To get the checklist, download the
script and run sudo bash install.sh, or pass the flags above.
To add a skipped component later:
hal0 app install openwebui, hal0 agent install hermes,
sudo hal0 agent install pi, hal0 comfyui models install <id>, and
hal0 model pull <id> for the brain model. Hindsight memory has no deferred
install command; re-run the installer to add it. A re-run also re-enables the
other components you skipped, except Pi, which stays opt-in, unless you repeat
the opt-outs, for example
sudo bash install.sh --no-owui --no-comfyui --no-hermes --no-brain-model.
Install log and failure reports
Every run tees its full output to /var/log/hal0/install-<ts>-<random>.log
(/tmp/hal0-install-<random>.log when not root) — the path is printed at the
start and end, and hal0 doctor bundle includes the latest one. If the
installer aborts, it also writes a redacted hal0-install-report-<ts>-<random>.txt
next to the log (environment, failed units, Podman state, port owners, unit
status, redacted config, hardware summary, log tail, hal0-api journal) and
prints its path. Secret values are masked throughout the report, not only
where their key names them. See installer/README.md for the full
breakdown of what each report contains.
--summary-json
sudo bash installer/install.sh --summary-json=/tmp/hal0-install-summary.json
Writes a schema: "hal0.install-summary.v1" JSON document — hal0 version,
--dev/--no-start flags, models dir, network bind info, the detected
hardware class, which brain model was pulled, the components map, a warning/error count, and
measured per-step durations — atomically, so a script polling for the file
never reads a half-written one. Full field reference and an example payload
are in installer/README.md.
Production filesystem layout
${HAL0_PREFIX}/hal0-<version> # versioned code tree
${HAL0_PREFIX}/current # symlink hal0 update swaps atomically
/etc/hal0 # config: hal0.toml, slots/, profiles.toml
/var/lib/hal0 # state: models, registry, slots, openwebui, cache
Under --dev, all of the above lands under $PWD/.hal0ai/ instead.
Verify the install
hal0 status
hal0 slot list
curl http://localhost:8080/api/health
journalctl -fu hal0-api
hal0 status reports system + slot + memory health; hal0 slot list
shows configured slots; the /api/health curl is a lightweight liveness
probe (200 the moment the API is serving); journalctl -fu hal0-api
tails the control-plane log if something looks wrong. The installer itself
waits up to 60 s for /api/health after starting hal0-api. For the full
six-step “did it work” checklist — health, model list, first chat,
dashboard, logs, and hal0 doctor verify — see
Verify the install.
Uninstall
hal0 uninstall # conservative: keep /etc/hal0 + models/registry
hal0 uninstall --purge # clean slate: also wipe config, data, user, images
The conservative default stops services and removes code, units, venvs,
binaries, and every hal0 podman container, but keeps /etc/hal0 (config)
and the data directory (models, registry, OpenWebUI state) so a re-install
reuses them. --purge additionally removes the
config and data directories, the hal0 system user and group, and all
hal0 runner and OpenWebUI podman images — it prompts for a typed DELETE confirmation
unless you pass --force (or set HAL0_FORCE=1).
Next steps
- Pull a model and assign it to a slot — see
Load your first model. - Open the dashboard at
http://<host>:8080/to manage slots, profiles,
and stacks.