Fleet nodes (USB/disk, built from release memstick) use freebsd-update —
one command, zero flags. OSA uses pkgbase, carrying the repo-editing +
IGNORE_OSVERSION complexity. Make the distinction visible before anyone
starts reading steps meant for the other path.
The node OS version changed after the upgrade, but the mother hive_nodes
row still shows the old freebsd_version. Re-running the probe + node_register
makes the upgrade visible to the scheduler.
Renumbered: 8→9 (vulnerability audit).
Four corrections from Codex review:
1. One-time caveat: OSVERSION/IGNORE_OSVERSION is for the boundary only.
Remove it after reboot — persisting would spoof the wrong version on
the next upgrade and silently pull mismatched packages.
2. IGNORE_OSVERSION=yes as the canonical idiom (does not require knowing
the exact __FreeBSD_version number).
3. ABI="FreeBSD:15:amd64" marked as redundant (it is already the default
on 15.x; OSVERSION is the actual lever).
4. Date format: DD.mon.YY → DD.mon.YYYY (matches eu-date-format convention).
Live BE renamed to 15.1-upgrade-25.jun.2026.
Two improvements from the live OSA upgrade run:
1. Boot environment rollback: step 2 (before any base changes) now creates
a BE with naming convention MAJOR.MINOR-upgrade-DD.mon.YY. pkgbase does
NOT auto-snapshot ZFS — this must be done manually. If the upgrade
misbehaves after reboot, bectl activate + reboot = instant rollback.
2. Cross-release override: pkgbase refuses to fetch 15.1 packages while
running 15.0 userland. Document the env OSVERSION=1501000 override
needed to cross the boundary.
Renumbered subsequent steps 2→3, 3→4, ..., 7→8.
Covers the case where df unchanged after rm -rf or cargo clean because
sanoid snapshots captured the deleted files. Documents the vacuum
procedure: identify holding snapshots, destroy them to reclaim space
immediately, or use sanoid --prune-snapshots for the gentler path.
Updates Pitfalls to acknowledge this as the exception to "never touch
sanoid-managed snaps."
Discovered 2026-06-24: cargo clean freed 5.5G but df showed 16G unchanged.
usedbysnapshots = 26.6G across 9 sanoid snapshots. Full vacuum freed 13G
(16G → 29G free, pool 80% → 72%).
Covers: canonical command with FEATURE_COLIBRI=YES, flag matrix with
cache dependencies, pre-flight checklist, build steps overview, tmux
usage for long builds, --live-default-password, and common pitfalls.
Distilled from 2026-06-22 build session on OSA.
Discovered 2026-06-22: zroot/home/clawdie was missing from sanoid config,
allowing 10 autosnaps from April to accumulate 23.6G of dead weight.
Skill covers: pool/dataset audit, sanoid coverage check, safe destroy
of orphaned snapshots, template reference, and pitfall avoidance.
Session-based operations with no interactive prompts. Covers:
- Session setup from provider.env
- Read (list, get by name, get by ID)
- Create (base64-encoded JSON, with collection)
- Update (get → modify → pipe to edit)
- Delete
- Upsert pattern (create if absent, update if exists)
- Rebuild authorized_keys from vault items
Proven working: full round-trip of key creation → vault
publish → read back → delete on OSA 2026-06-21.
truss traces every kernel call a process makes. Quick reference,
full walkthrough (start daemon→trigger→stop→analyze), common
daemon pitfalls and their truss signatures, ktrace alternative.
Proven debugging colibri-daemon jail-spawn Permission Denied:
found bare command names unresolved under daemon(8) PATH and
staging directory ownership issues.
Reword the naming guidance from a "not X" anti-pattern to the decision we
actually made: name content/file-type recognition "detection" or "discovery".
Keeps the plain-language intent without prescribing what to avoid.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
SOUL.md now defines:
- Clawdie (bare-metal service): production target — Colibri + zot
on bare FreeBSD (ZFS RAID1, PostgreSQL + pgvector, bhyve VMs,
Bastille jails), developed from USB, deployed as rc.d service
- Keeps the dual-OS survivability framing below it
domedog is Docker-free by choice (overhead not yet worth it); the probe in
HOST-MATRIX confirms it. Reframe the "Who we are" bullet so Linux stays the
daily driver / ecosystem reach, but Docker is scoped to debby and domedog is
noted as running lean on the host. Survivability framing is unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pull durable knowledge out of agent session memory into the cross-harness
contract so every harness/agent honors it, not just this session:
- USER.md: new Conventions & voice section (EU date format DD.mon.YYYY,
positive instruction framing, plain-language naming + detection not
sniffing, lean/current docs). Colibri fact 12 -> 13 crates, MIT, v0.11.0.
- AGENTS.md: two operating rules (verify on the forge not local git status;
CI dormant by choice, merges ride local gates, domedog stays Docker-free).
- HOST-MATRIX.md + AGENTS.md matrix: domedog isolation Docker -> host
(no Docker), matching the probe in HOST-MATRIX section 3.
- curated/: colibri 13 crates/MIT/0.11.0 + vault, python3=3.11 policy,
real Docker layout (debby only; domedog Docker-free), hermes-bsd row.
Validated: scripts/layered_soul.py validate . -> OK.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Per operator decision: stop fighting FreeBSD's PYTHON_DEFAULT=3.11 — python3 is
3.11 everywhere, python3.12 stays available for apps needing newer. This makes
Pillow trivial (py311-pillow imports on python3), so the prior "3.12 floor +
py312-pillow absent + run on 3.11 explicitly" explanation collapses.
- TOOLCHAIN.md: table row + decision section flipped to 3.11-default and cut to a
few lines (supersedes the 17.jun.2026 "3.12 floor" decision); symlink note now
says build.sh points python3 at 3.11.
- CAPABILITY-ROUTING.md: trimmed the osa line + worked example — image-render via
py311-pillow on python3, no version gymnastics.
- HOST-MATRIX.md: trimmed the operator-image image-render/screenshot note.
prettier + layered_soul validate clean. Dates in edited blocks use EU format.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Follow-on to clawdie-iso #85 (py311-pillow + join-hive capability detection):
the operator image now advertises image-render and screenshot, so the
capability is no longer Linux/domedog-only. Update the CAPABILITY-ROUTING worked
example and the HOST-MATRIX capability note accordingly.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reconcile the toolchain + capability docs with clawdie-iso #84 (FreeBSD
PYTHON_DEFAULT=3.11):
- TOOLCHAIN.md: the FreeBSD column claimed `py312-*` flavors; reality is
python312 (app) + python311 (pkg default, transitive), with py311-* prebuilt
and py312-* absent in the quarterly repo. Added the 3.11/3.12 coexistence note
("3.12 floor" = floor for our code, not a ban on the base's 3.11).
- CAPABILITY-ROUTING.md: corrected the imprecise "Pillow dropped on FreeBSD"
rationale. The blocker was the missing py312-pillow flavor, not Pillow itself;
the prebuilt py311-pillow is available, so image-render can be restored on
FreeBSD via 3.11. Clarified screenshot also needs a display (XFCE operator
image yes, headless osa no → image-render only there).
prettier + layered_soul validate clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
register-tenant/list-tenants (#101) and --jail-name/--jail-root on spawn
(#102) are merged to colibri main (PR #107). Update Status: CLI-driveability
moves to DONE/merged, the critical-path note reflects the manual SQLite +
raw-socket steps are now CLI commands, and the one-line plan drops the
"merge #101/#102" step.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
External skill marketplaces (clawhub.ai, skills.sh, lobehub, browse.sh,
claude-marketplace) are unvetted instruction streams ingested into an agent's
context — a prompt-injection / supply-chain vector, the same class of risk as
`pkg install` from a random mirror, one layer up. Combined with the poudriere
plan, the conclusion is a first-party repository for BOTH layers.
- HIVE-ONBOARDING §10 (new): the trusted supply chain. pkg.clawdie.si (packages)
gets a sibling first-party skill repo (proposed skills.clawdie.si). External
sources become staging/review input, never a direct tenant runtime dep:
curate → pin → sign → publish. Clarifies clawhub.ai is third-party, unrelated
to pkg.clawdie.si (different layer + ownership).
- HIVE-ONBOARDING §5: mother expanded as the PAID product surface — paid tenants
are provisioned first-party-only; that hardening is the thing worth paying for.
§6 moat + §7 invariant + Status open-work updated to match.
- HOST-MATRIX §2: new "Registry & supply-chain provenance" table (first-party vs
third-party per layer); mother-build row notes it serves pkg.clawdie.si.
Validation: prettier@3 --check; python3 scripts/layered_soul.py validate . — pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Follow-up to #74. Two concrete fixes to the "identity wallpaper on join" step:
1. tmp policy: the join script hardcoded WP=/tmp/clawdie-wallpaper.png, passing
it to clawdie-wallpaper-gen and overriding the safe SCRATCH_DIR default that
9ae8d25 had just introduced (project-local tmp/ or app-owned cache). The
generator now prints its chosen path on stdout (human note → stderr) and the
join script captures it: WP=$(clawdie-wallpaper-gen). No host-global /tmp.
2. wallpaper actually applies: replaced the hardcoded
/backdrop/screen0/monitor0/workspace0/last-image with an enumeration over
every existing */last-image property (XFCE keys backdrops by connector name,
e.g. monitorHDMI-1, not monitor0), falling back to creating the default
property on first boot/headless, then xfdesktop --reload.
SKILL.md updated to document the stdout contract and multi-monitor wiring.
Validation: sh -n on both scripts; prettier@3 --check SKILL.md;
python3 scripts/layered_soul.py validate . — all pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Panel indicator: add have() checks for nc/python3, warn on missing
deps instead of failing silently, distinct states for socket-down
vs no-response with actionable tooltip text
- Join Hive: generate and apply identity wallpaper on success as
visual 'you're in' confirmation via xfconf-query
- SKILL.md: document new behaviors
Sync the wallpaper helper and iso-visuals guidance with the project-local tmp policy, falling back to app-owned live cache paths when no project root exists.\n\nValidation: sh -n skills/iso-visuals/scripts/clawdie-wallpaper-gen.sh skills/iso-visuals/scripts/clawdie-join-hive.sh; npx --yes prettier@3 --check skills/iso-visuals/SKILL.md; python3 scripts/layered_soul.py validate .
Mirror the Clawdie ISO Join Hive and wallpaper helper hardening in the iso-visuals skill, fix the desktop Exec path, and clarify staged-helper versus wired-default behavior.\n\nValidation: sh -n skills/iso-visuals/scripts/clawdie-join-hive.sh skills/iso-visuals/scripts/clawdie-wallpaper-gen.sh; npx --yes prettier@3 --check skills/iso-visuals/SKILL.md; python3 scripts/layered_soul.py validate .
Three improvements for the Clawdie ISO first-boot desktop:
1. Panel health indicator (xfce4-genmon)
- polls colibri socket every 30s
- green/red dot + agent count + task count
- click to open colibri status in terminal
2. Identity wallpaper generator
- overlays hostname, Tailscale IP, Colibri port, FreeBSD release
- runs on first boot, caches result
- requires ImageMagick (add to ISO pkg list)
3. Join Hive launcher
- one-click agent registration in visible terminal
- checks daemon → vault creds → detect capabilities → register
- idempotent, safe to re-run
- pauses on result so operator reads before closing
All three scripts + skill.md + desktop entry in skills/iso-visuals/.
- provenance table: add vultr-svc row (Forgejo + Vaultwarden, verified off-OVH
but a shared-box SPOF) — the third provider now in the picture.
- DPIA gate: scope to automated decisions about individuals (Art. 35/22); the
internal agent scheduler (routing to machines) does not trigger it.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Append to HOST-MATRIX §4, grounded in a verified DNS check:
- Forgejo + Vaultwarden both run on Vultr (different provider than osa/OVH —
good), but share ONE box = single point of failure for backups AND secrets;
that box needs its own off-box backup + test-restore.
- broaden MFA to every master-key account (OVH, Vultr, registrar, Forgejo,
Vaultwarden) + domain auto-renew (lapsed domain kills pkg.clawdie.si/ACME/SSH).
- billing hygiene (auto-renew/commitment/price-EOL windows).
- continuity plan is contractually required (GTS §6.3); multi-host survivability
is the recovery plan since provider SLA = credits only.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Use the 460 W high-load fan/PSU mark as the planning assumption for multitenant use, with GEN-I energy and URO network tariff estimates.\n\nValidation: npx --yes prettier@3 --check docs/HOST-MATRIX.md; python3 scripts/layered_soul.py validate .
Track hosting spend as a verified fleet fact alongside disk and hardware, seed TBD rows for osa/domedom/debby/proposed OVH build capacity/ML350p, and update HIVE status now that first-proof blockers are code-complete.\n\nValidation: npx --yes prettier@3 --check docs/HOST-MATRIX.md docs/HIVE-ONBOARDING.md; python3 scripts/layered_soul.py validate .
Persist the reconstructed plan: all four MVP steps code-complete on colibri main;
first proof is not code-blocked (interim manual runbook path); open work
categorized (hardening #100/#92, CLI-driveability #101/#102, naming #98/iso#70).
PR #90 (tenants table) closed as superseded — already on main.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
First proven end-to-end uses a scratch jail + throwaway test collection only; no
real tenant data until path hardening (#92) lands. First-proof blockers are #88
(resolve collection by name) and #89 (per-call unlock); #92 is hardening.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The handoff's work shipped (hermes-osa LIVE, validated, Telegram consolidated,
cross-host routing done); its facts now live in HOST-MATRIX. It carried the last
legacy 'do not do the old thing' content (Autolycus / AUTOLYCUS_HOME / preserve
clawdie-ai runtime) — removed per its own deletion criteria and the
decisions-match-shipped-code principle.
Kept (deliberately): security rules (never commit secrets/share tokens, bootstrap
never enters the jail) and technical guidance (FreeBSD --remote, lock ordering,
test counting) — those are correct current decisions stated as imperatives, not
legacy cruft.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
debby is a laptop that powers off periodically; osa is the always-on VPS and
already hosts the colibri board. The hub must live where it never disappears, so
the orchestrator role moves to hermes-osa; debby drops to secondary agent + soul
backup.
- AGENTS.md, HOST-MATRIX, agent-roster, tailscale-network: role swap + always-on/
intermittent facts
- HOST-MATRIX + CAPABILITY-ROUTING: corrected 'debby orchestrator dispatches' ->
osa hosts the board, debby/domedog are clients
- integration doc + SOUL/project-structure survivability lines reconciled
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Real tailnet IPs and Telegram bot handles were being committed in docs/
memories/skills. Scrubbed all tracked markdown to ${VAR} placeholders; real
values now live in fleet.env (gitignored) and stay live via 'tailscale status'.
- add fleet.env.example (committed) + fleet.env (gitignored); .gitignore *.env
- AGENTS.md + HOST-MATRIX: masking convention so it can't recur
- also: domedog registered as Colibri agent (image-render/ffmpeg/build lane);
correct CAPABILITY-ROUTING example to real registered caps (domedog headless)
Past commits not rewritten (history moves to Codeberg at v1.0); this fixes HEAD.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>