Strux OS
The open-source framework and device runtime.
You write a web frontend and a Go backend. Strux turns them into a complete, bootable image for your target hardware, kernel and bootloader included, and gives you one workflow to develop, build, flash, and update it.
curl -fsSL https://strux.sh/install.sh | shInstall
One command downloads the CLI for your machine and puts it on your PATH. Builds run inside Docker, so the host stays clean.
curl -fsSL https://strux.sh/install.sh | shThe script picks the right binary for Linux x64 and arm64 and for macOS on Intel and Apple silicon. Windows users download the executable from the releases page, where Debian and RPM packages and every plain binary are published too.
# check the install
0.3.0
| On your machine | Why |
|---|---|
| Dockerrequired | Every build step runs inside the strux-builder container. |
| Go 1.24+required | Compiles your backend in dev mode and powers type generation. |
| Node.js and npmrequired | Scaffolds and runs your frontend with Vite. |
| QEMUoptional | Boots your image on your laptop for strux run and strux dev. |
A project is two files and a board folder.
The frontend is a normal Vite project. The backend is one Go file whose exported fields and methods become the page's typed API. Everything hardware-specific lives under the board folder, so your app code stays the same across boards.
my-kiosk/
├── strux.yaml project configuration
├── main.go Go backend entry point
├── go.mod / go.sum pinned to the runtime matching your CLI
├── frontend/ your web app (Vite project)
│ └── src/strux.d.ts generated TypeScript types for the backend
├── bsp/
│ └── qemu/ board profile for local testing
│ ├── bsp.yaml BSP configuration
│ ├── scripts/ lifecycle scripts (make-image.sh)
│ └── overlay/ board-specific filesystem overlay
├── assets/
│ └── logo.png splash screen logo
├── overlay/ global filesystem overlay
├── strux-update.key update signing key (private, gitignored)
├── strux-update.pub update verification key (built into images)
└── .gitignore
Dev mode is where you spend your time.
One session builds a development image, boots it, and streams your changes to it. Frontend edits hot-reload through Vite. Go edits recompile and push the new binary in seconds. No reboot, no reflash.
strux dev
remote board
QEMU on your machine
A virtual machine with GPU acceleration where available, USB passthrough, and a serial console. No hardware needed.
Real boards on the bench
Boards find the dev server over mDNS, or over a USB cable when there is no network. Each board gets its own dev server.
A terminal UI with the whole picture
Logs from the app, the compositor, the system, Vite, and QEMU in one place, with filtering, an actions panel, and a build pane.
Headless for agents
The same session with plain log output on stdout, and the MCP endpoint for coding agents.
A build pipeline that knows what changed.
Every step runs inside the builder container and tracks its own inputs: source files, individual keys of your configuration, the builder image itself. A rebuild reruns only the steps whose inputs changed, and the first build is the slow one.
- 01FrontendGenerate strux.d.ts, then bundle the web app with Vite.
- 02ApplicationCross-compile the Go backend for the target architecture.
- 03Cage compositorCompile the Wayland compositor that runs the kiosk full-screen.
- 04WPE extensionCompile the bridge between WebKit and your Go process.
- 05Strux clientCompile the on-device lifecycle, update, and fleet agent.
- 06Base rootfsBootstrap a minimal Debian root filesystem.
- 07KernelCompile the board's kernel when the BSP configures one.
- 08BootloaderBuild U-Boot or GRUB when the BSP configures one.
- 09Post rootfsInstall packages, apply overlays, configure services.
- 10BSP scriptsRun the board's lifecycle hooks.
- 11BundleCollect every artifact for the image.
- 12Image assemblyWrite the bootable disk image, and the signed update bundle when updates are enabled.
The runtime: one API surface on every board.
Everything your app can call beyond its own code lives under window.strux in the page and on the Runtime object in Go. Built-in services work on every board. Board capabilities are stable Strux APIs whose implementation comes from the board support package.
main.go
You write
frontend/src/strux.d.ts
Generated
frontend/src/App.vue
You write
Built in
Every board, including QEMUstrux.bootHide the boot splash, reboot, power off.
strux.devRead and change the on-device dev-mode configuration.
strux.displayList and configure outputs: modes, layout, rotation, scale.
strux.profilesThe application profile selected at build time.
strux.projectName, versions, BSP, architecture, and build time of the running image.
strux.systemBSP name, CPU architecture, hardware model, hostname.
strux.updateUpdate progress and A/B slot state.
strux.capabilitiesWhich capabilities and optional features this device implements.
strux.ipcYour app's own event bus between Go and the page.
Board capabilities
Provided by the BSPstrux.audioMaster volume, mute, output routing. Optional auto-switching and capture.
strux.batteryBattery packs, power sources, aggregate charge, critical shutdown.
strux.cellularMobile data: SIM, registration, signal, data session, APN settings.
strux.deviceSigningA device-bound signing key and challenge signing in a trusted backend.
strux.networkWired-first interface management, DHCP and static IPv4.
strux.wifiScanning, connecting, saved profiles, IP configuration.
Ask before you call
A board that lacks a capability rejects every call to it with a clear error. The frontend asks strux.capabilities first, which is exactly what QEMU makes you handle in dev mode.
Optional features
A capability can declare method groups a board may implement on top of the contract, such as a microphone on an audio board. Availability is reported per feature.
Typed events
Services that own hardware push updates on their own channel, separate from your app's event bus, with payloads the runtime type-checks on the Go side.
One project, several products, several screens.
A profile tells your frontend which product experience an image should show, without teaching it board names. The display section maps pages of the same app to physical outputs, so one device can drive a touch panel and a wall display at once.
strux.yaml
profiles
bsp: qemu
profiles:
- name: kiosk
label: Self-service kiosk
bsp:
- qemu
- rt101-rk3568
- name: wallboard
label: Production wallboard
bsp:
- qemu
- hd215-rk3576strux.yaml
display
display:
monitors:
- path: /
resolution: 1920x1080
transform: 90
names: [DSI-1, Virtual-1]
- path: /tv
resolution: 1280x720
names: [HDMI-A-1, Virtual-2]Updates replace the whole OS, atomically.
A bundle is a complete root filesystem with a signed manifest. The device streams it into its idle slot, verifies it twice, and asks the bootloader to try the new slot a bounded number of times. A broken update rolls back by itself.
- Manifests are signed with RSA-PSS by a 4096-bit key the project owns. Keys under 4096 bits are refused, and there is no unsigned mode.
- The manifest pins the payload by size and SHA-256, so verifying the small manifest transitively verifies the whole image.
- The archive puts the manifest before the payload, which is what lets the device install straight from the stream with no temporary copy.
- A bundle names the board it was built for. A device refuses a bundle built for another.
- The boot environment is written twice so a power cut cannot lose the slot state.
strux.yaml
updates
update: enabled: true auto_bundle: true
# sign a bundle from the last build, then send it to a device
# or let a Fleet deliver it
Board support packages hold everything hardware-specific.
A BSP is a folder: the kernel and bootloader configuration, a filesystem overlay, lifecycle scripts that run at fixed points of the build, runtime extensions that provide capabilities, and the script that flashes the board. Your project ships with the QEMU one and grows a folder per board.
Kernel
Source, version, defconfig, configuration fragments, patches, device trees, and overlays. Open the kernel's own menuconfig inside the builder when you need it.
Bootloader
U-Boot, GRUB, systemd-boot, or a custom build, with the firmware blobs and device trees the board expects.
Lifecycle scripts
Hooks before and after every pipeline step, the image assembly step itself, and the flash script that runs on your machine.
Runtime extensions
Go providers for the capabilities the board can back: audio, battery, cellular, network, Wi-Fi, display backlight, and your own namespaces.
Overlay and packages
Files copied into the root filesystem for this board only, and the Debian packages it needs on top of the base.
Version compatibility
An extension can declare which Strux API versions it supports, so one BSP carries implementations for several releases from a single tree.
Every tool an agent needs, on one endpoint.
Strux dev embeds an MCP server with tools to observe the device, interact with it, and build and deploy, plus the documentation for the exact CLI version, embedded and searchable offline.
Strux Local MCP
strux dev
Observe
device_status device_logs screenshot backend_bindings docs_search docs_read docs_list
Interact
click drag scroll pointer_move key type_text frontend_eval backend_call exec push_file
Build and deploy
watcher rebuild_app rebuild_components build_image create_update_bundle install_update flash_device reboot_device
Questions people ask first.
Building single-purpose devices: kiosks, digital signage, point-of-sale terminals, control panels, and exhibits. You write a web frontend and a Go backend; Strux turns them into a bootable Linux image and gives you one workflow for developing, building, updating, and operating it.