HopOSRun the machineHOPRun the jobsSURFBring them to the screen

HopOS · bare metal, in Rust

Compute, with fewer moving parts.

An operating system written in Rust around a small job: give an app memory, give it compute, connect it, and reclaim its resources when it finishes. No Linux underneath. One static binary is the OS, on ARM64 and RISC-V, from a small board to a many-core server.

HOP decides what runs where · meet the orchestrator →

The execution model

Your app owns its memory.
You choose how it uses the cores.

Give a compute job dedicated cores, including several cores for one app. Let explicitly trusted apps share a core cooperatively when that fits the workload. Each resident keeps its own hardware-enforced memory partition. There is no shell, no libc, no userland and no processes.

The kernel is mechanism only: it owns the cage, the switch, the storage and the clock. HOP, the orchestrator, is the first resident, an app with one privilege no other app has: the right to place, stop and replace apps. HOP owns the policy.

01Allocate

Claim the app’s memory and compute.

02Place

Stream the image into its own partition.

03Run

Do work; park the core when there is none.

04Release

Confirm the stop, then return ownership.

What it can do

A small kernel. Useful capabilities.

01 / Compute

Dedicated or deliberately shared.

Give a busy app whole cores, or several cores for one SMP app. Put trusted, intermittent workloads together in a sharegroup on one core. Where a board is short on cores, HOP itself can share the OS core with the kernel. Every form uses the same lifecycle and keeps separate memory partitions, and there is no maximum number of apps: the node-internal LAN has room for 65,533.

02 / Updates

Flip the kernel. Keep the apps.

A running node replaces its kernel without a reboot. The apps, HOP, their connections through the switch, the NAT flows and the volumes stay; only the kernel changes. An outgoing TCP connection of an app runs on across the jump. A cold flip, for a kernel with a different switch code, stops the apps first and places them again.

03 / Rust

Written in Rust, by the book.

All state has exactly one owner, and that owner is a task: no mutexes, messages instead. The kernel tree denies unwrap, panic and todo through lints; every unsafe block carries its reason. Each layer is a crate, and the import direction is a build rule the gate enforces. Boot, vectors and the switch are the only assembly.

04 / Go compatibility

Rust or Go. Same ABI.

An app is one ELF that speaks the slot ABI: the same tail, control page, rings and call frames whichever language built it. A Go image from the TamaGo toolchain and a Rust image from the app library are placed, connected and stopped by the same job spec. HOP sees no difference. Both SDKs are maintained in the tree.

One path for work

One network entry. One doorbell per resident.

Each app has its own network stack on a node-internal LAN. The kernel’s switch routes between residents, publishes ports to the uplink and masquerades outbound traffic. The app’s system calls travel over the same path as its other traffic, one caller at a time.

receiveNetwork device
routeNode switch
publishResident RX ring
notifyOne doorbell

Publish first. Then ring.

The switch writes frames into the resident’s ring and rings its doorbell. A notification tells the resident to look; the ring holds the actual work. Between two apps on one node the switch moves frames from ring to ring, which is why app-to-app traffic on a Mac mini M4 reaches 6,380 MB/s.

Always an interrupt. Never a poll.

Every network device and every disk feeds this path through its own interrupt line: MSI-X on the Pi 5, MSI-X through the GICv3 ITS for the Altra’s NIC and every NVMe, wired lines for the Pi 4, the Radxa Zero 3E, the Orion O6N’s Realtek, the LicheeRV and the Mac mini M4’s NIC and storage, virtio on QEMU. A line that does not arrive is an error with its reason on the console: the device does not start. Polling no longer exists.

Measured on hardware

Native speed is the point.

6,380 MB/sapp to app through the switch, Mac mini M4
4,950 MB/sraw NVMe writes, Mac mini M4
175,000 IOPSrandom 4 KiB reads, sixteen in flight, Mac mini M4

No VM, no WASM, no interpreter, no container: an app runs natively on its own cores at full clock speed, and the kernel is one hop away over a ring. The numbers above were measured on real boards; the measurements page keeps the spread per board, the command and the console marker for each.

What these numbers include scope and provenance

App to app: one app pulls 800 MiB from another on the same Mac mini M4 through the kernel’s switch, on a performance core, measured on 1 October 2026 at 6,379 and 6,383 MB/s; 40 GiB sustained at 2,813 MB/s. Storage: the raw NVMe benchmark at boot on the M4’s Apple NVMe with 1 MiB commands over 16 MiB wrote 4,952 and read 1,925 MB/s; through the full app storage path, 256 MiB in 1 MiB calls, an app wrote 1,288 and read 1,675 MB/s. Random 4 KiB reads with sixteen commands in flight reached 175,055 per second raw in the kernel; through the app path, with sixteen reads bundled in one call, four apps together read 161,000 and six apps 171,000 blocks per second (28,800 for four apps at one read per call). Smaller boards: app to app 407–435 MB/s on a Raspberry Pi 4 and 257–262 MB/s on a Radxa Zero 3E at its firmware clock of 816 MHz.

Measurements and conditions →

One OS, two ways to use it

One node or a fleet. The same apps.

one machine

Post a job. The node runs it.

HOP is built into the node as a standalone leader. Post a job spec to its API, and the kernel places the app, publishes its port and keeps it running. HOP keeps its state on the node’s own storage and reads it back after a restart.

job spec→HOP on the node→your app
no external store · no cluster required

a fleet

Keep the truth outside every machine.

Name a lock in the node config, and HopOS nodes and Linux or macOS agents form one cluster: one lease on a hoplockserver or in an S3 bucket, one committed cluster state next to it, and whichever node holds the lease leads.

HOP→lease + state→every node
shared state · replaceable machines

Software running on the kernel

Rust or Go. One app model.

An app is one ELF that speaks the slot ABI. A Rust app links against a small app library with its own network stack; a Go app builds with the TamaGo toolchain against the Go SDK. Both produce the same kind of image, placed by the same job spec.

Rust apps

From a welcome page to a home controller.

In the tree: a welcome page, a network bench, a board doctor that runs the performance tests, a display app for the screen and a decoder for the hardware codec. Beside it: Stulp, a home controller with ten device plugins, written in Rust. Browse the apps →

Go apps

cloudflared, unchanged, on TamaGo.

The Cloudflare tunnel client, built from its own Go source with the TamaGo toolchain, runs through the same ABI as the Rust apps; every release ships it as an image. A Go image built for the previous generation runs unchanged. Build a Go app for v3 →

Cluster services

Routing, DNS, metrics and locks.

hoplb, hopdns, hopprom, hoplockserver and a Rust Cloudflare tunnel client ship with every HOP release. Each runs as a host daemon next to HOP or as a resident on a node. See the HOP workflow →

Storage

SQLite on HopFS.

Replica links native SQLite into a no_std app over the kernel’s file calls, with a confirmed sync barrier. The full persistence proof, write, restart, recover and repair, takes about 0.2 s on the M4. Read the barrier contract →

Where it runs

From a tiny board to a many-core server.

Apps are built once per architecture, not once per board. The kernel binary picks exactly one board, which supplies boot and device wiring. On UEFI machines its own EFI stub takes over from the firmware, and on the Mac mini M4 it boots from iBoot — no GRUB in between.

Raspberry Pi 5arm64 · GUI Raspberry Pi 4arm64 · GUI Radxa Zero 3Earm64 · GUI Radxa Orion O6Narm64 · NVMe · hardware codec · GUI Mac mini M4arm64 · NVMe Ampere Altraarm64 · NVMe · GUI LicheeRV Nanoriscv64 UEFI arm64arm64 · GUI

Try it

Write a card. Power on.

The HopOS Imager downloads the newest signed release, writes and verifies the card, keeps config during updates and finds the node on your network.

on hardware
  1. Choose your board, headless or with a screen.
  2. Write and verify a USB stick or SD card.
  3. Power on. FIND shows the node and its boot log.
from source, without hardware
$ git clone https://github.com/hop-os/HopOS
$ cd HopOS
$ sh image/qemu-run.sh
HOP_UP
Prefer a direct image?

Each file is the complete medium. GUI boots with the screen (on the O6N with the hardware codec too), Headless contains no graphics code. Each release also carries a flip bundle per board, for a running node. The links resolve to the newest release; release candidates of the next version are listed with the releases, and every board builds from the repository with one script, with rust-toolchain.toml pinning the compiler.