Get littlestar

The next generation of
secure edge infrastructure.

littlestar is a Rust-built operating system that boots signed, stays immutable, stays reachable over iroh and updates itself. Nobody logs in. Nobody needs to.

1signed file boots
01

It starts signed.

Kernel, initramfs and command line ship as one unified kernel image, signed for Secure Boot. Flip a byte and it won't boot.

02

It stays small.

A purpose-built image where every file is accounted for. Less to download over thin links, less to attack.

03

It has no door.

No SSH daemon. Root locked. Boot failures reboot instead of opening a shell. There is nothing to log into.

04

It stays connected.

Every node is reachable by its key over iroh, through any NAT or firewall, without opening a port. Offline for days? It keeps its last state and catches up exactly once.

05

It takes orders by API.

Nodes, Apps, Models and Rollouts are declared resources. lsctl and the console are generated from the same spec.

06

It updates itself.

Apps roll out in batches behind health gates. New OS images stage, apply with one reboot and return to the last image if they aren't healthy.

Everything it does.
Nothing it doesn't need.

Built in Rust, built from source

Every package compiled from upstream source by a toolchain that rebuilds itself. Rust where it matters: uutils coreutils, bootc, netavark, and every littlestar component.

Immutable bootc image

The OS is one signed container image on a composefs root. No package manager on the node, nothing drifting, nothing to patch by hand.

Connected by iroh

Nodes dial out over QUIC and are addressed by key, not IP. Through any NAT, carrier network or firewall, with zero inbound ports and no VPN.

No SSH. No shell. No door.

Root is locked, early-boot failures reboot instead of dropping to a shell, and the kernel command line can't be edited. There is nothing to log into.

A Machine API, not a terminal

Every Node, App, Model and Rollout is a resource in an OpenAPI 3.1 spec, with ETags, problem+json and live SSE watches. lsctl and the console are generated from it.

Updates apps and the OS

Apps roll out in batches behind health gates. New OS images stage, apply with one reboot and roll back on their own if the health check fails.

Signed boot, end to end

Kernel, initramfs and command line ship as one signed UKI under Secure Boot. Change one byte and it doesn't boot.

Ask “why is this running here?”

Placement is decided by Cedar policy, deny by default, and recorded as an Agreement you can query.

Three parts.
One known, signed state.

littlestar OS

A minimal, immutable bootc image built entirely from upstream source. 0.15 GB compressed. Boots only a signed kernel image under Secure Boot.

The hub

Rust services that hold the fleet's desired state (apps, models, OS images, host config and policy) and record why every workload runs where it does.

The agent

A Rust service on every node. Pulls desired state over NATS, applies it with Podman Quadlets and bootc, and reports what is actually running.

Why littlestar

Built around the ways edge fleets fail.

Data-center tooling assumes reachable, connected, physically secure machines. The edge is none of those.

Nodes sit behind NAT, carrier networks and firewalls nobody controlsEvery node dials out over iroh (QUIC). The hub reaches any node by its key, with no inbound ports and no VPN.
Links drop for hours or daysEach node runs its own NATS leaf with JetStream. Desired state is a NATS KV key, so a node keeps its last state offline and catches up exactly once.
Machines are physically exposed; anyone at the console is a threatSigned UKI under Secure Boot, a locked root, no shell on failure and a kernel command line that can't be edited.
General-purpose distributions ship gigabytes nobody auditsBuilt from source with a provenance check on every file. The release image is 0.36 GB uncompressed.
OS and apps drift between nodesOne desired state per node, written only by the hub. Image-based OS updates with automatic rollback.
“Why is this running here?” has no answerPlacement is decided by Cedar policy and recorded as an Agreement, queryable in the API and console.
Sensors, cameras and models need low-latency local dataZenoh carries device streams at the site; models are served on the node and answer over NATS.
littlestar OS

Built with love by Mainsail.

A small, purpose-built distribution, compiled from verified upstream source, where every file is accounted for.

Built from source

We compile littlestar ourselves from verified upstream source. No binaries from other distributions, nothing we can't account for.

Every file accounted for

Each image ships with an SBOM, and every file in it traces back to the package that built it.

Rust first

Every littlestar component is written in Rust, and we use mature Rust implementations wherever they exist.

Image-based and immutable

The OS ships as one signed bootc image on a read-only composefs root. Updates replace the whole image, never pieces of it.

Image (amd64)Uncompressedzstd
General-purpose bootc base1.99 GB1.06 GB
littlestar OS0.36 GB0.15 GB
littlestar OS + signed UKI + skopeo0.45 GB0.19 GB

About a sixth the size of a general-purpose bootc image: faster over thin links, quicker to update, less to attack.

Trusted boot

One signed file boots. Nothing typed changes it.

Signed unified kernel image

Kernel, initramfs, OS release and command line are one EFI binary, signed for Secure Boot and loaded by a signed systemd-boot.

A command line that can't be edited

With Secure Boot on, the UKI ignores any command line from the boot loader, a boot entry or SMBIOS. init=/bin/sh and rd.shell=1 do nothing.

Tampering is refused

One changed byte, a stripped signature or an unsigned boot loader: it does not boot.

No shell on failure

Shipped images lock root and boot with rd.shell=0 rd.emergency=reboot. Emergency and rescue modes reboot; debug shells are removed or masked.

Kernel and runtime

Advanced hardening.

The config starts from allnoconfig and enables only what containers, VMs, microVMs, storage, networking and security need.

KSPP baselineThe Kernel Self Protection Project's recommended settings as the baseline
Clang hardeningkCFI control-flow integrity, zeroed stack variables and call-used registers, full structure randomisation
LockdownLockdown LSM in integrity mode stops root from changing the running kernel
Module signingModules signed at build time; unsigned ones refused (MODULE_SIG_FORCE)
LSM stackLockdown, Yama, Landlock, SELinux and BPF LSM
Attack surface64-bit only, no unprivileged BPF, io_uring off by default, no SysRq
Network exposureDefault-deny firewall; every listener declared and authenticated. LLMNR and mDNS off; smoke test fails any non-loopback listener
ServicesA disable-all preset: only journald, udev, logind, D-Bus, networkd, resolved, timesyncd and the serial console run
No build toolsNo compiler, assembler, linker or headers ship on nodes
Workload isolationContainers under Podman, and libkrun microVMs through crun's krun handler
The hub

The hub owns what should be. The agent owns what is.

Each node's desired state is one NATS KV key, written only by the hub's controller.

ls-api

Serves every resource from the OpenAPI 3.1 spec, backed by Postgres

ls-controller

Decides placement and drives rollouts

ls-ca

Issues node and user identities

ls-policy

Evaluates Cedar, deny by default

zot

Stores images and models, with a registry view of digests and signatures

Console

Built on starlight-ui, on the generated API client

Resources

Kubernetes-style, with spec, status and conditions. ETags, problem+json errors and server-sent-event watches. lsctl and the console are generated from the spec.

NodeMachineFleetAppModelRolloutAgreementPolicyDeviceDeviceClassCluster
$ lsctl apply -f - <<'EOF'
kind: App
metadata: { name: thermal-cam }
spec:
  image: zot.hub/cams/thermal@sha256:9c1e…
  quadlet: thermal-cam.container
  rollout: { batch: 10%, healthGate: Ready, autoRollback: true }
EOF
app/thermal-cam configured ✓

$ lsctl why thermal-cam --node yard-07
Agreement ag-31f2  state=running
  policy: site-has-camera  ✓ permit
  policy: gpu-not-required ✓ permit

Policies and agreements

Placement is decided by Cedar policy, deny by default. Every placement is recorded as an Agreement: which App, which node, which policies decided it, and its state (proposed, accepted, running, cancelled).

Registry

A read view over zot lists every image and model, its digests and signatures, and the Apps and Models that use it.

Updates

Apps and the OS, the same safe way.

  1. image v42 staged
  2. one reboot
  3. health gate
  4. v42 running ✓

health gate failed? → back to v41 automatically, no truck roll.

Updating applications

An App is an image digest plus a Podman Quadlet. The hub places it by policy, writes it into each node's desired state, and the agent starts it and reports Ready. Rollouts go in batches with health gates and roll back on their own.

Updating the OS

The OS image is part of each node's Machine resource. A new bootc image is staged, applied with one reboot inside the maintenance window, and rolled back if its health gate fails. Kernel args, network, storage and firewall changes use the same flow, and a network change that leaves a node less connected reverts on its own.

Messaging and connectivity

Three planes, each for what it does best.

Every subject, key, protocol and port is versioned with its own breaking-change check.

NATfarm-02NATship-11NATyard-07NATtower-3NATkiosk-9hub

iroh QUIC

Carries Every connection between machines: the NATS uplink, console, file transfer, Machine control

Why Nodes are addressed by key, not IP. Connections punch through NAT and fall back to the hub's own relays.

NATS JetStream

Carries Desired state (KV), status and events (streams), artifacts (object store), model requests (request/reply)

Why Each node runs a NATS leaf uplinked over iroh. Messages queue locally while the WAN is down and drain on reconnect.

Zenoh site mesh

Carries Device data at the site: sensors, cameras, SDRs

Why Low-latency peer-to-peer pub/sub between machines on one site. Multicast scouting is off.

The controller writes desired state to the ls_desired KV bucket; agents publish status on ls.status.<node> and events on ls.events.>. Every littlestar listener is authenticated, declared and bound to the one interface it serves.

AI serving and agents

Models are fleet resources, like apps.

Shipped as signed OCI artifacts, placed by Cedar policy, served on the node and reached over NATS.

Model serving

A Model names an artifact digest, a runtime (llama.cpp, vLLM or mistral.rs) and its GPU needs. Pulled once, cached in the NATS object store, served on the node. GPUs via CDI.

One subject contract

Every model answers on models.<id>.{chat,embed,status} with request/reply and queue groups. A remote provider can stand behind the same subjects.

Agents over NATS

Edge agents speak the Synadia Agent Protocol and discover tools through NATS micro services. Every tool call is authorised by Cedar; model output is data, never instructions.

Model rollouts

Send a share of nodes the new model, gate on eval scores, roll back automatically.

SystemAI

The hub's operations assistant answers “is the fleet healthy, and if not, why and what do I do?” from the docs and live, read-only fleet state. It acts as the asking user and is authorised by the same Cedar decision.

The base for Starlight

Starlight for your organization. littlestar for your machines.

The hub is a Starlight plugin

Hub services ship as container images and Quadlet units in a Starlight plugin, and also run standalone.

Identity flows down

Starlight is the OIDC issuer and pushes users and groups over SCIM. Starlight tokens never reach nodes.

Policy flows down

Starlight's Cedar policies are a parent set: littlestar can narrow access, never widen it.

Built for disconnection

Nodes enforce their last signed policy bundle for as long as they're offline. A monotonic serial stops an older bundle replacing it.

The upgrade · x0 clusters + s0 storage

littlestar-x. Kubernetes and storage that never lose a write.

littlestar-x turns any littlestar site into a private Kubernetes cloud. It adds two integrated components: x0 delivers isolated clusters, each node in its own microVM, and s0 turns the local NVMe in your nodes into replicated block storage under them. Same OS, same hub, same API, switched on as an upgrade, from a minimum of two nodes and a small witness.

Thoroughly tested against server loss, power cuts and network splits.

x0 Real clusters. Real isolation. Your servers.

A microVM per node

Every controller and worker runs in its own libkrun microVM with its own kernel, disk and network identity. One cluster can't see or starve another.

Standard Kubernetes inside

k0s or k3s (Kubernetes 1.36), with the same kubectl, Helm charts and operators teams use today.

Many clusters per server

Capacity is reserved up front across servers. A request that won't fit is refused at once, never left half-built.

One operator surface

x0ctl (CLI and terminal UI) creates, scales, upgrades and deletes clusters; x0ctl kube runs kubectl with credentials delivered for you.

A management plane that survives

x0d runs active/passive behind one floating address, with its own state on a replicated s0 volume.

Secure by default

Mutual TLS between every component, an identity per host and cluster, SELinux enforcing and FIPS mode.

s0 Replicated block storage that never guesses.

Two copies plus a witness

Every acknowledged write is on two servers. A small witness breaks ties so a split network never produces two writers.

Native to Kubernetes

The s0-csi driver gives clusters dynamic volumes, online expansion, snapshots and clones through standard StorageClasses.

Mature parts, small control plane

OpenZFS for data, kernel NVMe/TCP for transport, DRBD 9 for replication. s0 adds identity, placement, writer ownership, fencing and audit.

Thin or thick

Thin volumes with overcommit limits and capacity alarms; thick volumes keep writing even when thin space runs out.

Fenced takeover

A copy takes over only after a majority agrees and the old writer is fenced. When copies diverge, s0 never picks a side.

Authenticated everywhere

mTLS 1.3 API with per-scope authorization, NQN allow-lists and bidirectional DH-HMAC-CHAP on NVMe/TCP.

Built for the bad day: when a server dies

  1. Applications keep writingVolumes whose writer was on the lost server move to the surviving copy; pods resume on their existing data.
  2. The operator confirms the lossStarlight never declares a server dead on its own, so a slow network can never cost data.
  3. Clusters healx0 replaces lost workers on healthy servers and restores single-controller clusters from replicated state, only if no write would be lost.
  4. The server returns safelyOn power-up it quarantines itself, retires its stale copies and rejoins only after the operator readmits it.
  5. Redundancy comes backs0 rebuilds the second copy, and every volume is protected again.

There is no “accept data loss” override anywhere. If a step can't be done safely, Starlight refuses it and says why.

Edge and remote sitesReplicated storage and many clusters from two or three commodity servers; safe recovery after power cuts.
Regulated and public sectorMicroVM per node, SELinux enforcing, FIPS mode, mutual TLS throughout.
Platform teamsA cluster per team or app from one CLI, densely packed, standard Kubernetes inside.
Stateful applicationsSynchronous two-copy volumes; writes acknowledged only once both copies have them.
bootc

Made in Rust.
Fearless by design.

We love Rust. It's memory-safe, fast and a joy to build with, so every littlestar component is written in it, and we reach for mature Rust tools wherever they exist. Everything else is built from verified source with security best practices at every step.

RustbootcirohNATS JetStreamZenohCedarSecure BootcomposefsPodman QuadletsOpenAPI 3.1uutilslibkrun

Sleep through your next update.

Source available to qualified government and critical-infrastructure partners.