The rc.conf.sample on the live USB now sets require_secured=YES.
Together with the paired colibri change, this ensures the daemon
disables autospawn until the console gate writes .secured.
clawdie-iso half of the .secured interlock:
- build.sh writes colibri_daemon_require_secured="YES" to the operator image's
rc.conf. Opt-in so DEPLOYED colibri hosts (shared colibri_daemon.in via the
FreeBSD port, no firstboot gate) are unaffected — they never set this knob.
- gate skip message upgraded to 'agent will NOT start or register until secured'.
Depends on the colibri-side consumer (colibri_daemon.in prestart): when
colibri_daemon_require_secured is YES and /var/db/colibri/.secured is absent,
export COLIBRI_AUTOSPAWN=NO (after the provider.env source block). Tracked as the
colibri follow-up; both must ship in the same 0.12 image for the message to hold.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The '.secured' marker is written but not yet consumed by colibri, so the gate
must not imply colibri/zot are blocked. Reword the skip message to state the
node is UNSECURED and the agent SHOULD NOT register/run while unsecured — true
as a policy statement, without claiming enforcement we haven't built. Upgrade to
'will not' once the colibri .secured interlock lands.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the silent trailing sleeps with a counting-down message so the operator
sees the result (secured / skipped) and a clear cue before clawdie_live_gpu
repaints the screen. Same ~3s pause, now visible.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reorder the gate to REQUIRE: FILESYSTEMS devfs / BEFORE: clawdie_live_gpu LOGIN
so it runs on the plain early boot text console, before clawdie_live_gpu does its
KMS/framebuffer mode-switch. That removes the console-flush race entirely, so the
sleep 1 + screen-clear workaround is gone. Still before LOGIN, hence before sddm
and colibri_daemon (race-free property preserved).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds clawdie_firstboot_rootpw, an rc.d gate ordered BEFORE sddm and
colibri_daemon. On the text console (operator present at first boot) it runs a
15s countdown to engage; if engaged it forces a root AND operator (clawdie)
password, echo-off, applied via 'pw usermod -h 0' over stdin (secret never in
argv/ps, never near the agent). Idempotent via a persistent success marker
/var/db/colibri/.secured (/var persists: varmfs=NO). Skipping leaves the node
open and re-prompts next boot — never bricks an unattended/headless boot.
Running before the daemon means the security decision is always made before any
agent can autospawn/node_register, so no cross-component interlock is needed
(rc ordering replaces it). The .secured marker is also the signal a future
colibri change can read to label an unsecured node to mother.
Tests: tests/firstboot-rootpw-test.sh proves marker skip, password validation,
and that the secret is delivered on stdin and NEVER appears in argv (10/10).
Console interactivity (read -t countdown, stty echo-off on /dev/console) must be
verified by booting on osa/bhyve before merge.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Layer 0 (seed-import-test.sh): runs the real clawdie-live-seed importer in a
sandbox (CLAWDIE_SEED_TEST=1, all paths overridden) and asserts the seed->runtime
propagation contract — env split, provider.env, dual-home ssh, soul staging, and
AGENTS.md -> $ZOT_HOME (the global slot the autospawned zot reads). Idempotent
re-import is checked. REQUIRE_AGENTS_MD=1 enforces the AGENTS.md install added on
this branch; it passes 23/23 here.
Layer 2 (mcp-boundary-test.sh): exercises the mother MCP-over-SSH boundary on
Linux — colibri-mcp-ssh forced-command allowlist (""/"tools" route, everything
else rejected) and the MCP tools/list handshake, including a real loopback sshd
with command=. Skips cleanly when colibri isn't a sibling checkout.
Verified end to end on Linux before merge: importer target path and the ZOT_HOME
pin in colibri (fix/zot-home) both resolve to /var/db/colibri/.local/state/zot.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A. ZOT_VERSION drift: build.cfg defaulted to v0.2.42 while build.sh
preflight hint said v0.2.47. Now both default to v0.2.47.
B. AGENTS.md hw-probe phrasing: told zot to run clawdie-hw-probe,
but the daemon already collects it into CLAWDIE_HW_PROFILE at
autospawn time. zot should read the env var, not shell out.
C. RPC_PROMPT missing: COLIBRI_AUTOSPAWN=YES starts zot in RPC mode,
but without RPC_PROMPT, zot blocks on stdin and idles. Added
a prompt telling zot to read CLAWDIE_HW_PROFILE, call node_register
on mother, and report its assigned capabilities.
Adds seed/ directory with:
- AGENTS.md: zot operational rules (mother, verbs, capabilities)
- harness.toml: harness="zot", model="deepseek-v4-pro"
- env.placeholder: template for API key injection
build.sh seed population step reads provider keys from the build host's
/usr/local/etc/colibri/provider.env and writes them to the seed partition's
env file. Also installs AGENTS.md, harness.toml, and the layered-soul backup.
Keys are NEVER committed — only placeholders. Real keys are injected at build
time from the build host's provider.env (DEEPSEEK_API_KEY, OPENROUTER_API_KEY).
The seed importer already dual-writes SSH material to the daemon home.
Adds an AGENTS.md install block targeting /var/db/colibri/.local/state/zot/ —
the path pinned by colibri_daemon.in's ZOT_HOME export. Zot reads this as
its first AGENTS.md source, giving the autospawned agent operational rules
(mother, verbs, capabilities) on first boot.
The preflight checkout hint defaulted to v0.2.42 while the FreeBSD
build-lane handoff still named v0.2.29. Pin both to the current latest
zot tag (v0.2.47) so every reference the FreeBSD agent follows agrees,
and a release build targets one fixed agent version.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Convert US/ISO prose dates to EU format across iso docs (CHANGELOG, plans,
handoffs, wiki-linked docs). Left as-is (data, not prose): the sample log lines
in FIRSTBOOT.md and the ADMIN-PANEL.md UI mockup (timestamps/snapshot names);
ISO is correct for machine output.
Markdown format gate clean.
Three blockers fixed from review of fix/ootb-mother-mcp:
1. Real Tailscale IP removed from image/repo.
- external-mcp.json uses "mother" host alias (resolved by SSH config).
- Key path: /var/db/colibri/.ssh/mother-mcp (daemon user home).
- The real IP lives only on the offline seed (ssh/config), never in
the repo or the shipped image.
2. Cross-user key access fixed.
- The daemon runs as colibri (home /var/db/colibri), not clawdie.
- Seed importer now installs SSH material to both clawdie AND
colibri homes (same seed material, same key, separate ~/.ssh).
- build.sh dev convenience also copies to both homes.
- clawdie-live-seed.README.txt already documents the seed layout.
3. Doc fully de-obfuscated.
- All m0th3r/c0l1br1/n0d3_r3g1st3r → mother/colibri/node_register.
- All real IPs → <mother-tailscale-ip> placeholder.
- Removed Step 2 (manual external MCP) + Step 3 (register) — both
are now baked into the ISO.
- Removed trailing "colibri-mcp" remote command from examples
(hardened wrapper rejects non-allowlisted commands).
Two changes so the USB connects to mother on first boot with no manual steps:
1. stage-colibri-iso.sh: external-mcp.json is now pre-configured with the
mother server entry (colibri@100.72.229.63, no remote command — the
hardened wrapper starts colibri-mcp in stdio MCP mode). Previously
staged as empty {}; the operator had to create it manually or run
clawdie-enable-mother.
2. provider.env now includes COLIBRI_MCP_EXTERNAL_CALL=1 by default
(already set on osa; missing from the ISO defaults).
3. SETUP-USB-TO-MOTHER.md: removed Step 3 (manual external-mcp.json),
fixed the diagram to match the hardened wrapper (no remote command),
corrected the server name from "m0th3r"/"c0l1br1" to the real names.
The SSH key, config, and known_hosts still come from the CLAWDIESEED
seed partition — the image carries no secrets. Without the seed the
connection fails gracefully.
README said 'no separate feature flag', but the build keeps FEATURE_COLIBRI
(build.cfg default YES) as an internal escape hatch (e.g. building without a
colibri checkout). Clarify: colibri is staged by default; FEATURE_COLIBRI=NO is
an internal build-time hatch, not a user-facing option. Resolves a wiki-ledger
residue item.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The mother MCP scripts were copied into clawdie-iso (packaging/mother/) AND
colibri. The iso copies drifted: node-register-mcp on iso main was the old,
SQL-injectable version (E'${HOST_ESCAPED}' string interpolation) using
usb_nodes — while colibri #161 carries the reviewed, parameterized (psql -v
:'var') hive_nodes version.
One canonical home: colibri. Remove packaging/mother/ from the iso (nothing in
the iso build references it), redirect the two doc path references to the colibri
repo, and align the docs to hive_nodes (matching the colibri schema rename).
Supersedes #127 (which only renamed docs and conflicted after the iso copies
landed). Doc-only + file removals; markdown gate green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New packaging/mother/node-register-mcp accepts JSON-RPC tools/call,
inserts hw_profile into mother_hive.usb_nodes, and returns the row
with auto-derived capabilities (derive_capabilities trigger fires).
Requires one-time PostgreSQL setup on mother:
CREATE ROLE colibri WITH LOGIN;
GRANT CONNECT ON DATABASE mother_hive TO colibri;
GRANT INSERT, UPDATE ON usb_nodes TO colibri;
GRANT USAGE ON SEQUENCE usb_nodes_id_seq TO colibri;
Also updates docs to reflect 0.12 daemon behavior: hw-probe is
collected by the daemon (not the agent) and passed via CLAWDIE_HW_PROFILE
env var. COLIBRI_AUTOSPAWN_ARGS default is binary-dependent (zot->rpc,
others->--mode json).
The image shipped a hard pin (@earendil-works/pi-coding-agent@0.78.0) while
'pi upgrade' on hosts had moved to 0.80.2, so builds lagged. Switch Pi to the
@latest dist-tag so every image bundles the newest Pi.
To keep the floating spec traceable, record the version that actually got
fetched in build-manifest.json as pi_version, derived from the bundled tarball
name (earendil-works-pi-coding-agent-<version>.tgz) after fetch+install.
fetch-npm-globals.sh now also echoes the resolved tarball so the build log
shows the version a dist-tag resolved to.
Other globals (bw) stay pinned. Image is node24, compatible with current Pi
(the legacy-node20 dist-tag is for node20 only).
Verified: fetch resolves @latest → 0.80.2; version extraction matches npm.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Harness-neutral, lighter wording for the optional local test-double agent
(colibri-test-agent), matching the colibri-side fake→sample rename. Only the
two references that named it 'fake-agent' (build.cfg comment, AGENTS.md
staging note); the unrelated /tmp/fake-usb example path in FIRSTBOOT.md is a
different context and left as-is.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
5 steps from nothing to working: SSH key + config → enable
external MCP → register mother server → install hw-probe →
restart daemon. Uses real hosts (osa.smilepowered.org at
100.72.229.63, USB as clawdie-usb) with l33t placeholder keys.
ASCII architecture diagram showing persistent SSH child process,
JSON-RPC over stdin/stdout, mother-side forced-command wrapper.
Includes: end-to-end test, future autospawn flow, and
troubleshooting table for all common failure modes.
USB can connect to mother right now with 0.11 daemon —
colibri_external_mcp_call_tool is already in the tools list.
Just needs: SSH key, external-mcp.json, COLIBRI_MCP_EXTERNAL_CALL=1,
hw-probe installed, and daemon restart.
Architecture: USB spawns 'ssh colibri@mother colibri-mcp' as
persistent child process, JSON-RPC over stdin/stdout. Mother-side
wrapper strips forced-command layer. One SSH connection for
daemon lifetime.
Missing: node_register MCP tool on mother (needs implementation),
auto-key from seed partition (planned for 0.12 ISO build).
Cross-reference from OSA audit (2026-06-23): SSH hardening,
MCP socket, firewall, listening ports, service accounts,
external MCP servers. Each check has command + expected output.
OSA exceptions documented: password auth kept for dev access.
USB should be stricter — key-only SSH, no 0.0.0.0 bindings.
Skill saved: security-audit-clawdie (freebsd category)
Each step has diagrams, input/output schemas, test cases.
Added Step 6: mother-blender-render — photorealistic 3D via
Blender on mother node. USB requests renders via MCP, same
pattern as build-colibri.sh. 1 GiB Blender stays on mother;
light nodes get PNGs back. ~30h total implementation estimate.
GURS WFS endpoints for parcel boundaries, address lookup, and
spatial data (CC BY 4.0, free). Google 3D Tiles for photorealistic
backgrounds (paid). Four-phase plan: address → parcel → dome
placement → site-specific BOM. All Slovenian data sources
documented with endpoint URLs and coordinate systems.
Records the decision to use a pure-Python geodesic dome tool
(6KB, numpy+Pillow) instead of Blender (1 GiB, 53 packages).
OSA registered as first node in mother_hive PostgreSQL with
real hardware profile: 12GB RAM, no GPU, geodesic_dome_mcp=true.
This document serves as a capability baseline — any node that
can run Python can generate dome wireframes and structural BOMs.
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.