Pi-era residue in current-tense docs/strings (CHANGELOG history left intact):
- ONBOARDING-SIMPLIFICATION: COLIBRI_AUTOSPAWN_PI -> COLIBRI_AUTOSPAWN; 'Pi
agent' -> 'agent'.
- clawdie-join-hive.sh: user-facing 'Pi agent is live' / 'no Pi agent' ->
harness-neutral (default agent is now zot).
- clawdie-live-seed.README.txt: COLIBRI_AUTOSPAWN_PI -> COLIBRI_AUTOSPAWN.
- stage-colibri-iso.sh provider.env.sample: the AUTOSPAWN_ARGS example showed
'--mode json' (invalid for the zot default); note the default is
harness-derived (zot -> rpc, pi -> --mode json).
Also restore the markdown format gate: 5 docs from the 0.12.0 work were
prettier-dirty, so ./scripts/check-format.sh was already failing on main (the
gate was red and unenforced — same pattern as the colibri build break).
prettier --write brings them to style; gate is green again. No prose changes
in those 5 — formatting only.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two variants of a photorealistic 6V frequency geodesic dome
encapsulating an organic farm at golden hour. Generated via
OpenRouter (google/gemini-2.5-flash-image, upscaled to 3840x2160).
The existing clawdie-operator-bg remains as the default — these
are alternatives the operator can select.
Replace the filled gradient triangle with the geodesic 2V logo:
outer triangle + inverted inner triangle at midpoints. Cyan
on dark gradient. SVG + 2560x1440 PNG render.
- Update ssh/config example to show mother-mcp key with both Host entries
(mother MCP and code.smilepowered.org with IdentitiesOnly yes)
- Add dedicated mother-mcp section explaining the key serves two roles:
1. MCP calls to mother (command=colibri-mcp,restrict)
2. Git pull from Forgejo as a read-only deploy key
- Note that read-only is sufficient and limits blast radius
- Update START-HERE.txt to mention git pull works OOTB with seeded key
CPU graph now comes before the systray (NetworkManager + volumeicon),
followed by the keyboard layout switcher and clock. Language widget
display-scale reduced from 60 to 50 (was still too large).
The baked mother key (build/mother-ssh-key) puts a private key in the image,
which only works for a non-published personalized stick. The offline FAT32
seed is the correct home for per-node secrets.
Teach the importer to install outbound SSH client material from an agent's
ssh/ dir into the agent home:
- config -> ~/.ssh/config (0600)
- known_hosts* -> ~/.ssh/known_hosts* (0644, merged + de-duped)
- <name>.pub -> ~/.ssh/<name>.pub (0644)
- <name> -> ~/.ssh/<name> (0600, any other file = private key)
authorized_keys stays inbound-only via _seed_install_authorized_keys.
This closes the 'without manual key exchange' gap: known_hosts pins mother's
host key so the first node->mother connect does not prompt, and the private
client key rides on the offline seed instead of the base image — so the
published image stays secret-free. Supersedes the baked-key path (#112),
which can retire once this is validated on hardware.
Verified offline (CLAWDIE_SEED_TEST): correct perms (key 0600, pub/known_hosts
0644, config 0600, .ssh 0700) and idempotent known_hosts merge across re-runs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The live seed importer merged the active agent's provider keys into the
operator ~/.env, but colibri_daemon reads /usr/local/etc/colibri/provider.env
(rc.conf colibri_daemon_provider_env). So a personalized seed carrying real
provider keys never reached the daemon and no agent auto-spawned.
Route the active agent's non-BW_* keys into provider.env (0600 root) in
addition to ~/.env. The importer runs as root BEFORE LOGIN and colibri_daemon
REQUIREs LOGIN, so the daemon starts after the keys land and auto-spawns the
agent on first boot — no Join Hive click, no Vaultwarden round-trip, no typing.
This makes a personalized seed the zero-touch onboarding primitive: the image
stays generic/publishable, the FAT32 seed is the (offline) personalization
layer. BW_* still route to vault-bootstrap.env for the vault-fetch path.
Docs: seed README, START-HERE, and ONBOARDING-SIMPLIFICATION updated to
describe the direct-keys path (supersedes the xdg-autostart plan).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PR #102 wired the standalone tailscale-auth-key vault item, but the
out-of-the-box path (no baked key) could not actually start the service:
- clawdie-tailscale-up kept required_files=<keyfile>, which onestart still
enforces; the keyfile is absent on the OOTB image. Removed it — the start
function already returns 0 when neither provider.env nor the keyfile carries
a key, so the guard is redundant.
- join-hive called `service ... start`: refused because the service defaults to
enable=NO without a baked key, and it lacked root. Now `mdo -u root service
... onestart` (root + bypass rcvar).
- join-hive's post-join cleanup ran `sed ... provider.env/d` — a stray /d on the
file path made it error. Dropped it; the rc.d strips the key on success.
- join-hive interpolated the key into `sh -c "..."` argv (visible in ps). Now
piped via stdin.
Also keep provider.env at 0600 after the rc.d rewrite (it still holds BW_*).
Validated: sh -n on both scripts, ./scripts/check-format.sh clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- join-hive.sh: sed -i '' '/^TAILSCALE_AUTH_KEY=*** → .../d' (delete was missing)
- tailscale-up: grep -v pattern aligned to match any value, not literal ***
- Both files pass sh -n
Adds step [2b] to join-hive: if bw is available and the node is not
yet on Tailscale, fetch the tailscale-auth-key item from Vaultwarden,
write TAILSCALE_AUTH_KEY to provider.env, and trigger tailscale-up.
- Handles both naming variants (tailscale-auth-key / tailscale_auth_key)
- One-shot: key removed from provider.env after successful join
- tailscale-up now reads from provider.env first, legacy key file as fallback
- Graceful: no vault item → clear message, no break
Vault-mediated key exchange (direction B — we call mother). After ensuring the
colibri SSH identity, enable-mother now upserts the pubkey into Vaultwarden as
`hive-pubkey-<hostname>` (via bw, run as root so it can read the BW_* bootstrap
creds from provider.env). Mother's mother-sync-hive-keys rebuilds its
authorized_keys from these items, so no operator copy-paste between machines.
The printed pubkey + restricted command= line remain as a manual fallback when
the vault publish is unavailable. Uses the bitwarden-cli-vault skill's
session+upsert pattern. sh -n clean; embedded JSON/id-extraction tested.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Track C's enable-mother overwrote external-mcp.json with a single mother
server. Use jq to merge the mother entry into the existing registry so other
configured servers are preserved, written atomically (mktemp in same dir + mv).
This is the concrete consumer that makes jq a real dependency of the MCP path;
fails loudly if jq is absent.
(Re-applied: the original commit was lost to a branch-recreation race when #97
merged at the packages-only commit.)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Per Hermes' review of the cred-capture flow: after the daemon restart that
loads the pulled keys, poll colibri status (up to 10s) for a live agent so the
operator sees confirmation that the Pi auto-spawn actually came up — instead of
just "daemon restarted". Prints "Pi agent is live." or a check hint.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Workstream C of the next ISO rebuild.
C1 — Auto-spawn lit up out of the box:
provider.env now ships COLIBRI_AUTOSPAWN_PI="YES", so colibri#137 fires on
the booted image once a DeepSeek key is present (pulled by Join Hive, A).
C2 — External MCP registry staged:
/usr/local/etc/colibri/external-mcp.json shipped as {"servers":{}} at the
path colibri-mcp reads by default. Empty = mother off by default.
C3 — Opt-in "Enable Mother Link" (clawdie-enable-mother + desktop entry):
Direction is "our Pi calls mother's tools" — colibri-mcp dials OUT to mother
over SSH-stdio and proxies mother's tools to the Pi via its external-call
path. The toggle:
- provisions an SSH identity for the colibri service account
(/var/db/colibri/.ssh — the daemon and its Pi run as `colibri`),
- writes the mother entry into external-mcp.json (ssh -i <key> ... mother),
- upserts COLIBRI_MCP_EXTERNAL_CALL=1 into provider.env,
- restarts the daemon and prints colibri's pubkey to authorize on mother.
provider.env.sample documents the new toggles. sh -n clean on all scripts;
the empty default and the emitted mother entry validate as JSON and match the
ExternalMcpRegistry {servers:{command,args,env}} shape.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Workstream A of the next ISO rebuild. The booted XFCE image's "Join Hive"
flow now collects the 3 Vaultwarden bootstrap values and pulls the provider
keys, instead of only warning when they are missing.
Step [2/4] now:
- If provider.env lacks BW_*, prompts for BW_CLIENTID/BW_CLIENTSECRET/
BW_PASSWORD (secret + password read with echo off) and upserts them into
provider.env (root-owned 0600). Entering nothing skips — manual floor intact.
- Then runs clawdie-vault-fetch against provider.env (as bootstrap and as
--write-env target) to pull DEEPSEEK_API_KEY (and other agent-secrets), and
restarts colibri_daemon so it loads the new keys — which triggers the Pi
auto-spawn (colibri#137).
Secrets never appear in process arguments: values stay in shell variables and a
0600 temp under ~/.cache/clawdie; provider.env is read/written via mdo. The
upsert preserves the endpoint line and other keys (verified: special characters
in the secret/password survive, no duplicate BW_* lines).
provider.env stays the single secret store — the daemon's vault provisioning and
the existing provider_env_has_bw_creds check already assume that.
sh -n clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Stop fighting FreeBSD's PYTHON_DEFAULT=3.11: make python3 resolve to 3.11
(python312 stays installed and available as python3.12 for anything needing
newer). This also makes Pillow trivial — py311-pillow imports on plain python3,
so the image-render/screenshot skill needs no version gymnastics.
- build.sh: python3/python symlink → 3.11 (prefer python3.11, else lowest).
- pkg-list-live-operator.txt: add py311-pillow.
- clawdie-join-hive.sh: advertise image-render when `python3 -c import PIL`
works, and screenshot when $DISPLAY is set.
- BUILD.md: short note (python3=3.11; python3.12 available; image-render via
py311-pillow).
Validated: sh -n build.sh + join-hive clean; markdown gate clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
FreeBSD pkg repos build against PYTHON_DEFAULT=3.11, so system packages
(git, libinput, npm-node24) pull python311 as transitive deps. We keep
python312 as the application Python — it wins the python3 symlink via
sort -V. Document this in BUILD.md, build.sh, package lists, and
bootstrap.html so the dual-version reality is explicit and intentional.
Add COLIBRI_STAGE_TEST_AGENT with dev/release defaults so validation builds can include colibri-test-agent while production/release operator USB images omit it by default. Keep poudriere guidance test-friendly and document binary roles in BUILD.md.\n\nValidation: sh -n build.sh scripts/stage-colibri-iso.sh live/operator-session/colibri-live-rebuild; ./scripts/check-format.sh; ./scripts/test-release-gate.sh; build.cfg default/override checks.
clawdie_live_power is a one-shot boot script that applies the power_profile
C-state policy once (FreeBSD's power_profile is nostart and otherwise only
runs on a devd AC-line transition). Comment-only clarification — no behavior
change:
- Move the PROVIDE/REQUIRE/BEFORE/KEYWORD rcorder block to the top (convention;
rcorder scans the whole file, so behavior is identical).
- Document scope explicitly: this selects a CPU C-state/freq profile ONLY —
never suspend/sleep/blank/DPMS (screen-blank is the separate no-blank stack).
- Record the wake-safety invariant: both AC (0x01) and battery (0x00) branches
are safe because rc.conf pins performance_cx_lowest AND economy_cx_lowest to
C3, so neither can select a deeper C-state that breaks USB resume. Guard-rail
for future editors: do not deepen on the live USB.
sh -n clean; rcorder tags intact.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Build installs /usr/local/bin/clawdie-join-hive (no .sh).
Desktop Exec had the .sh suffix — launcher would fail silently.
One-character fix: drop .sh from Exec line.
Stage a non-secret /usr/local/etc/colibri/provider.env with the Clawdie Vaultwarden endpoint so operators only add BW bootstrap credentials. Also teach clawdie-vault-fetch to honor BW_SERVER and fail closed if an existing bw login points at a different server.\n\nChecks: sh -n live/operator-session/clawdie-vault-fetch scripts/stage-colibri-iso.sh; ./scripts/check-format.sh; git diff --check; COLIBRI_REPO=/home/clawdie/ai/colibri scripts/stage-colibri-iso.sh <tmp>
bw config server refuses with 'Logout required before server config update'
when the CLI is already authenticated. The helper treated that as fatal
(exit 1), which broke every repeat run on an already-logged-in host — exactly
the 'refresh .env from vault' case the helper exists for.
The bw login block already tolerates 'already logged in'; mirror that for
bw config: capture stderr/stdout and tolerate 'logout required' /
'already configured' / 'already set', failing only on a real error.
Verified on domedog: fixed helper runs cleanly from the logged-in state
(previously exited 1 at the config step).
Checks: sh -n; git diff --check; ./scripts/check-format.sh (prettier clean).
Co-Authored-By: Hermes & Sam <hello@clawdie.si>
Address the 5 review concerns on the secrets-out-of-the-box feature:
1. Seed↔fetch path alignment: _seed_split_env routes BW_* creds out of .env
into ~/.config/vault-bootstrap.env (SEED_VAULT_BOOTSTRAP_REL), the path
clawdie-vault-fetch actually reads — so 'seed bootstrap → fetch out of
the box' now lines up without an explicit --bootstrap arg.
2. Drop unused COLLECTION_ID from clawdie-vault-fetch. Items are fetched by
name via 'bw get password', which is fail-closed on ambiguity; document
that item names must be unique in the visible vault.
3. Agent dir validation: _seed_agent_name_ok rejects leading-dot dirs
(.Spotlight-V100, .fseventsd) and traversal; _seed_agent_has_payload
requires a recognized payload so an empty/stray dir can't become active.
4. No phantom homes: extra agent dirs stage under /var/db/clawdie/seed/<agent>
only — _seed_stage_agent never writes a home or SSH keys.
5. Bootstrap file mode enforcement: clawdie-vault-fetch now stat-checks the
bootstrap file and refuses group/world-readable unless
VAULT_ALLOW_INSECURE_BOOTSTRAP is set.
Also renames _seed_import_env → _seed_merge_env + _seed_split_env and adds
_seed_key_ok to guard env var names.
Checks: sh -n on vault-fetch/live-seed/build.sh; git diff --check;
./scripts/check-format.sh (prettier clean); 5 concerns verified present.
Co-Authored-By: Hermes & Sam <hello@clawdie.si>
Two parallel, additive paths so a host gets its secrets out of the box;
the manual setup wizard stays the floor (no config = no-op).
clawdie-vault-fetch (new): language-neutral bw bridge. Reads a 0600
~/.config/vault-bootstrap.env, pulls keys from the agent-secrets
collection (item name = env var name, value in password field, so no jq),
prints KEY=VALUE or --write-env upserts 0600. Exit codes distinguish
skip (3, no bootstrap) / broken (1) / no bw (4). Pinned
@bitwarden/cli@2026.5.0 for offline bundling; staged in
configure_live_operator_session.
clawdie-live-seed: extend the CLAWDIESEED FAT32 importer from the
authorized_keys allowlist to a per-agent directory convention —
/<agent>/ with env (merged 0600), harness.toml (pi|zot|local), soul/
(staged), ssh/authorized_keys. Live USB single-agent (first dir = active);
extra dirs staged + flagged for deployed multi-agent. Optional
consume-and-shred. Import core is unit-testable via CLAWDIE_SEED_TEST.
README rewritten to document the per-agent contract and the operator
decision to allow plaintext secrets on the seed (seeded sticks are
secret-bearing media; 0600 landing + shred mitigations).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Seed live /home/clawdie/ai repos as shallow git checkouts with .git metadata and .clawdie-source.json provenance, remove stale hardcoded ISO version strings, and keep markdown formatting green.\n\nChecks: sh -n build.sh; sh -n scripts/stage-colibri-iso.sh; git diff --check; npx --yes prettier@3 --check BUILD.md README.md live/operator-session/bootstrap.html; ./scripts/check-format.sh; local file:// shallow clone smoke.
Switch ISO staging/docs from colibri-smoke-agent to colibri-test-agent, include rust/pkgconf for live Colibri rebuilds, stage provider.env.sample, wire the provider env rc.conf path, and document LLM key setup on the Firefox bootstrap page.\n\nChecks: npx --yes prettier@3 --check docs/LIVE-COLIBRI-REBUILD.md live/operator-session/bootstrap.html BUILD.md TESTING.md README.md; sh -n scripts/stage-colibri-iso.sh; sh -n build.sh; fake Colibri staging + sh -n staged rc.d script; git diff --check.
Installs read-only and trusted-write MCP client config examples under /usr/local/share/clawdie-iso/mcp-examples and links them from the bootstrap page.\n\nChecks: ./scripts/check-format.sh; sh -n build.sh scripts/stage-colibri-iso.sh; python3 -m json.tool MCP examples; git diff --check
Makes colibri-mcp a required Colibri artifact for the live operator USB, copies it into the image, documents the read-only default and explicit trusted COLIBRI_MCP_WRITE profile, and updates ISO build handoff docs.\n\nChecks: ./scripts/check-format.sh; sh -n build.sh scripts/stage-colibri-iso.sh; git diff --check
Removes stale Herdr references, reserves service clawdie for deployed disk/server targets, and keeps the live USB on colibri_daemon. Drops the baseline live rc.d/clawdie wrapper so the mounted-image contract matches the docs.\n\nChecks: ./scripts/check-format.sh; git diff --check; sh -n over scripts/ firstboot/ live/operator-session/ executables
Opt-in NVIDIA_UNIVERSAL lane (default NO; normal/single-branch builds unchanged):
one ISO that adapts to an unknown NVIDIA target.
- build.cfg: NVIDIA_UNIVERSAL flag.
- build.sh: install_nvidia_universal_repo() stages an on-image pkg repo with all
three branches (390/470/580 + settings), pkg-repo metadata, and a file:// repo
conf; universal mode bakes no branch and sets clawdie_live_gpu_mode=nvidia-auto.
- clawdie_live_gpu: nvidia-auto mode detects the device id (PR #30 fix) -> branch
{390,470,590} -> pkg-name -> `pkg install -r clawdie-nvidia` -> kldload, all
best-effort with fallback to integrated/scfb (never blocks boot).
- doc/NVIDIA-UNIVERSAL-HANDOFF.md: Codex FreeBSD build + hardware validation plan.
sh -n clean; detector+branch+pkg map unit-tested on Linux
(1c8c->590->nvidia-driver-580, 0fc8->470, 0e22->390). The pkg fetch/repo layout,
offline boot install, writable root, kernel ABI, and image size MUST be validated
on the FreeBSD build host + real NVIDIA hardware (see handoff).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The #29 detector grepped `chip=0x10de...`, but FreeBSD's chip field is
chip=0x<device><vendor> with vendor 0x10de in the LOW 16 bits — so it never
matched and the device id / recommended-branch logic was dead.
- nvidia_device_id: match `chip=0x<4hex>10de` and strip to the device id
(chip=0x1c8c10de -> 1c8c).
- nvidia_branch_for_device: non-overlapping architecture ranges returning the
build's lane labels {390,470,590} so detected vs staged compare correctly;
empty/unknown -> 590 (safe default for modern unknown hardware).
Validated on Linux against representative ids: Fermi 0e22->390, Kepler 0fc8->470,
Maxwell 1380 / Pascal 1b81 / Turing 1c8c / Ada 2684 ->590, empty->590. sh -n clean.
This is the detection brain for the universal NVIDIA auto-install lane; the
on-image NVIDIA repo + boot-time install is the FreeBSD build-side work (handoff).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Consolidates the operator-USB work into main now that the AMD ASUS hardware-evidence collection is closed and Codex is parked. Brings the live-session hardware lane (XInput/libinput touchpad guard, internal audio + resolver bootstrap, hw-report with gated public upload, operator-USB branding) and the config-only XFCE panel polish (Pass 1 + Pass 2: branded Whisker PNG, xkb text mode, panel 40px, systray square-icons).
Conflict: doc/LLM-PROVIDER-HARNESS.md was evolved on both sides. Resolved as a union with no content lost — the xfce-side harness/provider/fabric restructure is the base, and main's two unique blocks (Verifying Key Cleanup flow, the 2D Platform x Harness matrix + populate/add procedures) are preserved. The doc owner may later dedupe the overlap between the two 1D matrices and the 2D matrix.
Verification debt stays explicit and open (not closed by this merge): XFCE visual-polish confirmation and the next rebuilt-image hardware retest, per doc/XFCE-PANEL-BUGS-HANDOFF.md and PLAN-OPERATOR-USB-NEXT.md.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>