clawdie-iso/docs/ONBOARDING-SIMPLIFICATION.md
Sam & Claude ba2f09f290 feat(seed): route seeded provider keys to provider.env for zero-touch boot
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>
2026-06-22 08:56:46 +02:00

5.6 KiB

Onboarding Simplification — Decision Doc

2026-06-22 | colibri#143 (zot-rpc-driver) | clawdie-iso

Context

The ISO ships with a manual onboarding flow: operator opens START-HERE.txt in Mousepad, types 3 Vaultwarden bootstrap credentials into a terminal (clawdie-join-hive), waits for API key fetch, restarts the daemon.

A zot extension was proposed as an interactive replacement. That was rejected — the onboarding must be agent-independent (chicken-and-egg: zot needs DEEPSEEK_API_KEY, which onboarding fetches), and the existing shell flow already implements masked input, validation, and the full fetch→restart chain.

The real lever is removing the step, not reskinning it.

Current state (proven, live)

Manual path (no seed partition)

  1. Operator boots ISO
  2. START-HERE.txt opens in Mousepad (bootstrap autostart)
  3. Operator double-clicks "Join Hive" on desktop
  4. Prompted for BW_CLIENTID, BW_CLIENTSECRET (masked), BW_PASSWORD (masked)
  5. clawdie-vault-fetch pulls API keys from Vaultwarden
  6. colibri_daemon restarted
  7. Pi agent auto-spawned and live

Seed partition path (one double-click)

Identical except step 4 is skipped — the seed importer (clawdie-live-seed, rc.d BEFORE LOGIN) already wrote the BW creds to provider.env. The operator just double-clicks "Join Hive" and the fetch runs automatically.

Files:

Component Path Role
Seed importer live/operator-session/clawdie-live-seed rc.d service, runs before login, mounts CLAWDIESEED, routes BW_* creds to provider.env
Vault fetcher live/operator-session/clawdie-vault-fetch Standalone: login→unlock→fetch keys by name→write env
Join Hive live/operator-session/clawdie-join-hive.sh Desktop launcher: checks for creds → prompts or auto-fetches
Seed README live/operator-session/clawdie-live-seed.README.txt Operator-facing seed partition instructions

Zero-touch: direct keys on the seed (implemented)

The click only existed to trigger the Vaultwarden round-trip. For a personalized stick that already holds the real provider keys, that round-trip is unnecessary — and the boot ordering already favors zero-touch:

  • clawdie_live_seed runs as root, BEFORE: LOGIN.
  • colibri_daemon runs REQUIRE: LOGIN — strictly after.

So the importer now merges the active agent's direct provider keys (everything except BW_*) into the daemon's provider.env as well as the operator's ~/.env. The daemon starts afterward, finds DEEPSEEK_API_KEY, and auto-spawns the agent (COLIBRI_AUTOSPAWN_PI=YES) — no click, no vault round-trip, no typing. BW_* still route to ~/.config/vault-bootstrap.env for operators who prefer the vault-fetch path.

This makes the personalized seed the onboarding primitive:

  • The image stays generic and publishable; secrets are never baked in.
  • The seed (FAT32 CLAWDIESEED) is the personalization layer and stays physical/offline — env (direct keys + optional TAILSCALE_AUTH_KEY), harness.toml, soul/, ssh/authorized_keys, optional /shred to wipe keys off the stick after first import.
  • The seed can be generated by an agent (e.g. Hermes) that already holds the soul and key material, written straight onto the mounted partition.

This supersedes the earlier xdg-autostart "delete the click" plan: it removes the click for free without a first-login sentinel or a network dependency at first boot.

The 3-credential bootstrap (BW_CLIENTID + BW_CLIENTSECRET + BW_PASSWORD) could collapse to a single pasted token via colibri-vault tenant provisioning. The vault would pre-generate a one-time enrollment token; the operator pastes it once; the host exchanges it for permanent API credentials. This eliminates the Vaultwarden account setup step entirely.

Status: not yet designed. Depends on colibri-vault tenant provisioning (colibri#91).

Zot extensions — verdict

Idea Verdict Rationale
Onboarding panel (zot ext) Reject Chicken-and-egg: zot needs secrets that onboarding fetches. Already solved by clawdie-join-hive.sh.
Guard (dangerous bash) ⏸ Defer Guards zot, not Pi (OOTB agent). String matcher is a nudge, not a boundary. Ship through first-party extension lane after zot is the runtime.
MCP bridge (zot↔Colibri) Keeper Sanctioned lane. Gated on zot-rpc-driver (colibri#143). First extension worth building — gives zot access to task board, vault, spawn, skills.

Sequencing

  1. Now (no dependencies): seed-partition zero-touch — delete the one remaining click. Biggest simplification, zero dependency on the zot saga.
  2. Gated on colibri#143: MCP bridge extension — zot↔Colibri, gives zot reason to be the runtime.
  3. After zot is OOTB runtime: guard extension shipped through first-party extension lane, paired with jail confinement for the real boundary.