Skip to content
at_.DEVELOPMENT
FLAGSHIP PROJECT

hal0

Open-source software that turns a Linux box you already own into your own private AI system — chat, search, image and speech generation, no per-request bill.

PODMANSYSTEMDOPENAI APILINUX
hal0 — hero screenshot
102 tok/s
RUNNING 35B MOE MODELS
258 tok/s
CHAT AND SEARCH, AT THE SAME TIME
26
MODELS BENCHMARKED END TO END
Solo
DESIGNED, BUILT AND OPERATED
01 — THE PROBLEM

Running local AI should be accessible, not a folder of scripts piling up

Running AI on your own machine is genuinely appealing: no per-request bill, and your data never leaves the building. But the path there is discouraging enough that most people give up and go back to a vendor’s API. You end up with a pile of half-finished pieces — one script for chat, a separate setup for search, another for image generation, none of them aware the others exist. Nothing shares a way to check whether it’s working. Nothing shares a common interface. Every capability is its own island, and adding one more means learning that island’s quirks from scratch.

It doesn’t have to work like that. hal0 makes local AI something you install once and then simply use: chat, search, embeddings, ranking, transcription, speech and image generation all answer at one address on the box, speaking the same contract every existing AI tool already expects. Point an app at it and it works, because as far as that app is concerned nothing has changed except where the answer came from.

It runs best on a machine like a Ryzen AI Max+ 395 with 128 GB of shared memory — enough to hold several models at once — but it runs on anything with enough RAM. No cost per request, and no company sitting between you and your own data.

02 — ARCHITECTURE

Each feature runs on its own, so one failure doesn’t take the rest down

hal0 is explicitly not another llama-server wrapper. Every inference workload — the chat model, the embedder, the reranker, the image generator — runs as its own podman container, managed by its own hal0-slot@<name>.service systemd unit. There is no shared inference daemon juggling every model in one process, and no extra process to babysit outside systemd itself.

hal0-slot@<name>
podman container · one workload
hal0-api :8080
control plane · state machines
/v1/*
OpenAI-compatible dispatch

hal0-api is the only thing that knows about all the slots. It owns their state machines, dispatches requests to the right slot port, and serves the dashboard — nothing else on the box needs to.

Slot units are cheap to define and easy to reason about in isolation, which is what makes a single control plane tractable: hal0-api doesn’t run the model, it just knows which container is ready and where to send the request.

hal0 inference engine view listing each active slot with its model, device, and live telemetry.
Each row is a systemd-managed podman container. This is the live view hal0-api reads to know which slot is ready and where to route a request.

Slot units are never hand-written. hal0-api renders a podman Quadlet .container file per slot and lets systemd generate the hal0-slot@<name>.service unit from it, so the dependency graph and restart semantics come from systemd rather than from bespoke supervision code.

/ETC/CONTAINERS/SYSTEMD/HAL0-SLOT@CODER.CONTAINER (SHAPE)
01[Container]
02ContainerName=hal0-slot-coder
03Image=<runner image for the slot's provider>
04Exec=<provider-rendered argv>
05PublishPort=<host port>:<container port>
06Volume=<model store>:/models
07AddDevice=/dev/kfd
08
09[Service]
10Restart=on-failure
11RestartSec=5
12
13[Install]
14WantedBy=hal0.target

WantedBy=hal0.target is the line that matters: hal0.target is the boot-enable anchor every slot depends on. If it is missing or not enabled, slots that read healthy before a reboot quietly stay down after one — which is why hal0 doctor grew a dedicated check for it.

03 — MIGRATION

When your tests and your users are running different software

The most useful bug in the project’s history was invisible to every test that existed. A routine dependency update — a minor version of the web framework underneath the API — quietly changed how it reported its own list of routes. hal0 builds the control surface its AI agents use by reading that list at startup. The list came back empty. The startup code caught the resulting error, logged it, and carried on reporting perfectly healthy, so the entire agent control surface simply never came up. Found live only after twenty-one boots with zero successful mounts.

The reason no test caught it is the part worth keeping. The test environment installed the framework from a locked file, pinned to an older version that still behaved the old way. Real installs resolved it from the project’s own dependency list, which set a floor and no ceiling — so every fresh install pulled the newer, changed version. The tests and the users were running different software, and had been for a while.

BEFORE

Tests resolve the framework from a lockfile pinned to an older version. Real installs resolve it from a dependency floor with no upper bound, so they get a newer one that behaves differently. The mismatch is invisible: the API reports healthy either way.

AFTER

Dependency capped at a known-good ceiling, so tests and installs agree. The route reader walks the new structure rather than assuming the old one. A control surface that fails to come up is now a loud error recorded on the app's own state, not a swallowed log line.

Three fixes, and only one of them is the code change. Capping the dependency closed the gap between test and production. Rewriting the route reader to handle both shapes made it resilient to the next change. But the one that mattered most was making a failed startup loud — the bug was survivable for twenty-one boots precisely because something caught the error and let the service claim it was fine. A health check that lies is worse than one that fails.

04 — WHAT SHIPPED

What the platform actually does

hal0 stacks tab showing a declarative bundle of slot, profile, and model selections.
A stack pins a slot, profile, and model set as one unit, applied atomically instead of layered on one flag at a time.
01
Slots, not models — the idea everything else rests on
Nothing points at a model. Things point at a slot: a named job like agent, coder, embed or img. An agent asks the coder slot for a completion and has no idea which model is behind it. Swap the model, change the quantisation, move the work from the GPU to the NPU — the slot keeps its name and its address, so nothing that calls it has to change. That one indirection is what makes endless tinkering safe: you can benchmark three models against the same slot, keep the winner, and never touch the things depending on it.
02
hal0-brain — a small model that can operate the platform itself
A compact tool-calling model ships with the install and is wired into the dashboard chat, no setup step. It drives the platform through a 180-tool catalogue: pull a model, swap what a slot is running, write a profile, read hardware, start a benchmark. Destructive calls pause the turn for approve-or-deny rather than executing, and the floor on that is not editable — no persona tweak can un-gate deletes or anything that touches secrets.
03
Two MCP servers, and memory that is a graph rather than a log
One MCP server exposes platform administration, the other exposes long-term memory, and any MCP-speaking client can use them — Claude Code, your own scripts, a retrieval service. Memory runs on Hindsight, which extracts facts and the relationships between them instead of storing a transcript, so recall is a graph query rather than a similarity guess. Two other memory engines were tried and removed along the way: carrying more than one meant every fix to the permission logic had to be verified twice, and it was already being verified too rarely.
04
One-shot setup, because a second setup step never gets done
The installer is the whole setup — there is no first-run wizard afterwards. It probes the machine, writes down what it found, seeds ten slots covering every capability, pulls the one model it needs to be useful, and starts the API. Slots gate on their own hardware at load time rather than failing loudly: the NPU slot simply stays greyed out on a box without the hardware. Everything it chose is editable afterwards in settings, and a slot you deliberately delete stays deleted even if you re-run the installer.
05
Speech that runs at conversational speed on the same box
Speech generation runs at roughly twice real time on the GPU, which is the threshold where a spoken reply stops feeling like a wait. Transcription can run on the CPU or move to the NPU without reconfiguring the slot that uses it — the same request, a different piece of silicon, chosen by a setting. Both answer on the standard endpoints, so anything already speaking that dialect works, including the bundled chat interface.
06
Seven kinds of AI, one address
Chat, completions, embeddings, ranking, transcription, speech and image generation all answer at the same place, in the same format every existing AI tool already expects. Point a client at the box and it works — no per-capability SDK, no separate service to remember the port of. Image generation runs through its own container like everything else, so a heavy render cannot stall a chat request.
07
Custom runners, so new hardware tricks arrive when they land
The container images the models run inside are built and pinned in-house rather than taken off a shelf, which is the only reason the platform can target an AMD integrated GPU that most tooling ignores. It runs an FPX-quantised llama.cpp fork with multi-token prediction — formats and techniques that general-purpose runners tend to pick up much later, if at all. The cost is owning a build chain and a supply chain; the return is not waiting for someone else to decide your hardware is worth supporting.
hal0 memory graph view showing Hindsight facts and extracted relationships between them.
Durable writes land here. If the backend was ever unreachable, the replay described below shows up as new facts and edges the moment it heals.
05 — RESULTS

From a working prototype to something you can trust

The first working version shipped in ten days, with fifteen releases building up the core system and its feature model. A rework in early August took the parts that worked on one machine and rebuilt the parts that wouldn’t survive someone else’s hardware — proven by the fact that the “finished” 1.0.0 release itself needed a fix the very next day. The eight days that followed were dedicated to testing against real hardware — fresh installs, in-place upgrades, and machines with different graphics setups — with sixteen of the eighteen problems that surfaced fixed before the next release went out.

Speed is the part people assume you give up by running your own models, so it gets measured rather than claimed. Twenty-six models were benchmarked end to end on the reference machine — an AMD Ryzen AI Max+ 395 with 128 GB of shared memory — recording response speed, memory use, power draw and time to first word. A 35-billion-parameter model answers at 102 tokens per second, comfortably faster than anyone reads. A small model hits 169.8. Chat and search running concurrently sustain 258 tokens per second between them, and speech generation runs at roughly twice real time — a sentence is spoken faster than you could say it. Benchmarking is a built-in subsystem, not a spreadsheet someone maintained once: results are recorded, deduplicated and journaled so a slowdown shows up as a regression instead of a rumour.

Release process kept pace with the work: every release now ships its own changelog, and the update process checks a signed package and warns about breaking changes and migration steps before it touches anything — with a one-command rollback if something still goes wrong.

~2 GB
THREE JOBS, ONE NPU
all three share one neural-processor context in about two gigabytes, which leaves the graphics chip completely free for the large model
7
KINDS OF AI, ONE API
chat, completions, search, ranking, transcription, speech and image generation all answer at the same address
$0
PER REQUEST
the models run on hardware you already own, so usage costs electricity rather than a metered bill

Let's Build Something Cool._

Have a project, a fractional need, or just want to say hi? I read every message myself.