diff --git a/.gitignore b/.gitignore index 9ab181be..4199344c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +# Never commit FreeBSD/pkg cache blobs anywhere in the repo. +**/*.pkg +**/*.txz + # Build artifacts (generated by build.sh) *.img *.img.sha256 diff --git a/AGENTS.md b/AGENTS.md index ac8cb2b5..e8cf6a2c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,196 +1,218 @@ -# 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 Codeberg; 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 | - -### 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 Codeberg 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 `. -- 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 two repos. Changes often require coordinated updates. - -| Repo | Purpose | Remote | -| ------------- | ---------------------------------------- | ------------------------------------------ | -| `Clawdie-AI` | Agent runtime, control plane, channels | `git@codeberg.org:Clawdie/Clawdie-AI.git` | -| `clawdie-iso` | ISO builder, firstboot wizard, installer | `git@codeberg.org:Clawdie/Clawdie-ISO.git` | - -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/-HANDOFF.md` or `-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) -``` + 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 `. + 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-`) 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| + | Repo | Purpose | Remote | + | ------------- | ---------------------------------------- | -------------------------------------------------- | + | `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/-HANDOFF.md` or `-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| \ No newline at end of file diff --git a/build.sh b/build.sh index 9d127254..046d743a 100755 --- a/build.sh +++ b/build.sh @@ -542,10 +542,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 ALL installed icon theme caches, not just the four + # commonly expected ones. Applications install icons into hicolor + # and their own theme directories; missing caches cause broken + # launcher icons (pcmanfm, xfce4-terminal, firefox, etc.). + for _icon_theme_dir in "${MOUNT_POINT}/usr/local/share/icons"/*/; do + _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 @@ -772,6 +775,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 +835,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" @@ -1378,14 +1385,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" diff --git a/doc/DEEPSEEK-V4-SMOKE.md b/doc/DEEPSEEK-V4-SMOKE.md index e71d0e88..6a11e8dd 100644 --- a/doc/DEEPSEEK-V4-SMOKE.md +++ b/doc/DEEPSEEK-V4-SMOKE.md @@ -108,6 +108,73 @@ Or export in your shell profile: export DEEPSEEK_API_KEY="" ``` +## Verifying Key Deletion / Revocation + +### 1. Confirm the key is gone from pi + +```sh +cat ~/.pi/agent/auth.json +``` + +If empty `{}`, no stored key. If it contains a `deepseek` entry, remove +it: + +```sh +# Back up first +cp ~/.pi/agent/auth.json ~/.pi/agent/auth.json.bak +# Edit to remove the deepseek entry, or wipe entirely: +echo '{}' > ~/.pi/agent/auth.json +``` + +### 2. Confirm the env var is unset + +```sh +echo "DEEPSEEK_API_KEY is set: ${DEEPSEEK_API_KEY:+yes}" +``` + +If blank, no env key. If still set: + +```sh +unset DEEPSEEK_API_KEY +``` + +### 3. Confirm the revoked key is rejected by the API + +```sh +DEEPSEEK_API_KEY="" pi --provider deepseek --model deepseek-v4-flash -p "test" 2>&1 +``` + +Expected error: + +``` +401 Authentication Fails, Your api key: ****XXXX is invalid +``` + +If you see `401`, the key is properly revoked at DeepSeek's side. + +### 4. Confirm clean "no key" state + +```sh +pi --provider deepseek --model deepseek-v4-flash -p "test" 2>&1 +``` + +Expected error: + +``` +No API key found for deepseek. +``` + +If you see this, pi has no stored or env key for DeepSeek — fully clean. + +### Error Reference + +| Scenario | Error message | +| ---------------------------- | ------------------------------------------------------------- | +| No key at all | `No API key found for deepseek.` | +| Revoked / invalid key | `401 Authentication Fails, Your api key: ****XXXX is invalid` | +| Rate limited (too many reqs) | `429 Rate limit reached...` | +| Quota exhausted | `402 Insufficient balance` | + ## Deletion Criteria - Lane confirmed in agent capability table diff --git a/doc/LLM-PROVIDER-HARNESS.md b/doc/LLM-PROVIDER-HARNESS.md index 21bcd16b..336d8c4d 100644 --- a/doc/LLM-PROVIDER-HARNESS.md +++ b/doc/LLM-PROVIDER-HARNESS.md @@ -112,3 +112,70 @@ When a key needs rotation: 4. Delete the old key at the provider dashboard. Never paste provider keys into chat, commit messages, logs, or public docs. + +## Verifying Key Cleanup + +After revoking a key, confirm it's fully removed: + +```sh +# 1. No stored key +cat ~/.pi/agent/auth.json # should be {} + +# 2. No env var +echo "Key set: ${DEEPSEEK_API_KEY:+yes}" # should be blank + +# 3. Revoked key is rejected +DEEPSEEK_API_KEY="" pi --provider deepseek --model deepseek-v4-flash -p "test" 2>&1 +# Expected: "401 Authentication Fails, Your api key: ****XXXX is invalid" + +# 4. Clean "no key" state confirmed +pi --provider deepseek --model deepseek-v4-flash -p "test" 2>&1 +# Expected: "No API key found for deepseek." +``` + +--- + +## Platform × Harness Matrix + +Level 1 is the **platform** (FreeBSD main, Linux auxiliary). +Level 2 is the **harness** — which agent runtime lives where and which +LLM providers each can reach. + +### Level 1: Platform + +| Platform | Role | Primary harness | Herdr | Notes | +| --------------------- | ----------------------------- | --------------- | ----- | -------------------------- | +| **FreeBSD (main)** | ISO build, live USB, validate | pi + codex | no | Authoritative build host | +| **Linux (auxiliary)** | Review, deploy, Colibri, UX | pi + herdr | yes | Opencode + Claude sessions | + +### Level 2: Harness × LLM Provider Combos + +Each cell shows: provider/model — smoke status. + +| Harness / Agent | DeepSeek v4 | GLM-4.7 (z.ai) | GPT-5.5 (OpenAI/Codex) | Claude (Anthropic) | Gemini (Google) | +| --------------- | ------------------------------- | -------------------------- | ----------------------------- | ------------------------- | ---------------------- | +| **pi** | `deepseek/v4-flash` PASS | `zai/` TRANSPORT OK | `openai-codex/gpt-5.5` ACTIVE | `anthropic/claude-*` TODO | `google/gemini-*` TODO | +| **codex** | n/a | n/a | built-in PASS | n/a | n/a | +| **claude-code** | DeepSeek via OpenAI compat TODO | n/a | n/a | native PASS | n/a | +| **opencode** | n/a (no DeepSeek config yet) | native PASS (this session) | n/a | n/a | n/a | +| **gemini-cli** | n/a | n/a | n/a | n/a | native TODO | + +### What populates the matrix + +- **FreeBSD live USB**: ships `pi` + `codex` only (per live CLI policy) +- **FreeBSD build host**: `pi` with `openai-codex/gpt-5.5` for Colibri review/fixes +- **Linux with herdr**: runs `pi`, `claude-code`, `codex`, `gemini-cli`, + and `opencode` — all visible in herdr panes +- **Opencode** (this session): currently GLM-4.7 via z.ai; other + providers can be wired via opencode's config +- **pi**: supports all providers via `--provider` flag; key in env or + `auth.json` + +### How to add a combo + +1. Pick an empty cell above. +2. Configure the agent for that provider (key, model). +3. Run the smoke (see Quick Start). +4. Update the cell with the exact `provider/model` string and PASS/FAIL. +5. Create a smoke doc if one doesn't exist. +6. Commit and push. diff --git a/doc/XFCE-PANEL-BUGS-HANDOFF.md b/doc/XFCE-PANEL-BUGS-HANDOFF.md index 44785b40..c194c009 100644 --- a/doc/XFCE-PANEL-BUGS-HANDOFF.md +++ b/doc/XFCE-PANEL-BUGS-HANDOFF.md @@ -2,7 +2,7 @@ **From:** Claude Reviewer / XFCE Tweaker (Linux) **Date:** 24.maj.2026 -**Status:** OPEN — hand off to Claude for XFCE visual-polish lane; base hardware collection is closed +**Status:** Visual-polish lane COMPLETE (Pass 1 + Pass 2, on `main`, build-ready: panel XML valid, `build.sh` install paths + Whisker icon verified). → **Awaiting ISO rebuild on the FreeBSD build host (osa) + a boot on the AMD/ASUS box** to check the verification items below. No domedog/config work remains. ## Pre-build changes applied (2026-05-24) diff --git a/firstboot/shell-ssh.sh b/firstboot/shell-ssh.sh index 25995748..c6e834c3 100644 --- a/firstboot/shell-ssh.sh +++ b/firstboot/shell-ssh.sh @@ -25,6 +25,7 @@ clawdie_shell_ssh_setup() { # 1. Configure SSH keys (if provided) # 2. Set system passwords (if provided or auto-generate) # 3. Configure SSH auth methods (key-only or key+password) + # 4. Seed SSH client defaults (~/.ssh/config) log_msg "[ssh] Starting SSH and password setup" @@ -42,7 +43,8 @@ clawdie_shell_ssh_setup() { if [ -n "${SSH_PUBLIC_KEY:-}" ]; then clawdie_shell_ssh_install_pubkey clawdie_shell_ssh_disable_password_auth - log_msg "[ssh] SSH public key installed, password auth disabled" + clawdie_shell_ssh_seed_client_config + log_msg "[ssh] SSH public key installed, password auth disabled, client config seeded" else clawdie_shell_ssh_enable_password_auth log_msg "[ssh] No SSH key provided, password auth enabled (less secure)" @@ -102,6 +104,38 @@ clawdie_shell_ssh_install_pubkey() { return 0 } +# ============================================================================ +# SSH CLIENT CONFIGURATION (seed ~/.ssh/config) +# ============================================================================ + +clawdie_shell_ssh_seed_client_config() { + # Seed SSH client defaults for the clawdie user. + # .profile / .bashrc / .tmux.conf are handled by shell-system.sh + # (which runs after this module). + # Run after clawdie_shell_ssh_install_pubkey (requires user to exist). + + local ssh_config="/home/clawdie/.ssh/config" + + # --- ~/.ssh/config: auto-load key on first use, no agent forwarding --- + if [ ! -f "$ssh_config" ]; then + cat > "$ssh_config" <<'SSHEOF' +Host * + AddKeysToAgent yes + ForwardAgent no +SSHEOF + chmod 600 "$ssh_config" + chown clawdie:clawdie "$ssh_config" 2>/dev/null || true + log_msg "[ssh] Seeded ~/.ssh/config with AddKeysToAgent yes" + else + if ! grep -q 'AddKeysToAgent' "$ssh_config" 2>/dev/null; then + printf '\nHost *\n AddKeysToAgent yes\n ForwardAgent no\n' >> "$ssh_config" + log_msg "[ssh] Appended AddKeysToAgent to existing ~/.ssh/config" + fi + fi + + return 0 +} + # ============================================================================ # SSH AUTH METHOD CONFIGURATION # ============================================================================ diff --git a/firstboot/shell-system.sh b/firstboot/shell-system.sh index 2c61c9ca..7c12ad49 100755 --- a/firstboot/shell-system.sh +++ b/firstboot/shell-system.sh @@ -354,6 +354,12 @@ EOF cat > /home/clawdie/.profile <<'EOF' # Clawdie operator POSIX shell profile. [ -r /etc/profile.d/clawdie.sh ] && . /etc/profile.d/clawdie.sh + +# Start SSH agent on login (FreeBSD: no systemd, no X11 agent launcher). +# Non-login shells (tmux windows) use ~/.bashrc fallback instead. +if [ -z "$SSH_AUTH_SOCK" ]; then + eval $(ssh-agent -s) > /dev/null 2>&1 +fi EOF cat > /home/clawdie/.bash_profile <<'EOF' # Clawdie operator bash login profile. @@ -365,14 +371,50 @@ EOF } [ -r "${HOME}/.bashrc" ] && . "${HOME}/.bashrc" EOF - cat > /home/clawdie/.bashrc <<'EOF' -# Clawdie operator interactive bash profile. + cat > /home/clawdie/.bashrc <<'BASHRC' +# Clawdie operator interactive bash shell. +# Non-interactive shells stop here. +case $- in *i*) ;; *) return ;; esac + +# ── PATH (FreeBSD: /usr/local first) ────────────────────────── +export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" [ -r /etc/profile.d/clawdie.sh ] && . /etc/profile.d/clawdie.sh -if [ -n "${PS1:-}" ]; then - export HISTFILE="${HISTFILE:-/tmp/clawdie/bash_history}" - mkdir -p /tmp/clawdie 2>/dev/null || true + +# ── Privilege escalation ────────────────────────────────────── +# Clawdie ISO: no sudo pkg. Use FreeBSD mac_do instead. +# mac_do rules (gid=0>uid=0) allow wheel→root transitions. +# ZFS auto-snapshot provides safety net — no confirmation prompts. +sudo() { + local pool + pool=$(zpool list -H -o name 2>/dev/null | head -1) + if [ -n "$pool" ]; then + (zfs snapshot "${pool}@cli-$(date +%s)" 2>/dev/null &) + fi + mdo -u root "$@" +} + +# ── SSH agent (fallback for non-login shells) ───────────────── +# .profile starts the agent for login shells; tmux windows +# (non-login) inherit via SSH_AUTH_SOCK if the parent had one, +# but if not, try a stored env file from a prior login. +if [ -z "$SSH_AUTH_SOCK" ] && [ -f ~/.ssh-agent-env ]; then + . ~/.ssh-agent-env 2>/dev/null || true fi -EOF + +# ── Prompt ──────────────────────────────────────────────────── +PS1='\h:\w\$ ' + +# ── History ─────────────────────────────────────────────────── +export HISTFILE="${HISTFILE:-/tmp/clawdie/bash_history}" +export HISTSIZE=5000 +export HISTFILESIZE=10000 +mkdir -p /tmp/clawdie 2>/dev/null || true + +# ── Aliases ─────────────────────────────────────────────────── +alias ll='ls -lah' +alias la='ls -A' +alias lt='ls -laht' +BASHRC cat > /home/clawdie/.zprofile <<'EOF' # Clawdie operator zsh login profile. [ -r /etc/profile ] && . /etc/profile diff --git a/live/operator-session/autostart/clawdie-xfce-visuals-guard.desktop b/live/operator-session/autostart/clawdie-xfce-visuals-guard.desktop new file mode 100644 index 00000000..f817d6b2 --- /dev/null +++ b/live/operator-session/autostart/clawdie-xfce-visuals-guard.desktop @@ -0,0 +1,7 @@ +[Desktop Entry] +Type=Application +Name=Clawdie XFCE Visuals Guard +Comment=Re-assert wallpaper, theme, and panel settings after XFCE creates monitor-specific state +Exec=/usr/local/bin/clawdie-xfce-visuals-guard.sh +X-GNOME-Autostart-enabled=true +NoDisplay=true diff --git a/live/operator-session/clawdie-xfce-visuals-guard.sh b/live/operator-session/clawdie-xfce-visuals-guard.sh new file mode 100644 index 00000000..97a38e26 --- /dev/null +++ b/live/operator-session/clawdie-xfce-visuals-guard.sh @@ -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 diff --git a/live/operator-session/panel-skel/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-panel.xml b/live/operator-session/panel-skel/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-panel.xml index 1c021c56..8acfbbc2 100644 --- a/live/operator-session/panel-skel/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-panel.xml +++ b/live/operator-session/panel-skel/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-panel.xml @@ -44,7 +44,7 @@ - + diff --git a/scripts/fetch-npm-globals.sh b/scripts/fetch-npm-globals.sh index a29182f8..f8b20540 100755 --- a/scripts/fetch-npm-globals.sh +++ b/scripts/fetch-npm-globals.sh @@ -8,6 +8,7 @@ # Notes: # - Codex is shipped via the FreeBSD `codex` pkg (see pkg-list-host.txt), # not via npm — kept out of this bundle on purpose. +# - Claude Code is intentionally not bundled in the XFCE USB image path. # - opencode + cursor have no working FreeBSD distribution (upstream gap). # - Output is dual-purpose: bundled into the ISO and used by firstboot. #