Skip to content

docs: install the engine on any Linux with Lemonade from its own package (PPA) - #860

Open
bong-water-water-bong wants to merge 26 commits into
mainfrom
docs/install-any-distro
Open

bong-water-water-bong wants to merge 26 commits into
mainfrom
docs/install-any-distro

Conversation

@bong-water-water-bong

@bong-water-water-bong bong-water-water-bong commented Nov 2, 2026 •

Copy link
Copy Markdown
Collaborator

Item 8 of ~/briefs/TLEMONADE-PPA.md (owner: "that would be a huge win, then they can take any linux distro really. we would need to leave instructions"), plus item 6's packaging.

The finding this rests on (item 5, measured)

A stock Lemonade runs our engine — no fork, no patch, nothing upstream. Its llamacpp-hrx recipe
(recipe llamacpp-hrx, config_section hrx, binary llama-server) resolves its backend binary through
BackendUtils::find_external_backend_binary(): LEMONADE_<SECTION>_<BINKEY> in the environment, else the
config key <section>.<bin_key>, and a directory is resolved to binary inside it. Measured on the PPA
deb 2026.44.1~26.04 (extracted, run isolated, no model load): backend state installable → installed,
both from LEMONADE_HRX_HRX_BIN=<dir> and from {"hrx": {"hrx_bin": "<dir>"}} alone.

So the plug-in contract is: ship <dir>/llama-server, point hrx_bin at <dir>. Everything in this PR is
that, and the reason llama-server is a shim rather than our binary: the recipe's own
build_server_environment() hands the backend exactly one variable, GGML_DISABLE_VULKAN=1, so Lemonade
would otherwise spawn the engine without the no-SVM trio — the configuration engine#715 page-faults in.

What is added

  • scripts/mk-plugin-package.sh <1bit-bundle-dir> <out-dir> <version> — emits 1bit-engine_<v>_amd64.deb
    and 1bit-engine-<v>-linux-x86_64.tar.zst: the engine, its HRX llama.cpp build, the HSA runtime the HRX
    backend dlopens (placed beside libhrx.so, which searches $ORIGIN), the sealed NPU kernel sets, the
    llama-server shim, a lemond.service.d drop-in carrying LEMONADE_HRX_HRX_BIN, and the config-key
    fragment for a lemond without systemd. Userspace only: no kernel module, no Python at runtime.
  • docs/install-any-distro.md — PPA + package + wiring steps for Ubuntu 26.04/24.04, the 1bit OS case, and
    the tarball path for other distros; per-device host prerequisites; verification (one chat per device plus
    1bit-engine serve alone); and the two limits of this route (no 1bit serve preflight, no NPU catalog
    rows — our rows can ride along through the config dir's user_models.json).

Measured

claim where
the deb installs and runs clean ubuntu:26.04 container: dpkg -i → install ok installed; 1bit-engine --version, the shim (version: 1 (d8bd0ff6)) and 1bit serve --help all run; 3 NPU kernel sets present; 0 .ko files
a stock Lemonade takes the binary extracted PPA deb on the dev box: llamacpp-hrx installable → installed, env form and config-key form
the recipe's env for its backend is one variable this tree, src/cpp/server/backends/hrx/hrx_server.cpp build_server_environment()
PPA lemonade-server pulls no kernel bits; amdxdna-dkms does clean container apt-get -s: 11 packages, zero dkms/xrt/amdxdna; the dkms package pulls dkms + build-essential + linux-headers-*-generic and DKMS installs into /lib/modules/$(uname -r)/updates/ — the driver this board resets with (scripts/mkimage.sh), so the doc says not to install it

Not measured here: a chat through stock Lemonade on the engine (GPU window queued behind other lanes at
the time of writing; the wiring it depends on is the installed result above). I will post the number here
when it lands, and the doc's table only lists claims that were run.


87c20b96 — the package shipped a runtime that cannot load (found on the board, 2026-11-02)

The 1bit OS appliance rebooted into a GPU it could not use (invalid device: HRX0, libhsa-runtime64.so.1
never opened). Two causes; the second one was this script's shape too:

  1. the appliance named the runtime with ONEBIT_HRX_LIBHSA=…, a CMake compile definition that nothing
    reads at run time — the engine's runtime knob is IREE_HAL_AMDGPU_LIBHSA_PATH (or a scan of
    /opt/rocm-therock, app/serve.cpp:201). Reproduced on this box by emptying /opt/rocm-therock: the
    shipped plan then carries no HSA path and the backend dies with the board's exact error.

  2. a TheRock libhsa-runtime64.so.1 is not a standalone file. It names TheRock's own libraries in
    NEEDED and carries RUNPATH=$ORIGIN, so shipping it alone give a dlopen that fails:

    $ env -i python3 -c "import ctypes; ctypes.CDLL('/tmp/app_libhsa.so')"      # the board's own runtime
    OSError: librocm_sysdeps_elf.so.1: cannot open shared object file: No such file or directory
    

    readelf -d on it: RUNPATH [$ORIGIN], NEEDED librocm_sysdeps_elf.so.1, librocprofiler-register.so.0,
    librocm_sysdeps_drm.so.2, librocm_sysdeps_drm_amdgpu.so.1, librocm_sysdeps_numa.so.1.

The script now ldds the chosen runtime, copies every resolved private library beside it (skipping
/lib, /usr/lib, which stay dpkg Depends), and re-ldds from inside the staged directory, refusing the
build if anything is unresolved:

   HSA runtime: libhsa-runtime64.so.1 + 9 sibling libraries, ldd clean

Measured on the built deb (1bit-engine_2026.11.02-2_amd64.deb, 18.9 MB):

check result
packaged runtime under env -i (no ROCm, no LD_LIBRARY_PATH) loads (the same file alone: FAIL -> librocm_sysdeps_elf.so.1)
build with LIBHSA= a lone file refused, naming the five libraries it could not stage
installed engine on a box with /opt/rocm-therock emptied, trio only, no env path health ok, chat on HRX0 88.5 tok/s, backend maps <prefix>/hrx/llama/bin/libhsa-runtime64.so.1 through its own RUNPATH=$ORIGIN

So the package now installs a GPU that works on a machine with no ROCm at all, which is the claim this PR's
doc makes.

…ackage (PPA)

The engine needs no patched Lemonade: its llamacpp-hrx recipe resolves the
name llama-server inside the directory named by hrx_bin, so a stock Lemonade
runs our engine once hrx_bin (env LEMONADE_HRX_HRX_BIN, or the config key
hrx.hrx_bin) points at the package's lemonade-bin/ directory.

- scripts/mk-plugin-package.sh builds 1bit-engine as a .deb and a .tar.zst:
  the engine, its HRX llama.cpp build, the HSA runtime it dlopens beside it
  ($ORIGIN), the sealed NPU kernel sets, and a llama-server shim that sets
  the engine's HRX environment (the recipe hands its backend only
  GGML_DISABLE_VULKAN=1) and the -ngl 99 default. No kernel module, no Python.
- docs/install-any-distro.md: PPA + package steps, the wiring, per-device host
  prerequisites measured on the Strix Halo box, verification, and the warning
  that the PPA's amdxdna-dkms builds a stock module into modules/updates/,
  which is the driver this board resets with.

Measured: the deb installs in a clean ubuntu:26.04, the shim and the engine run,
and a stock Lemonade (PPA 2026.44.1) flips llamacpp-hrx from installable to
installed from the hrx_bin setting alone.
@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

PR Reviewer Guide 🔍

(Review updated until commit b221074)

Here are some key observations to aid the review process:

🎫 Ticket compliance analysis 🔶

715 - Partially compliant

Compliant requirements:

  • The PR introduces a mechanism to package the engine with the correct HSA runtime and shim, which ensures the trio is set correctly
  • The packaging script ensures the correct libhsa is used and copies its dependencies
  • The documentation explains how to install and use the engine with a stock Lemonade

Non-compliant requirements:

  • The PR does not implement the automatic detection and setting of the trio at runtime based on capability lines
  • The PR does not implement loud failure at init with the recipe
  • The PR does not log the libhsa path + sha256 in the HRX init line of every run
  • The PR does not fully settle the release-runtime question (it still allows for explicit selection)

Requires further human verification:

  • Verification that the trio is automatically set at runtime based on capability lines
  • Verification that the engine fails loudly at init when the unfavourable capability lines are detected
  • Verification that the libhsa path + sha256 is logged in the HRX init line of every run
  • Verification that the release-runtime question is fully settled
⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Missing automatic trio setting

The script packages the engine with the correct HSA runtime and shim, but it does not implement the automatic setting of the trio at runtime based on capability lines (XNACK enabled: NO / Coherent Host Access: FALSE). This is a key requirement from the ticket to avoid page faults on the rebuilt box.

#!/usr/bin/env bash
# Copyright 2026 bong-water-water-bong
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# mk-plugin-package.sh <1bit-bundle-dir> <out-dir> <version>
#
# Packs the engine as a SEPARATE package that plugs into a stock Lemonade (no fork, no patch):
# <out-dir>/1bit-engine_<version>_amd64.deb and <out-dir>/1bit-engine-<version>-linux-x86_64.tar.zst.
#
# <1bit-bundle-dir> is the 1bit/ directory of a Lemonade + onebit package (it carries 1bit, the HRX
# llama.cpp build with ggml-hrx, and the sealed NPU kernel sets). The package adds the two things a
# Lemonade on a plain distribution needs and the bundle does not carry: the HSA runtime the HRX
# backend dlopens (it searches $ORIGIN, so it lands beside libhrx.so), and a `llama-server` shim that
# sets the engine's own HRX environment before exec'ing the real binary. The shim is the whole
# plug-in contract: Lemonade's llamacpp-hrx recipe resolves the name `llama-server` inside the
# directory named by `hrx_bin`, so pointing `hrx_bin` at <prefix>/lemonade-bin is enough.
#
# Userspace only: no kernel module, no Python at runtime (scripts/weekly.sh's package checks).
#
# LIBHSA overrides the HSA runtime source; the default is the system's libhsa-runtime64.so.1.
set -euo pipefail

[ $# -ge 3 ] || { sed -n '18,34p' "$0"; exit 2; }
bundle=$(cd "$1" && pwd) out=$2 ver=$3
[ -x "$bundle/1bit" ] || { echo "not a 1bit bundle: $bundle (no 1bit binary)" >&2; exit 1; }
[ -d "$bundle/hrx/llama/bin" ] || { echo "not a 1bit bundle: $bundle (no hrx/llama/bin)" >&2; exit 1; }

# Only a runtime that registers gfx1151 will do. The distro's libhsa-runtime64 rejects the
# HSA_AMD_AGENT_INFO_PM4_EMULATION probe on gfx1151, so HRX then registers no device (docs/hrx.md:932-941) —
# and a clean `ldd` says nothing about that probe. So the bundle's own runtime is the default and there is no
# distro fallback; a bundle without one has to name a TheRock/gfx1151 runtime explicitly.
libhsa=${LIBHSA:-$bundle/hrx/llama/bin/libhsa-runtime64.so.1}
[ -f "$libhsa" ] || {
    echo "no libhsa-runtime64.so.1 at $libhsa; set LIBHSA=<the TheRock/gfx1151 runtime>" >&2
    echo "the distro's ROCr is not a substitute: it rejects the PM4-emulation probe on gfx1151 and HRX gets no device" >&2
    exit 1; }

pkg=1bit-engine
root=$(mktemp -d)/root
trap 'rm -rf "$(dirname "$root")"' EXIT
mkdir -p "$root/opt/1bit/engine" "$root/usr/share/doc/$pkg" "$root/usr/share/1bit" \
         "$root/usr/bin" "$root/usr/lib/systemd/system/lemond.service.d" "$out"

# the payload: 1bit, its backends, the sealed NPU kernel sets, the licences. LICENSE-BINARY travels with
# NOTICE-BINARY because LICENSE-BINARY section 2 ("every copy is accompanied by this license and
# NOTICE-BINARY") covers the HRX/NPU binaries in this payload, and package-linux.sh ships both in the
# bundle for the same reason.
cp -a "$bundle/1bit" "$bundle/hrx" "$bundle/npu" "$bundle/lemonade-hrx" "$bundle/NOTICE" \
      "$bundle/NOTICE-BINARY" "$bundle/LICENSE" "$bundle/LICENSE-BINARY" "$bundle/README.txt" \
      "$root/opt/1bit/engine/"
chmod 0755 "$root/opt/1bit/engine/1bit"

# The GGUF-on-NPU path is public helper scripts, not code compiled into 1bit: the binary looks for them
# BESIDE ITSELF (app/built_path.h:44-56 -> packaged_path("scripts/repack_gguf.py") at app/serve.cpp:2482,
# packaged_path("tools/gguf_to_q4nx.py") at app/serve.cpp:2589). Without them `1bit serve -m model.gguf
# --device npu` fails with "Q4NX repack script not found" even with python3 and the converter installed, so
# the payload keeps the two directories package-linux.sh stages (scripts/package-linux.sh:98-105).
for d in "$bundle/scripts" "$bundle/tools"; do
    [ -d "$d" ] || { echo "not a 1bit bundle: $d is missing (the NPU helper scripts travel beside 1bit)" >&2; exit 1; }
done
cp -a "$bundle/scripts" "$bundle/tools" "$root/opt/1bit/engine/"

# The HSA runtime is NOT a standalone file. A TheRock libhsa lists TheRock's own libraries in NEEDED
# (librocm_sysdeps_elf.so.1, librocm_sysdeps_drm.so.2, librocm_sysdeps_numa.so.1, librocm_sysdeps_z*…,
# librocprofiler-register.so.0) and carries RUNPATH=$ORIGIN, so the set has to land FLAT beside it or the
# backend's dlopen fails and HRX registers no device. Measured 2026-11-02 on the appliance's own libhsa
# (sha256 f6ef689d…): shipped as one file in /opt/1bit/libhsa it answered "librocm_sysdeps_elf.so.1: cannot
# open shared object file", and the board booted with a GPU it could not use. ldd is the arbiter here: the
# private siblings are copied in, and anything still unresolved refuses the build.
hsa_dir=$root/opt/1bit/engine/hrx/llama/bin
install -m 0644 "$libhsa" "$hsa_dir/libhsa-runtime64.so.1"
srcdir=$(cd "$(dirname "$libhsa")" && pwd)
libdirs=$srcdir:$srcdir/rocm_sysdeps/lib:$srcdir/../../_rocm_sdk_core/lib:$srcdir/../../_rocm_sdk_core/lib/rocm_sysdeps/lib:${LD_LIBRARY_PATH:-}
copied=0
for so in $(LD_LIBRARY_PATH=$libdirs ldd "$libhsa" | awk '/=> \// {print $3}' | sort -u); do
    case "$so" in /lib/* | /usr/lib/*) continue ;; esac   # the distro's own: dpkg-deb Depends, not ours to ship
    install -m 0644 "$so" "$hsa_dir/$(basename "$so")"
    copied=$((copied + 1))
done
missing=$(LD_LIBRARY_PATH=$hsa_dir ldd "$hsa_dir/libhsa-runtime64.so.1" | awk '/not found/ {print $1}' | tr '\n' ' ')
[ -z "${missing// /}" ] || {
    echo "libhsa needs $missing and this build could not stage it beside the runtime;
pass LIBHSA=<a runtime whose sibling libraries are next to it> (the release-gated TheRock set)" >&2
    exit 1; }
echo "   HSA runtime: $(basename "$libhsa") + $copied sibling libraries, ldd clean"
ln -s /opt/1bit/engine/1bit "$root/usr/bin/1bit-engine"

# the shim: the name the recipe resolves inside hrx_bin's directory. It is the bundle's own
# lemonade-hrx wrapper, which runs `1bit serve --print-backend-env` (serve's architecture and memory
# checks, and the environment serve gives an HRX backend: strict placement, the HSA runtime path,
# the CWSR save-area trio, ternary decode) and then execs the engine's llama-server on Lemonade's
# argv, with serve's defaults for what the argv left out (-ngl 99, --cache-reuse 256, -kvu above one
# slot). Lemonade's own build_server_environment() hands a backend only GGML_DISABLE_VULKAN=1, which
# is why the engine's wrapper and not our binary is what the recipe must start (engine#715).
[ -x "$root/opt/1bit/engine/lemonade-hrx" ] || {
    echo "the bundle has no lemonade-hrx wrapper; it is the shim this package installs" >&2; exit 1; }
mkdir -p "$root/opt/1bit/engine/lemonade-bin"
ln -s ../lemonade-hrx "$root/opt/1bit/engine/lemonade-bin/llama-server"

# wiring for an installed Lemonade: the unit drop-in (env form) and the config fragment (key form)
cat > "$root/usr/lib/systemd/system/lemond.service.d/10-1bit-engine.conf" <<'UNIT'
# 1bit-engine: run stock Lemonade's llamacpp-hrx recipe on this engine's llama-server.
# Only applies to a lemond started from this unit; the config key form (see the README) is equivalent.
[Service]
Environment=LEMONADE_HRX_HRX_BIN=/opt/1bit/engine/lemonade-bin
UNIT
cat > "$root/usr/share/1bit/lemonade-config-fragment.json" <<'FRAG'
{"hrx": {"hrx_bin": "/opt/1bit/engine/lemonade-bin"}}
FRAG

cat > "$root/usr/share/doc/$pkg/README.md" <<'DOC'
# 1bit-engine

The 1bit engine (HRX GPU kernels through llama.cpp's ggml-hrx backend, sealed NPU kernel sets) and
the shim that lets a **stock** Lemonade run it: no fork, no patch, nothing added upstream.

Userspace only: no kernel modules, no Python at runtime.

## Verify the payload

    1bit-engine --version
    /opt/1bit/engine/1bit serve --help | head -3

## Use it from an installed Lemonade

Either form is enough (they are equivalent):

    LEMONADE_HRX_HRX_BIN=/opt/1bit/engine/lemonade-bin          # environment for lemond
    {"hrx": {"hrx_bin": "/opt/1bit/engine/lemonade-bin"}}       # Lemonade's config.json

Restart lemond, then load any `*-HRX` model: Lemonade execs
`/opt/1bit/engine/lemonade-bin/llama-server` with
`-m <gguf> --ctx-size N --device HRX0 --port P --jinja --metrics --parallel 1`. That name is a link to
this package's `lemonade-hrx`, which asks `1bit serve` for the backend environment and serve's checks
before exec'ing the engine, so Lemonade's single `GGML_DISABLE_VULKAN=1` is not the whole story.

`docs/install-any-distro.md` in the engine repo has the host prerequisites per device and the
verification steps.
DOC
cp "$bundle/NOTICE" "$bundle/LICENSE" "$root/usr/share/doc/$pkg/"

size=$(du -sk --exclude=DEBIAN "$root" | cut -f1)
mkdir -p "$root/DEBIAN"
cat > "$root/DEBIAN/control" <<CTRL
Package: $pkg
Version: $ver
Architecture: amd64
Maintainer: bong-water-water-bong <bong-water-water-bong@1bit.gg>
Installed-Size: $size
Section: misc
Priority: optional
Depends: libc6 (>= 2.35), libstdc++6, libgomp1, libssl3t64 | libssl3, zlib1g, libzstd1, libpcre2-8-0
Recommends: lemonade-server
Description: 1bit engine - HRX GPU + sealed NPU kernels, plug-in for stock Lemonade
 The 1bit engine binary, its HRX llama.cpp build with the ggml-hrx backend and the HSA runtime
 library it dlopens, the sealed NPU kernel sets, and a shim that makes a stock Lemonade (its
 llamacpp-hrx recipe) run this engine with no patch and no fork.
 .
 Userspace only: no kernel modules, no Python at runtime.
CTRL

dpkg-deb --root-owner-group --build "$root" "$out/${pkg}_${ver}_amd64.deb" >/dev/null
tar -C "$root" --exclude=DEBIAN -I 'zstd -19 -T4' -cf "$out/${pkg}-${ver}-linux-x86_64.tar.zst" \
    opt usr/bin usr/share/1bit usr/share/doc usr/lib/systemd
echo "$out/${pkg}_${ver}_amd64.deb"
echo "$out/${pkg}-${ver}-linux-x86_64.tar.zst"
Missing init-time failure

The packaging script does not implement a loud failure at init when unfavourable capability lines are detected. This would prevent lanes from measuring off a faulting path.

#!/usr/bin/env bash
# Copyright 2026 bong-water-water-bong
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# mk-plugin-package.sh <1bit-bundle-dir> <out-dir> <version>
#
# Packs the engine as a SEPARATE package that plugs into a stock Lemonade (no fork, no patch):
# <out-dir>/1bit-engine_<version>_amd64.deb and <out-dir>/1bit-engine-<version>-linux-x86_64.tar.zst.
#
# <1bit-bundle-dir> is the 1bit/ directory of a Lemonade + onebit package (it carries 1bit, the HRX
# llama.cpp build with ggml-hrx, and the sealed NPU kernel sets). The package adds the two things a
# Lemonade on a plain distribution needs and the bundle does not carry: the HSA runtime the HRX
# backend dlopens (it searches $ORIGIN, so it lands beside libhrx.so), and a `llama-server` shim that
# sets the engine's own HRX environment before exec'ing the real binary. The shim is the whole
# plug-in contract: Lemonade's llamacpp-hrx recipe resolves the name `llama-server` inside the
# directory named by `hrx_bin`, so pointing `hrx_bin` at <prefix>/lemonade-bin is enough.
#
# Userspace only: no kernel module, no Python at runtime (scripts/weekly.sh's package checks).
#
# LIBHSA overrides the HSA runtime source; the default is the system's libhsa-runtime64.so.1.
set -euo pipefail

[ $# -ge 3 ] || { sed -n '18,34p' "$0"; exit 2; }
bundle=$(cd "$1" && pwd) out=$2 ver=$3
[ -x "$bundle/1bit" ] || { echo "not a 1bit bundle: $bundle (no 1bit binary)" >&2; exit 1; }
[ -d "$bundle/hrx/llama/bin" ] || { echo "not a 1bit bundle: $bundle (no hrx/llama/bin)" >&2; exit 1; }

# Only a runtime that registers gfx1151 will do. The distro's libhsa-runtime64 rejects the
# HSA_AMD_AGENT_INFO_PM4_EMULATION probe on gfx1151, so HRX then registers no device (docs/hrx.md:932-941) —
# and a clean `ldd` says nothing about that probe. So the bundle's own runtime is the default and there is no
# distro fallback; a bundle without one has to name a TheRock/gfx1151 runtime explicitly.
libhsa=${LIBHSA:-$bundle/hrx/llama/bin/libhsa-runtime64.so.1}
[ -f "$libhsa" ] || {
    echo "no libhsa-runtime64.so.1 at $libhsa; set LIBHSA=<the TheRock/gfx1151 runtime>" >&2
    echo "the distro's ROCr is not a substitute: it rejects the PM4-emulation probe on gfx1151 and HRX gets no device" >&2
    exit 1; }

pkg=1bit-engine
root=$(mktemp -d)/root
trap 'rm -rf "$(dirname "$root")"' EXIT
mkdir -p "$root/opt/1bit/engine" "$root/usr/share/doc/$pkg" "$root/usr/share/1bit" \
         "$root/usr/bin" "$root/usr/lib/systemd/system/lemond.service.d" "$out"

# the payload: 1bit, its backends, the sealed NPU kernel sets, the licences. LICENSE-BINARY travels with
# NOTICE-BINARY because LICENSE-BINARY section 2 ("every copy is accompanied by this license and
# NOTICE-BINARY") covers the HRX/NPU binaries in this payload, and package-linux.sh ships both in the
# bundle for the same reason.
cp -a "$bundle/1bit" "$bundle/hrx" "$bundle/npu" "$bundle/lemonade-hrx" "$bundle/NOTICE" \
      "$bundle/NOTICE-BINARY" "$bundle/LICENSE" "$bundle/LICENSE-BINARY" "$bundle/README.txt" \
      "$root/opt/1bit/engine/"
chmod 0755 "$root/opt/1bit/engine/1bit"

# The GGUF-on-NPU path is public helper scripts, not code compiled into 1bit: the binary looks for them
# BESIDE ITSELF (app/built_path.h:44-56 -> packaged_path("scripts/repack_gguf.py") at app/serve.cpp:2482,
# packaged_path("tools/gguf_to_q4nx.py") at app/serve.cpp:2589). Without them `1bit serve -m model.gguf
# --device npu` fails with "Q4NX repack script not found" even with python3 and the converter installed, so
# the payload keeps the two directories package-linux.sh stages (scripts/package-linux.sh:98-105).
for d in "$bundle/scripts" "$bundle/tools"; do
    [ -d "$d" ] || { echo "not a 1bit bundle: $d is missing (the NPU helper scripts travel beside 1bit)" >&2; exit 1; }
done
cp -a "$bundle/scripts" "$bundle/tools" "$root/opt/1bit/engine/"

# The HSA runtime is NOT a standalone file. A TheRock libhsa lists TheRock's own libraries in NEEDED
# (librocm_sysdeps_elf.so.1, librocm_sysdeps_drm.so.2, librocm_sysdeps_numa.so.1, librocm_sysdeps_z*…,
# librocprofiler-register.so.0) and carries RUNPATH=$ORIGIN, so the set has to land FLAT beside it or the
# backend's dlopen fails and HRX registers no device. Measured 2026-11-02 on the appliance's own libhsa
# (sha256 f6ef689d…): shipped as one file in /opt/1bit/libhsa it answered "librocm_sysdeps_elf.so.1: cannot
# open shared object file", and the board booted with a GPU it could not use. ldd is the arbiter here: the
# private siblings are copied in, and anything still unresolved refuses the build.
hsa_dir=$root/opt/1bit/engine/hrx/llama/bin
install -m 0644 "$libhsa" "$hsa_dir/libhsa-runtime64.so.1"
srcdir=$(cd "$(dirname "$libhsa")" && pwd)
libdirs=$srcdir:$srcdir/rocm_sysdeps/lib:$srcdir/../../_rocm_sdk_core/lib:$srcdir/../../_rocm_sdk_core/lib/rocm_sysdeps/lib:${LD_LIBRARY_PATH:-}
copied=0
for so in $(LD_LIBRARY_PATH=$libdirs ldd "$libhsa" | awk '/=> \// {print $3}' | sort -u); do
    case "$so" in /lib/* | /usr/lib/*) continue ;; esac   # the distro's own: dpkg-deb Depends, not ours to ship
    install -m 0644 "$so" "$hsa_dir/$(basename "$so")"
    copied=$((copied + 1))
done
missing=$(LD_LIBRARY_PATH=$hsa_dir ldd "$hsa_dir/libhsa-runtime64.so.1" | awk '/not found/ {print $1}' | tr '\n' ' ')
[ -z "${missing// /}" ] || {
    echo "libhsa needs $missing and this build could not stage it beside the runtime;
pass LIBHSA=<a runtime whose sibling libraries are next to it> (the release-gated TheRock set)" >&2
    exit 1; }
echo "   HSA runtime: $(basename "$libhsa") + $copied sibling libraries, ldd clean"
ln -s /opt/1bit/engine/1bit "$root/usr/bin/1bit-engine"

# the shim: the name the recipe resolves inside hrx_bin's directory. It is the bundle's own
# lemonade-hrx wrapper, which runs `1bit serve --print-backend-env` (serve's architecture and memory
# checks, and the environment serve gives an HRX backend: strict placement, the HSA runtime path,
# the CWSR save-area trio, ternary decode) and then execs the engine's llama-server on Lemonade's
# argv, with serve's defaults for what the argv left out (-ngl 99, --cache-reuse 256, -kvu above one
# slot). Lemonade's own build_server_environment() hands a backend only GGML_DISABLE_VULKAN=1, which
# is why the engine's wrapper and not our binary is what the recipe must start (engine#715).
[ -x "$root/opt/1bit/engine/lemonade-hrx" ] || {
    echo "the bundle has no lemonade-hrx wrapper; it is the shim this package installs" >&2; exit 1; }
mkdir -p "$root/opt/1bit/engine/lemonade-bin"
ln -s ../lemonade-hrx "$root/opt/1bit/engine/lemonade-bin/llama-server"

# wiring for an installed Lemonade: the unit drop-in (env form) and the config fragment (key form)
cat > "$root/usr/lib/systemd/system/lemond.service.d/10-1bit-engine.conf" <<'UNIT'
# 1bit-engine: run stock Lemonade's llamacpp-hrx recipe on this engine's llama-server.
# Only applies to a lemond started from this unit; the config key form (see the README) is equivalent.
[Service]
Environment=LEMONADE_HRX_HRX_BIN=/opt/1bit/engine/lemonade-bin
UNIT
cat > "$root/usr/share/1bit/lemonade-config-fragment.json" <<'FRAG'
{"hrx": {"hrx_bin": "/opt/1bit/engine/lemonade-bin"}}
FRAG

cat > "$root/usr/share/doc/$pkg/README.md" <<'DOC'
# 1bit-engine

The 1bit engine (HRX GPU kernels through llama.cpp's ggml-hrx backend, sealed NPU kernel sets) and
the shim that lets a **stock** Lemonade run it: no fork, no patch, nothing added upstream.

Userspace only: no kernel modules, no Python at runtime.

## Verify the payload

    1bit-engine --version
    /opt/1bit/engine/1bit serve --help | head -3

## Use it from an installed Lemonade

Either form is enough (they are equivalent):

    LEMONADE_HRX_HRX_BIN=/opt/1bit/engine/lemonade-bin          # environment for lemond
    {"hrx": {"hrx_bin": "/opt/1bit/engine/lemonade-bin"}}       # Lemonade's config.json

Restart lemond, then load any `*-HRX` model: Lemonade execs
`/opt/1bit/engine/lemonade-bin/llama-server` with
`-m <gguf> --ctx-size N --device HRX0 --port P --jinja --metrics --parallel 1`. That name is a link to
this package's `lemonade-hrx`, which asks `1bit serve` for the backend environment and serve's checks
before exec'ing the engine, so Lemonade's single `GGML_DISABLE_VULKAN=1` is not the whole story.

`docs/install-any-distro.md` in the engine repo has the host prerequisites per device and the
verification steps.
DOC
cp "$bundle/NOTICE" "$bundle/LICENSE" "$root/usr/share/doc/$pkg/"

size=$(du -sk --exclude=DEBIAN "$root" | cut -f1)
mkdir -p "$root/DEBIAN"
cat > "$root/DEBIAN/control" <<CTRL
Package: $pkg
Version: $ver
Architecture: amd64
Maintainer: bong-water-water-bong <bong-water-water-bong@1bit.gg>
Installed-Size: $size
Section: misc
Priority: optional
Depends: libc6 (>= 2.35), libstdc++6, libgomp1, libssl3t64 | libssl3, zlib1g, libzstd1, libpcre2-8-0
Recommends: lemonade-server
Description: 1bit engine - HRX GPU + sealed NPU kernels, plug-in for stock Lemonade
 The 1bit engine binary, its HRX llama.cpp build with the ggml-hrx backend and the HSA runtime
 library it dlopens, the sealed NPU kernel sets, and a shim that makes a stock Lemonade (its
 llamacpp-hrx recipe) run this engine with no patch and no fork.
 .
 Userspace only: no kernel modules, no Python at runtime.
CTRL

dpkg-deb --root-owner-group --build "$root" "$out/${pkg}_${ver}_amd64.deb" >/dev/null
tar -C "$root" --exclude=DEBIAN -I 'zstd -19 -T4' -cf "$out/${pkg}-${ver}-linux-x86_64.tar.zst" \
    opt usr/bin usr/share/1bit usr/share/doc usr/lib/systemd
echo "$out/${pkg}_${ver}_amd64.deb"
echo "$out/${pkg}-${ver}-linux-x86_64.tar.zst"
Missing libhsa logging

The packaging script does not log the libhsa path + sha256 in the HRX init line of every run, which is required for debugging and verification.

#!/usr/bin/env bash
# Copyright 2026 bong-water-water-bong
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# mk-plugin-package.sh <1bit-bundle-dir> <out-dir> <version>
#
# Packs the engine as a SEPARATE package that plugs into a stock Lemonade (no fork, no patch):
# <out-dir>/1bit-engine_<version>_amd64.deb and <out-dir>/1bit-engine-<version>-linux-x86_64.tar.zst.
#
# <1bit-bundle-dir> is the 1bit/ directory of a Lemonade + onebit package (it carries 1bit, the HRX
# llama.cpp build with ggml-hrx, and the sealed NPU kernel sets). The package adds the two things a
# Lemonade on a plain distribution needs and the bundle does not carry: the HSA runtime the HRX
# backend dlopens (it searches $ORIGIN, so it lands beside libhrx.so), and a `llama-server` shim that
# sets the engine's own HRX environment before exec'ing the real binary. The shim is the whole
# plug-in contract: Lemonade's llamacpp-hrx recipe resolves the name `llama-server` inside the
# directory named by `hrx_bin`, so pointing `hrx_bin` at <prefix>/lemonade-bin is enough.
#
# Userspace only: no kernel module, no Python at runtime (scripts/weekly.sh's package checks).
#
# LIBHSA overrides the HSA runtime source; the default is the system's libhsa-runtime64.so.1.
set -euo pipefail

[ $# -ge 3 ] || { sed -n '18,34p' "$0"; exit 2; }
bundle=$(cd "$1" && pwd) out=$2 ver=$3
[ -x "$bundle/1bit" ] || { echo "not a 1bit bundle: $bundle (no 1bit binary)" >&2; exit 1; }
[ -d "$bundle/hrx/llama/bin" ] || { echo "not a 1bit bundle: $bundle (no hrx/llama/bin)" >&2; exit 1; }

# Only a runtime that registers gfx1151 will do. The distro's libhsa-runtime64 rejects the
# HSA_AMD_AGENT_INFO_PM4_EMULATION probe on gfx1151, so HRX then registers no device (docs/hrx.md:932-941) —
# and a clean `ldd` says nothing about that probe. So the bundle's own runtime is the default and there is no
# distro fallback; a bundle without one has to name a TheRock/gfx1151 runtime explicitly.
libhsa=${LIBHSA:-$bundle/hrx/llama/bin/libhsa-runtime64.so.1}
[ -f "$libhsa" ] || {
    echo "no libhsa-runtime64.so.1 at $libhsa; set LIBHSA=<the TheRock/gfx1151 runtime>" >&2
    echo "the distro's ROCr is not a substitute: it rejects the PM4-emulation probe on gfx1151 and HRX gets no device" >&2
    exit 1; }

pkg=1bit-engine
root=$(mktemp -d)/root
trap 'rm -rf "$(dirname "$root")"' EXIT
mkdir -p "$root/opt/1bit/engine" "$root/usr/share/doc/$pkg" "$root/usr/share/1bit" \
         "$root/usr/bin" "$root/usr/lib/systemd/system/lemond.service.d" "$out"

# the payload: 1bit, its backends, the sealed NPU kernel sets, the licences. LICENSE-BINARY travels with
# NOTICE-BINARY because LICENSE-BINARY section 2 ("every copy is accompanied by this license and
# NOTICE-BINARY") covers the HRX/NPU binaries in this payload, and package-linux.sh ships both in the
# bundle for the same reason.
cp -a "$bundle/1bit" "$bundle/hrx" "$bundle/npu" "$bundle/lemonade-hrx" "$bundle/NOTICE" \
      "$bundle/NOTICE-BINARY" "$bundle/LICENSE" "$bundle/LICENSE-BINARY" "$bundle/README.txt" \
      "$root/opt/1bit/engine/"
chmod 0755 "$root/opt/1bit/engine/1bit"

# The GGUF-on-NPU path is public helper scripts, not code compiled into 1bit: the binary looks for them
# BESIDE ITSELF (app/built_path.h:44-56 -> packaged_path("scripts/repack_gguf.py") at app/serve.cpp:2482,
# packaged_path("tools/gguf_to_q4nx.py") at app/serve.cpp:2589). Without them `1bit serve -m model.gguf
# --device npu` fails with "Q4NX repack script not found" even with python3 and the converter installed, so
# the payload keeps the two directories package-linux.sh stages (scripts/package-linux.sh:98-105).
for d in "$bundle/scripts" "$bundle/tools"; do
    [ -d "$d" ] || { echo "not a 1bit bundle: $d is missing (the NPU helper scripts travel beside 1bit)" >&2; exit 1; }
done
cp -a "$bundle/scripts" "$bundle/tools" "$root/opt/1bit/engine/"

# The HSA runtime is NOT a standalone file. A TheRock libhsa lists TheRock's own libraries in NEEDED
# (librocm_sysdeps_elf.so.1, librocm_sysdeps_drm.so.2, librocm_sysdeps_numa.so.1, librocm_sysdeps_z*…,
# librocprofiler-register.so.0) and carries RUNPATH=$ORIGIN, so the set has to land FLAT beside it or the
# backend's dlopen fails and HRX registers no device. Measured 2026-11-02 on the appliance's own libhsa
# (sha256 f6ef689d…): shipped as one file in /opt/1bit/libhsa it answered "librocm_sysdeps_elf.so.1: cannot
# open shared object file", and the board booted with a GPU it could not use. ldd is the arbiter here: the
# private siblings are copied in, and anything still unresolved refuses the build.
hsa_dir=$root/opt/1bit/engine/hrx/llama/bin
install -m 0644 "$libhsa" "$hsa_dir/libhsa-runtime64.so.1"
srcdir=$(cd "$(dirname "$libhsa")" && pwd)
libdirs=$srcdir:$srcdir/rocm_sysdeps/lib:$srcdir/../../_rocm_sdk_core/lib:$srcdir/../../_rocm_sdk_core/lib/rocm_sysdeps/lib:${LD_LIBRARY_PATH:-}
copied=0
for so in $(LD_LIBRARY_PATH=$libdirs ldd "$libhsa" | awk '/=> \// {print $3}' | sort -u); do
    case "$so" in /lib/* | /usr/lib/*) continue ;; esac   # the distro's own: dpkg-deb Depends, not ours to ship
    install -m 0644 "$so" "$hsa_dir/$(basename "$so")"
    copied=$((copied + 1))
done
missing=$(LD_LIBRARY_PATH=$hsa_dir ldd "$hsa_dir/libhsa-runtime64.so.1" | awk '/not found/ {print $1}' | tr '\n' ' ')
[ -z "${missing// /}" ] || {
    echo "libhsa needs $missing and this build could not stage it beside the runtime;
pass LIBHSA=<a runtime whose sibling libraries are next to it> (the release-gated TheRock set)" >&2
    exit 1; }
echo "   HSA runtime: $(basename "$libhsa") + $copied sibling libraries, ldd clean"
ln -s /opt/1bit/engine/1bit "$root/usr/bin/1bit-engine"

# the shim: the name the recipe resolves inside hrx_bin's directory. It is the bundle's own
# lemonade-hrx wrapper, which runs `1bit serve --print-backend-env` (serve's architecture and memory
# checks, and the environment serve gives an HRX backend: strict placement, the HSA runtime path,
# the CWSR save-area trio, ternary decode) and then execs the engine's llama-server on Lemonade's
# argv, with serve's defaults for what the argv left out (-ngl 99, --cache-reuse 256, -kvu above one
# slot). Lemonade's own build_server_environment() hands a backend only GGML_DISABLE_VULKAN=1, which
# is why the engine's wrapper and not our binary is what the recipe must start (engine#715).
[ -x "$root/opt/1bit/engine/lemonade-hrx" ] || {
    echo "the bundle has no lemonade-hrx wrapper; it is the shim this package installs" >&2; exit 1; }
mkdir -p "$root/opt/1bit/engine/lemonade-bin"
ln -s ../lemonade-hrx "$root/opt/1bit/engine/lemonade-bin/llama-server"

# wiring for an installed Lemonade: the unit drop-in (env form) and the config fragment (key form)
cat > "$root/usr/lib/systemd/system/lemond.service.d/10-1bit-engine.conf" <<'UNIT'
# 1bit-engine: run stock Lemonade's llamacpp-hrx recipe on this engine's llama-server.
# Only applies to a lemond started from this unit; the config key form (see the README) is equivalent.
[Service]
Environment=LEMONADE_HRX_HRX_BIN=/opt/1bit/engine/lemonade-bin
UNIT
cat > "$root/usr/share/1bit/lemonade-config-fragment.json" <<'FRAG'
{"hrx": {"hrx_bin": "/opt/1bit/engine/lemonade-bin"}}
FRAG

cat > "$root/usr/share/doc/$pkg/README.md" <<'DOC'
# 1bit-engine

The 1bit engine (HRX GPU kernels through llama.cpp's ggml-hrx backend, sealed NPU kernel sets) and
the shim that lets a **stock** Lemonade run it: no fork, no patch, nothing added upstream.

Userspace only: no kernel modules, no Python at runtime.

## Verify the payload

    1bit-engine --version
    /opt/1bit/engine/1bit serve --help | head -3

## Use it from an installed Lemonade

Either form is enough (they are equivalent):

    LEMONADE_HRX_HRX_BIN=/opt/1bit/engine/lemonade-bin          # environment for lemond
    {"hrx": {"hrx_bin": "/opt/1bit/engine/lemonade-bin"}}       # Lemonade's config.json

Restart lemond, then load any `*-HRX` model: Lemonade execs
`/opt/1bit/engine/lemonade-bin/llama-server` with
`-m <gguf> --ctx-size N --device HRX0 --port P --jinja --metrics --parallel 1`. That name is a link to
this package's `lemonade-hrx`, which asks `1bit serve` for the backend environment and serve's checks
before exec'ing the engine, so Lemonade's single `GGML_DISABLE_VULKAN=1` is not the whole story.

`docs/install-any-distro.md` in the engine repo has the host prerequisites per device and the
verification steps.
DOC
cp "$bundle/NOTICE" "$bundle/LICENSE" "$root/usr/share/doc/$pkg/"

size=$(du -sk --exclude=DEBIAN "$root" | cut -f1)
mkdir -p "$root/DEBIAN"
cat > "$root/DEBIAN/control" <<CTRL
Package: $pkg
Version: $ver
Architecture: amd64
Maintainer: bong-water-water-bong <bong-water-water-bong@1bit.gg>
Installed-Size: $size
Section: misc
Priority: optional
Depends: libc6 (>= 2.35), libstdc++6, libgomp1, libssl3t64 | libssl3, zlib1g, libzstd1, libpcre2-8-0
Recommends: lemonade-server
Description: 1bit engine - HRX GPU + sealed NPU kernels, plug-in for stock Lemonade
 The 1bit engine binary, its HRX llama.cpp build with the ggml-hrx backend and the HSA runtime
 library it dlopens, the sealed NPU kernel sets, and a shim that makes a stock Lemonade (its
 llamacpp-hrx recipe) run this engine with no patch and no fork.
 .
 Userspace only: no kernel modules, no Python at runtime.
CTRL

dpkg-deb --root-owner-group --build "$root" "$out/${pkg}_${ver}_amd64.deb" >/dev/null
tar -C "$root" --exclude=DEBIAN -I 'zstd -19 -T4' -cf "$out/${pkg}-${ver}-linux-x86_64.tar.zst" \
    opt usr/bin usr/share/1bit usr/share/doc usr/lib/systemd
echo "$out/${pkg}_${ver}_amd64.deb"
echo "$out/${pkg}-${ver}-linux-x86_64.tar.zst"
Incomplete release-runtime settling

The documentation explains how to install and use the engine, but it does not fully settle the release-runtime question. It still allows for explicit selection of the libhsa runtime, which is not ideal.

<!--
Copyright 2026 bong-water-water-bong
SPDX-License-Identifier: Apache-2.0

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

# Install the 1bit engine on any Linux, with Lemonade from its own package

The engine does not need a patched Lemonade. A **stock** Lemonade discovers it through the
`llamacpp-hrx` recipe it already has: that recipe resolves the name `llama-server` inside the
directory named by its `hrx_bin` setting, so pointing `hrx_bin` at the engine package's
`lemonade-bin/` directory is the whole plug-in contract. Nothing is added upstream and nothing is
patched locally.

Two packages, from two places:

| piece | where it comes from | what it is |
|---|---|---|
| Lemonade server + CLI | Lemonade's own package (Ubuntu: its PPA, weekly) | `lemonade-server`, `lemond` |
| the engine | `1bit-engine_<version>_amd64.deb`, or the `.tar.zst` on a non-deb distro | `1bit`, its HRX llama.cpp build (`hrx/llama/bin/llama-server`), the sealed NPU kernel sets, the HSA runtime it dlopens, and the engine's `lemonade-hrx` wrapper, which is what the recipe's `llama-server` name points at |

The engine package is userspace only: no kernel module, no Python at runtime.

One indirection carries the whole contract, and it matters: Lemonade's recipe hands a backend exactly one
environment variable (`GGML_DISABLE_VULKAN=1`), so pointing `hrx_bin` at the engine's raw `llama-server`
would start the HRX kernels without the environment `1bit serve` gives them. `lemonade-bin/llama-server`
is therefore the engine's own `lemonade-hrx` wrapper: it asks `1bit serve --print-backend-env` for that
environment and for serve's architecture and memory checks, then `exec`s the engine on Lemonade's argv,
filling in serve's defaults for what the argv left out (`-ngl 99`, `--cache-reuse 256`, `-kvu` above one
slot).

## Ubuntu 26.04 (resolute) / 24.04 (noble)

```bash
# 1. Lemonade's own package. The archive is signed by key
#    881CF4B4 0B0BFA28 8D6776E8 3BF36CFA 0BD50AEC  (~lemonade-team).
sudo install -d /etc/apt/keyrings
curl -fsSL 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x881CF4B40B0BFA288D6776E83BF36CFA0BD50AEC' \
  | sudo gpg --dearmor -o /etc/apt/keyrings/lemonade.gpg
echo "deb [signed-by=/etc/apt/keyrings/lemonade.gpg] https://ppa.launchpadcontent.net/lemonade-team/stable/ubuntu $(. /etc/os-release; echo $VERSION_CODENAME) main" \
  | sudo tee /etc/apt/sources.list.d/lemonade.list
sudo apt-get update
sudo apt-get install -y lemonade-server

# 2. the engine
sudo apt-get install -y ./1bit-engine_<version>_amd64.deb

# 3. point Lemonade at it. The package already ships this drop-in as
#    /usr/lib/systemd/system/lemond.service.d/10-1bit-engine.conf, so on a stock systemd install there is
#    nothing to do here; a local override is only for a different path. Both forms are shipped, and
#    /usr/share/1bit/lemonade-config-fragment.json is the config-key form.
sudo mkdir -p /etc/systemd/system/lemond.service.d
sudo tee /etc/systemd/system/lemond.service.d/10-1bit-engine.conf >/dev/null <<'EOF'
[Service]
Environment=LEMONADE_HRX_HRX_BIN=/opt/1bit/engine/lemonade-bin
EOF
#   ... or, without systemd:  {"hrx": {"hrx_bin": "/opt/1bit/engine/lemonade-bin"}}
#                             in Lemonade's config.json
sudo systemctl daemon-reload && sudo systemctl restart lemond

Do not install amdxdna-dkms from that archive on a machine whose kernel you did not build. It is
in the same PPA but nothing pulls it, and it is the wrong thing for this engine: its closure is
dkms + build-essential + linux-headers-<ver>-generic and it builds a stock amdxdna module
for the running kernel. Our boards reset with the stock driver (see scripts/mkimage.sh), which is
why 1bit OS ships a private build of it, and a DKMS module lands in
/lib/modules/$(uname -r)/updates/, i.e. in front of whatever the board was meant to load.

Verify the plug-in (no model needed):

curl -s localhost:13305/api/v1/system-info | grep -A2 '"llamacpp-hrx"'
#   -> the "hrx" backend should read state=<installed>; on a machine without an AMD GPU it reads
#      "unsupported: Unsupported GPU" before it ever looks at the binary, which is expected.

Then one real chat per device is in "Verify" below.

1bit OS (Puppy appliance)

Nothing to do: the appliance already ships the engine and Lemonade. This page is the recipe for
everything else, and the appliance's own check is 1bit-release-check / puppy-check.

Other distributions

Unpack the tarball at /opt/1bit/engine and install Lemonade your distro's way (its .deb/.rpm,
its container, or a source build — anything that reports llamacpp-hrx in system-info):

sudo tar -C / --zstd -xf 1bit-engine-<version>-linux-x86_64.tar.zst opt
sudo ln -sf /opt/1bit/engine/1bit /usr/local/bin/1bit-engine
# then the same two lines as above, in whatever runs lemond: the env var, or the config key.

If your Lemonade runs under systemd, the drop-in from the deb applies verbatim; in a container or a
hand-started lemond, export LEMONADE_HRX_HRX_BIN=/opt/1bit/engine/lemonade-bin in its environment.

Host prerequisites, per device (measured on the Strix Halo development box)

GPU / HRX. No ROCm install, no HIP user-space: the package carries the HSA runtime the HRX
backend dlopens, and it is found because the recipe's libraries and ours share $ORIGIN.

  • amdgpu loaded, with /dev/kfd and /dev/dri/renderD* both root:render, mode 0660; the user
    running lemond must be in the render group (a container needs --group-add <render gid>, and
    that group must exist inside the image or the GID is dropped).
  • amdgpu.cwsr_enable=0 is what the shipping hardware reports. In that configuration the engine
    sets HSA_USE_SVM=0 HSA_USERPTR_FOR_PAGED_MEM=0 HRX_ALLOW_NO_SVM=1; without it the kernels take
    the ROCr SVM path and a nightly libhsa page-faults (engine#715). Those come from the engine's own
    wrapper (1bit serve --print-backend-env), so Lemonade's child gets them even though Lemonade
    itself passes only GGML_DISABLE_VULKAN=1.
  • Kernels: an HRX build needs a KFD that supports the device (gfx1151 here on
    7.3.0-rc4-1bit-perfopt+); it does not need a patched kernel.

NPU. amdxdna bound to the device, plus the board firmware files under
/lib/firmware/amdnpu/ (17f0_10, 17f0_11 on Strix Halo) and memlock unlimited — the NPU
runtime is compiled into 1bit and locks command buffers.

  • Which amdxdna matters. The in-tree driver from your distro's kernel is the default; this board
    resets the machine with the stock module and is shipped with a private build of the same vermagic
    dropped over it (scripts/mkimage.sh). On a distro kernel, use that kernel's own amdxdna first
    and only replace it with a build for the exact kernel you run.
  • Secure Boot: the engine package contains no module, so it is unaffected. An out-of-tree amdxdna
    replaces a module the kernel trusts, so it must be signed by an enrolled MOK
    (/var/lib/shim-signed/mok/MOK.priv + .der on 1bit OS); the kernel side of that is
    CONFIG_LOCK_DOWN_IN_EFI_SECURE_BOOT in the distro kernel, which the 1bit OS kernel leaves unset.

Verify

One chat per device, through Lemonade, on a model the recipe knows (*-HRX in Lemonade's catalog):

# GPU
curl -s -X POST localhost:13305/api/v1/load -H 'Content-Type: application/json' \
  -d '{"model_name":"Qwen3-4B-Instruct-2507-HRX"}'
curl -s -X POST localhost:13305/api/v1/chat/completions -H 'Content-Type: application/json' \
  -d '{"model":"Qwen3-4B-Instruct-2507-HRX","messages":[{"role":"user","content":"2+3?"}],"max_tokens":32}'

The engine alone, which is the fastest way to separate "Lemonade" from "the engine" when something
is wrong:

1bit-engine serve -m <model>.gguf --device hrx          # GPU, prints the HRX0 backend it starts
1bit-engine serve -m <model>.gguf --device npu          # NPU

What this route does not do, compared with the fork's onebit recipe: the model list is Lemonade's
own catalog, not our 27 rows — ours can be added on the side through the config directory's
user_models.json, below — and there are no NPU catalog rows, because Lemonade has no recipe for our
NPU route at all (NPU stays on the engine: 1bit serve --device npu). The engine's own checks do run:
the wrapper is 1bit serve --print-backend-env, so a model that does not fit is refused by serve
(exit 3) with Lemonade reporting the load failure, not silently started.

Our own catalog rows can ride along through the config directory's user_models.json, which Lemonade
reads at start and lists like its own (recipe must be llamacpp-hrx, and the checkpoint names a
registry model, since this Lemonade version has no local-file registration):

{"Qwen3.6-35B-A3B-NPU-1bit": {"checkpoint": "owner/repo:VARIANT", "recipe": "llamacpp-hrx", "labels": ["chat"]}}

What has been measured where

claim where result
a stock Lemonade takes a backend binary from hrx_bin / LEMONADE_HRX_HRX_BIN extracted PPA deb 2026.44.1~26.04 on the dev box, isolated cache/config llamacpp-hrx backend installable → installed, both forms, with no fork and no patch
the same recipe, both packages side by side clean ubuntu:26.04 container: PPA lemonade-server + this .deb lemond 2026.44.1 starts, 1bit-engine --version and the shim run; the recipe's backend state is hardware-gated there (unsupported: Unsupported GPU), so the end-to-end chat is the hardware row below
the shim is the engine's own wrapper 1bit/lemonade-hrx from this repo's package (scripts/package-linux.sh) it runs 1bit serve --print-backend-env and then execs the engine with serve's environment and defaults; lemonade-bin/llama-server is a symlink to it
the recipe's env for its backend is one variable this tree, src/cpp/server/backends/hrx/hrx_server.cpp build_server_environment() Lemonade passes its backend GGML_DISABLE_VULKAN=1 only — which is why the wrapper, not our binary, has to be what the recipe starts
amdxdna-dkms from the PPA drags kernel bits clean container, apt-get -s install amdxdna-dkms dkms, build-essential, linux-headers-7.0.0-42-generic, linux-headers-generic, amdxdna-dkms

</details>

</td></tr>
</table>

…ade-hrx wrapper

Lemonade's llamacpp-hrx build_server_environment() hands its backend exactly
one variable (GGML_DISABLE_VULKAN=1), so pointing hrx_bin at the raw engine
binary starts the HRX kernels without the environment 1bit serve gives them --
measured on hardware: a stock PPA lemond exec'd the shim with

  -m <gguf> --ctx-size 40960 --device HRX0 --port 8001 --jinja --metrics --parallel 1

and the engine refused the device (invalid device: HRX0) because the shim had
only the trio and not serve's plan (HSA runtime path and the rest).

So the package now installs lemonade-bin/llama-server as a symlink to the
bundle's own lemonade-hrx, which is exactly that contract already: it runs
1bit serve --print-backend-env (architecture and memory checks, the backend
environment) and then execs the engine on Lemonade's argv with serve's defaults.
The doc's limits section is corrected with it: serve's checks DO run on this
route (a model that does not fit is refused with exit 3, not silently started);
what is missing is our catalog rows and any NPU recipe.
@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown

Persistent review updated to latest commit 459ff86

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: READY at 459ff8603 — the contract it rests on is real, and I built the package end to end

The Lemonade side, checked in the source tree on this box (~/wt/lemonade-44-1):
BackendUtils::find_external_backend_binary() reads LEMONADE_<SECTION>_<BINKEY> as an environment override
(backend_utils.cpp:374) or the config value, and when the value is a directory it resolves spec->binary
inside it (is_directory(dir) -> dir / spec->binary, top level only) — so <dir>/llama-server plus
hrx_bin=<dir> is the supported form, exactly as the page says. And hrx_server.cpp:78 returns the backend
environment as {{"GGML_DISABLE_VULKAN", "1"}} and nothing else, which is why the shim (rather than a bare
symlink) is needed at all.

The package, built here against the release payload bundle
(~/wt/rel-payload/lemonade-onebit-rc-2026-11-02/1bit):

scripts/mk-plugin-package.sh <bundle> /tmp/plug 0.0.0-prs        rc 0
1bit-engine_0.0.0-prs_amd64.deb                    17,370,000 B
1bit-engine-0.0.0-prs-linux-x86_64.tar.zst         17,458,722 B

dpkg -c / extraction show what the doc promises: opt/1bit/engine/1bit, the HRX build under
hrx/llama/bin/ with libggml-hrx.so, libhrx.so and libhsa-runtime64.so.1 beside it (the $ORIGIN
lookup), the sealed NPU kernel sets, lemonade-bin/llama-server (the shim), the
usr/lib/systemd/system/lemond.service.d/10-1bit-engine.conf drop-in carrying
Environment=LEMONADE_HRX_HRX_BIN=/opt/1bit/engine/lemonade-bin, and
usr/share/1bit/lemonade-config-fragment.json = {"hrx": {"hrx_bin": "/opt/1bit/engine/lemonade-bin"}} for a
lemond without systemd. Control: Package: 1bit-engine, Recommends: lemonade-server, and the description says
"userspace only: no kernel modules, no Python at runtime" — which the tree backs: no .ko, no .py in the
extracted package.

The shim's mechanism, run: 1bit serve -m <gguf> --device hrx --llama-server /bin/true --print-backend-env
prints NAME=VALUE lines that include the no-SVM trio the engine needs
(HRX_ALLOW_NO_SVM=1, HSA_USERPTR_FOR_PAGED_MEM=0, plus GGML_HRX_REPORT/STRICT), so the shim can inject what
stock Lemonade's single GGML_DISABLE_VULKAN=1 never would. The flag exists at this head (app/serve.cpp:2769)
and in the shipped rc-2026-11-02 bundle's binary.

bash -n clean, shellcheck -S warning silent on the new script, tools/copyright.py --check rc 0.

Two caveats, neither a gate:

  • I built the package; I did not install it on a bare distro, so the Depends/Recommends list is
    unexercised (the page's "per-device host prerequisites" is the part a fresh-box test would settle).
  • one discipline note on my side, not yours: --print-backend-env prints the HRX plan line but loads no weights
    and starts no backend; still it is GPU-adjacent, so I will wrap even that in a gpu-hold claim from now on.

@bong-water-water-bong bong-water-water-bong added the tprs-ready TPRS: review verdict READY posted by the standing reviewer; merge gate satisfied label Nov 2, 2026
…hsa cannot load)

The package installed libhsa-runtime64.so.1 as a single file. A TheRock libhsa is not
standalone: it names TheRock's own libraries in NEEDED (librocm_sysdeps_elf.so.1,
librocm_sysdeps_drm.so.2, librocm_sysdeps_drm_amdgpu.so.1, librocm_sysdeps_numa.so.1,
librocm_sysdeps_z*.so, librocm_sysdeps_liblzma.so.5, librocm_sysdeps_bz2.so,
librocprofiler-register.so.0) and carries RUNPATH=$ORIGIN, so a lone file dlopens to
"librocm_sysdeps_elf.so.1: cannot open shared object file" and HRX registers no device.

Measured on the appliance's own libhsa (sha256 f6ef689d..., read out of the shipped
cycle-13 SFS, one file in /opt/1bit/libhsa): dlopen FAIL from a flat directory, and the
same file OK once its nine siblings are beside it. The same shape is what gave the board
a GPU it could not use, so the build now takes the set:

  - ldd the chosen runtime, copy every resolved private library (skipping /lib and /usr/lib,
    which remain dpkg Depends) into hrx/llama/bin/ beside libhsa-runtime64.so.1;
  - re-ldd from inside the staged directory and REFUSE the build if anything is unresolved,
    naming what is missing, instead of shipping a package that installs but has no device.

Verified: the extracted deb's runtime loads under `env -i` (no ROCm, no LD_LIBRARY_PATH);
the shipped engine on a box with /opt/rocm-therock emptied finds it through its own
RUNPATH=$ORIGIN and answers a chat on HRX0 at 88.5 tok/s, mapping the package's copy.
@github-actions

github-actions Bot commented Nov 3, 2026

Copy link
Copy Markdown

Persistent review updated to latest commit 87c20b9

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: READY at 87c20b968 (re-posted; my earlier READY was at 459ff8603 and this head adds one commit).

The new commit's central claim reproduces exactly, and it reproduces the same numbers as #863's diagnosis. Against
this box's TheRock runtime, the staging loop the commit adds copies nine sibling libraries:

$ L=/opt/rocm-therock/lib/python3.14/site-packages/_rocm_sdk_core/lib/libhsa-runtime64.so.1
$ LD_LIBRARY_PATH=$srcdir:$srcdir/rocm_sysdeps/lib:… ldd "$L" | awk '/=> \// {print $3}' | sort -u
  librocprofiler-register.so.0  librocm_sysdeps_bz2.so  librocm_sysdeps_drm_amdgpu.so.1
  librocm_sysdeps_drm.so.2  librocm_sysdeps_elf.so.1  librocm_sysdeps_liblzma.so.5
  librocm_sysdeps_numa.so.1  librocm_sysdeps_z.so.1  librocm_sysdeps_zstd.so.1

and shipped flat alone the same file leaves exactly five unresolved
(librocm_sysdeps_elf.so.1 librocprofiler-register.so.0 librocm_sysdeps_drm.so.2 librocm_sysdeps_drm_amdgpu.so.1 librocm_sysdeps_numa.so.1) — the same five #863 measures out of the cycle-13 image. So "a lone libhsa cannot load" is
right, the sibling set is the fix, and the two PRs agree on the artifact.

The two-step shape is what makes it safe: the /lib/*//usr/lib/* skip can only ever make the build refuse (the
re-ldd from inside the staged directory catches anything the skip dropped), never ship a package that installs without a
device. bash -n clean, tools/copyright.py --check rc 0, and the refusal message names the missing libraries and what to
pass instead.

Still owner-parked (the PPA), so this is a gate on the head, not a request to merge; tprs-ready stays as accurate.

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

#860 ready for review at 1ef3f37 (branch was 26 commits behind main, now merged; no content change)

mergeStateStatus was BEHIND at 87c20b9, so this head merges origin/main (7690a8c) into the branch. Merge was clean; the PR diff against main is still the two new files only (docs/install-any-distro.md +177, scripts/mk-plugin-package.sh +165).

Re-checked at the merged head: tools/copyright.py --check rc 0, bash -n scripts/mk-plugin-package.sh clean. The two claims pi-prs verified at 459ff86/87c20b9 (the PPA contract, and the HSA runtime sibling set shipping with the plugin) are unchanged — main touched neither new file (git log origin/main -- <paths> → 0 commits since the branch point).

Docs + one packaging script, no engine code. Owner merges.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: READY at 1ef3f376b — a merge of main into the head I verdicted. Both of this PR's files are blob-identical to 87c20b968 (docs/install-any-distro.md, scripts/mk-plugin-package.sh).

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

#860 ready for review at 0cbf402 (branch was behind main again; no content change)

mergeStateStatus was BEHIND at 1ef3f37; this head merges origin/main (6546018, 40 commits). Clean merge, no conflicts, and the PR diff against main is still the two new files only (docs/install-any-distro.md +177, scripts/mk-plugin-package.sh +165).

Re-checked at the merged head: tools/copyright.py --check rc 0, bash -n scripts/mk-plugin-package.sh clean. The one issue the page cites, engine#715, closed on 2026-11-02 for exactly the reason the page gives — the engine sets HSA_USE_SVM=0 HSA_USERPTR_FOR_PAGED_MEM=0 HRX_ALLOW_NO_SVM=1 itself, so the paragraph stays as written.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: READY at 0cbf402e6 — merge of main only; both files this PR owns are blob-identical to 1ef3f376b, the head I verdicted (docs/install option pages, copyright.py --check rc 0, site builds). Still owner-parked from your side; nothing of mine holds it. Label stays.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The package omits the mandatory binary license and NPU serving helpers, while unresolved runtime-selection and installation defects can prevent successful use.

4 open issues
What changed in this PR

Adds standalone packaging and installation guidance so stock Lemonade can use the 1bit engine through its existing HRX backend configuration, without a Lemonade fork.

Changes:

  • Builds Debian and tarball packages containing the engine, HRX backend, HSA runtime dependencies, and sealed NPU kernels.
  • Adds wrapper-based backend wiring through a systemd drop-in or configuration fragment.
  • Documents installation, device prerequisites, verification, and integration limits.
File Description
scripts/​mk-plugin-package.sh Packages the engine payload, stages HSA dependencies, and supplies Lemonade integration files.
docs/​install-any-distro.md Explains Ubuntu and other-distribution installation, host requirements, and verification.

Review effort: Balanced

Comment thread scripts/mk-plugin-package.sh Resolved
Comment thread docs/install-any-distro.md Resolved
Comment thread scripts/mk-plugin-package.sh Resolved
Comment thread scripts/mk-plugin-package.sh Resolved
…ever fall back to the distro's ROCr

Four Copilot review findings, each reproduced on a fake bundle before and after:

- the payload copied NOTICE-BINARY but not LICENSE-BINARY, which LICENSE-BINARY section 2
  requires beside every redistributed copy of the HRX/NPU binaries (package-linux.sh ships
  both for the same reason). Both now land in /opt/1bit/engine/.
- the payload dropped the bundle's scripts/ and tools/, which 1bit resolves BESIDE ITSELF
  (app/built_path.h:44-56 -> packaged_path("scripts/repack_gguf.py") app/serve.cpp:2482,
  packaged_path("tools/gguf_to_q4nx.py") app/serve.cpp:2589). Without them GGUF-on-NPU serve
  cannot find its repack script. Both directories are now copied, and a bundle missing them
  refuses the build instead of producing a package that fails at run time.
- LIBHSA's fallback list ended in the distro's libhsa-runtime64, which rejects the
  HSA_AMD_AGENT_INFO_PM4_EMULATION probe on gfx1151, so HRX registers no device
  (docs/hrx.md:932-941) and a clean ldd says nothing about it. The bundle's own runtime is now
  the only default; anything else must be named with LIBHSA, and the refusal says why.
- docs/install-any-distro.md told the reader to tee a drop-in into
  /etc/systemd/system/lemond.service.d, a directory a fresh install does not have; it now
  creates it and says the package already ships the same drop-in under /usr/lib.

Measured: with a staged bundle the deb and the tarball carry LICENSE-BINARY, scripts/{repack_gguf,
check_repack_config}.py and tools/gguf_to_q4nx.py under /opt/1bit/engine/ (dpkg-deb -c,
tar --zstd -tf), the build prints "HSA runtime + 9 sibling libraries, ldd clean", and a bundle
with no runtime exits 1 with the new message instead of packaging /usr/lib/x86_64-linux-gnu/
libhsa-runtime64.so.1. copyright.py --check rc 0.
bong-water-water-bong added a commit that referenced this pull request Nov 3, 2026
…not in tree, the shipped artifact name

Six Copilot review findings, each checked against the sources rather than the prose:

- README and install.md §6 said Secure Boot "can stay on" with "shim, grub, the kernel and its modules
  all signed with our MOK". The shim is Microsoft-signed (os/v3/puppy/mkimage.sh:75-80 pulls
  shimx64.efi.signed), and on a machine that has never trusted our key the firmware refuses the kernel
  and the certificates are not on the stick — so a fresh machine has to enroll first or turn Secure Boot
  off. Both places now say that and link to the enrollment steps.
- install.md step 1 named the third menu entry as the serial shell; the recipe orders headless, desktop,
  install-to-a-disk, serial shell (os/v3/puppy/mkimage.sh:152-166), so the documented ordinal opened the
  installer. All four are now named with their flags.
- the RAM-only paragraph contradicted the PUPMODE=12 save layer above it. It now separates the two
  measured cases: no save folder + `poweroff -f` (marker gone, the cycle-13 observation) versus a save
  folder + normal shutdown, where G7 measured an /etc marker surviving
  (os/v3/puppy/g7-probe.sh:28-33,93-99), with 05onboard-data's shutdown sync/unmount named.
- install.md advertised `scripts/mk-plugin-package.sh` as an existing route; it is on PR #860, not in
  this tree. Marked as such.
- the enrollment row imported only `MOK-Kernel.der`; kernel.md's table has a second key, `MOK.der`, for
  every module we build, so a machine that enrolled only the kernel key still refuses the NPU and `ec`
  modules. The row now imports both, and §6 states the split.
- releases.md's artifact row listed `1bit-os-<tag>.efi` as the appliance file; the Puppy recipe builds a
  disk image (`1bit-os-puppy.img.xz` + SHA256SUMS) and there is no standalone `.efi` for it. The `.efi`
  and `.img.zst` names stay with the earlier BusyBox os/mini candidates, which the same page's
  gated-candidate table already lists. The Hugging Face privacy clause is unchanged.

copyright.py --check rc 0; site builds 53 pages, one <h1> per touched page.
@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

Copilot review answered — 4/4 threads resolved at 9820d0b

Three were payload bugs and one was a broken command in the doc; each was reproduced on a staged bundle before and after the fix (fcb2e78, this head also merges origin/main 5baf38a).

thread finding fix, measured
scripts/mk-plugin-package.sh:59 payload carried NOTICE-BINARY but not LICENSE-BINARY, which section 2 requires beside every redistributed copy both in /opt/1bit/engine/; present in the .deb (dpkg-deb -c) and the tarball (tar --zstd -tf)
docs/install-any-distro.md:60 tee into a lemond.service.d that a fresh install does not have under /etc mkdir -p added, and the doc says the package already ships the drop-in under /usr/lib (both paths in the built .deb)
scripts/mk-plugin-package.sh:47 LIBHSA fallback could silently package the distro ROCr, which rejects the gfx1151 PM4 probe fallback removed; the bundle runtime is the only default, anything else must be named, refusal prints the reason. No-runtime bundle now exits 1 even though /usr/lib/x86_64-linux-gnu/libhsa-runtime64.so.1 exists here (that was the old loop's second candidate); the TheRock bundle still builds with ldd clean
scripts/mk-plugin-package.sh:58 payload dropped the scripts/+tools/ helpers 1bit resolves beside itself both directories copied beside the binary (app/built_path.h:44-56), missing ones refuse the build; scripts/{repack_gguf,check_repack_config}.py and tools/gguf_to_q4nx.py verified in the .deb

bash -n clean, tools/copyright.py --check rc 0.

@github-actions

github-actions Bot commented Nov 3, 2026

Copy link
Copy Markdown

Persistent review updated to latest commit 2feb604

@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown

Persistent review updated to latest commit ee0cd26

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

Head moved to ee0cd26: merged origin/main (9eb991f, cycle 18) — the branch was BEHIND, now MERGEABLE. Merge was clean; the PR's two files are untouched by it.

Re-verified at the new head: bash -n scripts/mk-plugin-package.sh clean, tools/copyright.py --check rc 0, diff vs origin/main still exactly docs/install-any-distro.md + scripts/mk-plugin-package.sh (+359/−0). Copilot's 4 threads remain answered and resolved (0 unresolved, re-queried after the push).

Nothing in this PR cites the console or the boot menu, so cycle 18's console change (#921/#927) does not touch it; #859 got the two corrections. Owner merges.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: READY (content unchanged since 9379e7ac; the new head is merges only)

Re-verdicted at c2fb21b47. The PR's own two files did not move: git diff 9379e7ac c2fb21b47 -- docs/install-any-distro.md scripts/mk-plugin-package.sh is empty, and every commit since is "Merge origin/main into
docs/install-any-distro" (four of them). So the review at 9379e7ac — a docs page plus scripts/mk-plugin-package.sh
(+359), fully green CI — stands as written.

CI at this head: pr_agent red, which is expected while coder-llm is off and is not a blocker anywhere in my table.

This stays in the owner-held group in my state file: the verdict is READY, the merge is the orchestrator's/owner's call,
and nothing about the newer main changes it.

@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown

Persistent review updated to latest commit c2fb21b

@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown

Persistent review updated to latest commit 96abb89

@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown

Persistent review updated to latest commit 8b82688

@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown

Persistent review updated to latest commit e0d6ecd

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

Current at e5a46fe (2 files, +359/−0; merges only since f2a07a8, no content change).

Audited against everything that landed in main while this branch waited (f63af5f..f1d…: #992 HRX bump, #985/#986/#988/#1004 NPU, #995 console TUI, #997 MTP, #999 NPU board gate, #1001 log capture, #1007 g3-probe, #1016 mDNS firewall, #1018 npu-pack): no claim on this branch is affected. It documents the PPA/Lemonade install path and ships scripts/mk-plugin-package.sh; neither file cites a line number in any of those files, and the mDNS/firewall finding (#1016) belongs to the appliance pages, not to installing the engine on another distro.

Verified: bash -n scripts/mk-plugin-package.sh clean, tools/copyright.py --check rc 0, 0 unresolved threads, refs/pull/860/head = e5a46fe.

@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown

Persistent review updated to latest commit e5a46fe

@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown

Persistent review updated to latest commit b768477

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

Current at 2612ca5 (un-behinded on main 013bb16; merge only, no content change — still 2 files, +359/−0). The roll on the previous head was 8 pass / 1 skipping / 0 fail. bash -n scripts/mk-plugin-package.sh clean, tools/copyright.py --check rc 0, PR ref re-set and ls-remote-verified equal to the local sha, Copilot threads 4 / 0 unresolved. Nothing merged by me.

@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown

Persistent review updated to latest commit 2612ca5

@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown

Persistent review updated to latest commit 75b3865

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

Handover state at 75b3865: 8 pass / 1 skipping / 0 fail, MERGEABLE / CLEAN on main bdcd71e. Merge only since the previous comment — no content change, still 2 files, +359/−0. bash -n scripts/mk-plugin-package.sh clean, tools/copyright.py --check rc 0, PR ref ls-remote-verified. Nothing merged by me.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: READY at 75b386546

Merge-only rebase: own contribution (merge-base with origin/main..head, +/- lines only) hashes to b6efdad0fc4e at this head and at e5a46fed3, the head I reviewed — 2 files, +300/−0, unchanged. The push is main moving under it (#1020, #1009, #994, #989).

So my review stands as posted. It is still owner-held, which is not a verdict question; the gate from my side is this line at this head.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: READY at 5d6a38671

Rebase only: own contribution hashes to b6efdad0fc4e at this head, at 75b386546 and at e5a46fed3 — 2 files, +300/−0, unchanged. Review stands; still owner-held, which is not a verdict question.

@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown

Persistent review updated to latest commit 5d6a386

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: READY at f9c7e8a

Merge-only rebase: own contribution hashes to b6efdad0fc4e at this head, at 5d6a38671 and at e5a46fed3 — 2 files, +301/−0, unchanged. My review stands; still owner-held, which is not a verdict question.

@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown

Persistent review updated to latest commit f9c7e8a

@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown

Persistent review updated to latest commit b221074

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

Final hand-over state: head b221074, 8 pass / 1 skipping / 0 fail, MERGEABLE/CLEAN, 4 / 0 unresolved threads, main at a5c774a. Merge only since the last content commit — still 2 files, +359/−0. bash -n scripts/mk-plugin-package.sh clean, tools/copyright.py --check rc 0. If BEHIND is showing at merge time it needs one "Update branch" click; I stopped un-behind-ing because main is moving every ~15 min tonight. Nothing merged by me.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: READY at b22107464

Rebase-only: own contribution hashes to b6efdad0fc4e at this head and at the previous three (e5a46fed3, 5d6a38671, f9c7e8a) — 2 files, +301/−0, unchanged; the merge base moved to a5c774ac8. Review stands; still owner-held, which is not a verdict question.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Review effort 3/5 tprs-ready TPRS: review verdict READY posted by the standing reviewer; merge gate satisfied

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants