Lemonade#
A Strix Halo machine gets its GPU and NPU paths inside Lemonade from the
1bit engine, which runs there as Lemonade's onebit backend; the onebit recipe passes Lemonade's own LLM
test suite on HRX: 31 of 31 tests run, all pass (2 skipped;
2026-11-05). Lemonade
is the server users talk to, with its own catalog, downloads, router and UI. For the models it
serves with 1bit, it runs the engine as a backend, the same way it runs llama-server. For a GGUF
it starts the engine's HRX llama-server directly, one HTTP hop
(#475, below); for
the other routes it starts 1bit serve (1bit serve), waits for /health, and forwards
OpenAI requests to it. The engine exposes nothing but that OpenAI-compatible API.
Recovery stays Lemonade's: when a backend hangs, 1bit serve answers /health with 503 and, once
a request has had no progress for --watchdog seconds, kills its backend and exits non-zero
(serve.md, "When a backend hangs"). Lemonade's BackendWatchdog
then loads the model again.
Getting Lemonade with the engine#
Two ways, and the rest of this page is what sits under them.
- The appliance. 1bit OS is Lemonade Server with the engine inside, on a USB stick that
boots a Ryzen AI MAX+ 395 with Secure Boot on, and
1bit-installputs the same system on a disk (Releases). - An Ubuntu that already runs Lemonade. The
lemonade-onebitpackage adds the engine as a Lemonade backend and nothing else changes; on Ubuntu 26.04 the engine plugs into the stocklemondfrom Lemonade's own PPA (below).
Either way, the models Lemonade routes to 1bit are served on the Radeon 8060S iGPU or on the XDNA 2 NPU (Models measured, NPU engine, the Strix Halo guide).
How it got here#
Step 1 first went the other way. 1bit lemonade ran Lemonade v11.9.0's server
core inside the 1bit process, and this repository carried Lemonade local
recipes for the engine (onebit, mlx, zinc, the hrx_device option).
A review1 pointed out that the engine should be embedded into Lemonade, not
the reverse. So on 2026-09-23:
third_party/lemonadeand every local delta were removed. The engine no longer builds Lemonade's code or its fetched libraries.1bit servetook over what the local recipes did, for every device: NPU, Vulkan, HRX, ZINC and MLX.
The recipe that runs it#
One recipe in Lemonade runs the engine, onebit, in the same shape as its
llama-server recipe:
1bit serve -m <model> --port <p> [--device ...] [--ctx-size N] [--alias <name>]
Lemonade downloads and resolves GGUF checkpoints as for llamacpp, and its
backend selector picks the device (hrx or npu; unset,
the recipe sends --device auto). Replies already carry Lemonade's model name (--alias),
so requests pass through unchanged.
One hop for GGUF models (fork branch 1bit/one-hop). For a .gguf, the recipe first runs that
command with --print-backend: serve makes its load-time checks (architecture, memory, recipes)
and prints the llama-server it would start, and Lemonade starts that llama-server itself and
talks to it directly, as it does for llamacpp. A request then crosses one HTTP hop instead of
two. NPU model directories, --pm and --laya still run through 1bit serve
(serve exits 5 for them), and LEMONADE_ONEBIT_ONE_HOP=0 keeps serve in the path for every model
(serve.md, "One hop from Lemonade").
The recipe lives in our Lemonade fork,
1bit-MONSTER/lemonade: upstream
Lemonade plus the onebit backend (fork PR #1). Build lemond from the fork and
put 1bit on PATH (or set $LEMONADE_ONEBIT_BIN).
Without the engine the recipe is still listed, but its models are not: /api/v1/models?show_all=true
answers 180 rows, 0 of them onebit, against 207 rows, 27 onebit (4 of them *-NPU-1bit) with
LEMONADE_ONEBIT_BIN set — measured on the packaged lemond of lemonade-onebit-rc-2026-11-02, the
release's own. /api/v1/system-info says why: the recipe's hrx/npu backends read state: installable,
"the 1bit binary was not found", against installed/0.0.1 when it is. /models itself carries no
reason, so the row count is the check — which is the argument for starting lemond through the release
package's own lemond-onebit launcher: a unit that ran bin/lemond directly would serve an appliance
with no onebit models and no error.
The engine pins the Lemonade it is tested with: third_party/lemonade is the fork at a
fixed commit. It is never linked into the engine. scripts/build-lemonade.sh builds
lemond and the lemonade CLI from it:
scripts/build-lemonade.sh ~/.cache/lemonade-pin
LEMONADE_ONEBIT_BIN=$PWD/build/1bit ~/.cache/lemonade-pin/bin/lemond
.github/workflows/bump-lemonade.yml opens a PR here when the fork's main moves (after
the upstream release sync below). Before merging, rebuild and rerun the LLM suite on Strix Halo.
On Strix Halo the recipe passes Lemonade's own LLM test suite
(test/server_llm.py --wrapped-server onebit) on HRX (the checklist below has the counts;
Vulkan passed too before RFC #213 stage 3 removed it). It is not proposed upstream yet: the plan is to embed the engine fully
in the fork first, then propose it upstream. The fork follows upstream's releases:
.github/workflows/sync-lemonade-fork.yml checks daily and ports upstream's latest
release onto main (never a pre-release, never main itself), so each engine release
carries the Lemonade release current when it was built. It ports rather than merges
because the fork's main follows upstream's main: a release tag is cut from a release
branch, so merging the tag's tree would revert every commit main has gained since that
branch was cut: the sync built fork #27's branch from the tag (4eb0319ef, 44 commits behind
main), and merging the tag was 530 files, +56,326/−128,510 against main — a revert of all
44, our onebit registration included. The branch was then replaced in place by the content-only port the
PR now shows (9 files, a61ce765c), and
#642 changed the workflow so its fallback
starts from main. Concretely: the release's
own commits are cherry-picked onto main in order; a commit that applies cleanly and
still leaves onebit registered is pushed to main; a commit the fork also changed keeps
the fork's side, goes to a sync/<tag> branch and is listed in a PR in the fork, so a
sync branch can never revert main. It also keeps the fork's own copies of upstream's
workflows disabled. Lemonade asks for an RFC before a new backend.
Embedding checklist#
What "fully embedded" still needs, measured on Strix Halo. The runs use the pinned fork
(third_party/lemonade), the engine from main, and Lemonade's LLM suite
(test/server_llm.py --wrapped-server onebit --backend <device>).
| device | 2026-09-25, start | now |
|---|---|---|
| HRX | 19 / 31 | 31 / 31 run, all pass (2 skipped; 2026-11-05, against the ported lemond 2026.47.0~1759.f44ff953 — the fork tip when the suite ran; the pin moves, so read git ls-tree third_party/lemonade for the one that ships today — not the c22 package that booted the board: test/server_llm.py --wrapped-server onebit --backend hrx, exit status 0, 110.6 s, every backend on HRX0, measured at load 28.5 with two foreign HRX clients resident, engine payload lemonade-onebit-rc-2026-11-05-c25) |
| NPU | 3 / 31 | in progress (NPU engine); the suite's small test models are GGUF |
| Vulkan (removed in RFC #213 stage 3) | 19 / 31 | 29 / 29 run, all pass, before its removal |
- ~~Declare what already works.~~ Done (fork #6). The recipe now declares tool calls,
stop, async, the Responses API, slots, tokenize, embeddings and reranking. - ~~Test on the device asked for.~~ Done (fork #6). The harness passes
--backendtoonebit. - ~~Forward the rest of llama-server's API.~~ Done (#69).
1bit serveforwards/v1/responses,/tokenize,/slots,/propsand/metricson the llama-server devices. - ~~Embedding and reranking models.~~ Done (#70, fork #6).
1bit serve --embedding/--reranking, and the recipe serves those modes. - ~~Reranking on HRX.~~ Done. jina-reranker-v1-tiny reranks on HRX (the suite's three
rerank tests return the same top 3 as on Vulkan), and
1bit serve --rerankruns on HRX (#281). - The NPU from Lemonade. The path works end to end: Lemonade downloads the Q4NX checkpoint
repo, the recipe hands
1bit servethe directory, and the engine runs it on the NPU (the experimental Qwen3.6-35B-A3B route builds with a closed add-on only, NPU engine). Still open:- the NPU engine's kernels built from source, verified but not merged (NPU engine);
- ~~
reasoning_content~~: done (#73), the NPU route splits the thinking out as llama-server does; - ~~models in our own Hugging Face repos~~: the 35B is
1bit-MONSTER/Qwen3.6-35B-A3B-NPU(fork #8). (engine + fork)
- Beyond the LLM suite:
- the Laya router.
echo and generation parameters are skipped, because Lemonade's own llamacpp recipe
declares neither.
Ubuntu 26.04: the PPA's lemond#
On Ubuntu 26.04 Lemonade installs from its PPA, and that lemond (2026.44.1~26.04 on
2026-10-31; 2026.42.1~26.04 when this path was written) is upstream's,
with no onebit recipe. The fork's Debian 13 .deb does not install there either: it depends
on libcpp-httplib0.41, which 26.04 does not have. So on 26.04 the engine plugs into the stock
lemond through the HRX recipe it already has, llamacpp-hrx, with no patch to Lemonade:
lemondlooks for that recipe'sllama-serverinLEMONADE_HRX_HRX_BIN, then inhrx.hrx_binin itsconfig.json. A path there skips its download of its own HRX build.- The engine package's systemd drop-in,
lemonade/1bit-hrx.conf(config/lemonade/1bit-hrx.conf), setsLEMONADE_HRX_HRX_BINtolemonade-hrxin the package. lemonade-hrx(scripts/lemonade-hrx) runs the package's HRXllama-server, with our HIP kernels, on Lemonade's arguments. First it runs1bit serve --print-backend-env, which makes serve's load-time checks (architecture, memory) and prints the environment serve gives an HRX backend: strict placement (GGML_HRX_STRICT=1), TheRock's HSA runtime, CWSR placement (engine#315) and the ternary decode. It also fills in what Lemonade's arguments leave to llama-server's defaults with serve's values:-ngl 99,--cache-reuse 256, and-kvuabove--parallel 1. A variable already set inlemond's environment wins, as it does under serve.
That printed environment is also the only place where the save-area trio
(HSA_USE_SVM=0, HSA_USERPTR_FOR_PAGED_MEM=0, HRX_ALLOW_NO_SVM=1) can reach the backend
Lemonade starts, since the package's lemond-onebit launcher does not export it and neither path
can pass --hrx-cwsr-placement (engine#715, fixed in #816). So it is worth asking directly:
env -u HSA_USE_SVM -u HSA_USERPTR_FOR_PAGED_MEM -u HRX_ALLOW_NO_SVM \
1bit serve -m <model.gguf> --device hrx --print-backend-env | grep -c '^HRX_ALLOW_NO_SVM=1'
1 is the pass. 0 means the one-hop backend and scripts/lemonade-hrx's exec'd
llama-server run without the trio, which is the configuration #715 page-faults in; nothing
warns when it happens. Measured on Strix Halo with the trio unset in the shell:
lemonade-onebit-rc-2026-10-31c (engine from before #794/#813) prints 0 and its serve log
still says "CWSR is off; save-area placement unchanged"; lemonade-onebit-rc-2026-11-01b
(save area placed in GTT by default) also prints 0, because serve exported the trio into its
own environment before building the plan, and the plan's env filter keeps only names the
caller did not already have — that is the bug #816 removes. lemonade-onebit-rc-2026-11-03-c22
(any package built after #816) prints 1, and --print-backend's env carries the trio as
well, so the one-hop llama-server is started with all three while the caller exports none
(checked in its /proc/<pid>/environ), and the filter still leaves out a name the caller did
set (GGML_HRX_STRICT=0 in the shell removes that line from the printed env).
To install:
sudo add-apt-repository ppa:lemonade-team/stable
sudo apt install lemonade-server
tar -I zstd -xf 1bit-<version>-linux-x86_64.tar.zst
sudo 1bit-<version>-linux-x86_64/install-lemonade-ppa.sh # to /opt/1bit; restarts lemond
install-lemonade-ppa.sh (scripts/install-lemonade-ppa.sh)
copies the package to /opt/1bit (or the directory it is given, outside /home, since the
service runs with ProtectHome=yes). It writes the drop-in to
/etc/systemd/system/lemond.service.d/1bit-hrx.conf and reloads systemd. If the PPA's postinst
did not already add the lemonade user to render, the script does. HRX also needs TheRock in
/opt/rocm-therock (HRX).
To run lemond as yourself instead of as the service, set the same variable for it
(LEMONADE_HRX_HRX_BIN=/opt/1bit/lemonade-hrx lemond) or put the path in hrx.hrx_bin in its
config.json.
Lemonade's HRX catalog (the *-HRX models) then runs on the engine, and so does a GGUF you
register with recipe: "llamacpp-hrx". Per-model arguments go in Lemonade's hrx_args, except
the ones Lemonade sets itself (-m, --ctx-size, --device, --port, --jinja,
--metrics). NPU model directories, --pm and --laya are not
llama-server, so they stay with /opt/1bit/1bit serve (1bit serve), outside the stock
lemond.
scripts/check-ubuntu-2604-lemond.sh runs this whole path
in a clean ubuntu:26.04 container: PPA, package, a model registered with llamacpp-hrx, a load
and a chat completion. It passes when lemond started lemonade-hrx rather than installing its
own HRX build, and when the llama-server it ran has GGML_HRX_STRICT=1. Without --gpu it
needs no GPU: a stand-in records the llama-server command and environment, then runs Ubuntu's
CPU llama.cpp. On Strix Halo, --gpu runs the real one on HRX0:
scripts/check-ubuntu-2604-lemond.sh out/1bit-<version>-linux-x86_64.tar.zst ~/models/Qwen3-0.6B-Q4_K_M.gguf --gpu
Vulkan, ROCm, Metal and CUDA are Lemonade's#
On the GPU the engine is pure HRX with HIP kernels; no Vulkan, ROCm backend, Metal, ZINC or CUDA (RFC #213 stage 3, 2026-10-01: HRX + NPU only; the core strip, 2026-10-04: no ZINC, so no CUDA; 2026-10-12: no MLX/Metal route and no Windows package). Lemonade ships its own backends for Vulkan, ROCm, CUDA, the CPU, MLX on Apple Silicon and Windows, so a model, feature or platform the engine does not run on HRX or the NPU is Lemonade's to serve:
1bit serve --device vulkan,--device rocm,--device zincand--device mlxexit at once with that reason, as do--lean,--adaptive,--long-model,--prefill-device,--zincand--mlx-server(1bit serve).- An architecture only the removed Vulkan build ran (Zyphra Zamba, Zamba2 and BlackMamba, and a
few upstream-only ones) is refused with a pointer to Lemonade's
llamacpprecipe. Qwen3.8-Flash-Next (qwen4exp) runs on HRX since llama.cpp pine57beb97.
In the pinned fork (1bit-MONSTER/lemonade,
third_party/lemonade at 80064ba72a98, fork #15 on main), the onebit backend has two entries, hrx and npu
(backend_versions.json); its vulkan and cuda entries are gone. Lemonade offers onebit
models only on machines with hrx or npu. Lemonade's other recipes (its llamacpp Vulkan, ROCm
and CUDA backends, MLX and the rest) are Lemonade's own and unchanged.
On its own#
1bit serve also works without Lemonade, for any OpenAI client:
1bit serve -m ~/models/Qwen3-0.6B-Q4_K_M.gguf --port 8000 # --device auto: HRX0, else the CPU
curl http://127.0.0.1:8000/v1/chat/completions -H 'Content-Type: application/json' \
-d '{"messages": [{"role": "user", "content": "Hello"}]}'