# Install hal0 (hal0 docs)

**URL:** <https://forum.hal0.dev/t/install-hal0-hal0-docs/20>\
**Category:** Start here\
**Created:** [August 22, 2026, 6:49am UTC](https://forum.hal0.dev/t/install-hal0-hal0-docs/20 "2026-08-22T06:49:17Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![system](https://forum.hal0.dev/user_avatar/forum.hal0.dev/system/32/37_2.png) [@system](https://forum.hal0.dev/u/system)\
**Post date:** [August 22, 2026, 6:49am UTC](https://forum.hal0.dev/t/install-hal0-hal0-docs/20/1 "2026-08-22T06:49:17Z")

</div>

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`).

```sh
curl -fsSL https://hal0.dev/install.sh | sudo bash

```

> [@](#):
>
> **Note**
> 
> The installer needs root to write to `/etc`, `/usr/lib`, and the systemd  
> unit directory. If you pipe through plain `bash` (no `sudo`), it re-execs  
> itself under `sudo` automatically — as long as `sudo` is on `PATH`.

## Channels

By default the bootstrap fetches the latest `stable` release manifest.  
Pick a different channel with `HAL0_CHANNEL`:

```sh
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 for `tar`,  
`sha256sum`, `jq` and `python3`, installs any that are missing with the  
system package manager, and fetches its own pinned `cosign`.
- **Linux, x86\_64** — hal0 ships amd64-only binaries (the FastFlowLM  
`.deb` and the runner container images). ARM and macOS/Windows are not  
supported.
- **systemd** — `systemctl` must be on `PATH` (outside `--dev` mode).
- **Python 3.12 to 3.14** — hal0 requires `>=3.12` and is tested on 3.12, 3.13 and 3.14. If the default `python3` is older, the installer uses `python3.14`, `python3.13` or `python3.12` when one is already on `PATH`, and otherwise tries to install `python3.12` through 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_PYTHON` at 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 prebuilt `ui/dist` and 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:

1. **Pre-flight checks** — architecture, systemd, Python, container  
runtime, disk space, free ports.
2. **System user** — creates the `hal0` service account.
3. **Filesystem layout** — creates the FHS directory tree (or the `--dev`  
tree under `$PWD/.hal0ai`).
4. **Python environment** — builds the shared venv and `pip install`s  
hal0 into it.
5. **Node.js toolchain** — provisions Node only if this tree ships the  
dashboard’s npm project.
6. **Dashboard UI** — builds `ui/dist` (or reuses a release’s prebuilt  
copy).
7. **Configuration** — writes `/etc/hal0/hal0.toml`, `api.env`,  
`upstreams.toml`, `openwebui.env` — never overwriting existing files.
8. **Systemd units** — writes and enables `hal0-api.service` and  
`hal0-openwebui.service` (unless `--no-start`).
9. **Container slot seeds** — copies default slot TOMLs into  
`/etc/hal0/slots/` (never overwriting operator edits).
10. **Hardware probe** — detects CPU/RAM/GPU/NPU and writes  
`/etc/hal0/hardware.json`.
11. **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](#starter-image-model)).
12. **NPU prerequisites** — installs the FastFlowLM runtime on  
AMDXDNA/apt hosts (fail-soft elsewhere).
13. **Bundle picker manifests** — writes the dashboard’s first-run bundle  
catalog.
14. **Bundled agent skills** — installs the shipped agent skill set.
15. **Service start** — starts `hal0-api` and `hal0-openwebui` (unless  
`--no-start`), waits up to 60 s for `/api/health` to answer before the post-install checks run, stands up the Hindsight memory engine, then provisions the bundled Hermes agent (skip with `HAL0_SKIP_HERMES=1`; install later with `hal0 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](https://forum.hal0.dev/t/environment-variables-bootstrap-install-time-preflight/117#install-time-overrides).

## Flags and environment variables

```sh
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`

```sh
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

```auto
${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

```sh
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](https://forum.hal0.dev/t/verify-the-install/109).

## Uninstall

```sh
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](https://forum.hal0.dev/t/load-your-first-model/18).
- Open the dashboard at `http://<host>:8080/` to manage slots, profiles,  
and stacks.
