Find your way around the dashboard

The dashboard has two layers: a shell that’s on screen no matter what page
you’re looking at, and the pages themselves. This guide maps the shell —
the command palette, the notifications bell, the Agent Chat launcher, the
sidebar, and the dock — then explains the memory figures the dashboard
shows, and walks every page under Settings, so nothing in the operator
surface is a surprise.

The chrome

Command palette

Press ⌘K (or Ctrl+K) anywhere in the dashboard to open the command
palette — a fuzzy-search launcher over everything the dashboard knows
about. On mobile, the same surface opens from the Quick actions row in
the nav drawer.

Typing filters a grouped list:

  • Routes — jump to Dashboard, Slots, Runner Images, Models, Profiles,
    Operator Board, Benchmarks, Hardware, Logs, Agent, or Settings.
  • Slots — every configured slot, live; selecting one opens its edit
    drawer.
  • Models — every catalogue and installed model; selecting one opens
    the Models page.
  • Settings — a deep link straight into most Settings pages (see
    below) — the palette has an entry for every page except Model
    Defaults
    , which has no deep link.
  • Actions — global actions that are always live: Create slot, Add
    model from HF, Open Chat Pro UI (when OpenWebUI is reachable), and Open
    docs. A Cancel download action appears only while a model pull is
    actually running.
  • Copy — clipboard utilities for hitting the API directly, currently
    just Copy API base URL. Rendered as its own group, separate from
    Actions.
  • Slot actions — per-slot verbs (Restart, Stop or Start, View logs,
    Copy curl) that only show up once you type a verb or a slot name — they
    stay out of the default list to keep it uncluttered.

Arrow keys move the selection, Enter runs it, Escape closes the palette.

Notifications bell

The bell in the top bar aggregates everything that needs your attention
into one panel, grouped into sections:

  • needs attention — pending agent tool-call approvals and slots that
    have failed and need a restart.
  • downloads — active and failed model pulls, with cancel/retry
    controls and a link to the full downloads pane.
  • updates — an available hal0 release, slots running a pre-update
    config that need a restart, and any model updates available on
    Hugging Face.
  • messages — developer/system notices pushed into the dashboard at
    runtime.

The badge shows a live count; when nothing needs you, the panel says so.

Agent Chat drawer

The Agent Chat button in the top bar (the two-hemisphere brain icon)
toggles a slide-out drawer — the UI surface for talking to hal0’s brain.
This page only covers the drawer as a piece of chrome; for what the brain
is and how it’s configured, see Brain.

Documentation and sidebar

The book icon next to Agent Chat opens the hosted docs in a new tab. The
sidebar below it lists the primary destinations — Overview, Slots (with
Endpoints, Runner Images, and Stacks as sub-pages), Models (with
Profiles), Benchmarks, Agents (with Memory, when the memory subsystem is
enabled, and MCP), Services, Logs, and Settings — plus a Services
zone pinned to the bottom of the sidebar with quick external launchers:
Kanban (the in-app Operator Board, the Hermes kanban proxied through hal0-api; also reachable with ⌘B),
OpenWebUI, and Hermes Dash — the latter two only appear when the
backend reports them reachable.

Slots: the Image Gen tab

The Slots page splits into Inference and Image Gen tabs, beside
Endpoints, Runner Images and Stacks. Image Gen is the ComfyUI engine’s pane,
three sub-tabs directly under the tabs, Generate, Models and Engine,
at #slots/image/generate, #slots/image/models and #slots/image/engine. The
pane draws no memory gauges of its own: a model’s fit meter reads the same
memory budget as the figures below. Installing models, generating and reading
the GPU’s state are in Generate images. What the
GPU is doing, what an image costs chat and the buttons that fit live in the
dock on every page (see The dock); the paused slots’ cards on the
Inference tab keep their paused · image mode chip, and the
slot rail beside the Inference pane shows them hollow-blue.

Services

The Services page is the management surface for hal0’s companion
processes — OpenWebUI, ComfyUI, Hermes, and Hindsight — all four sourced
from one server-side catalog (hal0.services.registry.SERVICES), so the
page and the dock’s services pip group can never disagree about which
services exist. Each card shows:

  • a real up/down state (never a placeholder) — ComfyUI via its own
    /system_stats + /queue probe, OpenWebUI via a loopback GET /health,
    and Hermes/Hindsight via their systemd unit state, distinguishing a
    deliberate stop (grey, “stopped — starts on demand”) from a crash (red,
    “crashed — systemd unit failed”);

  • the systemd unit, browser URL (when one exists — Hermes and Hindsight are
    loopback-only; ComfyUI’s link opens from anywhere while it binds the LAN, the
    default, and under [network].comfyui_listen = "loopback" only from a page on
    the box itself, disabled anywhere else beside an SSH tunnel command), and mDNS
    .local URL when advertised;

  • lifecycle buttons (Restart/Start/Stop) limited to the verbs that service
    actually permits — ComfyUI exposes Start/Restart only, since a raw
    systemctl start would bypass the GPU-arbiter switchover that hands the
    iGPU back from inference mode;

  • a journald logs drawer.

A service the backend has no real probe for (nothing in the current
catalog, but a future extension-provided service could arrive this way)
reports honestly as unmonitored rather than a fabricated “up” — the same
rule the Overview card’s services pip group and the dock’s ready count
follow.

The Discovery (mDNS) card at the top shows whether avahi-daemon is
active, the dashboard’s own <hostname>.local announcement, and lets you
advertise or withdraw the addon services (OpenWebUI; ComfyUI listens on
loopback and is not announced) as their own <name>.local entries. The
installer writes the base hal0.service avahi file itself when avahi is
present, alongside the same permission fix-up that lets the daemon (running as the unprivileged hal0 user) write the
addon files — so both announcements come up out of the box, not just the
addons.

The dock

The dock is the console’s one status surface, at the bottom of every page. It
pushes the page up when it opens and never covers it. Always visible, one row
shows:

  • the GPU segment — a headline and a one-line detail from the GPU arbiter
    (GPU · chat mode, Rendering · <model> · step n/N, …) and up to two
    buttons for what fits right now (Hold, Keep, Unpin, Stop image mode, Cancel,
    Restart engine, Dismiss). Click the headline for the gpu tab. A box with
    no GPU pool reading or no image engine shows no segment,
  • a slots group — one pip per active slot (colored by state) and a
    ready count,
  • a services group — one pip per backing service and a ready count
    (a single warn-toned “services unknown” pip appears if the health
    check itself hasn’t answered, rather than falsely reporting all-green),
  • an update chip when a new hal0 release is available,
  • the dock toggle, with a +N badge for the events that arrived while it
    was closed.

Under the row, a two-row ticker shows the newest events, newest at the bottom.
The toggle expands the dock into three tabs:

  • events — journal lines (tagged J) merged with activity actions (tagged
    A) in one timeline, newest last. Filter by stream (all, journal,
    activity), severity, source and slot, or search. Click an activity row for
    its action, target, outcome and before/after. Export downloads the
    activity trail with the severity, source and slot filters; journal lines are on the
    Logs page.
  • gpu — the full status with its step chips and render progress, every
    action that applies (including Restart engine, Logs, Open
    editor
    , which needs an editor link, and Cancel, which needs a run
    started in this browser), and a grid of facts: mode, phase, engine and gate, queue, chat waiting, GPU pool,
    slots, and the last image made in this browser.
  • downloads — active, queued, completed and failed model pulls with
    cancel, retry and clear controls.

Slot rail

On the Inference tab, the right column is the slot rail: every slot,
grouped by device (GPU · vulkan, GPU · rocm, NPU, CPU), with its state dot,
device chip, tok/s or state, model and loaded GB. The header reads N / M ready, the same fraction as the dock’s slots group, and the rail’s footer shows the
GB loaded and the pool’s free GB. A row flashes when an event for that slot
lands in the dock’s feed; click a row to jump to its card. The Image Gen tab
has no side column, so its pane takes the full width.

Memory figures

The Slots page opens with a telemetry bar, the Overview page carries a health
strip and a Unified memory card, and Settings ▸ Overview has a live
hardware panel. They all take their pool, RAM and per-owner figures from one
place, the memory block of GET /api/stats/hardware, so two screens cannot
show two answers. The block holds two budgets that are never added together,
because they are different resources:

  • GPU pool · shared is what the GPU loads models into on a unified-memory
    machine: a pool shared with the host and with every other guest on the same
    GPU. The ruler under the telemetry bar is titled “memory · GPU pool · shared”,
    and its total and usage are the kernel’s own live counters. On a discrete card
    the pool is VRAM and the ruler is titled “memory · VRAM”. When the box has
    no usable GPU, or the kernel’s counters for the pool cannot be read, there is
    no pool figure: the ruler is titled “memory · RAM” and measures this box’s RAM
    instead.
  • RAM (this box) is the memory this machine may use. The “CPU · RAM” cell
    shows RAM in use over this box’s RAM limit, and the Overview health strip’s
    “RAM” cell and the “RAM” row in Settings ▸ Overview show the same figure.
    When hal0 runs in a container or under a cgroup limit, the cell reads
    “/ N GB limit” and the other two say “container limit”; on a plain machine it
    reads “/ N GB”, the machine’s total. hal0 reads the limit on every refresh,
    from the machine’s total and from every cgroup limit between the service and
    the root, and takes the smallest, so a cap on a systemd slice or an LXC guest
    counts. RAM in use
    leaves out reclaimable page cache. It is system-wide, so under a cap below the
    machine’s total it can read above the limit. If hal0 cannot read RAM, these
    cells show “—” and no figure. hal0 treats GPU pool memory as not charged to a
    container’s RAM limit, so unloading GPU slots frees little RAM.

The ruler splits the pool’s usage by who holds it. Each of this box’s GPU slots
is a segment named for the slot, sized by hal0’s estimate of the memory it
holds (the tooltip says “estimated”). image engine is the memory ComfyUI
reports for its own device on a unified pool, or the img slot’s estimate when
ComfyUI does not answer; on a discrete card it is always the img slot’s
estimate, because ComfyUI’s reading covers the whole card. The tooltip says
“estimated” whenever it is the estimate. other guests is the striped block for whatever the pool holds that
nothing on this box accounts for, such as a second guest on the same GPU, and it
appears only when that is more than zero. On a box with no GPU pool, the
Unified memory card shows “system” in that place instead: RAM in use beyond
what loaded models hold. Estimates can add up to more than the counter. The
total always comes from the counter, so the ruler scales its segments to fit
the bar, the API reports the difference as attribution_excess_gb, and a real
second guest can hide inside the overshoot.

“free” is the pool’s total less its usage. “headroom” is what is free in the
resource that binds, less a 2 GB safety margin: the pool, this box’s RAM when
there is no pool, or the Proxmox host when one is configured and has less free.
“limited by” names which one bound it.

For the field list behind these figures, see the
Memory budget API reference;
the design is recorded in
ADR-0039.

Settings

Settings groups its pages into four sections in the left rail. Several
pages are the primary documentation surface for another guide — those get
one line and a link here rather than a repeat.

GENERAL

  • Overview — the landing page: overall health status, per-service
    health, live hardware/power counters, the /v1 request rollup, and the
    telemetry opt-in.
  • Security — auth posture only (never a key value): whether auth is
    required, whether an admin key is set, and the tier; rotates the admin
    or client key; shows the live route-exposure table. See
    Auth.
  • Network — the browser origins hal0 accepts on top of the installer’s
    list: the reverse-proxy Public URL and Extra origins, saved to
    hal0.toml [network] and applied on the next request. Same as
    hal0 network. See Allow the public URL.
  • Doctor — runs and renders hal0 doctor’s typed diagnoses (id,
    severity, evidence, next steps) over HTTP. Every fail/warn row carries at
    least one real next step, not just a description of the problem: a
    command step shows the exact command in mono and offers Copy, plus
    Run when it maps onto an existing repair action (restarting the
    affected systemd service, or restarting a named runner slot); a doc step
    opens the relevant guide; a manual step expands inline. A diagnosis with
    two or more steps also gets a Steps button that opens a numbered
    drawer with the same actions.

MODELS & INFERENCE

  • Loaded Models, Model Defaults, and AI Capabilities (TTS,
    STT, embeddings, reranking, image generation, plus the NPU anchor) —
    see Choose models for the catalogue and
    the per-model file facts (Model Defaults edits the chat template only; tunes
    live on profiles), and
    Generate images (the Image panel also sets
    the default image size and steps) /
    Speech to text and text to speech for
    the capability slots.

SYSTEM

  • Hardware & Runtimes — read-only evidence: detected hardware,
    available backends, and the runner-image registry per slot. See
    Manage slots and
    Manage runner images for what
    actually controls what a slot runs on.
  • Storage — where hal0 reads and writes model files on disk. Covered
    in detail below.
  • Memory — the memory engine, graph extraction, and reranker. The
    graph panel’s Engine model picker chooses a local slot or an upstream
    model for the engine and applies without a restart; the agents Memory tab
    carries the same picker. See Enable memory.
  • Updates — signed self-update plus version/license identity. See
    Update and roll back.
  • Advanced — low-level dispatcher and activity-log tuning rendered
    straight from the server’s settings schema, plus a hal0-api restart
    control.

INTEGRATIONS

  • Secrets — provider keys, pull-auth, and custom env vars. This is
    not an encrypted store: values are persisted as plaintext
    double-quoted KEY="value" lines in /etc/hal0/api.env, root-only at
    mode 0600 — the same systemd EnvironmentFile= hal0-api reads at
    start. Includes a dedicated HF_TOKEN field that applies live (no
    restart) so a gated or large pull can authenticate right away. See
    REST API: secrets and Proxmox credentials
    for the write path.
  • Agent Chat — the [brain_chat] policy surface: kill switch,
    read-only guardrail, chat model override, tool-routing model, and loop
    knobs. tool_model (where a tool-calling round reroutes when the chat
    model can’t emit tool calls this runtime parses) has its own picker
    here, with a warning banner when the saved value has no loaded slot to
    route to — the shipped hal0/agent default on a fresh install, before
    a model is pulled into that slot. See Brain.
  • Realtime — the [realtime] WS voice-endpoint surface: kill switch,
    sample rate, which slots serve speech-to-text/text-to-speech, the
    energy-VAD turn-detection thresholds, and output framing. Every key
    applies on the next connection — no restart.

Agent Chat and Realtime save through Review & save, which shows the exact
per-key diff from POST /api/settings/preview before Apply writes it.

Settings ▸ Storage, in detail

Storage holds one field: Storage location, an absolute directory that
every model consumer — the pull engine, the registry, slots — resolves
through. Alongside it:

  • Current state — a live probe of the effective path: whether it
    exists, file count, bytes used, bytes free, and whether it’s writable.
  • Suggested locations — clickable preset paths, each labeled with its
    current state.
  • Auto-scan on start — whether hal0-api walks the storage path at
    startup and registers any new files it finds.
  • File extensions — read-only; edit via hal0 config edit.

Changing the location: the migration flow

If you change Storage location to a path that doesn’t yet hold your
existing model files, Saving doesn’t move anything right away. hal0 first
does a dry run and shows a confirmation dialog: it will move a specific
number of files (with a total size) from the old path to the new one. If
source and target are on the same filesystem the move is effectively
instant; across filesystems it’s a real copy and can take a while. Only
after you confirm does hal0 actually touch disk.

On confirm, hal0 moves the files first and persists the new path to
hal0.toml second — deliberately in that order, so a failed move leaves
your prior config and your files exactly where they were; you can safely
re-run the move. Once the new path is saved, hal0 immediately rescans it
and registers any files it finds, so newly-visible models show up in the
registry without waiting for a restart.

If a move partially fails, the files that already moved are not
rolled back — the operator can re-run the same move (now effectively a
no-op for what already succeeded) to finish it safely.