Centralize salmanoff snapcraft, dangerous-model image scripts, and QEMU workflow so UC26 can be reproduced from the SMO repo without ubuntu-core-practice. Co-authored-by: Cursor <cursoragent@cursor.com>
12 KiB
Salmanoff on Ubuntu Core — Plan (derived from Yocto work)
Purpose of this document
This plan is not a translation of an original Yocto design doc. It reflects what we actually built and validated in the Yocto path, reframed as goals for Ubuntu Core. Use it as primary context when scaffolding snaps, gadget/model, and dev VM workflow.
When done, snap definitions and support files land in the SMO repo under:
smo/distro/ubuntuCore/
(parallel to the existing smo/distro/yocto/meta-salmanoff/).
What we proved in Yocto (facts, not aspirations)
We shipped a minimal headless image that runs the Salmanoff (SMO) cognitive robotics runtime on QEMU x86-64, bridged onto a lab LAN, talking to a Livox LiDAR on a fixed IP.
Lab network (canonical — carry forward unchanged)
| Host | IP | Role |
|---|---|---|
| Laptop / gateway | 10.42.0.1 |
Gateway + DNS |
| RPi5 (production target) | 10.42.0.2 |
Future production node |
| Dev guest (QEMU / UC VM) | 10.42.0.16 |
SMO dev runtime |
| Livox Avia | 10.42.0.139 |
LiDAR sensor |
Runtime configuration we validated
- Body file:
yocto-qemu-x86-headless.dapss— Livox-only, headless (no win0/camera),smo-ip=10.42.0.16, includesavia0.dapss. - SMO build profile (CMake):
RelWithDebInfoENABLE_LIB_lcameraDev=ON,ENABLE_STIMBUFFAPI_lcameraBuff=ON(libcamera + OpenCL YUV path compiled in; no camera passthrough needed in QEMU)ENABLE_LIB_xcbXorg=OFF,COMPILE_PCL_TOOLS=OFF,ENABLE_TESTS=OFF,ENABLE_LCAMERADEV_TOOLS=OFF- Git submodules required (
libspinscale, etc.)
- Runtime command shape (approximate):
(exact installed
salmanoff -d /usr/share/salmanoff/devices/bodies/body_yocto_qemu_x86_headless.daps -p /usr/lib -v.dapsfilename follows DAPSS build output naming)
Platform services / packages we pulled into the image
| Need | What we used in Yocto |
|---|---|
| SMO runtime + libs | salmanoff recipe (libspinscale, liblcameraDev, liblcameraBuff, liblivoxGen1, …) |
| Boost | Pinned 1.86 (shared boost-system; must stay < 1.89) |
| liburing | Runtime dep |
| libcamera + v4l-utils | Present on image; camera optional at runtime |
| OpenCL | Mesa Rusticl via opencl distro feature; needs RUSTICL_ENABLE=llvmpipe or platform shows 0 devices |
| OpenCL verify | clinfo (also discovered 256M RAM OOMs OpenCL probe — use ≥ 2G for dev VM) |
| Network | Static eth0: 10.42.0.16/24, gw 10.42.0.1 |
| Dev access | SSH (openssh on Yocto image) |
| Kernel probe | rseqsliceprobe + kernel config append for rseq slice extension |
| QEMU dev | Host bridge br-smo, runqemu with bridge=br-smo, nographic, -m 2048 |
Repo / packaging decisions already made in SMO
- Yocto layer vendored at
smo/distro/yocto/meta-salmanoff/(committed onclast). - SMO source changes on
clast: headless body, flex/bison repo-relative#linepaths, etc. - Fetch uses private Gitea (
hayodea/salmanoff, branchclast, submodules vialibspinscaleon separate SSH host alias).
Conceptual goals (portable to Ubuntu Core)
These are the intent items — independent of BitBake:
- Repeatable dev environment — headless guest on
10.42.0.16, reachable from laptop, Livox at10.42.0.139. - SMO as first-class payload — not “install deps manually”; runtime +
.dapsbodies + plugin.sos packaged and startable. - Same CMake feature profile as Yocto (lcamera + OpenCL enabled; xcb/PCL tools off).
- OpenCL that actually works headless — Rusticl/llvmpipe with env var set before SMO starts.
- libcamera stack present — libraries available even when no camera device is passed through (QEMU/UC dev).
- Boost version constraint honored — do not silently pick Boost ≥ 1.89.
- Production path to RPi5 — same snap(s), different body/IP (
10.42.0.2), gadget/kernel for Pi hardware. - Distro metadata lives in SMO —
distro/ubuntuCore/committed back into SMO when stable (mirrors Yocto layout).
Yocto → Ubuntu Core mapping
| Yocto (what we did) | Ubuntu Core (target) |
|---|---|
meta-salmanoff/ layer |
distro/ubuntuCore/ — snaps, gadget, model, helper scripts |
salmanoff-image.bb |
Model assertion + core + gadget snap + app snaps on seeded image |
salmanoff.bb recipe |
salmanoff snap (snapcraft.yaml: cmake build, submodules, organize libs + daps) |
IMAGE_INSTALL |
Snap stage-packages / parts / content snaps (mesa, libcamera deps) |
salmanoff-rusticl-env recipe |
Snap environment: block or wrapper script: RUSTICL_ENABLE=llvmpipe |
init-ifupdown static IP |
Netplan via gadget default config, network-setup snap, or system-connections on UC |
runqemu-salmanoff-bridge |
Dev VM script: UC image in QEMU/LXD/multipass on br-smo, static 10.42.0.16, 2G RAM |
DISTRO_FEATURES += opencl |
Ensure Mesa/OpenCL ICD available to snap (layout + plugs or bundled libs) |
DEPENDS / RDEPENDS |
Snapcraft build-packages, stage-packages, slots/plugs, layout: for /usr/lib ICD paths |
gitsm:// + SRCREV |
Snapcraft source + source-submodules or override-pull git submodule update |
yocto-qemu-x86-headless.dapss |
Installed by salmanoff snap; UC-specific body can be ubuntu-core-x86-headless.dapss later |
rseqsliceprobe |
Validate UC kernel/base; custom kernel snap only if probe fails on stock UC kernel |
| SSH on image | UC: serial console, ssh-keys in model, or dedicated snap — don’t assume openssh like Yocto |
| Boost 1.86 pin | Pin in snapcraft (stage-packages version) or build Boost part from source |
RelWithDebInfo + debug maps |
Snapcraft override-build cmake flags; consider debug snap or stripped separate artifact |
Proposed Ubuntu Core architecture
Host (10.42.0.1)
└── bridge br-smo (10.42.0.0/24)
└── UC dev VM / RPi5 (10.42.0.16 or .2)
├── snap: core (or core24)
├── snap: gadget-<platform> (boot, partitions, default netplan)
├── snap: salmanoff (daemon — main payload)
└── optional: mesa-support / libcamera-support content snaps if not bundled
salmanoff snap (primary deliverable)
Type: likely daemon (simple) or daemon (notify) once startup semantics are known.
Build (mirror Yocto recipe intent):
- Source: SMO repo
clast(submodules!) - CMake options: same as Yocto
EXTRA_OECMAKEblock - Install:
salmanoffbinary,lib*.so*,/usr/share/salmanoff/devices/** - Apps: main daemon + optional
salmanoff.probefor debugging
Runtime environment:
environment:
RUSTICL_ENABLE: llvmpipe
Interfaces to evaluate early (exact set TBD by confinement testing):
network/network-bind— Livox UDP/TCP to10.42.0.139hardware-observe— may be needed for camera discovery on Picamera— for libcamera on production Piopengl— if Mesa GL stack needed beyond OpenCL ICDraw-usb/serial-port— only if Livox path requires it on some platformshome— usually avoid; use$SNAP_DATAfor state
Layouts (likely needed):
- OpenCL ICD loader expects
/etc/OpenCL/vendorsor knownLD_LIBRARY_PATH - May need
layout:bind mounts for MesalibRusticlOpenCL.so/ gallium stack
Platform snaps
| Platform | Gadget | Notes |
|---|---|---|
| QEMU x86 dev | pc or custom gadget |
Static IP 10.42.0.16, 2G RAM, bridged NIC |
| RPi5 production | pi gadget (22+ arm64) |
Static IP 10.42.0.2, libcamera, Livox |
Bodies / config
- Dev (UC VM): start from Yocto body or add
ubuntu-core-x86-headless.dapsswith same Livox-only intent andsmo-ip=10.42.0.16. - Production (RPi5): reuse/adapt existing
rpi5-persys-headless.dapsspattern withsmo-ip=10.42.0.2.
Body files stay in SMO devices/bodies/; snap selects default via config or snap config hook.
Phased plan (recommended order)
Phase 0 — Repo scaffold
- New repo (or
distro/ubuntuCore/in SMO) withsnapcraft.yamlskeleton - Document lab IP table and bridge prerequisites (port
runqemu-salmanoff-bridgeconcepts) - Link to SMO
clastbranch + submodule SSH host requirements
Phase 1 — Build snap on host (no hardware)
snapcraft/craftbuilds SMO with same CMake profile as Yocto- Confirm submodule pull (
libspinscale) in clean CI/local environment - Resolve Boost < 1.89 (stage-package pin or source part)
- Package
.daps+ shared libs; verifysalmanoff -v/ dry-run in snap run environment
Phase 2 — OpenCL + libcamera in confinement
- Replicate Yocto OpenCL stack inside snap (bundled vs system Mesa)
- Confirm
RUSTICL_ENABLE=llvmpipe→clinfoshows ≥1 device inside snap - Confirm
liblcameraDev/liblcameraBuffload; no crash without camera device - Document RAM requirement (≥ 2G for dev VM)
Phase 3 — UC dev VM on lab LAN
- Boot Ubuntu Core x86 VM bridged to
br-smo - Static IP 10.42.0.16 (netplan/gadget)
- Install seeded
salmanoffsnap (devmode first, then strict) - Ping gateway; reach Livox at
10.42.0.139 - Run headless body; validate Livox traffic / SMO logs
Phase 4 — Production path (RPi5)
- Model assertion for Pi5 + arm64 core
- Gadget with
10.42.0.2netplan - libcamera plug + Pi body file
- OTA refresh via snap channels
Phase 5 — Commit back to SMO
- Move stable
distro/ubuntuCore/into SMO repo - Commit on
clast(or dedicated branch); do not block on unfinished WIP snaps
Known constraints & pitfalls (from Yocto — expect repeats)
- OpenCL: platform visible but 0 devices until
RUSTICL_ENABLE=llvmpipe. - Memory: 256M insufficient for Rusticl/
clinfo; use 2G for dev VM. - Boost: must stay < 1.89 (shared
boost-systemlinkage). - Submodules:
libspinscaleis mandatory; fetch must be recursive; separate SSH host alias on Gitea. - lcamera without hardware: compile and ship libs; no QEMU camera passthrough required for basic bring-up.
- PCL / xcb: keep off unless explicitly needed (MPI/cmake pain in Yocto).
- Private git: snapcraft build needs SSH keys / credentials for Gitea fetch (or vendored source tarball part).
- Strict confinement: biggest unknown vs Yocto — plan devmode → strict iteration; interfaces will take multiple passes.
- rseq kernel feature: validate on UC base; custom kernel snap is expensive — only if probe fails.
Success criteria (match Yocto milestone)
Minimum “we’re at parity” for UC dev:
- UC VM at
10.42.0.16on10.42.0.0/24via host bridge salmanoffsnap installed and daemon running (or manualsnap runequivalent)- Headless Livox body loaded; SMO stable with Livox on
10.42.0.139 - OpenCL initialized (llvmpipe); lcamera libs present
- Snap definitions committed under
smo/distro/ubuntuCore/
Stretch (production):
- Same snap on RPi5 at
10.42.0.2with Pi-appropriate body
Explicit non-goals (for now)
- Re-implement Yocto layer / BitBake in UC repo
- Camera passthrough in QEMU/UC x86 dev
- PCL tools / xcb window stack
- lcameraDev probe tools (need test support libs — off in Yocto too)
- Full OTA/signing production pipeline (Phase 4+)
Reference: Yocto artifacts in SMO repo
When unsure, read the working Yocto implementation:
smo/distro/yocto/meta-salmanoff/
conf/layer.conf
conf/salmanoff-local.inc # opencl distro feature
recipes-salmanoff/salmanoff/salmanoff.bb
recipes-core/images/salmanoff-image.bb
recipes-core/init-ifupdown/... # 10.42.0.16 static IP
recipes-support/salmanoff-rusticl-env/
scripts/runqemu-salmanoff-bridge
smo/devices/bodies/yocto-qemu-x86-headless.dapss
SMO branch: clast on hayodea/salmanoff (Gitea).
Instructions for the LLM in the Ubuntu Core repo
- Treat Yocto work as validated reference, not something to re-derive from scratch.
- Preserve lab IP plan and CMake profile unless user says otherwise.
- Start with snapcraft build on host, then UC VM, then strict confinement — same order we used (build → package QA → runtime).
- Plan for
distro/ubuntuCore/in SMO as the final home of snaps/gadget/model/scripts. - Ask before committing snaps into SMO; user will commit when done.
- Do not assume UC has openssh or classic Ubuntu package management — everything is snaps + interfaces.