---
task_id: souveraine-cicd-001
title: CI/CD pipeline — Souveraine as an installed program across laptop, phone, desktop/servers
status: partial
assignee:
priority: high
phase: infrastructure
---

# Task: Real build/install pipeline for Souveraine across all machines

## Implemented status — 2026-07-13

The core package rail is now real, although this document's original Gitea
native-registry design was implemented as a signed rolling Gitea Release
repository instead:

- ArchDev runs the `archdev` Actions runner and cross-builds `aarch64`; it also
  builds the native `x86_64` binary.
- CI produces and signs separate architecture-specific pacman databases and
  package assets for the `edge` release.
- The archive key is installed and locally trusted on the laptop. Its private
  Gitea credentials are held in a root-owned, `alpm`-readable netrc and used
  only by the internal archive fetch wrapper.
- Laptop installation is verified: `souveraine 0.1.r137.gc8c72ecbf222-1` owns
  `/usr/bin/souveraine`, runs as an enabled systemd user service, and is
  discoverable/upgradable through pacman.
- Phone rollout is pending the return of its USB/network connection. No phone
  data was changed after the link disappeared.

The remaining delivery gap is the QuickShell body. Core packages intentionally
ship no QML or ii overlay files. Its package boundary and safe opt-in adoption
contract now live in `quickshell-surface-package.md`.

## Casey's framing (2026-07-12)

Souveraine has been running as hand-shipped binaries + live edits while the
agent itself is "acting on its own memory stuff (good stuff)" — but it "needs
to be an installed program before too long, referencing the actual souveraine
builds." A fresh session should build the CI/CD pipeline between laptop,
phone, and desktop/servers — that makes more logistical sense than more
one-off deploys.

## What tonight's wrap already put in place (build on this, don't redo)

- `surfaces/quickshell/deploy.sh` — manifest symlink deploy, `--phone` mode
  (rsync + on-device symlinks). Live edits now land in a git tree.
  Committed 037dc06.
- `packaging/deploy-phone.sh` — ships cross-built binary + user unit to the
  phone; seed-id excluded (machine binding doctrine). Committed 2c218fb.
- `packaging/arch/PKGBUILD` — builds from a synced local checkout, no network
  fetch. Same commit. This is the "installed program" seed: `pacman -U` beats
  scp-to-/usr/local.
- `packaging/souveraine.service` — the systemd user unit.
- `scripts/build-cross.sh` (untracked — scripts/ is deliberately gitignored on
  the public branch; decide where build tooling lives when designing the
  pipeline).
- Infra facts: ArchDev LXC (10.10.20.123) is the build host; aarch64 sysroot
  at ~/aarch64-sysroot + ~/aarch64-blueline.toolchain.cmake (proven by the
  OpenAuto build); gitea (10.10.20.120:4455) is the source-of-truth remote and
  the kernel already follows a commit->gitea->ArchDev-build->flash loop worth
  imitating.

## DESIGN (settled 2026-07-12, verified against live infra — build to this)

Verified: gitea is 1.25.5 (Actions + native Arch package registry both in).
ArchDev already has cargo + BOTH rust targets (x86_64 + aarch64-unknown-
linux-gnu) installed. Missing: act_runner, registry enablement, workflow.

The spine: gitea is hub AND package server. No new services.

1. **act_runner on ArchDev** (host executor, NOT docker — unprivileged LXC,
   and the proven cross env lives on the host). Label `archdev`. Systemd
   service, registration token from gitea admin.
2. **Souveraine workflow** (.gitea/workflows/build.yml): on push to main —
   cargo build --release for both targets (aarch64 linker =
   aarch64-linux-gnu-gcc, already installed for the kernel), makepkg via
   packaging/arch/PKGBUILD for both CARCHes, upload .pkg.tar.zst to gitea's
   Arch registry (PUT /api/packages/Fimeg/arch/<repo>/<distro>).
3. **Clients** (phone aarch64, laptop/desktop x86_64) add to pacman.conf:
   [souveraine] Server = http://gitea…/api/packages/Fimeg/arch/<repo>/<arch>
   Install/upgrade = `pacman -Syu souveraine`. Same command fresh or
   upgrade (idempotence doctrine). Auth: token-user in URL, or set package
   registry visibility public while source repos stay private.
4. **pkgver from git describe** — start tagging releases; CI stamps the
   PKGBUILD pkgver so every package maps to a commit.
5. **Doctrine unchanged**: package NEVER carries seed-id or ~/.souveraine;
   systemd user unit ships in the package; per-machine identity stays.
6. **Migration**: first packaged install lands in /usr/bin + systemd unit
   path; then remove the hand-shipped /usr/local/bin/souveraine copies.
   deploy-phone.sh stays as the emergency/dev path, no longer the main one.
7. **Later, same rails**: souveraine-surfaces package (files to /usr/share,
   user opt-in symlink script; deploy.sh symlink mode stays the dev loop),
   and linux-blueline publishing to the same registry (flash stays a
   deliberate manual step via deploy-kernel.sh — never auto-flash).

**Agent session split** (three independent sessions, in order):
- **infra**: enable Actions + package registry in gitea app.ini, install +
  register act_runner on ArchDev, prove with a hello-world workflow and one
  hand-uploaded package installed via pacman on the laptop.
- **build**: the real workflow — both arches, pkgver stamping, registry
  publish. Deliverable: push to main produces installable packages.
- **rollout**: pacman.conf on phone + laptop, adopt packaged paths, retire
  hand copies, verify fresh==upgrade on both machines, then souveraine on
  the phone updates itself via one `pacman -Syu`.

## Shape to aim for (original sketch, superseded by DESIGN above)

1. Push to gitea -> CI builds (x86_64 + aarch64) on ArchDev (or a runner) ->
   versioned artifacts: pacman packages (PKGBUILD exists) or a small package
   repo machines can point at.
2. Install = `pacman -Syu souveraine` (or -U a fetched pkg) on phone and
   desktop; systemd unit from the package; /usr/local hand-copies retired.
3. Per-machine identity stays doctrine: packages NEVER carry seed-id or
   ~/.souveraine data; each instance is its own federated machine.
4. The quickshell surface rides the same train (package or the deploy.sh
   manifest — decide; symlink-into-checkout is the dev mode, package is the
   install mode).
5. Update path must be idempotent: same command fresh-installs AND upgrades.

## Related

- [[blueline-souveraine-kernel-os-provenance]] — partially superseded: the
  deploy script + PKGBUILD adoption happened 2026-07-12; the remaining audit
  (what else on the phone isn't repo-sourced) folds into this pipeline work.
- [[blueline-dock-provenance-and-deploy]] — the surface half, done via
  surfaces/quickshell.
