Skip to content

hal0 v1.2.0

Latest

Choose a tag to compare

@github-actions github-actions released this 03 Sep 21:59
· 15 commits to main since this release
c631aa4

Highlights

  • Profiles carry a runtime, and the dashboard shows it everywhere a profile
    appears.
    A profile can pin a runner; profile cards carry a runtime badge,
    the import preview shows the envelope's runtime before commit, and the slot
    Edit drawer's apply preview enumerates the runtime, lane, flags and restart a
    profile change would actually cause before you save it.
  • The seed profile catalog is pruned from 18 to a 10-profile minimal core,
    and the eight demoted tunes ship as portable .hal0profile.json addon
    envelopes under community/addons/ that Profiles → Import installs from a
    paste or an upload.
  • The model and slot drawers were reworked end to end — task-grouped slot
    fields, rich selects, GTT hints, inline model pull, tune pills, a facts band,
    and an overrides ledger naming every field that diverges from the stamped
    profile.
  • Host-truth GTT feasibility. GET /api/hardware carries live
    gtt_used_mb/gtt_free_mb from the amdgpu sysfs counters, and the slot load
    path emits an advisory slot.gtt_feasibility warning — never a block — when a
    model's weights exceed the free GTT pool.
  • Arch-aware model↔runner fit-check. GGUF general.architecture is detected
    and persisted at registration, and binding a model whose arch the runner
    denylists now WARNS at assignment, naming the catalogued image that can serve
    it, instead of leaving the operator at a silent crash-loop.
  • The dashboard surfaces the decisive crash line when a slot container dies
    during model load, stamped on slot state and carried by the crash-breaker
    chip's tooltip.
  • The Proxmox VE quick-start script builds a privileged GPU-passthrough LXC by
    default
    , so a fresh container reaches the GPU without a manual pass.

Fixed

  • Editing a profile whose stored runtime key has left this box's runner
    registry (renamed, dropped by a build, or a downgrade) no longer 422s with
    profiles.unknown_runner. The drawer re-sends the stored runner on every
    save, so screening an unchanged value rejected a write that changes nothing
    and made the profile un-editable in every field. PUT /api/profiles/{name}
    now screens runner only when it actually changes — the same grandfathering
    the profile's stored flags get (#1411); creates stay strict (#2183).
  • Clearing a profile's Runtime back to "Auto" in the profiles drawer now
    actually clears it. PUT /api/profiles/{name} reads runner: null as
    "leave unchanged" (as it does for every other field), so the Auto option
    silently no-op'd and the runtime badge came back after save. The empty
    string is now the explicit clear sentinel on that field — never screened,
    so it is also the way off a stored runtime this box no longer has (#2186).
  • hal0 update now reads the installed version from the active release's
    current/VERSION file instead of the wheel metadata. A nightly wheel
    deliberately carries only the BASE version in pip metadata (PEP 440 has no
    shape for v<base>-nightly.<stamp>), so a box already on the newest
    nightly compared 1.1.0 < 1.1.0-nightly.<stamp> and looped "update
    available" forever, re-staging the same release on every run.

Added

  • The Proxmox VE quick-start script (scripts/proxmox-ve/hal0.sh) now builds
    the production hal0 container shape instead of a vanilla CPU-only one: a
    privileged Ubuntu 26.04 LXC with nesting/keyctl/fuse/mknod, every
    GPU/NPU device node the host exposes forwarded as devN, the matching
    lxc.cgroup2.devices.allow rules, lxc.prlimit.memlock: unlimited, and
    lxc.apparmor.profile: unconfined. It verifies the forwarded nodes are
    actually visible inside the container before installing anything, so a
    broken passthrough fails loudly instead of quietly seeding CPU slots. New
    env knobs: IP_CIDR/GATEWAY, NAMESERVER, SEARCHDOMAIN, TIMEZONE,
    TAGS, ONBOOT, STARTUP, MOUNTS, FEATURES, GPU_PASSTHROUGH,
    RUN_BOOTSTRAP. UNPRIVILEGED=1 GPU_PASSTHROUGH=0 OS_TYPE=debian OS_VERSION=13 reproduces the previous behaviour. Guest prerequisites are
    no longer pre-staged by the script — bootstrap and install.sh install
    their own (curl excepted: it is what fetches the bootstrap).

  • hal0_lxc_kind in installer/lib/preflight.sh classifies the platform as
    none / lxc-privileged / lxc-unprivileged from /proc/self/uid_map,
    and the installer's /dev/kfd gid-repair fallback and container-runtime
    gate now narrate the remedy that is actually possible on the container at
    hand instead of always describing the unprivileged one.

  • The dashboard now surfaces the decisive crash line when a slot container
    dies during model load. On a load failure the slot manager tails the
    unit's journal, extracts the one line that names the fault (e.g.
    llama_model_load: error loading model: unknown model architecture,
    unable to allocate ROCm0 buffer, or the hal0-runner death summary from
    #2037/#2126) and stamps it on the slot state (metadata.last_crash_line);
    the crash-breaker chip's tooltip carries it, so "trial pending" finally
    says why instead of pointing at journalctl -u hal0-slot@<name>.

  • Runner-image catalogue rows now carry runtime_family and
    supported_backends runtime metadata merged from the
    hal0.runner-images.v1 manifest, and the slot drawer's
    "catalogued · downloaded" pin lane gates each row on its declared
    runtime family instead of assuming every catalogue row is a
    llama-server fork (#2174).

  • Host-truth GTT feasibility signal. GET /api/hardware now carries live
    gtt_used_mb/gtt_free_mb from the amdgpu mem_info_gtt_* sysfs counters
    (host truth even inside an LXC container, where the cgroup-shaped meminfo
    can show tens of GiB "available" while a GTT weight allocation fails), the
    slot load path emits an advisory slot.gtt_feasibility warning — never a
    block — when a model's weights exceed the free GTT pool, and the dashboard's
    Detected-hardware panel shows the live free-GTT figure.

  • Arch-aware model↔runner fit-check (#2118 follow-up). GGUF
    general.architecture is now detected and persisted at model
    registration (scan commit, add-from-path, pull, curated auto-scan), and
    runner registry entries can denylist archs their llama.cpp build rejects
    (Runner.unsupported_archsqwen4exp on the default ROCmFPX image).
    Binding such a model to a slot now WARNS at assignment — API
    model_fit_warning on slot create/config/swap, plus a notice by the slot
    drawer's Model select — naming the catalogued image that can serve the
    arch, instead of the operator meeting a silent crash-loop at load. An
    image_pin disarms the check (the pin is the documented escape hatch);
    nothing is ever blocked and no image is auto-switched.

  • Seed profile catalog pruned to a 10-profile minimal core. The seeded
    catalog carried 18 profiles — one per runtime family, the generic
    llama-server workloads, and eight WORKLOAD VARIANTS of those generics
    (chat-long-context, dense, moe, thinking, coding,
    chadrock-dense, chadrock-moe, promptforge) — and since a seed is
    virtual and can never be edited or deleted, shipping eighteen of them made
    the Profiles page mostly un-actionable furniture. The eight move
    byte-identically into legacy_seed_profiles.toml
    (LEGACY_SEED_PROFILES) and stop being seeds. An install upgrading past
    the prune gets them injected once into its own profiles.toml as
    ordinary custom entries (ProfilesConfig.legacy_seeds_migrated), so
    nothing an operator's slots or models already point at disappears — the
    entries just become editable and deletable like any custom profile,
    which a seed never could be. A FRESH install never sees them in its
    catalog, but the curated slots and seed stacks it ships still name three;
    each such name is adopted into profiles.toml on first reference,
    independently of the others, and stays deleted once deleted.

  • Pruned seeds ship as portable addon envelopes. The eight demoted
    tunes are published as .hal0profile.json envelopes under
    community/addons/ (scripts/export_addons.py, byte-for-byte
    reproducible, --check for CI drift), alongside a versioned
    index.json catalog (kind: hal0.addon-index) a site can serve
    statically so a client can see title, description, runtime family and
    checksum before fetching an envelope. The dashboard's Profiles → Import
    installs one with a paste or an upload. min_hal0_version is 1.2.0 —
    1.1.0 shipped portable profiles without the import-side unknown-runner
    handling the addon contract relies on. See
    docs/reference/profile-addons.mdx.

  • Profiles carry a runtime; the dashboard shows it everywhere a profile
    appears.
    A profile can now optionally pin a runner (a RUNNER_IMAGES
    registry key, validated on write, stripped to Auto on import if the box
    doesn't have it) — the profiles form drawer gets a full Runtime select
    with a consequence hint, profile cards carry a runtime badge/state
    chip/blurb, the import preview shows the envelope's runtime and runtime
    family before commit, and the slot Edit drawer's apply preview enumerates
    the runtime, lane, flags and restart a profile change would actually
    cause before you save it.

Changed

  • The ComfyUI runner family now defaults to hal0's own published image
    ghcr.io/hal0ai/hal0-comfyui (digest-pinned in manifest.json) instead of
    the third-party docker.io/kyuz0/amd-strix-halo-comfyui. The image mirrors
    the kyuz0 layout by construction, so existing img slots need no
    reconfiguration; --purge uninstall still removes the old kyuz0 image on
    upgraded boxes (#2171).
  • The model and slot drawers were reworked end to end. The slot drawer
    regroups its fields by task, uses rich selects for model/profile/runtime,
    carries GTT hints and an inline pull for a model it does not have yet, and
    shows one Advanced image row (a single ref with a live-state chip) instead
    of the previous overflow. The model drawer gains header meta, a
    seed-from-profile button, tune pills, a facts band, an explicit engine
    field, and an overrides ledger that names every field diverging from the
    stamped profile (#2206, #2208, #2210, #2215).
  • Dashboard: the model Capabilities/Labels editors are retired (#2193). Capabilities
    display read-only in the model drawer; the Add-from-HF flow now offers a repo's
    mmproj projector directly and derives the vision label from that choice; the
    add-by-path flow always auto-detects labels. /api/models contracts are unchanged.

Migrations

  • profiles.toml gains two bookkeeping keys and is not readable by
    1.1.0.
    The seed prune records its one-time work in the file itself:
    legacy_seeds_migrated (the bulk demotion has run) and
    legacy_seeds_adopted (which demoted names this install has already
    materialized or deleted, so a delete sticks and a fresh box can still adopt
    each one on first reference). Both are written automatically on the first
    load or profile save after upgrading — nothing to run by hand. But
    ProfilesConfig is extra = "forbid" on 1.1.0 and earlier, so rolling
    back to 1.1.0 after the upgrade fails to parse the migrated
    profiles.toml
    and the profile catalog will not load on the old build.
    Back up /etc/hal0/profiles.toml before upgrading if you may downgrade;
    restoring that copy (or deleting the two keys) makes the file readable by
    1.1.0 again.