Repository navigation
docs: install the engine on any Linux with Lemonade from its own package (PPA) - #860
Conversation
…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.
PR Reviewer Guide 🔍(Review updated until commit 9494f97)Here are some key observations to aid the review process:
|
…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.
|
Persistent review updated to latest commit 459ff86 |
bong-water-water-bong
left a comment
There was a problem hiding this comment.
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/Recommendslist 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-envprints the HRX plan line but loads no weights
and starts no backend; still it is GPU-adjacent, so I will wrap even that in agpu-holdclaim from now on.
…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.
|
Persistent review updated to latest commit 87c20b9 |
bong-water-water-bong
left a comment
There was a problem hiding this comment.
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.
|
#860 ready for review at 1ef3f37 (branch was 26 commits behind
Re-checked at the merged head: Docs + one packaging script, no engine code. Owner merges. |
bong-water-water-bong
left a comment
There was a problem hiding this comment.
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).
|
#860 ready for review at
Re-checked at the merged head: |
bong-water-water-bong
left a comment
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
🟡 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
…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.
…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.
Copilot review answered — 4/4 threads resolved at
|
| 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.
|
Persistent review updated to latest commit 2feb604 |
|
Persistent review updated to latest commit ee0cd26 |
|
Head moved to Re-verified at the new head: 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. |
|
Persistent review updated to latest commit 75b3865 |
|
Handover state at |
bong-water-water-bong
left a comment
There was a problem hiding this comment.
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
left a comment
There was a problem hiding this comment.
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.
|
Persistent review updated to latest commit 5d6a386 |
bong-water-water-bong
left a comment
There was a problem hiding this comment.
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.
|
Persistent review updated to latest commit f9c7e8a |
|
Persistent review updated to latest commit b221074 |
|
Final hand-over state: head |
bong-water-water-bong
left a comment
There was a problem hiding this comment.
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.
…4 (noble) is not an install target The page offered 'Ubuntu 26.04 (resolute) / 24.04 (noble)' for both halves. Measured on the shipping package (readelf -V on the extracted 1bit from the cycle-26c bundle, and on the 2026-10-31c bundle - both the same): the highest requirement is GLIBC_2.43, and it is exactly one symbol, sqrtf@GLIBC_2.43. Noble ships glibc 2.39, so the deb installs, ldd is happy, and the binary then fails to load with "version 'GLIBC_2.43' not found". Lemonade's own PPA does publish noble builds, so the engine half is what pins the distribution. The heading is now 26.04 only, the measured floor and the one symbol are stated with the failure text, and the noble path is named for what it actually is: build from source, or run on 26.04. The 'other distributions' section gets the same floor, because the tarball carries the same binary. Also verified end to end while checking this page: scripts/mk-plugin-package.sh, run against the cycle-26c bundle with the release-gated TheRock set (LIBHSA=~/wt/libhsa-runtime), produces 1bit-engine_<ver>_amd64.deb (19,001,738 B) and 1bit-engine-<ver>-linux-x86_64.tar.zst (19,097,540 B, top dir opt/); the deb's Depends has no Python (libc6, libstdc++6, libgomp1, libssl3t64|libssl3, zlib1g, libzstd1, libpcre2-8-0); it stages libhsa plus its 9 sibling libraries and ldd is clean; the extracted 1bit runs (--version -> 1bit 0.0.1) and lemonade-bin/llama-server resolves to the real backend. So the page's claims about the package shape hold.
|
pi-prs: Fixed: the page offered Ubuntu 24.04 (noble); the engine package needs glibc 2.43. Measured with Verified end to end ( One thing the page does not need to change but a maintainer should know: the script's |
bong-water-water-bong
left a comment
There was a problem hiding this comment.
VERDICT: READY (owner-held, unchanged in substance)
Re-verdicted at 1810e22a. One commit since b2210746, and its measured claim reproduces on a binary I built at main:
$ readelf -V build/1bit | grep -oE 'GLIBC_[0-9.]+' | sort -Vu | tail -1
GLIBC_2.43
$ readelf --dyn-syms -W build/1bit | grep GLIBC_2.4[0-9]
152: … UND sqrtf@GLIBC_2.43 (34)
So "the engine package needs glibc 2.43" and "it is one symbol, sqrtf@GLIBC_2.43" are both exact, and this box's ldd --version is Ubuntu GLIBC 2.43-2ubuntu2.4 - which is why a noble (2.39) box would fail with version 'GLIBC_2.43' not found rather than something vaguer. The conclusion that follows (build from source on noble, or run 26.04+) is the right one, and the same floor applying to the .tar.zst is stated.
The licence header the file was missing earlier is now in it, so tools/copyright.py --check has nothing to red.
This stays owner-held per the standing exclusion (docs, the PPA install path); the verdict only keeps the record current at the head that would merge.
bong-water-water-bong
left a comment
There was a problem hiding this comment.
VERDICT: READY at 1810e22a (new commit 1810e22 reviewed at this head).
The new claim is that the engine package needs glibc 2.43 and that this is one symbol, sqrtf. Measured on a real packaged binary (the c22 payload's 1bit):
readelf -V 1bit | grep -o 'GLIBC_[0-9.]*' | sort -V -u | tail -3 -> 2.34 2.38 2.43
objdump -T 1bit | grep GLIBC_2.43
0000000000000000 DF *UND* 0000000000000000 (GLIBC_2.43) sqrtf
objdump -T 1bit | grep -c GLIBC_2.43 -> 1
One undefined symbol, sqrtf, and it is the library's own libm.so.6 version block that carries it — so "highest requirement is GLIBC_2.43, and it is exactly one symbol, sqrtf@GLIBC_2.43" is exact. The same three version names appear on every packaged copy I have (/work-c22/build/1bit, ~/wt/rlk-build/1bit), so it is the toolchain's floor and not one build's accident. Noble ships glibc 2.39 and this box runs 2.43, which is why the page's "installs, ldd is happy, then version 'GLIBC_2.43' not found at load" is the right description of the noble path rather than "does not install".
The rest of the commit is the same measured package shape the earlier verdict read, and the doc now names the floor in both places it applies (the Ubuntu heading and the tarball/other-distributions section).
…rget (#859) * docs: 1bit OS is the Puppy Linux appliance, and os/mini is a CI/VM target 1bit OS is Puppy Linux (ResolutePup64, woof-CE on the Ubuntu 26.04 resolute base) with Lemonade Server and the engine embedded, our MOK-signed 7.3 perfopt kernel, headless by default with a 1bit OS (desktop) boot entry, bash/sudo/apt, data and settings on 1BIT-DATA, Secure Boot on. The BusyBox os/mini image is the CI/VM target and is no longer called 1bit OS anywhere. No release is claimed: the next release carries the appliance. Files: README.md (get-started steps + a milestone row), os/README.md (the 1bit OS page is the appliance; os/mini, os/v2 and os/v3/puppy laid out), os/v2/README.md (title and 'ships today' line), os/LICENSES.md (which image carries what), docs/releases.md (top note, artifact row, known issues, os/mini build note), docs/os-v3.md (Puppy is v3, with the board result; the Ubuntu plan is the fallback), docs/os-v3-live-puppy-eval.md (dated update: the four blockers are closed and it booted on the board), docs/kernel.md (the kernel reaches 1bit OS as woof-CE's kernel package), docs/PORTING.md (same, one clause). * docs: install 1bit OS (stick, disk, USB) and connect a client to Lemonade docs/install.md covers the options the owner asked for, each with who it is for, the steps and what is erased: run from the stick, install to an internal disk or another USB drive with 1bit-install (the seven steps, the refusals, the firmware entry), keep the existing OS (no dual-boot wizard in this release), the engine on an existing Linux (advanced, no PPA route yet), Secure Boot and the MOK, and the Bosgame front-port note (#823). docs/clients.md covers the address and the key, curl, the web app, Lemonade Mobile on iPhone and Android, the OpenAI SDKs and any OpenAI-compatible app, the lemonade CLI from another machine, and the security/rotation rules. Every example was run against the cycle-13 appliance image booted in QEMU with Secure Boot on (~/wt/rlk-vm/verify.sh, results.txt): the key is enforced (401/401/200, /api/v1 and /v1), the web app is served at :13305, the curl and OpenAI-SDK chat examples returned 200 with content, the CLI flags and the LAN beacon work, and the firewall opens only 13305 and 22. The install ran end to end on a bare disk. Three defects it found are filed as #865 (an installed disk does not boot: init resolves pupsfs=<label> but not pupsfs=UUID=...), #866 (step 7's BootNext lands on the BootManagerMenuApp) and #867 (a dd-written stick never gets an API key minted, so Lemonade serves the LAN unauthenticated); the pages state each where it matters, with the measured label A/B that isolates #865. README: step 4 of Get started points at both pages. * docs/install: no unmeasured install duration * docs: the 1bit OS image ships from Hugging Face, not a GitHub release asset The Puppy image is 9,128,902,656 B written / 2,212,389,580 B as 1bit-os-puppy.img.xz, and a GitHub release asset is capped at 2 GiB, so the image lives at https://huggingface.co/1bit-MONSTER/1bit-OS with its SHA256SUMS. README, docs/install.md and docs/releases.md now say so and give the same two write lines everywhere (sha256sum -c SHA256SUMS --ignore-missing, then xz -dc ... | dd; balenaEtcher and Rufus DD mode take the .img.xz directly). The GitHub releases page keeps the lemonade-onebit package, the release notes and the release SHA256SUMS, and links to the image. History rows are untouched: the c18-c20 candidates really did ship the BusyBox os/mini image as 1bit-os-<tag>.img.zst, and those sizes and shas stay as recorded. * docs: the Hugging Face image repository is private until v2026.44 is published Every place a reader acts on the download (README quickstart, the install page's image row and write block, the release table's image row) now says the repository is private until v2026.44 is published, so the link is the download from publication day and an earlier release carries only the BusyBox os/mini image, the CI/VM target. Addresses the CHANGES on #859: the URLs are correct and the upload landed, but they answer 401 while the repository is private. * docs: the appliance boots as 1bit-os, and installer #866 is fixed Two claims in this branch were true of the cycle-13 image and are not true of the image that ships next: - docs/clients.md said the hostname is Puppy's per-machine puppypc<MAC>; the image sets /etc/hostname to 1bit-os (os/v3/puppy/embed/etc/hostname, and the c16 board boot read back 1bit-os). Keep the cycle-13 observation as history and tell the reader the name, not a guessed .local. - docs/install.md said installer step 7 and the pupsfs=UUID boot are both open. #866 is fixed on main by #889 (merged 2026-11-03); #865's fix is #890, open. * docs/clients: say puppypc<digits>, not <MAC digits> - the MAC derivation is unverified * docs/install: both installed-disk fixes are in main, and a dd-only stick does get a key now Three claims went stale since this branch opened, all measured against origin/main today rather than against the cycle-13 artifact: - the installed-disk blockquote said "until both are in an image". #890 (#865's init fix) merged 2026-11-03T12:45Z on top of #889 (#866), and its own probe boots a disk installed by `1bit-install` as the only disk in QEMU; an image built from main boots the installed disk as written. - the measurement table's #865 row still said "fix open as #890". - the dd-only stick paragraph said a stick with no key serves every endpoint unauthenticated and that #867 is an open defect of this image. On main it is not: 05onboard-data no longer pre-creates an empty lemond.conf and 10lemonade mints on "is there a key" rather than "is there a file" (#828). The cycle-13 measured behaviour is kept as history, with the fix pointer and how to read the minted key (console 1 -> Show API key). * docs: both MOKs are needed, the real menu order, the save layer, #860 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. * docs: the console is a menu that prints how to connect, not a login prompt The cycle-18 image puts a CONNECT block (address, web UI, API, ssh) above the console menu, and 1bit-console replaces plogin on a headless boot, so README's "console login" and the bare "a console with no X" no longer describe what comes up. Also names the desktop entry by its grub.cfg label, `1bit OS (desktop, JWM)` (os/v3/puppy/mkimage.sh:156). * docs: the appliance ships with no API key (cycle 20), and the console's item 1 is the toggle #934 made blank the shipped mode: 10lemonade starts with LEMONADE_API_KEY unset and binds 0.0.0.0:13305 anyway, so every request works with no header until a person turns a key on from console item 1 (which mints 48 hex into /etc/1bit/lemond.conf, 0600, on /data, restarts the service and prints it), or prepare-stick --mint writes one offline. install.md and clients.md still described the #867/#828 behaviour - 'the appliance mints one on its first boot', 'read the key with show API key', 'every request needs the API key', '401 without the key', 'Lemonade Mobile: on 1bit OS it is required'. All of those are now false of the shipped default and wrong in the unsafe direction (they imply the box is closed when it is open). Rewritten against the sources, with file:line: 10lemonade:43-62,78-81; 1bit-console-menu:238,242,300-370; console-tui/src/ui.rs:203-215, 280-292; prepare-stick.sh:346-410; vm-check.sh:710-730; 1bit-webapp-proxy:37-44. The cycle-13 measured rows stay as history, marked as that image's behaviour, and the os/mini media difference (it still mints) is stated per docs/os-v3.md. * docs/clients: a non-1bit-os hostname is a person's rename, not a fault (cycle-16 u2-hostname) The cycle-16 board booted as `strix` while the frozen image bytes still read `1bit-os`: a person renamed it at the console, and the release lane's `u2-hostname` red was that reading, not an image defect. Section 1 told a reader `hostname` prints `1bit-os` with no way to tell a rename from the `puppypc<digits>` regression it is contrasted with, so a reader on a renamed box would go looking for a fault. Name the console path (3 Network -> 3 Set the hostname, `1bit-console-menu:437,463-466,632`) and say to check the address instead of the name. * docs/os-v3: where v3 stands, as of cycle 20 — 33-row board runs and a blank key by default The standing paragraph was written on 2026-11-02 and had gone wrong in two ways in the same breath. It quoted '20 of puppy-check's 25 rows PASS' as the appliance's current state (the checker has 33 rows now; cycle 19 came back 33 rows, 0 failed, 1 skipped, and cycle 20's two reds were the acceptance script's own defect, engine#945, fix open as #951), and it said 'Lemonade answers on :13305 with its key' — false and unsafe since engine#934 made blank mode the shipped default (10lemonade:43-62 binds 0.0.0.0:13305 with LEMONADE_API_KEY unset; console item 1 turns a key on). Restate it against the c19/c20 board verdicts and the #934 sources, and add one sentence to the eval page's dated 2026-11-02 update so the 'with its key' reading there is marked as that cycle's behaviour rather than today's. * docs/os-v3: #945's fix landed as #951, so the sentence stops calling it open * docs/clients: the appliance announces 1bit-os.local from cycle 21 on The page told a reader 'mDNS is not claimed' and to read the address off the box. Cycle 21 item 10 (#953, merged b8a07df) ships the responder, asserts it at build time and prints it in the console's CONNECT block, so that sentence is now false in the direction that costs a reader a step. Said what the sources say, with the two limits kept: the announced name is $(hostname).local (so it follows a rename), the CONNECT row says when avahi is not running, and a peer resolving it over multicast is still not claimed on this page. * docs/clients: two citations point at the lines that carry the claim container-build.sh gained 12 lines in #976, so the mdns pack-checks it cites moved from 496/505 to 508/517; and the webapp proxy's foreign-Origin refusal is at 45-49 (the rule and ALLOWED_ORIGINS) and 74-77 (the code), not 37-44 - which is the config block and the sentence that introduces the key attachment. Both numbers read back out of the merged tree this pass, not carried over. * docs/clients: the 8080 chat page is not served on the c19/c20 boards Both boards log `OSError: [Errno 98] Address already in use` for 127.0.0.1:8080 (c19 finding, unchanged on c20, and #959's own body says so), so the proxy's chat page is not reachable there while Lemonade's own page on :13305 is. A reader sent to :8080 chases a dead port; the sentence names it and points at :13305, with the init script's own two lines cited. * docs: re-point two citations at the lines that now hold them (CMakeLists 322, serve.cpp 202-213, ui.rs 218-222) * docs/os-v3-live-puppy-eval: a bare `</dev/null` code span truncated the rendered page at that table row python-markdown reads the angle-bracket close tag as raw HTML and drops everything after it: 46,922 B of markdown rendered to 21,897 B, cutting the page mid-table in front of the whole cycle-13/19/20 acceptance evidence. Reworded to plain text (same meaning); the page now renders 61,087 B with the cycle-13 rows, and the site build is 56 pages, rc 0. * docs/clients: re-point the two vm-check.sh citations after #1001/#1007 moved them (616-621, 740-754) * docs/clients: the c22 board announced the name and nothing answered it - rc.firewall drops inbound mDNS Cycle 23 (#1016) opened udp/5353 in zz-onboard-ports for the LAN ranges and added the `U3 mdns rule` gate row. Section 1 said only the responder and the LAN could leave you reading an address, which reads as "works on a c22 stick" when the measured c22 board shows the opposite. Stated what was measured, with the fix's citations, and kept the one hop nobody has proved: the packets the rule accepts were avahi's own loopback announcements, not a peer's query. Also re-points the blank-mode U3 citation (:740-754 -> :749-762) after #1016. * docs: the image's kernel is 7.4.0-rc1-1bit since cycle 21, and the cycle-23 board is green os-v3.md said the appliance ships `7.3.0-rc4-1bit-perfopt`. Measured in the frozen images rather than taken from a note: the c20 image carries `7.3.0-rc4-1bit-perfopt+`, and the c21, c22 and c23 images carry `7.4.0-rc1-1bit` (string present in each), so the page now says which cycle moved it. The same paragraph's newest board was cycle 20; cycle 23 (4 Nov) is in, with its row counts and the two facts the c23 verdict records - the single red is a bug in the check's own u7-mdns row, not the image. clients.md: three citations re-pointed at the lines that now carry them after #1020 moved vm-check.sh and container-build.sh by 13 and 1 lines. * docs/clients: re-point the two vm-check.sh citations #989 moved again #989 added the U4 kernel rows above them, so the U3 mdns rule row is at 711-714 (was 689-692) and the blank/keyed U3 network block at 784-797 (was 762-775). The citations now also name the row, because this file has moved under them three times tonight. * docs/os-v3-live-puppy-eval: CMakeLists.txt:322 -> 331-332, moved by #1021 #1021 added nine lines to CMakeLists.txt above the HRX block; 331-332 is still target_compile_definitions(... ONEBIT_HRX_LIBHSA=...). * docs/clients: the mDNS fix now states the outbound leg too, and two citations #1025 moved #1025 (c24 prep) adds the outbound 5353 rule to open_mdns - intent, not a fix: the packed c23 image accepts all output, and the c23 board's "out: NONE" was the row demanding a rule the image correctly lacks. The page now says which half each cycle opened and why the second one exists, and the gate has a row per half. Citations: open_mdns 55-66 -> 56-74, the blank/keyed U3 block 784-797 -> 789-802. * docs/clients: re-point the three vm-check.sh citations after the file grew ~190 lines The gate script gained rows since these numbers were written, so the three citations in clients.md pointed at unrelated rows (616-621 landed in the service-up/U3-key rows, 711-714 in the driver-signature row, 789-802 in the engine-sha row). Re-read them against the merged tree: U3 mdns rule 849-852, U3 mdns out 884-886, U3 auth (blank vs keyed) 670-676, getent hosts 722-723. * docs/clients: the CONNECT name rows are ui.rs:236-238, not 213-216 Caught by re-reading every citation in the page with sed instead of trusting the string: 213-216 is the 'web UI: waiting for network' line. The name/mDNS rows the paragraph quotes are at 236-238 on main (#1041/#1059 moved them). * docs: the 1bit OS kernel is 7.4.0-rc1-1bit, and the boot entry label says so The appliance images from cycle 22 on carry 7.4.0-rc1-1bit (c22/c24/c26 hand-offs, and the c24 release verdict), but four current-state lines in this PR still named 7.3.0-rc4-1bit-perfopt: README's 1bit OS paragraph, os/README.md's kernel row, and install.md's boot step plus its Secure Boot chain. install.md's boot step is the sharpest: mkimage.sh builds the menu title from the vmlinuz version (`menuentry "1bit OS (headless console, ${kver})"`), so the label a reader sees is the kernel's own string. The dated cycle-13 measurement rows keep 7.3.0-rc4-1bit-perfopt+ - they say what that image carried, and install.md:277 and clients.md:254 say so. Also os/README.md names the second boot entry as mkimage.sh words it, `1bit OS (desktop, JWM)`. * docs/clients, docs/install: four citations point at the rows the prose names Re-read every file:line in both pages out of origin/main (fadcc1e) instead of trusting the earlier pass - the pattern that has failed in this lane before. Three had rotted under the cycle-25 console/logging work: - clients.md:78-81 -> 104-108 for "blank mode is LAN-reachable on purpose"; 78-81 is now the cycle-25 log_level comment, the LAN comment moved down. - clients.md:632 -> 645 for the console's top-level Network row; 632 is the closing brace of the CLI dispatcher. - install.md:218-222 -> 240-243 for the TUI's api row; 218-222 is the "web UI: waiting for network" block, the api/keyed rows are 240-244. And one was under-cited: clients.md:88 cited 10lemonade:43-62 for the 0.0.0.0:13305 bind, which is line 107-108. Now 43-62,107-108. Checked mechanically: /tmp citcheck over both pages, every ref printed with its first line, all twelve in clients.md and eight in install.md name what the sentence says. * docs/os-v3-live-puppy-eval: the update box's numbers are cycle 12's, and one citation went stale Two claims on this page had drifted, both found by checking them against today's tree rather than re-reading the prose: 1. The update box led with '20 of `puppy-check`'s 25 rows PASS' as if it were the appliance's acceptance state. That was cycle 12, the first hardware boot; cycle 19 came back 33 rows / 0 failed and cycle 23 41 rows / 40 PASS / 1 FAIL (the FAIL being the checker's own `u7-mdns` row). Within this same PR, docs/os-v3.md already carries those. The numbers stay, labelled as cycle 12's - they are what decided the plan - and the page now points at os-v3.md as the page of record instead of growing a second, diverging copy. 2. `ONEBIT_HRX_LIBHSA` is a CMake compile definition, cited at `CMakeLists.txt:331-332`; those lines are the npu_sources block now. It is at `CMakeLists.txt:356` (verified against origin/main). The other nine file:line citations in this branch were checked the same way and are correct (ui.rs:236-238 and 240-243, container-build.sh:508 and 518-522, vm-check.sh:670-676 / 722-723 / 849-852, prepare-stick.sh:346-410, g7-probe.sh:28-33, app/serve.cpp:202-213). * docs: the .img.xz size is approximate, because the exact bytes change with every cut pi-prs flagged 2,212,389,580 B as the one figure on the download pages a reader can falsify with `ls -l`: the only .xz on this box is ~/wt/hf-1bitos/1bit-os-puppy.img.xz at 2,212,388,768 B (3 Nov, an earlier cut), and the Hugging Face repository is private, so the published file cannot be read to check. Every re-cut changes it (c26 and c27 are both 9,128,902,656 B written but their images differ), so an exact compressed byte count is a number this page cannot keep true. Dropped it in favour of "about 2.2 GB compressed" (README, install.md, releases.md x2) and kept the figure that is stable across cuts, the 9,128,902,656 B written, which install.md:41 now pairs with the rule that matters: the size to check is the one `ls -l` prints after the download. No sha or exact size now depends on a cut this page cannot see. --------- Co-authored-by: pi-rlk <pi-rlk@1bit.gg> Co-authored-by: agent <agent@local> Co-authored-by: pi-rlk <rlk@1bit.local> Co-authored-by: bong-water-water-bong <bong-water-water-bong@users.noreply.github.com> Co-authored-by: bong-water-water-bong <bong-water-water-bong@1bit.gg> Co-authored-by: pi-os3 <pi-os3@1bit.local>
|
Persistent review updated to latest commit 9494f97 |


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-hrxrecipe(recipe
llamacpp-hrx,config_section hrx,binary llama-server) resolves its backend binary throughBackendUtils::find_external_backend_binary():LEMONADE_<SECTION>_<BINKEY>in the environment, else theconfig key
<section>.<bin_key>, and a directory is resolved tobinaryinside it. Measured on the PPAdeb
2026.44.1~26.04(extracted, run isolated, no model load): backend stateinstallable→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, pointhrx_binat<dir>. Everything in this PR isthat, and the reason
llama-serveris a shim rather than our binary: the recipe's ownbuild_server_environment()hands the backend exactly one variable,GGML_DISABLE_VULKAN=1, so Lemonadewould 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>— emits1bit-engine_<v>_amd64.deband
1bit-engine-<v>-linux-x86_64.tar.zst: the engine, its HRX llama.cpp build, the HSA runtime the HRXbackend dlopens (placed beside
libhrx.so, which searches$ORIGIN), the sealed NPU kernel sets, thellama-servershim, alemond.service.ddrop-in carryingLEMONADE_HRX_HRX_BIN, and the config-keyfragment 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, andthe tarball path for other distros; per-device host prerequisites; verification (one chat per device plus
1bit-engine servealone); and the two limits of this route (no1bit servepreflight, no NPU catalogrows — our rows can ride along through the config dir's
user_models.json).Measured
ubuntu:26.04container:dpkg -i→install ok installed;1bit-engine --version, the shim (version: 1 (d8bd0ff6)) and1bit serve --helpall run; 3 NPU kernel sets present; 0.kofilesllamacpp-hrxinstallable→installed, env form and config-key formsrc/cpp/server/backends/hrx/hrx_server.cppbuild_server_environment()lemonade-serverpulls no kernel bits;amdxdna-dkmsdoesapt-get -s: 11 packages, zero dkms/xrt/amdxdna; the dkms package pullsdkms+build-essential+linux-headers-*-genericand DKMS installs into/lib/modules/$(uname -r)/updates/— the driver this board resets with (scripts/mkimage.sh), so the doc says not to install itNot 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
installedresult above). I will post the number herewhen 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.1never opened). Two causes; the second one was this script's shape too:
the appliance named the runtime with
ONEBIT_HRX_LIBHSA=…, a CMake compile definition that nothingreads 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: theshipped plan then carries no HSA path and the backend dies with the board's exact error.
a TheRock
libhsa-runtime64.so.1is not a standalone file. It names TheRock's own libraries inNEEDED and carries
RUNPATH=$ORIGIN, so shipping it alone give a dlopen that fails:readelf -don it:RUNPATH [$ORIGIN], NEEDEDlibrocm_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 thebuild if anything is unresolved:
Measured on the built deb (
1bit-engine_2026.11.02-2_amd64.deb, 18.9 MB):env -i(no ROCm, noLD_LIBRARY_PATH)FAIL -> librocm_sysdeps_elf.so.1)LIBHSA=a lone file/opt/rocm-therockemptied, trio only, no env pathok, chat on HRX0 88.5 tok/s, backend maps<prefix>/hrx/llama/bin/libhsa-runtime64.so.1through its ownRUNPATH=$ORIGINSo 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.