# Copyright 1999-2026 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 EAPI=8 inherit cmake git-r3 desktop systemd DESCRIPTION="Local AI server: optimized LLM inference on AMD NPU + GPU" HOMEPAGE=" https://lemonade-server.ai/ https://github.com/lemonade-sdk/lemonade " EGIT_REPO_URI="https://github.com/lemonade-sdk/${PN}.git" LICENSE="Apache-2.0" SLOT="0" IUSE="openrc system-fastflowlm system-kokoro system-llamacpp system-rocm system-sdcpp system-therock system-whispercpp systemd tauri webui" # Only one system ROCm source can define ROCM_PATH. REQUIRED_USE="?? ( system-rocm system-therock )" # Missing cpp-httplib pkg-config metadata and optional libwebsockets cause # upstream FetchContent downloads at configure time. PROPERTIES="live" RESTRICT="network-sandbox" # Keep the systemd account/state across USE changes; OpenRC uses LEMONADE_USER. # Linux always links libdrm_amdgpu; require its flag. verified 2026-07-18 # Derive TheRock bounds from backend_versions.json on each live sync. # brotli is macOS-only; zstd-1.5.5 is upstream's floor. # verified 2026-09-03 against master RDEPEND=" >=app-arch/zstd-1.5.5:= >=dev-cpp/cli11-2.4.2 >=dev-cpp/cpp-httplib-0.26.0 >=dev-cpp/nlohmann_json-3.11.3 >=net-libs/libwebsockets-4.3.3 >=net-misc/curl-8.5.0 sys-libs/libcap x11-libs/libdrm[video_cards_amdgpu] acct-user/lemonade acct-group/lemonade system-fastflowlm? ( sci-ml/fastflowlm ) system-llamacpp? ( sci-misc/llama-cpp ) system-whispercpp? ( app-accessibility/whisper-cpp ) system-sdcpp? ( sci-misc/stable-diffusion-cpp ) system-kokoro? ( sci-ml/kokoros ) system-rocm? ( dev-util/hip ) system-therock? ( >=dev-util/therock-bin-7.13.0 /dev/null || true rmdir "${ED}/etc/lemonade/conf.d" "${ED}/etc/lemonade" 2>/dev/null || true fi if use openrc; then newinitd "${FILESDIR}/${PN}.initd" "${PN}" newconfd "${FILESDIR}/${PN}.confd" "${PN}" fi # Point services at system ROCm instead of downloading TheRock. The dependency # constrains therock-bin; manual launches still need ROCM_PATH. # verified 2026-07-16 local rocm_path= use system-rocm && rocm_path="/usr" use system-therock && rocm_path="/opt/therock-bin" if [[ -n ${rocm_path} ]]; then if use openrc; then sed -i -e "s|^#\?LEMONADE_ROCM_PATH=.*|LEMONADE_ROCM_PATH=\"${rocm_path}\"|" \ "${ED}/etc/conf.d/${PN}" || die fi if use systemd; then printf '[Service]\nEnvironment=ROCM_PATH=%s\n' "${rocm_path}" \ > "${T}/10-rocm-path.conf" || die local unitdir for unitdir in "$(systemd_get_systemunitdir)" "$(systemd_get_userunitdir)"; do insinto "${unitdir#"${EPREFIX}"}/lemond.service.d" newins "${T}/10-rocm-path.conf" 10-rocm-path.conf done fi fi # Route fetch-by-default backends to packaged binaries. Set both backend and # its matching *_bin: "auto" otherwise ignores the path. whispercpp has only # cpu_bin; kokoro and flm have no backend selector. These keys route binaries, # not GPU implementations, so do not add backend USE constraints. Guard each # section before jq can create a misplaced key. verified 2026-07-12 local -a jqf=() sections=() if use system-llamacpp; then jqf+=( '.llamacpp.backend="vulkan" | .llamacpp.vulkan_bin="/usr/bin/llama-server"' ) sections+=( llamacpp ) fi if use system-whispercpp; then jqf+=( '.whispercpp.backend="cpu" | .whispercpp.cpu_bin="/usr/bin/whisper-server"' ) sections+=( whispercpp ) fi if use system-sdcpp; then jqf+=( '.sdcpp.backend="vulkan" | .sdcpp.vulkan_bin="/usr/bin/sd-server"' ) sections+=( sdcpp ) fi if use system-kokoro; then jqf+=( '.kokoro.cpu_bin="/usr/bin/koko"' ) sections+=( kokoro ) fi if use system-fastflowlm; then # PATH is ignored without prefer_system; pin npu_bin to prevent a download. # verified 2026-07-25 jqf+=( '.flm.npu_bin="/usr/bin/flm"' ) sections+=( flm ) fi if [[ ${#jqf[@]} -gt 0 ]]; then # Patch the config seed, not its byte-identical resources copy. # verified 2026-07-12 with a fresh config local def="${ED}/usr/share/lemonade/defaults.json" local s for s in "${sections[@]}"; do jq -e "has(\"${s}\")" "${def}" >/dev/null \ || die "defaults.json has no '${s}' section; re-audit the reuse pin" done local filter printf -v filter '%s | ' "${jqf[@]}" jq "${filter% | }" "${def}" > "${T}/defaults.json" || die mv "${T}/defaults.json" "${def}" || die fi if use tauri; then # Upstream's configure-time install rules are unusable; install manually. dobin "${BUILD_DIR}/app/lemonade-app" domenu "${S}/data/lemonade-app.desktop" newicon -s scalable "${S}/src/app/assets/logo.svg" lemonade-app.svg fi } pkg_postinst() { elog "" elog "Lemonade ${PV} (live) installed. lemond binds 127.0.0.1:13305" elog "(loopback) by default; expose it beyond localhost only behind API-key" elog "auth (LEMONADE_API_KEY) or an SSH tunnel / WireGuard." elog "" ewarn "Privacy: at startup lemond sends a UDP presence broadcast on LAN" ewarn "(RFC1918) interfaces -- on by default, and it fires even with the" ewarn "loopback bind. Disable it by setting no_broadcast to true in" ewarn "~/.cache/lemonade/config.json." elog "" elog "Data lives under ~/.cache/lemonade (config + models) and" elog "~/.cache/huggingface (model cache + HF_TOKEN if set); model pulls" elog "fetch from HuggingFace over the network." elog "" if ! use system-sdcpp; then ewarn "Disk (AMD/ROCm): the first image (sd-cpp) request makes lemond" ewarn "download AMD's TheRock ROCm runtime into ~/.cache/lemonade --" ewarn "~3 GB compressed, >7 GB unpacked, on top of the model. Avoid it:" ewarn " - USE=system-sdcpp routes sd-cpp to the portage /usr/bin/sd-server" ewarn " (sci-misc/stable-diffusion-cpp) -- no runtime fetch. Recommended." ewarn " - Else set ROCM_PATH=/usr: lemond links its ROCm backend against" ewarn " the system ROCm and fetches only the ~228 MB backend binary," ewarn " not TheRock. The OpenRC service sets this by default; export it" ewarn " yourself for a manual or systemd launch." ewarn "acestep/thinksound (audio) have no system-* route yet and share" ewarn "this -- ROCM_PATH covers them too." ewarn "" fi elog "Quick start (manual):" elog " lemond # start the server (port 13305 by default)" elog " lemonade run # CLI client" elog "" elog "Live ebuild -- rebuild via: emerge --oneshot =sci-ml/lemonade-9999" elog "" if use webui; then elog "Web UI: lemond serves the bundled React app at the server root," elog "e.g. http://127.0.0.1:13305/ -- open it in a browser. It shares the" elog "API's bind, so it is loopback-only unless you widen LEMONADE_HOST." elog "A 'lemonade-web-app' launcher (+ \"Lemonade Web App\" menu entry)" elog "that opens the UI in your browser is installed too; start lemond first." elog "" fi if use tauri; then elog "Desktop app: run 'lemonade-app' (or launch \"Lemonade App\" from" elog "your menu) for the same UI in a native window. It is a client for" elog "a lemond server, so start lemond (or the service) first." elog "" fi if use openrc; then elog "OpenRC service (supervise-daemon; auto-restart on crash):" elog " edit /etc/conf.d/lemonade and set LEMONADE_USER (required)" elog " the --host default (127.0.0.1) keeps it loopback-only" elog " rc-service lemonade start" elog " rc-update add lemonade default # auto-start at boot" elog "" fi if use systemd; then elog "systemd service (runs as the dedicated 'lemonade' user):" elog " systemctl enable --now lemond # system-wide, or" elog " systemctl --user enable --now lemond # per-user" elog " host/port live in config.json, not env vars; HF_TOKEN and" elog " LEMONADE_API_KEY go in /etc/lemonade/conf.d/*.conf" elog "" fi if use system-llamacpp || use system-whispercpp || use system-sdcpp || use system-kokoro; then elog "system-* backends: lemond reuses portage-managed binaries instead" elog "of fetching prebuilts into ~/.cache/lemonade/ at runtime --" use system-llamacpp && elog " llamacpp -> /usr/bin/llama-server (sci-misc/llama-cpp)" use system-whispercpp && elog " whispercpp -> /usr/bin/whisper-server (app-accessibility/whisper-cpp)" use system-sdcpp && elog " sdcpp -> /usr/bin/sd-server (sci-misc/stable-diffusion-cpp)" use system-kokoro && elog " kokoro -> /usr/bin/koko (sci-ml/kokoros)" elog "" ewarn "Which GPU backend runs is decided by the BINARY, not lemond: ggml" ewarn "uses the first-registered backend (gpu_device 0). In a build with" ewarn "several GPU backends, ROCm/CUDA register before Vulkan, so a" ewarn "hip+vulkan or cuda+vulkan binary runs ROCm/CUDA -- not Vulkan." ewarn "Build the reused package with the backend you actually want" ewarn "(e.g. a vulkan-only build if you want Vulkan)." if use system-sdcpp; then ewarn "On Ryzen AI, stable-diffusion-cpp[opencl] makes sd-server abort" ewarn "at startup (XRT OpenCL ICD GGML_ASSERT) -- build it with -opencl." fi elog "" elog "The shipped defaults pin the vulkan routing (cpu for whisper/kokoro);" elog "new configs pick these up automatically. For an existing config, or" elog "if you built a different backend, set the bin (and matching backend):" elog " lemonade config set llamacpp.backend=vulkan llamacpp.vulkan_bin=/usr/bin/llama-server" elog "lemond does not verify these paths; if the package is removed the" elog "backend's model loads fail." elog "" fi if use system-rocm || use system-therock; then local _rp=/usr use system-therock && _rp=/opt/therock-bin elog "ROCm runtime: lemond is pointed at ${_rp} (ROCM_PATH), so its" elog "rocm-stable image/audio backends reuse that ROCm instead of" elog "downloading AMD's ~3 GB TheRock runtime. The OpenRC service (confd)" elog "and the systemd units (drop-in) set it automatically; for a MANUAL" elog "launch, export it yourself:" elog " export ROCM_PATH=${_rp}" if use system-therock; then elog "dev-util/therock-bin must major.minor-match lemond's pinned ROCm" elog "(7.13); the RDEPEND holds it to the 7.13 line. A mismatched version" elog "file makes lemond reject it and download TheRock anyway." fi elog "" fi if use system-fastflowlm; then elog "system-fastflowlm: the NPU runtime is provided by sci-ml/fastflowlm." elog "The config seed pins flm.npu_bin=/usr/bin/flm, so a fresh config" elog "reuses it with no runtime fetch. A bare flm on PATH is NOT auto-used" elog "-- lemond gates PATH resolution behind flm.prefer_system -- so an" elog "EXISTING ~/.cache/lemonade/config.json (which the rebuild does not" elog "touch) still shows the NPU backend as \"supported but not installed\"" elog "until you set the pin by hand:" elog " lemonade config set flm.npu_bin=/usr/bin/flm" elog "Confirm 'flm validate' passes before lemonade drives the NPU backend." else ewarn "Without USE=system-fastflowlm, lemond auto-downloads the FastFlowLM" ewarn "(flm) NPU runtime into ~/.cache/lemonade on first NPU use. It resolves" ewarn "flm as flm.npu_bin override -> PATH (only when flm.prefer_system is" ewarn "set) -> download; a bare flm on PATH is NOT used by default. Enable" ewarn "USE=system-fastflowlm (sci-ml/fastflowlm), which pins" ewarn "flm.npu_bin=/usr/bin/flm, to reuse the packaged runtime and skip the fetch." fi }