A minimal end-to-end walkthrough to build, boot and update a CuOS based system.
Audience: Engineers who want to try CuOS quickly (Variant 2 or 3 style) without reading all reference docs first.
Prerequisites: Linux/macOS build host, Docker,
jq, ~6 GB free disk space, a VM platform (QEMU/VirtualBox/Proxmox) or spare USB device.
If you only want a running system, you do not need this repository. Clone cuos-release, write a
system.jsonand run./cuos-release/tool.sh image— its README walks you through it. This page is for looking inside afterwards.
git clone https://github.com/cuos-dev/cuos.git
git clone https://github.com/cuos-dev/cuos-release.gitThis repository is the OS. Focus areas:
system/→ Base system Dockerfiles / CuOS servicesimage-factory/→ Raw disk image creationinstaller-factory/→ (Optional) ISO installersystem/cuos/→ Runtime scripts (API, update, init)
cuos-release is the build tooling: tool.sh runs the two factories above as
containers. The commands below are run from the directory holding both
checkouts, which is where output/ appears.
system.json drives system identity & updates. Minimal example (x86_64):
{
"os_image": "ghcr.io/cuos-dev/cuos-system",
"os_image_version": "latest",
"os_image_digest": "",
"updater_image": "ghcr.io/cuos-dev/cuos-updater",
"updater_image_version": "latest",
"updater_image_digest": "",
"init_image": "ghcr.io/my-org/my-init-app",
"init_image_version": "latest",
"init_image_digest": ""
}Place it beside the two checkouts, as system.json.
Tip: For production pin versions & use digests — or
"#include": ["cuos-release/release.json"], which pins them for you. It also pins CuOS IaC asinit_image, so leave that key out unless you bring your own container — see Your CuOS Init App.
tool.sh runs the image factory (raw BTRFS based target image):
./cuos-release/tool.sh image ./system.jsonResult: a .img in ./output/, named after your configuration —
./cuos-release/tool.sh name ./system.json prints the name.
Raw image can be started directly; allocate enough RAM & enable UEFI if desired.
IMAGE="output/$(./cuos-release/tool.sh name ./system.json).img"
qemu-system-x86_64 \
-m 2048 \
-drive format=raw,file="${IMAGE}" \
-nographic(Use another terminal with screen/tmux if no graphical console.)
Alternatively write to a USB device (DANGEROUS – ensure of= is correct!):
sudo dd if="${IMAGE}" of=/dev/sdX bs=4M status=progress conv=fsyncDuring first boot CuOS will:
- Mount BTRFS subvolumes (@os, @data, @swap)
- Initialize network (DHCP if not configured)
- Start CuOS services (
cuos-init,cuos-api,cuos-applogic) - Pull & run the
init_imageas containercuos-app
Verify:
cuos version
cuos state
cuos resourcesCheck logs:
cuos logYour CuOS Init App should be running:
docker ps | grep cuos-appEdit system.json locally and change os_image_version (or point to a forked custom image).
Example update trigger:
NEW_CONFIG=$(jq '.os_image_version = "next"' system.json)
cuos update - <<< "{\"config\": $NEW_CONFIG }"Observe update flow:
- Image pull & inactive subvolume preparation
- Boot config flip
- Reboot (if required)
- Post-boot state becomes
running
If no OS change was needed but config changed (e.g. only network):
- Update command returns exit code 0, system may not reboot
- Config applied in-place, app container may restart
Rollback (if you want to test):
cuos rollbackPatch hostname:
echo '"my-host"' | cuos patch-hostname -Patch network adapter 0 to DHCP:
cat <<EOF | cuos patch-network -
{
"network_id": 0,
"config": { "dhcp": true }
}
EOFTouch the trigger file or patch config:
touch /data/run-update
systemctl restart cuos-app.serviceOr change init_image_version via update or patch.
Inside the OS your app container can request system info through the socket (see API reference):
/var/run/cuos.sock
cuos factory-resetThis schedules asynchronous reset (logs in /data/log/factory-reset.log).
cuos reboot
cuos shutdown- Read the Glossary (
docs/common/glossary.md) to align terminology. - Explore
system/cuos/api.shfor full command list. - Dive into BTRFS layout (
docs/common/btrfs-usage.md). - Learn more about the CuOS Init App concept.
| Symptom | Quick Check |
|---|---|
| App not starting | journalctl -u cuos-app.service -b |
| Update stuck | cuos log last events; network / DNS? |
| Network dead | Validate config, try DHCP patch |
| Wrong version | cat /etc/image vs config intention |
For deeper guidance (planned): docs/common/troubleshooting.md.
- Pin versions / use digests for critical images.
- Restrict registry credentials (avoid embedding secrets in immutable images).
- Limit privileged flags in the app container unless strictly needed.
Boot → systemd → cuos-init → (config apply) → cuos-api socket → cuos-app-init (pull/run app) → steady state
Update: cuos update → prepare new @os → boot switch → verify → old becomes rollback target
- Have system.json? ✔
- Built image? ✔
- Booted & reached running state? ✔
- App container started? ✔
- Update path validated? ✔
You now have a baseline CuOS workflow running.