Merge pull request 'pi/main-live-boot-xfce-colibri-fixes' (#4) from pi/main-live-boot-xfce-colibri-fixes into main

Simplifying Clawdie service
This commit is contained in:
clawdie 2026-06-02 09:00:33 +02:00 committed by 123kupola
parent 7768edc39f
commit 8febb8e506
26 changed files with 1140 additions and 267 deletions

428
AGENTS.md
View file

@ -1,218 +1,216 @@
1|# Clawdie ISO Agent Guidelines
2|
3|## Agent Identity and Current Role Split
4|
5|The XFCE operator USB work now uses a git-coordinated split. Agents may review
6|or suggest across boundaries, but should not silently take over another role's
7|load-bearing responsibility.
8|
9|| Role name | Identity | Owns | Restrictions |
10|| ---------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
11|| **Pi ISO Developer** | Pi harness (this dev agent) | Source changes, docs, static checks, commits, pushes | Does not start ISO builds or flash media unless explicitly assigned |
12|| **Codex ISO Builder** | codex pkg on the FreeBSD 15 build host | `./build.sh`, mounted-image inspection, publishing, hardware validation | Should avoid broad source refactors; reports exact logs/output back through git or handoff notes |
13|| **Hermes USB/IMG Deployer** | Hermes on Debian/Linux | Downloading verified published artifacts, USB target identification, flashing | Does not need Codeberg (mirror only); pushes to Forgejo exclusively |
14|| **Claude Reviewer / XFCE Tweaker** | Claude (Linux) | Review/plans plus Track E XFCE GUI polish | Cannot build ISO, cannot run FreeBSD-only validation, should mark speculative runtime claims as such |
15|| **Opencode / Z.ai Integrator** | Opencode CLI on Linux | Linux-side Herdr/dashboard experiments plus Pi/DeepSeek v4 provider-lane smoke wiring | Cannot claim FreeBSD runtime proof; uses Sam-provided API keys only for provider validation |
16|| **Operator (Sam)** | Human operator | Product, hardware, acceptance, release judgment | Human approval required for release/tagging decisions |
17|
18|### Git Coordination Rules
19|
20|- Coordinate through git: fetch before commenting on remote state, push small
21| reviewable commits, and include test/build status in commit messages.
22|- Claude may push critique/suggestion commits, but Pi ISO Developer should
23| re-check and adjust implementation details before the next build target is
24| treated as final.
25|- Codex ISO Builder consumes pushed build targets, builds/publishes artifacts,
26| and reports hardware findings with exact commands and output.
27|- Hermes USB/IMG Deployer consumes published artifact URLs/manifests, verifies
28| checksums on Linux, identifies the USB target, and owns the final image-to-USB
29| deployment handoff.
30|- Opencode / Z.ai Integrator owns Linux-side Herdr/dashboard experiments and
31| the Pi/DeepSeek v4 smoke lane when Sam provides a `ZAI_API_KEY`; findings
32| should come back as exact commands, output, provider/version notes, and small
33| manifests/summaries that Colibri can ingest.
34|- If a change needs a long ISO build, USB flash, or real hardware proof, hand it
35| to the owning role instead of running it opportunistically.
36|
37|### Markdown Formatting Gate
38|
39|Markdown formatting is tool-owned, not taste-owned. Before pushing any commit
40|that edits `*.md`, run:
41|
42|```sh
43|./scripts/check-format.sh
44|```
45|
46|If it fails, format only the touched markdown files, then rerun the check:
47|
48|```sh
49|npx --yes prettier@3 --write path/to/file.md
50|```
51|
52|Do not hand-align Markdown tables or reflow prose manually. `.prettierrc` uses
53|`proseWrap: preserve` so existing prose line breaks stay intentional, while
54|Prettier still catches table padding, list spacing, and emphasis drift.
55|
56|### Private Planning Workspace
57|
58|`private/` is gitignored and may contain operator-private strategy notes or PRDs.
59|Agents on this host may read files there only when directly relevant to the
60|assigned work. Do not commit, quote, summarize publicly, or copy private content
61|to Forgejo unless the operator explicitly approves it.
62|
63|If working on custom ISO / hardware-report monetization, check
64|`private/PRD-CUSTOM-ISO.md` when present. Codex ISO Builder should focus first
65|on the local-only `hw-report` feasibility path and, after analysis,
66|return concise action notes for Claude Reviewer / XFCE Tweaker on what GUI
67|surface should expose for report collection and review.
68|
69|### Linux Agent Constraints
70|
71|Linux agents MUST NOT attempt to build the ISO (`./build.sh`, `./build-vps.sh`).
72|ISO builds require FreeBSD 15 system tools (`mdconfig`, `mount_msdosfs`, `pkg`).
73|Instead, guide Codex ISO Builder with exact commands to run on the FreeBSD 15
74|system.
75|
76|Agents on any platform MUST NOT start a new ISO build unless explicitly assigned.
77|Builds are long-running, mutate repo-local caches, and can leave mounted md(4)
78|devices that require cleanup.
79|
80|### Colibri Dependency
81|
82|The ISO build stages FreeBSD-native Colibri control-plane artifacts from the
83|adjacent `../colibri` checkout (`FEATURE_COLIBRI=YES` is the default lane). The
84|staging is wired into `build.sh` and `scripts/stage-colibri-iso.sh`; the ISO
85|does **not** build Rust while the image is mounted.
86|
87|- Build Colibri release artifacts on the FreeBSD/OSA host, not on Debian/Linux.
88|- Build order, binary verification, and cleanup timing live in the `iso-build`
89| skill (§Colibri artifact preflight).
90|- Staging layout (installed paths, rc.d, directory ownership) is owned by
91| Colibri `docs/ISO-INTEGRATION-PLAN.md`.
92|- Required by ISO preflight: `colibri-daemon`, `colibri`, `colibri-smoke-agent`.
93| `colibri-tui` is optional in staging code but desired for this USB target and
94| should be verified alongside the other three.
95|
96|**Invariant:** do not `cargo clean` the Colibri checkout until the ISO
97|preflight/build has consumed `../colibri/target/release`.
98|
99|---
100|
101|## Current XFCE Operator USB Baseline
102|
103|The active branch target is the XFCE live operator USB. Authoritative state
104|lives in `packages/` (what ships) and `PLAN-OPERATOR-USB-NEXT.md` (round-scope
105|decisions and any "for now" retention notes). Final graphical validation
106|requires real hardware — do not treat bhyve, nested VMs, or static image
107|inspection as final proof that SDDM/XFCE works.
108|
109|---
110|
111|## System Configuration
112|
113|**Privilege model:** distinguish build-host administration from live-USB runtime.
114|
115|- On the FreeBSD 15 build host, operator-facing commands may use `sudo`.
116|- Inside the live USB, `sudo` is intentionally absent (deleted via `pkg delete -f sudo`).
117|- Live privileged actions use FreeBSD `mac_do` via `mdo -u root <command>`.
118|- `~/.bashrc` aliases `sudo``mdo -u root` for muscle-memory compatibility.
119| The shell function wraps `mdo` with a fire-and-forget ZFS snapshot
120| (`zroot@cli-<timestamp>`) before each privileged invocation, so rollback
121| is always available without confirmation prompts or warning popups.
122|- Agent runtime code must not shell out to `sudo` for privileged host changes.
123|- Privileged Clawdie-AI host operations go through the hostd RPC layer.
124|
125|**Why `sudo` as alias, not as pkg:**
126|
127|| Approach | Install sudo pkg | Alias to mdo |
128|| ------------------- | ------------------------ | ---------------------------- |
129|| Extra package | Yes (sudo + deps) | No |
130|| Two privilege paths | `sudo` AND `mdo` coexist | Single path (`mdo`) |
131|| Audit surface | Two tools to audit | One kernel-enforced MAC |
132|| ZFS safety net | Requires sudoers hooks | Built into bash function |
133|| Agent confusion | Agents try both paths | Agents use `sudo`, get `mdo` |
134|| ISO size | Larger | Zero bytes |
135|
136|The alias approach keeps the ISO lean, eliminates dual-privilege-path
137|confusion, and bakes ZFS rollback safety directly into the operator shell.
138|`mac_do` is FreeBSD base system — no package dependency, kernel-enforced,
139|auditable via MAC framework.
140|
141|---
142|
143|## Installer Temp Files
144|
145|The GUI installer uses `/tmp/clawdie-install.conf` to pass wizard values to
146|`firstboot.sh`. This is an exemption from the project-local `tmp/` rule.
147|
148|**Rationale:**
149|
150|- Live ISO has no project root
151|- Single-user install phase (no other users on the system)
152|- File is consumed once by `firstboot.sh` then deleted on reboot
153|- PF firewall is not yet running during install
154|
155|**Applies to:**
156|
157|- `/tmp/clawdie-install.conf` — GUI wizard config output
158|- `/tmp/clawdie-firstboot.*` — firstboot progress and log (written by rc.d)
159|
160|## Repo-local ISO Build Workspace
161|
162|ISO builds use repo-local `tmp/` for large caches and output artifacts:
163|
164|- `tmp/cache` — build cache
165|- `tmp/cache/mnt` — temporary md(4) work-image mountpoint
166|- `tmp/output` — generated `.img.gz` artifacts and checksums
167|- `tmp/packages` — fetched package archives
168|
169|`tmp/cache/mnt` is an ISO-builder-specific mountpoint exception. Do not mount
170|unrelated datasets, recovery filesystems, or scratch filesystems elsewhere under
171|repo `tmp/`. If a build is interrupted, use the `iso-build-cleanup` skill before
172|retrying.
173|
174|---
175|
176|## Cross-Repo Coordination
177|
178|Clawdie spans three repos. Changes often require coordinated updates.
179|
# Clawdie ISO Agent Guidelines
## Agent Identity and Current Role Split
The XFCE operator USB work now uses a git-coordinated split. Agents may review
or suggest across boundaries, but should not silently take over another role's
load-bearing responsibility.
| Role name | Identity | Owns | Restrictions |
| ---------------------------------- | ----------------------------------- | ------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| **Pi ISO Developer** | Pi harness (this dev agent) | Source changes, docs, static checks, commits, pushes | Does not start ISO builds or flash media unless explicitly assigned |
| **Codex ISO Builder** | codex pkg on the FreeBSD build host | `./build.sh`, mounted-image inspection, publishing, hardware validation | Should avoid broad source refactors; reports exact logs/output back through git or handoff notes |
| **Hermes USB/IMG Deployer** | Hermes on Debian/Linux | Downloading verified published artifacts, USB target identification, flashing | Does not need git-host access; never flashes unverified artifacts or partition paths |
| **Claude Reviewer / XFCE Tweaker** | Claude (Linux) | Review/plans plus Track E XFCE GUI polish | Cannot build ISO, cannot run FreeBSD-only validation, should mark speculative runtime claims as such |
| **Opencode / Z.ai Integrator** | Opencode CLI on Linux | Linux-side Herdr/dashboard experiments plus Pi/DeepSeek v4 provider-lane smoke wiring | Cannot claim FreeBSD runtime proof; uses Sam-provided API keys only for provider validation |
| **Operator (Sam)** | Human operator | Product, hardware, acceptance, release judgment | Human approval required for release/tagging decisions |
## Agent / Codebase Check-In Matrix
Use this as the lightweight "who checks in where" matrix while work spans
multiple repos. Pushed commits, mounted-image reports, manifests, or explicit
handoff docs are the expected check-in surface.
| Agent lane / identity | Primary codebase(s) | Typical check-in artifact |
| ------------------------------ | ------------------------------------ | -------------------------------------------------------------- |
| **Pi ISO Developer** | `clawdie-iso` | Small pushed commit on active branch plus static-check result |
| **Codex ISO Builder** | `clawdie-iso`, adjacent `../colibri` | Build log, mounted-image sweep, publish manifest, smoke notes |
| **Hermes USB/IMG Deployer** | published ISO artifacts | Checksum/manifest verification plus flash-target confirmation |
| **Claude Reviewer / Tweaker** | `clawdie-iso` | Review/GUI-polish commit or explicit handoff note |
| **Opencode / Z.ai Integrator** | `clawdie-ai`, `colibri` | Provider smoke output, small manifest, or handoff doc |
| **Operator (Sam)** | all three repos | Final acceptance note, branch choice, release/publish approval |
### Git Coordination Rules
- Coordinate through git: fetch before commenting on remote state, push small
reviewable commits, and include test/build status in commit messages.
- Claude may push critique/suggestion commits, but Pi ISO Developer should
re-check and adjust implementation details before the next build target is
treated as final.
- Codex ISO Builder consumes pushed build targets, builds/publishes artifacts,
and reports hardware findings with exact commands and output.
- Hermes USB/IMG Deployer consumes published artifact URLs/manifests, verifies
checksums on Linux, identifies the USB target, and owns the final image-to-USB
deployment handoff.
- Opencode / Z.ai Integrator owns Linux-side Herdr/dashboard experiments and
the Pi/DeepSeek v4 smoke lane when Sam provides a `ZAI_API_KEY`; findings
should come back as exact commands, output, provider/version notes, and small
manifests/summaries that Colibri can ingest.
- If a change needs a long ISO build, USB flash, or real hardware proof, hand it
to the owning role instead of running it opportunistically.
### Markdown Formatting Gate
Markdown formatting is tool-owned, not taste-owned. Before pushing any commit
that edits `*.md`, run:
```sh
./scripts/check-format.sh
```
If it fails, format only the touched markdown files, then rerun the check:
```sh
npx --yes prettier@3 --write path/to/file.md
```
Do not hand-align Markdown tables or reflow prose manually. `.prettierrc` uses
`proseWrap: preserve` so existing prose line breaks stay intentional, while
Prettier still catches table padding, list spacing, and emphasis drift.
### Private Planning Workspace
`private/` is gitignored and may contain operator-private strategy notes or PRDs.
Agents on this host may read files there only when directly relevant to the
assigned work. Do not commit, quote, summarize publicly, or copy private content
to Forgejo unless the operator explicitly approves it.
If working on custom ISO / hardware-report monetization, check
`private/PRD-CUSTOM-ISO.md` when present. Codex ISO Builder should focus first
on the local-only `hw-report` feasibility path and, after analysis,
return concise action notes for Claude Reviewer / XFCE Tweaker on what GUI
surface should expose for report collection and review.
### Linux Agent Constraints
Linux agents MUST NOT attempt to build the ISO (`./build.sh`, `./build-vps.sh`).
ISO builds require FreeBSD system tools (`mdconfig`, `mount_msdosfs`, `pkg`).
Instead, guide Codex ISO Builder with exact commands to run on the FreeBSD
system.
Agents on any platform MUST NOT start a new ISO build unless explicitly assigned.
Builds are long-running, mutate repo-local caches, and can leave mounted md(4)
devices that require cleanup.
### Colibri Dependency
The ISO build stages FreeBSD-native Colibri control-plane artifacts from the
adjacent `../colibri` checkout (`FEATURE_COLIBRI=YES` is the default lane). The
staging is wired into `build.sh` and `scripts/stage-colibri-iso.sh`; the ISO
does **not** build Rust while the image is mounted.
- Build Colibri release artifacts on the FreeBSD/OSA host, not on Debian/Linux.
- Build order, binary verification, and cleanup timing live in the `iso-build`
skill (§Colibri artifact preflight).
- Staging layout (installed paths, rc.d, directory ownership) is owned by
Colibri `docs/ISO-INTEGRATION-PLAN.md`.
- Required by ISO preflight: `colibri-daemon`, `colibri`, `colibri-smoke-agent`.
`colibri-tui` is optional in staging code but desired for this USB target and
should be verified alongside the other three.
**Invariant:** do not `cargo clean` the Colibri checkout until the ISO
preflight/build has consumed `../colibri/target/release`.
---
## Current XFCE Operator USB Baseline
The active branch target is the XFCE live operator USB. Authoritative state
lives in `packages/` (what ships) and `PLAN-OPERATOR-USB-NEXT.md` (round-scope
decisions and any "for now" retention notes). Final graphical validation
requires real hardware — do not treat bhyve, nested VMs, or static image
inspection as final proof that SDDM/XFCE works.
---
## System Configuration
**Privilege model:** distinguish build-host administration from live-USB runtime.
- On the FreeBSD build host, operator-facing commands may use `sudo`.
- Inside the live USB, `sudo` is intentionally absent.
- Live privileged actions use FreeBSD `mac_do` via `mdo -u root <command>`.
- Agent runtime code must not shell out to `sudo` for privileged host changes.
- Privileged Clawdie-AI host operations go through the hostd RPC layer.
---
## Installer Temp Files
The GUI installer uses `/tmp/clawdie-install.conf` to pass wizard values to
`firstboot.sh`. This is an exemption from the project-local `tmp/` rule.
**Rationale:**
- Live ISO has no project root
- Single-user install phase (no other users on the system)
- File is consumed once by `firstboot.sh` then deleted on reboot
- PF firewall is not yet running during install
**Applies to:**
- `/tmp/clawdie-install.conf` — GUI wizard config output
- `/tmp/clawdie-firstboot.*` — firstboot progress and log (written by rc.d)
## Repo-local ISO Build Workspace
ISO builds use repo-local `tmp/` for large caches and output artifacts:
- `tmp/cache` — build cache
- `tmp/cache/mnt` — temporary md(4) work-image mountpoint
- `tmp/output` — generated `.img.gz` artifacts and checksums
- `tmp/packages` — fetched package archives
`tmp/cache/mnt` is an ISO-builder-specific mountpoint exception. Do not mount
unrelated datasets, recovery filesystems, or scratch filesystems elsewhere under
repo `tmp/`. If a build is interrupted, use the `iso-build-cleanup` skill before
retrying.
---
## Cross-Repo Coordination
Clawdie spans three repos. Changes often require coordinated updates.
| Repo | Purpose | Remote |
| ------------- | ---------------------------------------- | -------------------------------------------------- |
| `clawdie-ai` | Agent runtime, control plane, channels | `git@code.smilepowered.org:clawdie/clawdie-ai.git` |
| ------------- | ---------------------------------------- | --------------------------------------------------- |
| `Clawdie-AI` | Agent runtime, control plane, channels | `git@code.smilepowered.org:clawdie/clawdie-ai.git` |
| `clawdie-iso` | ISO builder, firstboot wizard, installer | `git@code.smilepowered.org:clawdie/clawdie-iso.git` |
| `Colibri` | Cross-platform Rust control plane core | `git@code.smilepowered.org:clawdie/colibri.git` |
185|
186|When changes span repos, create a handoff doc in the secondary repo
187|listing what needs updating. See `Clawdie-AI/AGENTS.md` for full protocol.
188|
189|---
190|
191|## Agent Handoff Documents
192|
193|Use ephemeral handoff files to transfer context between agents.
194|
195|- **Name:** `doc/<FEATURE>-HANDOFF.md` or `<FEATURE>-HANDOFF.md` (repo root)
196|- **Lifecycle:** Create when handing off, delete when complete
197|- **Structure:** Must include task checklist, deletion criteria, results section
198|
199|See `Clawdie-AI/AGENTS.md` for the full handoff template and protocol.
200|
201|---
202|
203|## Attribution in Commit History
204|
205|Use attribution in commit messages, not in code comments.
206|
207|Labels:
208|
209|- `Sam & Codex` — changes made by Sam and Codex
210|- `Sam & Claude` — changes made by Sam and Claude
211|- `C&C` — joint change with equal credit for Claude and Codex
212|
213|Add the label to the commit subject or body. Example:
214|
215|```
216|Fix bhyve preflight checks (C&C)
217|```
218|
Primary remote: `code.smilepowered.org` (self-hosted Forgejo, SSH via local host
config). Codeberg is the public mirror only; do not treat it as the source of
truth for agent coordination or branch-state claims.
When changes span both repos, create a handoff doc in the secondary repo
listing what needs updating. See `Clawdie-AI/AGENTS.md` for full protocol.
---
## Agent Handoff Documents
Use ephemeral handoff files to transfer context between agents.
- **Name:** `doc/<FEATURE>-HANDOFF.md` or `<FEATURE>-HANDOFF.md` (repo root)
- **Lifecycle:** Create when handing off, delete when complete
- **Structure:** Must include task checklist, deletion criteria, results section
See `Clawdie-AI/AGENTS.md` for the full handoff template and protocol.
---
## Attribution in Commit History
Use attribution in commit messages, not in code comments.
Labels:
- `Sam & Codex` — changes made by Sam and Codex
- `Sam & Claude` — changes made by Sam and Claude
- `C&C` — joint change with equal credit for Claude and Codex
Add the label to the commit subject or body. Example:
```
Fix bhyve preflight checks (C&C)
```

View file

@ -90,7 +90,10 @@ When enabled, the image includes:
```
The build also creates the `colibri` service user/group and writes rc.conf
values for `colibri_daemon_enable`, paths, and `colibri_cost_mode`.
values for `colibri_daemon_enable`, paths, and `colibri_cost_mode`. Operator
USB builds stage Colibri by default but keep `colibri_daemon_enable=NO` unless
the build explicitly overrides `COLIBRI_DAEMON_ENABLE=YES`, so the daemon cannot
block SDDM/XFCE boot while service supervision is still being validated.
---

View file

@ -334,8 +334,8 @@ network setup hooks
```sh
ls -l /etc/resolv.conf
cat /etc/resolv.conf
host codeberg.org
ping -c 1 codeberg.org
host code.smilepowered.org
ping -c 1 code.smilepowered.org
```
#### 2. Touchpad base/input enablement and diagnostics
@ -614,6 +614,50 @@ Real-hardware acceptance should be recorded against `doc/AMD-ASUS-XFCE-LIVE-USB-
---
## 2.2. Live Self-Debug Code Checkout Seed
**Operator request — 2026-06-01 AMD live session:** the next rebuilt operator
USB should prepopulate the live `clawdie` home with the relevant source trees so
the operator can start a local `pi` session from XFCE, log in with a provider,
and let that agent inspect the live system and the shipped source side by side.
**Goal:** make the live USB self-debuggable without first cloning repositories
over a possibly flaky network.
**Candidate layout:** keep the source snapshots under one operator-facing
folder so `$HOME` stays uncluttered:
```text
/home/clawdie/ai/clawdie-iso
/home/clawdie/ai/clawdie-ai
/home/clawdie/ai/colibri
```
**Implementation notes:**
- Seed clean checkouts or source snapshots only; do not copy API keys,
`.env` files, SSH private keys, build caches, package caches, `tmp/`, or
other private host state.
- Prefer the exact branch/commit used by the image build, recorded in
`/usr/local/share/clawdie-iso/build-manifest.json` and visible from
`hw-report`.
- The snapshots should be owned by `clawdie:clawdie` and readable/writable from
XFCE terminals.
- Keep provider authentication manual. The image may include code, but it must
not bake provider credentials.
- If full `.git` history is too large, use shallow clones or archive snapshots
plus a small manifest that records remote URL, branch, commit, and dirty
state.
- This is a live-debug aid, not a build-host replacement: Linux agents still do
not build the ISO, and real hardware proof remains operator/Codex-owned.
**Why it matters:** when Colibri, XFCE, rc.d, input, or package-list bugs only
show up on real hardware, a local Pi session can read `/var/log`, `hw-report`,
XFCE config, and the source tree in the same environment where the bug occurs.
That shortens the loop between operator observations and source fixes.
---
## 3. Sequencing
Recommended order (each can be a separate PR / commit cluster):

View file

@ -98,7 +98,7 @@ later from the live session.
## Quick Start: Build Image
```sh
git clone https://codeberg.org/Clawdie/Clawdie-ISO.git
git clone https://code.smilepowered.org/clawdie/clawdie-iso.git
cd Clawdie-ISO
# Full build: fetch FreeBSD, packages, Clawdie-AI, then assemble image.

View file

@ -65,8 +65,28 @@ fi
# --- step 2: fetch Clawdie-AI tarball ---
if [ "$CLAWDIE_VERSION" = "latest" ] || [ -z "$CLAWDIE_VERSION" ]; then
echo "==> [2/6] Resolving latest Clawdie-AI version..."
CLAWDIE_VERSION=$(curl -s "https://codeberg.org/api/v1/repos/Clawdie/Clawdie-AI/releases?limit=1" \
| grep -o '"tag_name":"[^"]*"' | head -1 | cut -d'"' -f4 | sed 's/^v//')
CLAWDIE_VERSION=$(
curl -fsS "https://code.smilepowered.org/api/v1/repos/clawdie/clawdie-ai/releases?limit=20" 2>/dev/null \
| grep -o '"tag_name":"[^"]*"' \
| head -1 \
| cut -d'"' -f4 \
| sed 's/^v//'
)
if [ -z "$CLAWDIE_VERSION" ]; then
CLAWDIE_VERSION=$(
git ls-remote --tags "https://code.smilepowered.org/clawdie/clawdie-ai.git" 2>/dev/null \
| awk -F/ '$2 == "tags" && $3 ~ /^v[0-9]+\.[0-9]+\.[0-9]+$/ { print $3 }' \
| sed 's/^v//' \
| sort -t. -k1,1n -k2,2n -k3,3n \
| tail -n 1 \
| sed 's/^v//'
)
fi
if [ -z "$CLAWDIE_VERSION" ]; then
echo "ERROR: could not resolve latest Clawdie-AI release/tag from Forgejo."
echo " Pin --clawdie-version X.Y.Z explicitly."
exit 1
fi
echo " Resolved: v${CLAWDIE_VERSION}"
fi
@ -74,7 +94,7 @@ CLAWDIE_TARBALL="${CACHE_DIR}/clawdie-ai-v${CLAWDIE_VERSION}.tar.gz"
if [ "$SKIP_FETCH" -eq 0 ] || [ ! -f "$CLAWDIE_TARBALL" ]; then
echo "==> [2/6] Downloading Clawdie-AI v${CLAWDIE_VERSION}..."
curl -L --progress-bar -o "$CLAWDIE_TARBALL" \
"https://codeberg.org/Clawdie/Clawdie-AI/archive/v${CLAWDIE_VERSION}.tar.gz"
"https://code.smilepowered.org/clawdie/clawdie-ai/archive/v${CLAWDIE_VERSION}.tar.gz"
else
echo "==> [2/6] Clawdie-AI cached."
fi

View file

@ -29,7 +29,7 @@ IMAGE_SIZE="28G"
# build.sh derives IMAGE_NAME from desktop, the FreeBSD major-version codename,
# and the build date.
# Clawdie-AI ref to bundle from Codeberg.
# Clawdie-AI ref to bundle from Forgejo.
# Use main for install validation so ISO firstboot exercises the current
# post-install setup/token flow. Use --clawdie-version X.Y.Z for release builds.
CLAWDIE_VERSION="main"
@ -75,7 +75,10 @@ EMBED_DIMENSIONS="${EMBED_DIMENSIONS:-1024}"
FEATURE_COLIBRI="${FEATURE_COLIBRI:-YES}"
COLIBRI_REPO="${COLIBRI_REPO:-../colibri}"
COLIBRI_ARTIFACT_DIR="${COLIBRI_ARTIFACT_DIR:-}"
COLIBRI_DAEMON_ENABLE="${COLIBRI_DAEMON_ENABLE:-YES}"
# Stage Colibri binaries by default, but do not block live boot on the daemon.
# Hardware validation can start it manually after rc.d supervision is proven on
# the target image.
COLIBRI_DAEMON_ENABLE="${COLIBRI_DAEMON_ENABLE:-NO}"
COLIBRI_COST_MODE="${COLIBRI_COST_MODE:-smart}"
# Local LLM runtime (optional)

152
build.sh
View file

@ -283,11 +283,23 @@ preflight_colibri_artifacts() {
resolve_colibri_paths
_colibri_rc="${_resolved_colibri_repo}/packaging/freebsd/colibri_daemon.in"
_colibri_newsyslog="${_resolved_colibri_repo}/packaging/freebsd/newsyslog-colibri.conf"
if [ ! -f "${_colibri_rc}" ]; then
echo "ERROR: Colibri rc.d source missing: ${_colibri_rc}"
echo " Set COLIBRI_REPO=/path/to/colibri or FEATURE_COLIBRI=NO."
exit 1
fi
if ! grep -q '^command="/usr/sbin/daemon"' "${_colibri_rc}" || \
! grep -q '^procname="/usr/sbin/daemon"' "${_colibri_rc}"; then
echo "ERROR: Colibri rc.d source does not supervise with daemon(8): ${_colibri_rc}"
echo " Update the Colibri checkout before building; a foreground daemon blocks live boot."
exit 1
fi
if [ ! -f "${_colibri_newsyslog}" ]; then
echo "ERROR: Colibri newsyslog source missing: ${_colibri_newsyslog}"
echo " Set COLIBRI_REPO=/path/to/colibri or FEATURE_COLIBRI=NO."
exit 1
fi
for _colibri_bin in colibri-daemon colibri colibri-smoke-agent; do
if [ ! -x "${_resolved_colibri_artifact_dir}/${_colibri_bin}" ]; then
echo "ERROR: Colibri release binary missing: ${_resolved_colibri_artifact_dir}/${_colibri_bin}"
@ -332,7 +344,7 @@ json_escape() {
resolve_clawdie_commit() {
_ref="$1"
_repo="https://codeberg.org/Clawdie/Clawdie-AI.git"
_repo="https://code.smilepowered.org/clawdie/clawdie-ai.git"
if printf '%s' "$_ref" | grep -Eq '^[0-9a-fA-F]{40}$'; then
printf '%s\n' "$_ref"
return 0
@ -350,6 +362,29 @@ resolve_clawdie_commit() {
fi
}
resolve_latest_clawdie_tag() {
_repo_api="https://code.smilepowered.org/api/v1/repos/clawdie/clawdie-ai"
_repo_git="https://code.smilepowered.org/clawdie/clawdie-ai.git"
_tag=$(
curl -fsS "${_repo_api}/releases?limit=20" 2>/dev/null \
| grep -o '"tag_name":"[^"]*"' \
| head -1 \
| cut -d'"' -f4
)
if [ -n "$_tag" ]; then
printf '%s\n' "$_tag"
return 0
fi
git ls-remote --tags "$_repo_git" 2>/dev/null \
| awk -F/ '$2 == "tags" && $3 ~ /^v[0-9]+\.[0-9]+\.[0-9]+$/ { print $3 }' \
| sed 's/^v//' \
| sort -t. -k1,1n -k2,2n -k3,3n \
| tail -n 1 \
| sed 's/^/v/'
}
is_pinned_clawdie_ref() {
_ref="$1"
printf '%s' "$_ref" | grep -Eq '^[0-9a-fA-F]{40}$|^v[0-9]+\.[0-9]+\.[0-9]+$'
@ -542,10 +577,13 @@ refresh_live_desktop_caches() {
run_live_chroot /usr/local/bin/update-desktop-database /usr/local/share/applications
fi
if [ -x "${MOUNT_POINT}/usr/local/bin/gtk-update-icon-cache" ]; then
for _icon_theme in hicolor Adwaita AdwaitaLegacy Papirus; do
if [ -d "${MOUNT_POINT}/usr/local/share/icons/${_icon_theme}" ]; then
run_live_chroot /usr/local/bin/gtk-update-icon-cache -f -t "/usr/local/share/icons/${_icon_theme}" || true
fi
# Regenerate every installed icon theme cache. FreeBSD packages and
# Clawdie branding install icons into hicolor and other theme
# directories; missed caches show up as blank/dot panel icons.
for _icon_theme_dir in "${MOUNT_POINT}/usr/local/share/icons"/*/; do
[ -d "$_icon_theme_dir" ] || continue
_theme_name=$(basename "$_icon_theme_dir")
run_live_chroot /usr/local/bin/gtk-update-icon-cache -f -t "/usr/local/share/icons/${_theme_name}" || true
done
fi
@ -764,6 +802,67 @@ install_live_npm_globals() {
fi
}
seed_live_ai_source_repo() {
_repo_src="$1"
_repo_name="$2"
_repo_dest="${MOUNT_POINT}/home/clawdie/ai/${_repo_name}"
if [ ! -d "${_repo_src}" ]; then
echo " Skipping AI source seed ${_repo_name}: ${_repo_src} not found"
return 0
fi
if ! command -v git >/dev/null 2>&1 || ! git -C "${_repo_src}" rev-parse --git-dir >/dev/null 2>&1; then
echo " Skipping AI source seed ${_repo_name}: not a git worktree"
return 0
fi
echo " Seeding AI source snapshot: ${_repo_name}"
rm -rf "${_repo_dest}"
mkdir -p "${_repo_dest}"
git -C "${_repo_src}" archive --format=tar HEAD | tar -C "${_repo_dest}" -xf -
_repo_branch=$(git -C "${_repo_src}" symbolic-ref --short -q HEAD 2>/dev/null || echo detached)
_repo_commit=$(git -C "${_repo_src}" rev-parse HEAD 2>/dev/null || echo unknown)
_repo_origin=$(git -C "${_repo_src}" remote get-url origin 2>/dev/null || echo unknown)
_repo_dirty=false
if ! git -C "${_repo_src}" diff --quiet 2>/dev/null || ! git -C "${_repo_src}" diff --cached --quiet 2>/dev/null; then
_repo_dirty=true
fi
cat > "${_repo_dest}/.clawdie-source.json" <<EOF
{
"name": "$(json_escape "${_repo_name}")",
"source_path": "$(json_escape "${_repo_src}")",
"origin": "$(json_escape "${_repo_origin}")",
"branch": "$(json_escape "${_repo_branch}")",
"commit": "$(json_escape "${_repo_commit}")",
"dirty_at_build": ${_repo_dirty},
"snapshot_note": "git archive of HEAD; uncommitted changes and ignored/private files are not included"
}
EOF
}
install_live_ai_source_snapshots() {
echo " Installing live AI source snapshots..."
mkdir -p "${MOUNT_POINT}/home/clawdie/ai"
cat > "${MOUNT_POINT}/home/clawdie/ai/README.txt" <<'EOF'
Clawdie live AI source snapshots
These directories are included so the operator can start a local provider-backed
Pi session from the live XFCE desktop and inspect the shipped source beside the
running system.
No API keys, .env files, SSH private keys, build caches, package caches, tmp/
directories, or uncommitted worktree changes are included. Each snapshot has a
.clawdie-source.json file recording the source remote, branch, commit, and dirty
state at image build time.
EOF
seed_live_ai_source_repo "${SCRIPT_DIR}" "clawdie-iso"
seed_live_ai_source_repo "${SCRIPT_DIR}/../clawdie-ai" "clawdie-ai"
seed_live_ai_source_repo "${SCRIPT_DIR}/../colibri" "colibri"
chroot "${MOUNT_POINT}" chown -R clawdie:clawdie /home/clawdie/ai
}
configure_live_operator_session() {
echo " Configuring live operator session..."
@ -772,6 +871,8 @@ configure_live_operator_session() {
"${MOUNT_POINT}/usr/local/bin/clawdie-bootstrap-launch.sh"
install -m 0755 "${LIVE_SESSION_DIR}/clawdie-noblank-guard.sh" \
"${MOUNT_POINT}/usr/local/bin/clawdie-noblank-guard.sh"
install -m 0755 "${LIVE_SESSION_DIR}/clawdie-xfce-visuals-guard.sh" \
"${MOUNT_POINT}/usr/local/bin/clawdie-xfce-visuals-guard.sh"
install -m 0755 "${LIVE_SESSION_DIR}/hw-report" \
"${MOUNT_POINT}/usr/local/bin/hw-report"
@ -830,6 +931,8 @@ EOF
"${MOUNT_POINT}/usr/local/etc/xdg/autostart/clawdie-bootstrap.desktop"
install -m 0644 "${LIVE_SESSION_DIR}/autostart/clawdie-noblank-guard.desktop" \
"${MOUNT_POINT}/usr/local/etc/xdg/autostart/clawdie-noblank-guard.desktop"
install -m 0644 "${LIVE_SESSION_DIR}/autostart/clawdie-xfce-visuals-guard.desktop" \
"${MOUNT_POINT}/usr/local/etc/xdg/autostart/clawdie-xfce-visuals-guard.desktop"
mkdir -p "${MOUNT_POINT}/usr/local/etc/X11/xorg.conf.d"
install -m 0644 "${LIVE_SESSION_DIR}/xorg.conf.d/30-keyboard.conf" \
"${MOUNT_POINT}/usr/local/etc/X11/xorg.conf.d/30-keyboard.conf"
@ -1110,6 +1213,8 @@ EOF
"${MOUNT_POINT}/home/clawdie/Desktop/Clawdie Bootstrap.desktop" \
"${MOUNT_POINT}/home/clawdie/Desktop/Clawdie Hardware Report.desktop"
install_live_ai_source_snapshots
# The stock FreeBSD install memstick is intentionally read-only. This live
# operator USB needs a writable root so SDDM, Xorg, NetworkMgr, logs, and
# operator diagnostics can create runtime state on the flashed stick.
@ -1378,14 +1483,31 @@ EOF
cp "${_wallpapers_dir}"/* "${MOUNT_POINT}/usr/local/share/clawdie-iso/wallpapers/" 2>/dev/null || true
fi
# Brand icons (e.g. the Whisker Start-button triangle). Referenced by
# absolute path from xfce4-panel.xml so the button never depends on an
# icon-theme cache being current at first login.
# Brand icons (e.g. the Whisker Start-button triangle). Install both the
# raw files for direct diagnostics and hicolor theme names for XFCE plugins
# that do not reliably load absolute icon paths.
_icons_dir="${LIVE_SESSION_DIR}/icons"
if [ -d "$_icons_dir" ]; then
echo " Installing brand icons..."
mkdir -p "${MOUNT_POINT}/usr/local/share/clawdie-iso/icons"
mkdir -p \
"${MOUNT_POINT}/usr/local/share/clawdie-iso/icons" \
"${MOUNT_POINT}/usr/local/share/icons/hicolor/48x48/apps" \
"${MOUNT_POINT}/usr/local/share/icons/hicolor/64x64/apps" \
"${MOUNT_POINT}/usr/local/share/icons/hicolor/scalable/apps"
cp "${_icons_dir}"/* "${MOUNT_POINT}/usr/local/share/clawdie-iso/icons/" 2>/dev/null || true
if [ -f "${_icons_dir}/clawdie-start.png" ]; then
install -m 0644 "${_icons_dir}/clawdie-start.png" \
"${MOUNT_POINT}/usr/local/share/icons/hicolor/48x48/apps/clawdie-start.png"
install -m 0644 "${_icons_dir}/clawdie-start.png" \
"${MOUNT_POINT}/usr/local/share/icons/hicolor/64x64/apps/clawdie-start.png"
fi
if [ -f "${_icons_dir}/clawdie-start.svg" ]; then
install -m 0644 "${_icons_dir}/clawdie-start.svg" \
"${MOUNT_POINT}/usr/local/share/icons/hicolor/scalable/apps/clawdie-start.svg"
fi
if [ -x "${MOUNT_POINT}/usr/local/bin/gtk-update-icon-cache" ]; then
run_live_chroot /usr/local/bin/gtk-update-icon-cache -f -t /usr/local/share/icons/hicolor || true
fi
fi
rm -rf "${MOUNT_POINT}/home/clawdie/.cache" "${MOUNT_POINT}/etc/skel/.cache"
@ -1517,11 +1639,15 @@ else
fi
# --- step 4: fetch + prepare Clawdie-AI tarball (offline-ready) ---
# Resolve "latest" to the most recent Codeberg tag.
# Resolve "latest" from Forgejo releases first, then tags.
if [ "${CLAWDIE_REF:-${CLAWDIE_VERSION:-}}" = "latest" ] || [ -z "${CLAWDIE_REF:-}" ]; then
echo "==> [4/7] Resolving latest Clawdie-AI version..."
CLAWDIE_VERSION=$(curl -s "https://codeberg.org/api/v1/repos/Clawdie/Clawdie-AI/releases?limit=1" \
| grep -o '"tag_name":"[^"]*"' | head -1 | cut -d'"' -f4 | sed 's/^v//')
CLAWDIE_VERSION=$(resolve_latest_clawdie_tag | sed 's/^v//')
if [ -z "$CLAWDIE_VERSION" ]; then
echo "ERROR: could not resolve latest Clawdie-AI release/tag from Forgejo."
echo " Pin --clawdie-ref main or --clawdie-version X.Y.Z explicitly."
exit 1
fi
CLAWDIE_REF="v${CLAWDIE_VERSION}"
echo " Resolved: ${CLAWDIE_REF}"
fi
@ -1545,7 +1671,7 @@ else
fi
CLAWDIE_TARBALL="${CACHE_DIR}/clawdie-ai-${CLAWDIE_CACHE_KEY}.tar.gz"
CLAWDIE_TARBALL_URL="https://codeberg.org/Clawdie/Clawdie-AI/archive/${CLAWDIE_ARCHIVE_REF}.tar.gz"
CLAWDIE_TARBALL_URL="https://code.smilepowered.org/clawdie/clawdie-ai/archive/${CLAWDIE_ARCHIVE_REF}.tar.gz"
if [ "$SKIP_FETCH" -eq 0 ] || [ ! -f "$CLAWDIE_TARBALL" ]; then
echo "==> [4/7] Fetching Clawdie-AI ${CLAWDIE_REF} (${CLAWDIE_ARCHIVE_REF})..."
mkdir -p "$CACHE_DIR"

View file

@ -926,6 +926,34 @@ xrandr --query
xfconf-query -c xfce4-panel -p /panels/panel-1 -lv
```
## Follow-up live XFCE command evidence — 2026-06-01
After the report archive was collected, the operator ran direct `xfconf-query`
checks in the live XFCE session before rebooting.
Confirmed good state:
- `xsettings` had `Greybird`, `Papirus`, `DMZ-White`, `Noto Sans 11`, and
`Hack 11`; global GTK/icon/cursor/font configuration is loading.
- `xfce4-desktop` had `image-show=true`, `image-style=5`, and
`last-image=/usr/local/share/clawdie-iso/wallpapers/clawdie-operator-bg.png`;
the wallpaper config and image file exist.
- `xfce4-panel` had the intended panel size, opacity, plugin order, and launcher
entries; the panel seed is loading.
Confirmed problem state:
- The shipped live image only had `clawdie-start` under
`/usr/local/share/clawdie-iso/icons/`; `find /usr/local/share/icons -name
'clawdie-start*'` returned nothing until the operator manually copied the icon
into `hicolor` and rebuilt the cache.
- The Whisker button still did not visibly change during that live-session test,
so the next build should stage the icon in the theme at build time and verify
real first-login behavior rather than relying on hot panel reloads.
- `xfce4-mixer` auto-selected `ATIR6xxHDMI`/`Vol` even though FreeBSD selected
the internal Realtek speaker as the default device. The default panel should
not ship a mixer plugin that controls HDMI on AMD laptops.
## Fix-planning backlog derived from this report
This is a backlog only; solutions should be discussed separately.

View file

@ -66,14 +66,29 @@ FreeBSD/operator side. Pass 2 only improves _proportion and uniformity_.
- [ ] `square-icons` took effect on the systray (network/mixer icons square and
uniform) — confirm the installed `systray` plugin honors the property.
## Pre-build changes applied (2026-06-01) — Pass 3
Follow-up from the AMD live report and direct `xfconf-query` checks:
- **Start icon:** the live image had only `/usr/local/share/clawdie-iso/icons/*`;
no `clawdie-start` entries existed under `/usr/local/share/icons`. The build
now stages `clawdie-start.png` into `hicolor/48x48/apps` and
`hicolor/64x64/apps`, stages the SVG into `hicolor/scalable/apps`, updates the
`hicolor` cache at build time, and uses the themed icon name
`button-icon="clawdie-start"`.
- **Mixer:** `xfce4-mixer` auto-selected `ATIR6xxHDMI`/`Vol` on AMD hardware even
when FreeBSD's default sound unit was the internal Realtek speaker. The default
panel now omits the mixer plugin instead of shipping a visible control pinned
to HDMI. Re-add only after a reliable backend/default-device strategy exists.
## Deletion Criteria
- [ ] Whiskermenu Start button icon is visible (not missing/broken).
- [ ] Clock plugin renders date+time in the panel.
- [ ] Clipman re-added and loads without "could not be loaded" dialog (dropped
from this build pending D-Bus root-cause).
- [ ] Systray icons (NetworkMgr, mixer) and xkb flag icon are visually
uniform in size — no oversized or undersized outliers.
- [ ] Systray icons (NetworkMgr) and xkb flag/text display are visually uniform
in size — no oversized or undersized outliers.
- [ ] All fixes confirmed on real hardware boot (not just image inspection).
## Operator-Reported Issues

128
docs/ISO-MANIFESTS.md Normal file
View file

@ -0,0 +1,128 @@
# ISO Workflow Manifest Conventions
This repo is the producer of operator-USB workflow artifacts. Colibri and
operator dashboards consume the JSON manifests, summaries, and referenced logs;
they do not scrape terminal scrollback as the contract.
## Common rules
All ISO workflow manifests SHOULD include these top-level fields:
| Field | Meaning |
| ----------------------------- | ------------------------------------------------------------------------------- |
| `schema` | Stable schema id, for example `clawdie.iso.publish.v1` |
| `project` | `clawdie-iso` |
| `workflow` | Skill or script name that produced the manifest |
| `run_id` | Unique run id; include UTC time and commit or artifact stem when possible |
| `status` | `pass`, `fail`, `warn`, or `skipped` |
| `actor` | Responsible role or operator-visible identity |
| `host` | Host that performed the workflow |
| `branch` / `commit` | ISO repo branch and commit when a checkout is available |
| `started_at` / `completed_at` | UTC ISO-8601 timestamps; use `null` when unknown |
| `inputs` | Artifact URLs, image paths, package lists, device ids, or report paths consumed |
| `checks` | Array or object of named checks with pass/fail status and concise details |
| `outputs` | Manifest path, public URLs, copied reports, or produced artifact paths |
| `logs` | Paths to raw logs. Do not inline large logs. |
| `summary` | Short human-readable result suitable for Colibri activity text |
Secrets, API keys, auth keys, private SSH keys, and full unredacted environment
dumps MUST NOT be written into manifests. If a workflow uses a secret, record a
boolean such as `tailscale_auth_key_baked: true` or a public fingerprint only.
## Canonical schema ids and paths
| Workflow | Schema | Canonical output path |
| ---------------------- | ------------------------------ | --------------------------------------------------------------------------------------------- |
| ISO build | `clawdie.iso.build.v1` | `tmp/colibri/iso-build/<run_id>.json` and `tmp/colibri/iso-build/latest.json` |
| ISO publish | `clawdie.iso.publish.v1` | `tmp/output/<image>.manifest.json` |
| Flash verification | `clawdie.iso.flash.v1` | `tmp/colibri/iso-flash/<run_id>.json` and `tmp/colibri/iso-flash/latest.json` |
| Mounted validation | `clawdie.iso.validation.v1` | `tmp/colibri/iso-validation/<run_id>.json` and `tmp/colibri/iso-validation/latest.json` |
| Hardware report ingest | `clawdie.iso.hardware.v1` | `tmp/colibri/iso-hardware/<run_id>.json` and `tmp/colibri/iso-hardware/latest.json` |
| Package audit | `clawdie.iso.package-audit.v1` | `tmp/colibri/iso-package-audit/<run_id>.json` and `tmp/colibri/iso-package-audit/latest.json` |
`tmp/colibri/` is repo-local scratch/output state. It is intentionally not
committed. When a result must survive across hosts, commit a concise handoff
summary under `doc/` or publish the manifest with the image artifact.
## Workflow-specific fields
### `clawdie.iso.build.v1`
Use for the build result, not for the embedded image manifest alone. Include:
- build command and flags
- FreeBSD version/architecture
- source branch/commit/dirty state
- Colibri staging mode and artifact directory when `FEATURE_COLIBRI=YES`
- output image path, compressed image path when present, checksum path when present
- static checks run before build (`sh -n`, markdown format, Colibri preflight)
- build log path under `tmp/`
The image itself also carries
`/usr/local/share/clawdie-iso/build-manifest.json`; that file is for runtime
inspection from the live USB and does not replace the workflow result manifest.
### `clawdie.iso.publish.v1`
Produced by `scripts/write-artifact-manifest.sh`. Include:
- compressed image, checksum file, and manifest names
- SHA256 of the compressed image
- raw and compressed sizes when known
- public URLs when published
- checksum verification status
- publish host, actor, branch, and commit
### `clawdie.iso.flash.v1`
Use for Hermes USB/IMG Deployer verification and flashing. Include:
- consumed publish manifest URL/path
- downloaded image/checksum paths
- checksum and `gzip -t` results
- selected whole-disk device, model, serial when available, and size
- explicit confirmation that the target is a whole disk, not a partition
- flash command summary and post-flash sync/eject result
### `clawdie.iso.validation.v1`
Use for static or mounted-image validation on the FreeBSD build host. Include:
- image path and mount device/slices inspected
- SDDM, `clawdie-live-gpu`, `mdo`, CLI, seed-slice, no-blank, power, and panel
asset checks
- validation limitations, especially that mounted inspection is not graphical
hardware proof
### `clawdie.iso.hardware.v1`
Use for real-machine live USB reports. Include:
- hardware model, BIOS/UEFI version when collected, CPU, GPU, network, audio,
input summary
- `/var/log/clawdie-live-gpu.log` outcome
- GL renderer, SDDM/XFCE status, power/no-blank status
- `hw-report` output path and public `hw-probe` URL if the operator uploaded it
- operator-observed pass/fail notes for touchpad, Wi-Fi, audio, and display
### `clawdie.iso.package-audit.v1`
Use for package-list hygiene. Include:
- package list file audited
- package category (`boot-critical`, `operator-workflow`, `diagnostic`, or
`candidate-to-defer`)
- package size and flat size from the FreeBSD package database or archive
metadata
- reason kept and deferral risk
## Handoff expectations
- Skills should print the manifest path and a concise summary when they finish.
- If a workflow is manual-only, write the manifest from the collected facts before
handing off to another role.
- Raw logs stay in `tmp/` or with the published artifact; markdown handoffs should
quote only the exact failure lines needed for follow-up.
- Build, publish, and mounted validation remain FreeBSD-owner workflows. Flashing
remains Hermes-owned. Live hardware proof remains operator/Codex hardware
validation, not static inspection.

View file

@ -152,7 +152,7 @@ clawdie_shell_deploy_upgrade() {
mkdir -p "$STAGING_DIR"
if ! tar -xzf "$CLAWDIE_TARBALL" -C "$STAGING_DIR" --strip-components=1 2>/dev/null; then
# Try without --strip-components (Codeberg archives have a top-level dir)
# Try without --strip-components (Forgejo archives have a top-level dir)
tar -xzf "$CLAWDIE_TARBALL" -C "$(dirname "$STAGING_DIR")" 2>/dev/null || {
log_msg "[deploy] ERROR: Failed to extract upgrade tarball"
return 1

View file

@ -0,0 +1,8 @@
[Desktop Entry]
Type=Application
Name=Clawdie XFCE Visual Guard
Comment=Re-apply Clawdie live USB theme, icon, and wallpaper settings
Exec=/usr/local/bin/clawdie-xfce-visuals-guard.sh
OnlyShowIn=XFCE;
X-GNOME-Autostart-enabled=true
Terminal=false

View file

@ -7,7 +7,7 @@ echo "=== $(date -u '+%Y-%m-%dT%H:%M:%SZ') clawdie-xfce-session-inner start ==="
PANEL_TEMPLATE_ROOT="/usr/local/share/clawdie-iso/panel-skel"
PANEL_TEMPLATE_CONFIG="${PANEL_TEMPLATE_ROOT}/.config"
PANEL_STAMP="${HOME}/.config/clawdie/xfce-panel-seeded-v2"
PANEL_STAMP="${HOME}/.config/clawdie/xfce-panel-seeded-v3"
ensure_seeded_panel_profile() {
mkdir -p "${HOME}/.config/clawdie"
@ -22,6 +22,7 @@ ensure_seeded_panel_profile() {
if [ -f "$PANEL_STAMP" ] && \
[ -f "$_panel_xml" ] && \
grep -q 'whiskermenu' "$_panel_xml" 2>/dev/null && \
grep -q 'clawdie-start' "$_panel_xml" 2>/dev/null && \
[ -d "$_panel_launcher_dir2" ] && \
[ -d "$_panel_launcher_dir3" ] && \
[ -d "$_panel_launcher_dir4" ]; then

View file

@ -0,0 +1,87 @@
#!/bin/sh
# Best-effort live-session visual guard for XFCE.
#
# XFCE may create monitor-specific desktop keys only after xfdesktop starts, and
# some panel plugins are stricter about themed icon names than absolute paths.
# Re-assert the operator USB visual contract after login without failing the
# session if a component is missing.
LOG="${HOME}/.clawdie-xfce-visuals-guard.log"
WALLPAPER="/usr/local/share/clawdie-iso/wallpapers/clawdie-operator-bg.png"
START_ICON="clawdie-start"
log() {
printf '%s %s\n' "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" "$*" >>"$LOG" 2>/dev/null || true
}
set_xfconf() {
_channel="$1"
_property="$2"
_type="$3"
_value="$4"
command -v xfconf-query >/dev/null 2>&1 || return 0
xfconf-query -c "$_channel" -p "$_property" -s "$_value" >/dev/null 2>&1 || \
xfconf-query -c "$_channel" -p "$_property" -n -t "$_type" -s "$_value" >/dev/null 2>&1 || true
}
apply_theme() {
set_xfconf xsettings /Net/ThemeName string Greybird
set_xfconf xsettings /Net/IconThemeName string Papirus
set_xfconf xsettings /Net/CursorTheme string DMZ-White
set_xfconf xsettings /Net/CursorSize int 24
set_xfconf xsettings /Gtk/FontName string "Noto Sans 11"
set_xfconf xsettings /Gtk/MonospaceFontName string "Hack 11"
}
apply_panel() {
set_xfconf xfce4-panel /plugins/plugin-1/button-icon string "$START_ICON"
set_xfconf xfce4-panel /plugins/plugin-1/show-button-icon bool true
set_xfconf xfce4-panel /plugins/plugin-1/show-button-title bool true
set_xfconf xfce4-panel /panels/panel-1/size uint 40
set_xfconf xfce4-panel /panels/panel-1/icon-size uint 2
set_xfconf xfce4-panel /plugins/plugin-8/square-icons bool true
}
apply_wallpaper() {
[ -f "$WALLPAPER" ] || {
log "wallpaper missing: $WALLPAPER"
return 0
}
command -v xfconf-query >/dev/null 2>&1 || return 0
_bases="$(xfconf-query -c xfce4-desktop -l 2>/dev/null | awk '/\/last-image$/ { sub(/\/last-image$/, ""); print }')"
if [ -z "$_bases" ]; then
_bases='/backdrop/screen0/monitor0/workspace0
/backdrop/screen0/monitorDefault/workspace0'
fi
printf '%s\n' "$_bases" | while IFS= read -r _base; do
[ -n "$_base" ] || continue
set_xfconf xfce4-desktop "${_base}/last-image" string "$WALLPAPER"
set_xfconf xfce4-desktop "${_base}/image-path" string "$WALLPAPER"
set_xfconf xfce4-desktop "${_base}/image-style" int 5
set_xfconf xfce4-desktop "${_base}/image-show" bool true
set_xfconf xfce4-desktop "${_base}/color-style" int 0
done
if command -v xfdesktop >/dev/null 2>&1; then
xfdesktop --reload >/dev/null 2>&1 || true
fi
}
run_once() {
log "applying XFCE visual guard"
apply_theme
apply_panel
apply_wallpaper
}
# Run more than once because xfdesktop/panel may create monitor/plugin state
# after XDG autostart begins.
sleep 3
run_once
sleep 7
run_once
sleep 15
run_once

View file

@ -180,6 +180,7 @@ run_shell_capture dmesg-hardware-filter "dmesg | egrep -i 'drm|kms|amdgpu|i915|r
run_shell_capture dmesg-boot "for f in /var/run/dmesg.boot; do [ -e \"\$f\" ] || continue; echo \"===== \$f =====\"; cat \"\$f\"; echo; done"
run_shell_capture xorg-var-logs "for f in /var/log/Xorg.*.log*; do [ -e \"\$f\" ] || continue; echo \"===== \$f =====\"; cat \"\$f\"; echo; done"
run_shell_capture xorg-user-logs "for f in /home/clawdie/.local/share/xorg/Xorg.*.log*; do [ -e \"\$f\" ] || continue; echo \"===== \$f =====\"; cat \"\$f\"; echo; done"
run_shell_capture xsession-errors "for f in /home/clawdie/.xsession-errors /home/clawdie/.xsession-errors.old; do [ -e \"\$f\" ] || continue; echo \"===== \$f =====\"; cat \"\$f\"; echo; done"
run_shell_capture var-log-messages "for f in /var/log/messages*; do [ -e \"\$f\" ] || continue; echo \"===== \$f =====\"; case \"\$f\" in *.gz) zcat \"\$f\";; *.bz2) bzcat \"\$f\";; *.xz) xzcat \"\$f\";; *.zst) zstdcat \"\$f\";; *) cat \"\$f\";; esac; echo; done"
run_shell_capture sddm-log-files "for f in /var/log/sddm.log; do [ -e \"\$f\" ] || continue; echo \"===== \$f =====\"; cat \"\$f\"; echo; done"
run_shell_capture sddm-config "for f in /usr/local/etc/sddm.conf /usr/local/etc/sddm.conf.d/*; do [ -e \"\$f\" ] || continue; echo \"===== \$f =====\"; cat \"\$f\"; echo; done"
@ -191,7 +192,7 @@ run_if_present ifconfig ifconfig-a -a
run_if_present netstat netstat-rn -rn
run_shell_capture resolver-state "ls -l /etc/resolv.conf 2>/dev/null || true; readlink /etc/resolv.conf 2>/dev/null || true; cat /etc/resolv.conf 2>/dev/null || true"
run_shell_capture wlan-devices "sysctl net.wlan.devices"
run_shell_capture rc-conf-live "grep -E '^(hostname|kld_list|sshd_enable|tailscaled_enable|avahi_daemon_enable|pf_enable|sddm_enable|webcamd_enable|powerdxx_enable|clawdie_live_|performance_cx_lowest|economy_cx_lowest|dumpdev_enable)' /etc/rc.conf || true"
run_shell_capture rc-conf-live "grep -E '^(hostname|kld_list|sshd_enable|tailscaled_enable|avahi_daemon_enable|pf_enable|sddm_enable|webcamd_enable|powerdxx_enable|colibri_daemon_enable|clawdie_live_|performance_cx_lowest|economy_cx_lowest|dumpdev_enable)' /etc/rc.conf || true"
run_if_present service service-enabled -e
run_if_present sysctl sysctl-hw hw
@ -244,6 +245,7 @@ run_shell_if_present usbhid-dump usbhid-dump-version "usbhid-dump --help 2>&1 |
run_if_present cat clawdie-live-gpu-log /var/log/clawdie-live-gpu.log
run_if_present cat clawdie-noblank-guard-log /home/clawdie/.clawdie-noblank-guard.log
run_if_present cat clawdie-xfce-visuals-guard-log /home/clawdie/.clawdie-xfce-visuals-guard.log
run_if_present cat clawdie-touchpad-guard-log /home/clawdie/.clawdie-touchpad-guard.log
run_if_present cat sndstat /dev/sndstat
run_if_present mixer mixer-s -s
@ -254,9 +256,15 @@ run_shell_capture input-device-nodes "ls -l /dev/input /dev/input/* /dev/uhid* /
run_if_present xset xset-q q
run_shell_if_present xfconf-query xfce4-power-manager "xfconf-query -c xfce4-power-manager -l -v 2>/dev/null || true"
run_shell_if_present xfconf-query xfce4-panel-plugins "xfconf-query -c xfce4-panel -p /plugins/plugin-11 2>/dev/null; xfconf-query -c xfce4-panel -p /plugins/plugin-13 2>/dev/null"
run_shell_if_present xfconf-query xfce4-panel "xfconf-query -c xfce4-panel -l -v 2>/dev/null || true"
run_shell_if_present xfconf-query xfce4-desktop "xfconf-query -c xfce4-desktop -l -v 2>/dev/null || true"
run_shell_if_present xfconf-query xsettings "xfconf-query -c xsettings -l -v 2>/dev/null || true"
run_shell_if_present xfconf-query xfce4-pointers "DISPLAY=:0 XAUTHORITY=/home/clawdie/.Xauthority xfconf-query -c pointers -l -v 2>/dev/null || xfconf-query -c pointers -l -v 2>/dev/null || true"
run_shell_capture xfce-perchannel-xml "for f in /home/clawdie/.config/xfce4/xfconf/xfce-perchannel-xml/*; do [ -e \"\$f\" ] || continue; echo \"===== \$f =====\"; cat \"\$f\"; echo; done"
run_shell_capture xfce-panel-launchers "find /home/clawdie/.config/xfce4/panel -maxdepth 4 -type f -print -exec sed -n '1,80p' {} \\; 2>/dev/null || true"
run_shell_capture icon-theme-dirs "find /usr/local/share/icons -maxdepth 4 -type f \( -name 'icon-theme.cache' -o -name 'clawdie-start.*' \) -print 2>/dev/null || true"
run_shell_capture clawdie-iso-assets "find /usr/local/share/clawdie-iso -maxdepth 4 -type f -ls 2>/dev/null || true; for f in /usr/local/share/clawdie-iso/build-manifest.json; do [ -e \"\$f\" ] || continue; echo \"===== \$f =====\"; cat \"\$f\"; echo; done"
run_shell_capture colibri-service-state "service colibri_daemon status 2>&1 || true; egrep -n '^(command|command_args|procname)=' /usr/local/etc/rc.d/colibri_daemon 2>/dev/null || true; sysrc -n colibri_daemon_enable 2>/dev/null || true"
if [ -f /home/clawdie/.Xauthority ]; then
run_shell_if_present xinput xinput-list "DISPLAY=:0 XAUTHORITY=/home/clawdie/.Xauthority xinput list 2>/dev/null || true"
run_shell_if_present xinput xinput-list-props "DISPLAY=:0 XAUTHORITY=/home/clawdie/.Xauthority sh -c 'for id in \$(xinput list --id-only 2>/dev/null); do echo \"===== device \$id =====\"; xinput list-props \"\$id\"; echo; done' || true"

View file

@ -23,8 +23,10 @@
<value type="double" value="0.180000"/>
<value type="double" value="0.850000"/>
</property>
<!-- order intentional: mixer before xkb. clipman (plugin-13) dropped
pending D-Bus root-cause; see doc/XFCE-PANEL-BUGS-HANDOFF.md -->
<!-- clipman (plugin-13) dropped pending D-Bus root-cause. The mixer
plugin is also omitted by default because xfce4-mixer auto-pins the
first HDMI device on AMD laptops instead of FreeBSD's selected
internal speaker; see doc/XFCE-PANEL-BUGS-HANDOFF.md. -->
<property name="plugin-ids" type="array">
<value type="int" value="1"/>
<value type="int" value="2"/>
@ -35,7 +37,6 @@
<value type="int" value="7"/>
<value type="int" value="8"/>
<value type="int" value="9"/>
<value type="int" value="11"/>
<value type="int" value="10"/>
<value type="int" value="12"/>
</property>
@ -44,7 +45,7 @@
<property name="plugins" type="empty">
<property name="plugin-1" type="string" value="whiskermenu">
<property name="button-title" type="string" value="Start"/>
<property name="button-icon" type="string" value="/usr/local/share/clawdie-iso/icons/clawdie-start.png"/>
<property name="button-icon" type="string" value="clawdie-start"/>
<property name="show-button-title" type="bool" value="true"/>
<property name="show-button-icon" type="bool" value="true"/>
<property name="launcher-show-name" type="bool" value="true"/>
@ -91,10 +92,6 @@
<property name="size" type="int" value="36"/>
<property name="update-interval" type="int" value="4"/>
</property>
<property name="plugin-11" type="string" value="mixer">
<property name="sound-card" type="string" value=""/>
<property name="track" type="string" value=""/>
</property>
<property name="plugin-10" type="string" value="xkb">
<property name="display-type" type="uint" value="1"/>
<property name="display-name" type="uint" value="0"/>

View file

@ -42,24 +42,24 @@ cd /home/clawdie/clawdie-iso && sudo ./build.sh && sudo ./scripts/publish.sh
## Future: Forgejo Actions (push-triggered CI/CD)
When the ISO build is stable and you want push-triggered rebuilds, add a
self-hosted Forgejo runner on the controlplane. Codeberg runs Forgejo — no
new account needed.
self-hosted Forgejo runner on the controlplane. `code.smilepowered.org` is the
source of truth; Codeberg is only the public mirror.
### Install runner
```sh
pkg install forgejo-runner
# or fetch binary from codeberg.org/forgejo/runner/releases
# or fetch binary from the upstream Forgejo runner releases
```
### Register
1. Codeberg → `Clawdie/Clawdie-ISO` → Settings → Actions → Runners → Create Runner → copy token
1. Forgejo → `clawdie/clawdie-iso` → Settings → Actions → Runners → Create Runner → copy token
2. Run:
```sh
forgejo-runner register \
--url https://codeberg.org \
--url https://code.smilepowered.org \
--token <TOKEN> \
--name clawdie-build \
--labels freebsd \

View file

@ -146,7 +146,7 @@ cat > "${HTML_LATEST}" << HTMLEOF
<a class="brand" href="/">Clawdie<span>.</span></a>
<div class="nav-links">
<a href="/docs/">Docs</a>
<a href="https://codeberg.org/Clawdie/Clawdie-ISO" target="_blank">ISO</a>
<a href="https://code.smilepowered.org/clawdie/clawdie-iso" target="_blank">ISO</a>
</div>
</div>
</nav>

View file

@ -20,7 +20,7 @@ SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
REPO_ROOT=$(CDPATH= cd -- "${SCRIPT_DIR}/.." && pwd)
COLIBRI_REPO=${COLIBRI_REPO:-"${REPO_ROOT}/../colibri"}
COLIBRI_ARTIFACT_DIR=${COLIBRI_ARTIFACT_DIR:-"${COLIBRI_REPO}/target/release"}
COLIBRI_STAGE_ENABLE=${COLIBRI_STAGE_ENABLE:-YES}
COLIBRI_STAGE_ENABLE=${COLIBRI_STAGE_ENABLE:-NO}
COLIBRI_STAGE_INCLUDE_TUI=${COLIBRI_STAGE_INCLUDE_TUI:-1}
COLIBRI_COST_MODE=${COLIBRI_COST_MODE:-smart}
@ -30,7 +30,9 @@ ETC_DIR="${DESTDIR}/usr/local/etc/colibri"
DB_DIR="${DESTDIR}/var/db/colibri"
RUN_DIR="${DESTDIR}/var/run/colibri"
LOG_DIR="${DESTDIR}/var/log/colibri"
NEWSYSLOG_DIR="${DESTDIR}/usr/local/etc/newsyslog.conf.d"
RC_SOURCE="${COLIBRI_REPO}/packaging/freebsd/colibri_daemon.in"
NEWSYSLOG_SOURCE="${COLIBRI_REPO}/packaging/freebsd/newsyslog-colibri.conf"
require_file() {
if [ ! -f "$1" ]; then
@ -53,7 +55,8 @@ copy_bin() {
}
require_file "${RC_SOURCE}"
mkdir -p "${BIN_DIR}" "${RC_DIR}" "${ETC_DIR}" "${DB_DIR}" "${RUN_DIR}" "${LOG_DIR}"
require_file "${NEWSYSLOG_SOURCE}"
mkdir -p "${BIN_DIR}" "${RC_DIR}" "${ETC_DIR}" "${NEWSYSLOG_DIR}" "${DB_DIR}" "${RUN_DIR}" "${LOG_DIR}"
copy_bin colibri-daemon
copy_bin colibri
@ -64,6 +67,15 @@ if [ "${COLIBRI_STAGE_INCLUDE_TUI}" != "0" ] && [ -x "${COLIBRI_ARTIFACT_DIR}/co
fi
install -m 0555 "${RC_SOURCE}" "${RC_DIR}/colibri_daemon"
install -m 0644 "${NEWSYSLOG_SOURCE}" "${NEWSYSLOG_DIR}/colibri.conf"
if ! grep -q '^command="/usr/sbin/daemon"' "${RC_DIR}/colibri_daemon" || \
! grep -q '^procname="/usr/sbin/daemon"' "${RC_DIR}/colibri_daemon" || \
! grep -q -- '-o .*colibri_daemon_program' "${RC_DIR}/colibri_daemon"; then
echo "ERROR: staged colibri_daemon rc.d script does not supervise colibri-daemon with daemon(8)" >&2
echo " Update COLIBRI_REPO (${COLIBRI_REPO}) before building; the live USB must not block boot in rc.d." >&2
exit 66
fi
cat > "${ETC_DIR}/rc.conf.sample" <<EOF
# Colibri control plane service defaults for the Clawdie ISO.
@ -84,8 +96,10 @@ cat > "${ETC_DIR}/README.iso" <<'EOF'
Colibri ISO staging notes
=========================
The ISO build creates the colibri user/group and enables the rc.d service
according to build.cfg. Runtime validation:
The ISO build creates the colibri user/group and stages the rc.d service.
Current operator USB builds keep the daemon disabled at boot unless explicitly
overridden in build.cfg, so Colibri cannot block SDDM/XFCE startup. Runtime
validation:
service colibri_daemon start
colibri status

View file

@ -140,8 +140,16 @@ _gz_size="$(file_size "${_gz}")"
_branch="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo unknown)"
_commit="$(git rev-parse --short HEAD 2>/dev/null || echo unknown)"
_repo_dirty="null"
if git diff --quiet 2>/dev/null && git diff --cached --quiet 2>/dev/null; then
_repo_dirty="false"
elif git rev-parse --git-dir >/dev/null 2>&1; then
_repo_dirty="true"
fi
_host="$(hostname 2>/dev/null || echo unknown)"
_written_at="$(date -u '+%Y-%m-%dT%H:%M:%SZ')"
_run_stamp="$(date -u '+%Y%m%dT%H%M%SZ')"
_run_id="${_run_stamp}-${_stem##*/}"
_freebsd="$(freebsd-version -kru 2>/dev/null | tr '\n' ' ' | sed 's/[[:space:]]*$//')"
_builder="${BUILT_BY:-Codex ISO Builder}"
_build_command="${BUILD_COMMAND:-unknown}"
@ -159,11 +167,20 @@ fi
_tmp="${_manifest}.tmp.$$"
cat > "${_tmp}" <<EOF
{
"schema": "clawdie.iso-artifact.v1",
"schema": "clawdie.iso.publish.v1",
"legacy_schema": "clawdie.iso-artifact.v1",
"project": "clawdie-iso",
"artifact_type": "operator-usb-image",
"workflow": "iso-publish",
"run_id": "$(json_escape "${_run_id}")",
"status": "pass",
"actor": "$(json_escape "${_builder}")",
"host": "$(json_escape "${_host}")",
"branch": "$(json_escape "${_branch}")",
"commit": "$(json_escape "${_commit}")",
"repo_dirty": ${_repo_dirty},
"started_at": null,
"completed_at": "$(json_escape "${_written_at}")",
"artifact_type": "operator-usb-image",
"build_host": "$(json_escape "${_host}")",
"built_by": "$(json_escape "${_builder}")",
"image": "$(json_escape "${_raw_base}")",
@ -179,6 +196,25 @@ cat > "${_tmp}" <<EOF
"image_url": $(json_string_or_null "${_image_url}"),
"sha256_url": $(json_string_or_null "${_sha_url}"),
"manifest_url": $(json_string_or_null "${_manifest_url}"),
"inputs": {
"compressed_image_path": "$(json_escape "${_gz}")",
"sha256_path": "$(json_escape "${_sha}")"
},
"checks": [
{
"name": "checksum_file_matches_compressed_image",
"status": "pass",
"sha256": "$(json_escape "${_gz_hash}")"
}
],
"outputs": {
"manifest_path": "$(json_escape "${_manifest}")",
"image_url": $(json_string_or_null "${_image_url}"),
"sha256_url": $(json_string_or_null "${_sha_url}"),
"manifest_url": $(json_string_or_null "${_manifest_url}")
},
"logs": [],
"summary": "Published artifact manifest is ready for Hermes checksum/gzip verification and flashing.",
"notes": "Built on FreeBSD; ready for Hermes USB/IMG Deployer after checksum and gzip verification."
}
EOF

View file

@ -39,6 +39,14 @@ Keep the real paths as-is, but speak about them clearly:
- `tmp/cache/FreeBSD-*.img` = cached memstick base image
- `tmp/packages` = fetched package archives
## Manifest contract
The build workflow should emit or hand off `clawdie.iso.build.v1` results under
`tmp/colibri/iso-build/` when Colibri ingestion is part of the task. The image
itself also embeds `/usr/local/share/clawdie-iso/build-manifest.json` for live
runtime inspection. See `docs/ISO-MANIFESTS.md` for the schema fields and path
conventions.
## Preconditions
- Run on the FreeBSD build host, from the repo root
@ -124,7 +132,10 @@ switch to `iso-build-cleanup`.
`FEATURE_COLIBRI=YES` is the default for the next ISO lane. The ISO build
stages FreeBSD-native Colibri artifacts from the adjacent `../colibri` checkout;
it does **not** build Rust while the image is mounted.
it does **not** build Rust while the image is mounted. The daemon is staged but
kept disabled at boot by default (`COLIBRI_DAEMON_ENABLE=NO`) until rc.d
supervision has passed live-USB validation, so Colibri cannot block SDDM/XFCE
startup.
Build Colibri on the FreeBSD/OSA host, not on Debian/Linux. Do not cross-ship
from debby unless the native OSA build fails.

View file

@ -0,0 +1,106 @@
---
name: iso-flash-verify
description: Verify a published Clawdie operator USB artifact manifest, download and checksum the image, confirm the whole-disk USB target, flash it, and emit a Colibri flash manifest.
---
# iso-flash-verify
Use this skill for the Hermes USB/IMG Deployer lane. It consumes a published
`clawdie.iso.publish.v1` manifest and produces a `clawdie.iso.flash.v1`
manifest. Do not run it from this ISO developer host unless the operator
explicitly reassigns flashing.
## Safety rules
- Never flash from terminal scrollback alone; start from a manifest URL or path.
- Verify the SHA256 and run `gzip -t` before writing bytes.
- Flash only a whole disk such as `/dev/sdX` or `/dev/daX`, never a partition
such as `/dev/sdX1`.
- Record the selected device model, serial, and size before flashing.
- Abort if the target is smaller than the raw image size in the manifest.
## Manifest output
Write the result to:
```sh
tmp/colibri/iso-flash/<run_id>.json
tmp/colibri/iso-flash/latest.json
```
Schema: `clawdie.iso.flash.v1`. See `docs/ISO-MANIFESTS.md`.
## 1. Select the publish manifest
Set one of these:
```sh
MANIFEST_URL="https://osa.smilepowered.org/downloads/iso/<image>.manifest.json"
```
or:
```sh
MANIFEST_PATH="tmp/output/<image>.manifest.json"
```
## 2. Download artifacts
For a URL-based handoff:
```sh
mkdir -p tmp/flash-downloads
curl -fL -o tmp/flash-downloads/publish.manifest.json "$MANIFEST_URL"
```
Read the manifest and download the `image_url` and `sha256_url` it names. If
`jq` is available:
```sh
IMAGE_URL="$(jq -r .image_url tmp/flash-downloads/publish.manifest.json)"
SHA_URL="$(jq -r .sha256_url tmp/flash-downloads/publish.manifest.json)"
curl -fL -O --output-dir tmp/flash-downloads "$IMAGE_URL"
curl -fL -O --output-dir tmp/flash-downloads "$SHA_URL"
```
## 3. Verify checksum and gzip integrity
```sh
cd tmp/flash-downloads
sha256sum -c "$(basename "$SHA_URL")"
gzip -t "$(basename "$IMAGE_URL")"
cd -
```
If the checksum file is in FreeBSD `sha256(1)` format, compare manually:
```sh
sha256sum tmp/flash-downloads/*.img.gz
cat tmp/flash-downloads/*.img.gz.sha256
```
## 4. Identify the whole-disk target
On Linux:
```sh
lsblk -o NAME,TYPE,SIZE,MODEL,SERIAL,TRAN,RM,MOUNTPOINTS
```
Unmount any mounted partitions from the selected removable disk. Confirm the
whole-disk path with the operator before writing.
## 5. Flash
Example for Linux, replacing `/dev/sdX` with the confirmed whole disk:
```sh
gzip -dc tmp/flash-downloads/<image>.img.gz | sudo dd of=/dev/sdX bs=4M status=progress conv=fsync
sync
```
## 6. Emit flash manifest
Record pass/fail checks, the artifact URLs, selected target disk facts, flash
command summary, and completion time in `clawdie.iso.flash.v1`. Print the
manifest path and a one-line summary for Colibri ingestion.

View file

@ -0,0 +1,72 @@
---
name: iso-hardware-report-ingest
description: Ingest real-machine live USB hw-report evidence into a structured Colibri hardware manifest without treating static inspection as hardware proof.
---
# iso-hardware-report-ingest
Use this skill after the operator or Codex ISO Builder collects live USB evidence
from real hardware. It produces a `clawdie.iso.hardware.v1` manifest for Colibri
and dashboard consumers.
## Manifest output
Write the result to:
```sh
tmp/colibri/iso-hardware/<run_id>.json
tmp/colibri/iso-hardware/latest.json
```
Schema: `clawdie.iso.hardware.v1`. See `docs/ISO-MANIFESTS.md`.
## Inputs to collect from the live USB
Prefer files copied from the live session over paraphrased observations:
```sh
hw-report > /tmp/clawdie-hw-report.txt
pciconf -lv > /tmp/clawdie-pciconf-lv.txt
ifconfig -a > /tmp/clawdie-ifconfig-a.txt
cat /var/log/clawdie-live-gpu.log > /tmp/clawdie-live-gpu.log
```
When debugging GUI/input/audio issues, also collect the relevant exact command
output named in `PLAN-OPERATOR-USB-NEXT.md`, for example:
```sh
xinput list
xfconf-query -c pointers -lv
cat /dev/sndstat
sysctl hw.snd.default_unit
mixer
```
If `hw-probe` upload is intentionally run, record only the public probe URL in
the manifest. Do not upload private operator data without approval.
## Ingest checklist
Record these as manifest checks or evidence fields:
- machine vendor/model and firmware version when available
- CPU model
- GPU PCI IDs, selected KMS module, and reason from `clawdie-live-gpu.log`
- GL renderer if collected
- SDDM login result and XFCE session result
- internal display and external display behavior if tested
- touchpad, keyboard, webcam, audio, Wi-Fi, and USB Ethernet observations
- Tailscale status if it was part of the test
- no-blank/power behavior observed during the session
- image filename or commit shown by the live build manifest
## Finish
Write a concise summary such as:
```text
AMD ASUS UX325UA: pass for SDDM/XFCE/AMD KMS/USB Ethernet/webcam; touchpad needs follow-up.
```
Attach paths to raw captured files under `logs` or `outputs`. Keep the manifest
small enough for Colibri to ingest directly.

View file

@ -0,0 +1,80 @@
---
name: iso-package-audit
description: Categorize operator USB package-list entries, capture package size/flat-size evidence on FreeBSD, and emit a Colibri package-audit manifest.
---
# iso-package-audit
Use this skill for Track B package-list hygiene. It classifies package-list
entries and records size evidence before any removal is proposed. Do not remove
packages during the audit commit.
## Manifest output
Write the result to:
```sh
tmp/colibri/iso-package-audit/<run_id>.json
tmp/colibri/iso-package-audit/latest.json
```
Schema: `clawdie.iso.package-audit.v1`. See `docs/ISO-MANIFESTS.md`.
## Categories
Use exactly one primary category per package:
- `boot-critical` — kernel/firmware/X/SDDM/network/power pieces needed for the
live USB to boot and present a usable session.
- `operator-workflow` — tools the operator intentionally uses from the live USB,
such as browser, CLIs, terminal/editor, or remote access.
- `diagnostic` — hardware/debug/reporting tools such as `btop`, `hw-probe`,
`dmidecode`, or graphics/audio diagnostics.
- `candidate-to-defer` — rarely used or replaceable packages that may be removed
later after build/hardware evidence supports it.
## FreeBSD evidence commands
Run on the FreeBSD build host with the target package branch configured. Fetch
before reporting repo state:
```sh
git fetch origin
git status --short --branch
git rev-parse --short HEAD
```
For installed packages on a mounted image or host package DB:
```sh
pkg info -s <pkgname>
pkg info -f <pkgname> | egrep '^(Name|Version|Installed size|Flat size)'
```
For packages present only in the offline repo, inspect package metadata from the
archive under `tmp/packages` and record the exact command used.
## Audit output expectations
For each package-list entry, record:
- package name
- package-list file path and line number when practical
- category
- package archive size and flat/installed size
- reason kept
- deferral risk if categorized as `candidate-to-defer`
- evidence command or metadata source
If editing a package list, add comments only. Do not remove packages in the same
change as the first audit pass.
## Finish
Write the `clawdie.iso.package-audit.v1` manifest and a concise human summary
with totals per category and total size by category. If markdown package-list
comments were edited, run:
```sh
./scripts/check-format.sh
```

View file

@ -18,6 +18,14 @@ public download target.
- Public webroot: `/usr/local/www/osa/downloads/iso`
- Public base URL: `https://osa.smilepowered.org/downloads/iso`
## Manifest contract
`scripts/write-artifact-manifest.sh` writes the canonical
`clawdie.iso.publish.v1` manifest beside the image as
`tmp/output/<image>.manifest.json`. Hermes consumes that file for
`iso-flash-verify`; Colibri can ingest it directly. See
`docs/ISO-MANIFESTS.md` for shared fields and handoff rules.
## Preconditions
Run from the repo root on the FreeBSD host. Use one command at a time.

View file

@ -0,0 +1,80 @@
---
name: iso-validate-image
description: Inspect a freshly built Clawdie operator USB image or mounted root to validate static runtime contracts and emit a Colibri validation manifest.
---
# iso-validate-image
Use this skill on the FreeBSD build host after an image exists and the operator
has assigned mounted-image validation. This is static validation only; it does
not replace real hardware proof that SDDM/XFCE/input/audio work.
## Manifest output
Write the result to:
```sh
tmp/colibri/iso-validation/<run_id>.json
tmp/colibri/iso-validation/latest.json
```
Schema: `clawdie.iso.validation.v1`. See `docs/ISO-MANIFESTS.md`.
## Preconditions
Run from the repo root on FreeBSD. Fetch before reporting repo state:
```sh
git fetch origin
git status --short --branch
git rev-parse --short HEAD
ls -lh tmp/output
```
If an image is already mounted under `tmp/cache/mnt`, inspect it cautiously. If
mount state is stale or unclear, use `iso-build-cleanup` before retrying.
## Validation checklist
Record each item as a named check in the manifest:
- `/etc/rc.conf` enables `sddm`.
- `/etc/rc.conf` enables `clawdie_live_gpu`.
- `/etc/rc.conf` enables `powerdxx` and the expected no-blank power/session
policy files are present.
- `/usr/local/bin/mdo` exists and is executable; `sudo` is not required by live
operator-facing paths.
- Operator CLIs expected by the current plan are present (`pi`, `codex`, and any
intentionally retained package-list CLIs).
- `/usr/local/share/clawdie-iso/build-manifest.json` exists inside the image.
- `CLAWDIESEED` slice 3 exists when inspecting the full disk image.
- `clawdie-live-gpu` and hardware report scripts are present and executable.
- Intel and AMD KMS modules/firmware expected by the package lists are present;
NVIDIA packages are staged/offline but not forced to load by default.
- XFCE panel/session assets referenced by the live session are present.
- Colibri binaries and `colibri_daemon` rc.d script are present when
`FEATURE_COLIBRI=YES` was used.
## Suggested inspection commands
Use exact device names from `mdconfig`/`gpart` on the build host; do not paste
these blindly if another build is active.
```sh
IMG="tmp/output/<image>.img"
md=$(mdconfig -a -t vnode -f "$IMG")
gpart show -p "/dev/$md"
```
Mount the root partition read-only when possible, then inspect files under the
mountpoint. Clean up the md device before finishing.
## Finish
Write a `clawdie.iso.validation.v1` manifest with:
- image path and checksum/manifest inputs when available
- mount devices and mountpoint used
- pass/fail status for each checklist item
- cleanup status for unmounts and `mdconfig -d`
- an explicit limitation note: mounted validation is not graphical hardware proof