v0.1.2 — built on Raspberry Pi OS Lite (64-bit)

Flash. Boot.
Deploy anywhere.

piletOS turns your devices into self-managing nodes of your fleet. Deploy containers, ship updates over the air and watch state flow back. No cluster, no expertise, no downtime.

MQTT 5 broker pi-node-01 online · 12 ms pi-node-02 online · 8 ms pi-node-03 online · 21 ms pi-node-04 online · 15 ms pi-node-05 online · 6 ms

One broker. Any number of Raspberry Pis. Deploy from anywhere.

Fragile scripts. Heavy clusters. Meet the middle.

Managing IoT devices usually means brittle SSH scripts — or dragging a full orchestrator to the edge. piletOS gives you the discipline of one with the footprint of the other.

Hand-rolled scripts

SSH loops, cron, copy-paste

  • Zero infrastructure to run
  • No desired state — what runs where lives in someone's head
  • A dropped connection mid-update leaves the device half-configured
  • Nothing heals itself after a power cut
the middle ground

piletOS

one tiny agent, one broker

  • Declarative and self-healing — declare it once, the device converges
  • MQTT-light: built for flaky networks and tiny hardware
  • OTA updates with zero workload downtime
  • Flash, boot, done — no expertise required

Kubernetes at the edge

k8s / k3s on every site

  • Declarative and self-healing
  • Control plane is heavy for small devices
  • Assumes stable, cluster-grade networking
  • Real ops expertise required to run well

A control plane in every device.

piletOS brings two worlds together — the proven ideas of the Kubernetes ecosystem, adapted to the realities of IoT: small devices, unreliable networks, no ops on site.

MQTT-native support

QoS 1, retained state, MQTT 5 request/response — lightweight messaging that thrives on unreliable networks.

OTA updates, zero downtime

One message updates the agent: fetch, verify sha256, install, hand off to systemd. Your containers never stop serving.

Every app is a container

Install, modify or delete any Docker workload with a single message. Ports, env vars, CPU and memory limits — all in the spec.

Automatic reconcile

Declare what should run and the device converges to it — drift, crashes and missed messages heal on the next sync.

Survives power cuts & restarts

Pull the plug, plug it back in. The node boots, re-lists its desired state and revives every workload — no hands required.

AsyncAPI compatible

Every topic and payload is specified in a machine-readable AsyncAPI 3.1 contract.

Deploy any service in one message.

A little simulation, right in your browser. Press Deploy and watch the messages fly.

not deployed

nginx

nginx:alpine

web server — port 80 → device :8000

pi-node-01

Ready
model
Raspberry Pi 4B
ip
192.168.1.41
capacity
4 cpu · 7820Mi
pilet
v0.1.2

containers

— none —

mosquitto — pilet/v1/pi-node-01/#

subscribed. waiting for messages…

http://raspberry-ip:8000

This site can't be reached

nothing is serving on :8000 yet — press Deploy

OTA — over-the-air updates

Update the fleet while it works.

One message per device updates pilet over the air. Each device downloads the new version, verifies it and swaps itself over — no SD card, no SSH, no site visit.

Your workloads keep serving the whole time. Zero downtime.

fleet — 6 devices

Staggered rollout — old and new versions coexist safely mid-update.

Fleet-ready in three steps.

No expertise required. If you can flash an SD card, you can run a fleet.

01

Flash with Raspberry Pi Imager

Open the official Raspberry Pi Imager and follow the steps — when prompted to choose an OS, pick Use custom and select the piletOS image you downloaded.

Raspberry Pi Imager Use custom pilet-os-0.1.2.img.xz Raspberry Pi OS Lite (64-bit) Ubuntu Server 24.04 LTS (64-bit)
02

Drop your config on the card

After flashing, re-insert the SD card: it shows up as a small boot drive on any computer. Open it, find pilet.env and fill in your broker, device name, admin password and Wi-Fi. Read once at first boot, then deleted.

# boot/pilet.env

PILET_BROKER_HOST=192.168.1.32

PILET_DEVICE_ID=pi-node-01

ADMIN_PASSWORD=change-me

WIFI_SSID="MyNet"

WIFI_PASSWORD="secret"

WIFI_COUNTRY=GR

03

Boot. That's it.

Power on and the node announces itself with a retained status snapshot. It's already reconciling — deploy from anywhere.

$ mosquitto_sub -t 'pilet/v1/+/status'

pi-node-01 Ready · 4 cpu · 7820Mi · pilet v0.1.2

pi-node-02 Ready · 4 cpu · 3792Mi · pilet v0.1.2

pilet-os-0.1.2.img.xz

654 MB download · 4.8 GB on card · sha256 5cf29e6e…e54d09

Raspberry Pi 3, 4 & 5 (64-bit).

Download image

Speak the contract.

The whole protocol is specified in a contract compatible with the AsyncAPI 3.1 spec. Below: trimmed examples of the real payloads.

{
  "apiVersion": "pilet/v1",
  "kind": "Device",
  "metadata": { "name": "pi-node-01" },
  "status": {
    "nodeInfo": {
      "model": "Raspberry Pi 4 Model B Rev 1.4",
      "architecture": "aarch64",
      "containerRuntimeVersion": "docker://27.1.1",
      "piletVersion": "0.1.2"
    },
    "capacity": { "cpu": "4", "memory": "7820Mi", "maxContainers": 20 },
    "conditions": [
      { "type": "Undervoltage", "status": "False", "reason": "PowerOK" },
      { "type": "ThermalThrottled", "status": "False", "reason": "CpuCool" }
    ],
    "images": [{ "names": ["nginx:alpine"], "sizeBytes": 20512000 }],
    "addresses": [{ "type": "InternalIP", "address": "192.168.1.41" }]
  }
}
Download asyncapi.yaml Open in AsyncAPI Studio

6 channels · typed payloads · machine-readable — generate docs, clients and mocks with the AsyncAPI toolchain.