Install this version:
emerge -a =sci-ml/localai-4.9.0
If this version is masked, you can unmask it using the autounmask tool or standard emerge options:
autounmask =sci-ml/localai-4.9.0
Or alternatively:
emerge --autounmask-write -a =sci-ml/localai-4.9.0
# Copyright 1999-2026 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
EAPI=8
inherit go-env go-module
# Three distfiles below are generated by bentoo and hosted on
# distfiles.obentoo.org. They carry three independent versions because they
# have three different triggers -- pinning them all to ${PV} would mean
# republishing 45 MB of unchanged node_modules on every LocalAI release.
#
# 1. ${P}-vendor.tar.xz -- REGENERATE ON EVERY BUMP (go.mod moves with the
# release). pkg/grpc/proto is generated rather than shipped, and
# backend/go/* import it, so `go mod vendor` FAILS until protoc has run:
#
# tar xzf LocalAI-v${PV}-source.tar.gz -C src && cd src
# mkdir -p pkg/grpc/proto
# protoc --experimental_allow_proto3_optional -Ibackend/ \
# --go_out=pkg/grpc/proto/ --go_opt=paths=source_relative \
# --go-grpc_out=pkg/grpc/proto/ --go-grpc_opt=paths=source_relative \
# backend/backend.proto
# go mod vendor
# tar caf ${P}-vendor.tar.xz vendor
#
# Do NOT reach for `go get -tool` to pull the protoc plugins into the
# module graph: it downgrades grpc 1.80.0 -> 1.69.0-dev, protobuf
# 1.36.11 -> 1.34.2 and libp2p 0.48.0 -> 0.36.5, and drops cogito and nib
# outright. The tree would then be built against dependencies upstream
# never tested.
#
# 2. ${PN}-react-ui-node_modules-${NODE_MODULES_PV}.tar.xz -- REGENERATE WHEN
# core/http/react-ui/package-lock.json CHANGES, not every bump:
#
# cd core/http/react-ui
# npm ci --ignore-scripts # --ignore-scripts: @playwright/test's
# # postinstall would fetch browsers
# # vite resolves its native bits through per-platform optional deps, so
# # a tree built here is x86_64-only. Overlay the arm64 ones so one
# # distfile serves both KEYWORDS (costs 12 MB):
# npm ci --ignore-scripts --cpu=arm64 --os=linux # in a scratch dir
# cp -a scratch/node_modules/{lightningcss-linux-arm64-*} node_modules/
# cp -a scratch/node_modules/@rolldown/binding-linux-arm64-* \
# node_modules/@rolldown/
# tar caf ${PN}-react-ui-node_modules-${PV}.tar.xz node_modules
#
# Upstream's Makefile builds this with `npm install`; `npm ci` is used
# instead so the lockfile is honoured rather than re-resolved.
#
# 3. protoc-gen-go-grpc-${PGGG_PV}-vendor.tar.xz -- REGENERATE WHEN UPSTREAM
# REPINS THE PLUGIN (Makefile, install-go-tools). Only the gRPC generator
# is bundled; protoc-gen-go comes from LocalAI's own vendor tree instead.
# See src_compile.
#
# mkdir protoc-gen-go-grpc && cd protoc-gen-go-grpc
# go mod init bentoo.local/protoc-gen-go-grpc-bundle
# go get google.golang.org/grpc/cmd/protoc-gen-go-grpc@v${PGGG_PV}
# go mod edit -tool=google.golang.org/grpc/cmd/protoc-gen-go-grpc
# go mod tidy && go mod vendor && cd ..
# tar caf protoc-gen-go-grpc-${PGGG_PV}-vendor.tar.xz protoc-gen-go-grpc
# Upstream pins protoc-gen-go-grpc by commit SHA
# (1958fcbe2ca8bd93af633f11e97d44e567e945af); that SHA is release v1.4.0.
PGGG_PV="1.4.0"
# Bump only when core/http/react-ui/package-lock.json actually changes.
NODE_MODULES_PV="4.9.0"
MY_P="LocalAI-v${PV}"
DESCRIPTION="Self-hosted OpenAI-compatible inference API with a model gallery"
HOMEPAGE="https://localai.io/ https://github.com/mudler/LocalAI"
SRC_URI="
https://github.com/mudler/LocalAI/releases/download/v${PV}/${MY_P}-source.tar.gz
https://distfiles.obentoo.org/${P}-vendor.tar.xz
https://distfiles.obentoo.org/${PN}-react-ui-node_modules-${NODE_MODULES_PV}.tar.xz
https://distfiles.obentoo.org/protoc-gen-go-grpc-${PGGG_PV}-vendor.tar.xz
"
# The curated release tarball has NO top-level directory: it extracts straight
# into backend/ cmd/ core/ ... Getting this wrong produces a confusing
# "file not found" much later, in src_compile.
S="${WORKDIR}"
# MIT is LocalAI's own. The rest are the licences actually present in the
# vendored tree: Apache-2.0 (107 modules), MIT (151), BSD-3 (12), MPL-2.0 (6),
# ISC (2), BSD-2 (1).
LICENSE="MIT Apache-2.0 BSD BSD-2 ISC MPL-2.0"
SLOT="0"
KEYWORDS="~amd64 ~arm64"
# No acceleration USE flags, and that is deliberate rather than an omission:
# LocalAI resolves its inference backends as OCI artifacts at RUNTIME, so no
# backend is ever compiled in and a CPU-only install is the default. The
# acceleration matrix is optional by construction. IUSE is therefore not set
# at all -- an empty IUSE="" is a QA error, and the absence is the statement.
# The build reaches no network at all -- verified by building inside a network
# namespace with every interface down. Three upstream fetches are removed:
# the prebuilt protoc download (dev-libs/protobuf instead), install-go-tools'
# two `go install ...@ver` (see src_compile), and the react-ui `npm install`
# (the node_modules distfile). Hence no RESTRICT="network-sandbox".
# The test suite does download models, so it stays restricted.
PROPERTIES="test_network"
RESTRICT="test strip"
# No dev-go/protobuf-go here on purpose -- see src_compile: protoc-gen-go is
# built from LocalAI's own vendor tree so that the generator and the protobuf
# runtime are the same version.
# pkgcheck reports NonsolvableDepsInDev for the x32 dev profile
# (default/linux/amd64/23.0/x32) against the nodejs dependency. That is not a
# defect here and cannot be fixed here: net-libs/nodejs carries
# "~amd64 ~arm ~arm64 ~loong ~ppc64 ~riscv ~x86 ~x64-macos" and no x32 keyword
# at all, so every package that needs npm reports the same. Narrowing KEYWORDS
# to silence it would drop arches where this builds fine.
BDEPEND="
>=dev-lang/go-1.26.0
dev-libs/protobuf
>=net-libs/nodejs-24:*[npm]
"
# The service account only. Nothing else is linked in: CGO_ENABLED=0 makes the
# binary static, and the inference backends are OCI artifacts fetched at
# runtime rather than libraries resolved at build time.
RDEPEND="
acct-group/localai
acct-user/localai
"
# NOTE: src_unpack is deliberately NOT defined. go-module.eclass exports it,
# and go-module_src_unpack ends by calling go-env_set_compile_environment;
# a local `src_unpack() { default; }` would override the eclass and drop that
# call silently. The eclass's own version does the right thing here: it
# unpacks everything and then skips `ego mod verify` because ${S}/vendor
# exists. The three bentoo distfiles were packed with distinct top-level
# entries (vendor/, node_modules/, protoc-gen-go-grpc/) precisely so that
# none collides with the source tarball's own go.mod, go.sum or vendor/ when
# they all land in ${WORKDIR}.
src_prepare() {
# vite resolves dependencies relative to the project directory, so the
# staged tree has to sit next to package.json rather than at ${WORKDIR}.
mv "${WORKDIR}"/node_modules core/http/react-ui/ || die
# core/config/inference_defaults.json ships in the tarball, so the
# generator that would fetch it from unsloth is dead weight -- but a
# `go generate` would still run it and reach the network. Drop it.
# The grep guard matters: sed exits 0 when it matches nothing, so without
# it an upstream rename would silently restore the fetch.
grep -q '^//go:generate go run \./gen_inference_defaults/' \
core/config/inference_defaults.go \
|| die "the go:generate anchor moved; recheck core/config/inference_defaults.go"
sed -i '/^\/\/go:generate/d' core/config/inference_defaults.go || die
# .gitmodules names docs/themes/hugo-theme-relearn and
# backend/rust/kokoros/sources/Kokoros. The curated tarball ships both as
# EMPTY directories, so there is nothing to strip and nothing that can
# reach the network -- asserted rather than assumed, because a future
# tarball that did embed them would change the licence set.
local sub
for sub in docs/themes/hugo-theme-relearn backend/rust/kokoros/sources/Kokoros; do
if [[ -n $(find "${sub}" -mindepth 1 -print -quit 2>/dev/null) ]]; then
die "${sub} is no longer empty; re-check the submodule handling"
fi
done
default
}
src_compile() {
# protoc resolves its code generators through PATH, so both must exist as
# executables before it runs.
#
# protoc-gen-go is built from LocalAI's OWN vendor tree, which beats both
# alternatives: it is v1.36.11, the very version of the protobuf runtime
# the binary links against. Upstream's Makefile pins the generator at
# v1.34.2 and dev-go/protobuf-go follows ::gentoo; either can drift AHEAD
# of the vendored runtime, and generated code then demands a runtime newer
# than the one vendored -- a failure that reads like an upstream bug.
# Asserted rather than assumed: `go mod vendor` includes this package
# today, and a bump where it stops being included must fail here, loudly.
[[ -d vendor/google.golang.org/protobuf/cmd/protoc-gen-go ]] ||
die "protoc-gen-go left the vendor tree; regenerate the vendor distfile or move the plugin into the bundle"
mkdir -p "${T}"/bin || die
ego build -o "${T}"/bin/protoc-gen-go \
google.golang.org/protobuf/cmd/protoc-gen-go
# protoc-gen-go-grpc, by contrast, has no Gentoo package AND is not
# reachable from LocalAI's module graph -- cmd/protoc-gen-go-grpc is a
# separate module, so `go mod vendor` never brings it -- which is why it
# ships as its own self-contained vendored bundle.
pushd protoc-gen-go-grpc > /dev/null || die
GOFLAGS="-mod=vendor" ego build -o "${T}"/bin/protoc-gen-go-grpc \
google.golang.org/grpc/cmd/protoc-gen-go-grpc
popd > /dev/null || die
# pkg/grpc/proto is generated, never shipped; backend/go/* import it.
mkdir -p pkg/grpc/proto || die
PATH="${T}/bin:${PATH}" protoc --experimental_allow_proto3_optional \
-Ibackend/ \
--go_out=pkg/grpc/proto/ --go_opt=paths=source_relative \
--go-grpc_out=pkg/grpc/proto/ --go-grpc_opt=paths=source_relative \
backend/backend.proto || die "protoc code generation failed"
# core/http/app.go carries //go:embed react-ui/dist/*, so the UI is
# mandatory: without dist/ the Go build fails outright rather than
# producing a UI-less binary.
pushd core/http/react-ui > /dev/null || die
npm run build || die "react-ui vite build failed"
popd > /dev/null || die
# CGO_ENABLED=0 with an empty BUILD_TYPE is the CPU-only configuration:
# no accelerator is linked in, matching the runtime-OCI backend model.
# -trimpath keeps ${WORKDIR} out of the binary. Version and Commit are
# normally filled from `git describe`/`git rev-parse`, neither of which
# can work from a release tarball.
local -x CGO_ENABLED=0
ego build -trimpath \
-ldflags "-X github.com/mudler/LocalAI/internal.Version=v${PV} -X github.com/mudler/LocalAI/internal.Commit=v${PV}" \
-o local-ai ./cmd/local-ai
}
src_install() {
dobin local-ai
einstalldocs
# Upstream ships no service files of any kind, so the project rule about
# mirroring a systemd unit with an OpenRC script does not apply -- there is
# no unit to mirror. This installs the OpenRC pair anyway, because local-ai
# IS a daemon and without it the only way to run one is by hand, as root,
# in whatever directory happens to be current.
newinitd "${FILESDIR}"/local-ai.initd local-ai
newconfd "${FILESDIR}"/local-ai.confd local-ai
# 0640 root:root, not the 0644 newconfd leaves behind: this file is where
# LOCALAI_API_KEY, the OIDC client secret and HF_TOKEN belong. root:root
# rather than root:localai is deliberate and sufficient -- OpenRC sources
# conf.d as root and only then drops to the localai user, so the daemon
# never reads the file, and naming the group here would need the account to
# exist on the BUILD host, which it need not.
fperms 0640 /etc/conf.d/local-ai
# Created by the init script at first start rather than here: fowners by
# name would need the localai account on the build host.
keepdir /var/lib/localai
}
pkg_postinst() {
elog "Start the server with:"
elog " rc-service local-ai start"
elog
elog "It binds 127.0.0.1:8080 by default. That is not just hardening:"
elog "local-ai's own default is the wildcard \":8080\", and it REFUSES to"
elog "start on a wildcard or public address unless"
elog "--allow-insecure-public-bind is passed. Configure authentication"
elog "(LOCALAI_API_KEY or OIDC) in /etc/conf.d/local-ai before widening"
elog "LOCALAI_ADDRESS."
elog
elog "Models, backends and generated content live under /var/lib/localai."
elog "Inference backends are NOT built here: local-ai downloads them as OCI"
elog "artifacts at runtime, picking one that matches the hardware it finds,"
elog "so the server needs outbound network the first time a model is used"
elog "and a CPU-only machine needs nothing extra."
}
acct-group/localai acct-user/localai
>=dev-lang/go-1.26.0 dev-libs/protobuf >=net-libs/nodejs-24:*[npm]
| Type | File | Size | Source URLs |
|---|---|---|---|
| DIST | LocalAI-v4.9.0-source.tar.gz | 26097714 bytes | https://github.com/mudler/LocalAI/releases/download/v4.9.0/LocalAI-v4.9.0-source.tar.gz |
| DIST | localai-4.9.0-vendor.tar.xz | 30475172 bytes | https://distfiles.obentoo.org/localai-4.9.0-vendor.tar.xz |
| DIST | localai-react-ui-node_modules-4.9.0.tar.xz | 49366132 bytes | https://distfiles.obentoo.org/localai-react-ui-node_modules-4.9.0.tar.xz |
| DIST | protoc-gen-go-grpc-1.4.0-vendor.tar.xz | 202496 bytes | https://distfiles.obentoo.org/protoc-gen-go-grpc-1.4.0-vendor.tar.xz |