Files
salmanoff/distro/ubuntuCore/ubuntu-core-plan.md
T
hayodea 038d59f972 Add distro/ubuntuCore for UC26 snap and image builds.
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>
2026-06-25 23:01:52 -04:00

277 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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`, includes `avia0.dapss`.
- **SMO build profile** (CMake):
- `RelWithDebInfo`
- `ENABLE_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):
```bash
salmanoff -d /usr/share/salmanoff/devices/bodies/body_yocto_qemu_x86_headless.daps -p /usr/lib -v
```
(exact installed `.daps` filename 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 on `clast`).
- SMO source changes on `clast`: headless body, flex/bison repo-relative `#line` paths, etc.
- Fetch uses private Gitea (`hayodea/salmanoff`, branch `clast`, submodules via `libspinscale` on separate SSH host alias).
---
## Conceptual goals (portable to Ubuntu Core)
These are the **intent** items — independent of BitBake:
1. **Repeatable dev environment** — headless guest on `10.42.0.16`, reachable from laptop, Livox at `10.42.0.139`.
2. **SMO as first-class payload** — not “install deps manually”; runtime + `.daps` bodies + plugin `.so`s packaged and startable.
3. **Same CMake feature profile** as Yocto (lcamera + OpenCL enabled; xcb/PCL tools off).
4. **OpenCL that actually works headless** — Rusticl/llvmpipe with env var set before SMO starts.
5. **libcamera stack present** — libraries available even when no camera device is passed through (QEMU/UC dev).
6. **Boost version constraint honored** — do not silently pick Boost ≥ 1.89.
7. **Production path to RPi5** — same snap(s), different body/IP (`10.42.0.2`), gadget/kernel for Pi hardware.
8. **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 — **dont 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_OECMAKE` block
- Install: `salmanoff` binary, `lib*.so*`, `/usr/share/salmanoff/devices/**`
- Apps: main daemon + optional `salmanoff.probe` for debugging
**Runtime environment**:
```yaml
environment:
RUSTICL_ENABLE: llvmpipe
```
**Interfaces to evaluate early** (exact set TBD by confinement testing):
- `network` / `network-bind` — Livox UDP/TCP to `10.42.0.139`
- `hardware-observe` — may be needed for camera discovery on Pi
- `camera` — for libcamera on production Pi
- `opengl` — if Mesa GL stack needed beyond OpenCL ICD
- `raw-usb` / `serial-port` — only if Livox path requires it on some platforms
- `home` — usually **avoid**; use `$SNAP_DATA` for state
**Layouts** (likely needed):
- OpenCL ICD loader expects `/etc/OpenCL/vendors` or known `LD_LIBRARY_PATH`
- May need `layout:` bind mounts for Mesa `libRusticlOpenCL.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.dapss` with same Livox-only intent and `smo-ip=10.42.0.16`.
- **Production (RPi5)**: reuse/adapt existing `rpi5-persys-headless.dapss` pattern with `smo-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) with `snapcraft.yaml` skeleton
- [ ] Document lab IP table and bridge prerequisites (port `runqemu-salmanoff-bridge` concepts)
- [ ] Link to SMO `clast` branch + submodule SSH host requirements
### Phase 1 — Build snap on host (no hardware)
- [ ] `snapcraft` / `craft` builds 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; verify `salmanoff -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` → `clinfo` shows ≥1 device **inside snap**
- [ ] Confirm `liblcameraDev` / `liblcameraBuff` load; 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 `salmanoff` snap (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.2` netplan
- [ ] 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)
1. **OpenCL**: platform visible but **0 devices** until `RUSTICL_ENABLE=llvmpipe`.
2. **Memory**: 256M insufficient for Rusticl/`clinfo`; use **2G** for dev VM.
3. **Boost**: must stay **< 1.89** (shared `boost-system` linkage).
4. **Submodules**: `libspinscale` is mandatory; fetch must be recursive; separate SSH host alias on Gitea.
5. **lcamera without hardware**: compile and ship libs; no QEMU camera passthrough required for basic bring-up.
6. **PCL / xcb**: keep off unless explicitly needed (MPI/cmake pain in Yocto).
7. **Private git**: snapcraft build needs SSH keys / credentials for Gitea fetch (or vendored source tarball part).
8. **Strict confinement**: biggest unknown vs Yocto — plan devmode → strict iteration; interfaces will take multiple passes.
9. **rseq kernel feature**: validate on UC base; custom kernel snap is expensive — only if probe fails.
---
## Success criteria (match Yocto milestone)
Minimum “were at parity” for UC dev:
- [ ] UC VM at `10.42.0.16` on `10.42.0.0/24` via host bridge
- [ ] `salmanoff` snap installed and daemon running (or manual `snap run` equivalent)
- [ ] 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.2` with 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
1. **Treat Yocto work as validated reference**, not something to re-derive from scratch.
2. **Preserve lab IP plan and CMake profile** unless user says otherwise.
3. **Start with snapcraft build on host**, then UC VM, then strict confinement — same order we used (build → package QA → runtime).
4. **Plan for `distro/ubuntuCore/` in SMO** as the final home of snaps/gadget/model/scripts.
5. **Ask before** committing snaps into SMO; user will commit when done.
6. **Do not** assume UC has openssh or classic Ubuntu package management — everything is snaps + interfaces.