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>
133 lines
6.5 KiB
Markdown
133 lines
6.5 KiB
Markdown
# Hive Onboarding — `colibri-vault` and the "join the hive" primitive
|
|
|
|
**LIVE VS PLANNED.** This is a **design/vision** doc. The building blocks are real and
|
|
proven (Bastille jails on osa, capability routing, `register-agent`, and the
|
|
`clawdie-vault-fetch` flow validated end-to-end on domedog 2026-06-19). The *platform*
|
|
described here — `colibri-vault` as a crate, multi-tenant buckets, the mother skill — is
|
|
`[PLANNED]`. The thesis: it is mostly **composition of pieces we already have**, not new
|
|
invention. Sections are tagged `[LIVE]` / `[PLANNED]`.
|
|
|
|
---
|
|
|
|
## 1. The core idea
|
|
|
|
The Vaultwarden→`.env` fetch we proved is not a utility — it is the **onboarding
|
|
primitive**. Promote it from the `clawdie-vault-fetch` shell helper to a first-class
|
|
crate, **`colibri-vault`**, sitting beside `colibri-spawner` / `colibri-store`:
|
|
|
|
- **in:** a tenant id (→ a bucket) + a target jail/home
|
|
- **out:** a `0600` `.env` materialized *inside the jail*, owned by the jail user
|
|
- wraps the `bw` CLI for now (do **not** reimplement the Bitwarden protocol), fail-closed,
|
|
idempotent, no-op when there is no bucket
|
|
|
|
It stops being "a thing you run" and becomes "a thing the hive does to you when you join."
|
|
|
|
## 2. [PLANNED] "Join the hive" = one composed step
|
|
|
|
```
|
|
spawn jail → colibri-vault provision → register-agent
|
|
(spawner,LIVE) (new crate, PLANNED) (LIVE)
|
|
```
|
|
|
|
The first and third primitives already exist. **Vault-provision is the missing limb**
|
|
between an empty Bastille jail and a participating hive member. Once secrets land and the
|
|
agent registers its capabilities, everything else — capability routing, poll/worker loop,
|
|
the cross-host bridge — is already live (see [`CAPABILITY-ROUTING.md`](./CAPABILITY-ROUTING.md)).
|
|
|
|
## 3. The mapping (decided)
|
|
|
|
**`tenant_id` == Bastille jail name == Vaultwarden bucket**, 1:1:1. One row in
|
|
`colibri-store`: `(tenant_id, jail, collection_id, status, created_at)`. No more
|
|
indirection than that.
|
|
|
|
On "folder vs bucket":
|
|
|
|
- **Folders** are personal-vault organization → fine for *Clawdie's own internal* agents.
|
|
- **Organization + Collections** give *access-scoped isolation* → the multi-tenant
|
|
primitive. One customer = one Collection; a scoped credential reads only that collection.
|
|
- **Do not** run a separate Vaultwarden instance per customer — Collections are exactly
|
|
this feature.
|
|
|
|
## 4. The "one key" ideal — actually two ones
|
|
|
|
- **Customer's one key:** a single provider key in their bucket. **OpenRouter** is the
|
|
exemplar (one key → every model), but a single direct-provider key works too — DeepSeek
|
|
alone is the currently validated single-key case. The point is **one secret per tenant**.
|
|
- **Operator's one key:** the Vaultwarden **org service-account** credential, held only on
|
|
the orchestrator, that can read any tenant collection to provision jails.
|
|
|
|
Everything non-secret — harness, base config, model-routing prefs — **ships in the
|
|
clawdie-iso image**. The image is the *body*; the bucket is the *one private nerve*.
|
|
|
|
## 5. [PLANNED] The mother skill
|
|
|
|
The genesis routine every image carries — the one skill that turns a jail into an agent:
|
|
|
|
```
|
|
mother := resolve-identity (layered-soul)
|
|
∘ acquire-secrets (colibri-vault)
|
|
∘ register (colibri capabilities)
|
|
∘ heartbeat / poll
|
|
```
|
|
|
|
- **Narrow:** onboarding — births one working agent from a bare jail.
|
|
- **Wide:** self-replication. An agent that *holds* the mother skill can spawn and
|
|
provision more jails (a queen births workers, each inheriting the mother skill), gated
|
|
by capability/policy so it cannot run away. That is "agent swarms with a mother skill,"
|
|
and `colibri-vault` is how each birth gets its one nerve.
|
|
|
|
osa/FreeBSD/Bastille is the natural womb — cheap, dense, isolated jails.
|
|
|
|
## 6. The product, and the moat
|
|
|
|
> A customer pastes **one key** → gets a **private agent in an isolated jail** → that lean
|
|
> agent transparently borrows the **whole multi-OS swarm's capabilities** via the routing
|
|
> already shipped.
|
|
|
|
A one-key agent on osa needs `image-render`? It routes to a Linux lane (domedog). Needs a
|
|
build? Routes to a capable host. The customer pays for *one agent* but stands on a
|
|
survivable, multi-OS hive. Anyone can run an LLM in a container; few hand you a swarm
|
|
behind one key — **capability routing is the differentiator.**
|
|
|
|
- **osa** = the tenant-jail host (the hive body, dense Bastille jails)
|
|
- **debby / domedog** = capability lanes (specialized organs)
|
|
- **Vaultwarden** = per-tenant nerve store
|
|
- **clawdie-iso** = the shared body every jail boots from
|
|
|
|
## 7. The security invariant (non-negotiable)
|
|
|
|
**Bootstraps live on the host; jails hold only their resolved secrets.**
|
|
|
|
- The orchestrator holds the org service-account credential. It fetches a tenant's
|
|
collection, writes the resolved `.env` *into* the jail, and the **bootstrap never enters
|
|
the jail**. A compromised jail cannot re-fetch and cannot reach another tenant.
|
|
- Per-tenant blast radius = one collection. Scoped credential, never a master.
|
|
- This is the same shape the domedog smoke test validated (bootstrap on host, `.env` is the
|
|
output) — just made multi-tenant.
|
|
|
|
## 8. [PLANNED] Lean MVP — and what NOT to build yet
|
|
|
|
Smallest path that is real:
|
|
|
|
1. **`colibri-vault` crate** — lift `clawdie-vault-fetch` into Rust (lib + CLI), fetch a
|
|
named collection → jail `.env`. Retire the shell helper.
|
|
2. **`tenants` row in `colibri-store`** — the 1:1:1 map.
|
|
3. **Spawner hook** — call vault-provision right after jail create.
|
|
4. **`mother` skill in layered-soul** — the genesis sequence above.
|
|
|
|
**First-proof policy.** The first proven end-to-end runs against a **scratch jail + a
|
|
throwaway test collection only** — no real tenant data until the path hardening lands
|
|
(canonicalize + allowed-root containment, colibri issue #92). The two first-proof blockers
|
|
are colibri **#88** (resolve the collection by name) and **#89** (per-call unlock); #92 is
|
|
hardening that follows. Tracker state lives on those issues.
|
|
|
|
**Overengineering traps to avoid for now:** a custom Bitwarden web UI (Vaultwarden's own UI
|
|
+ a Collection is enough to start), billing/metering, a native Bitwarden protocol in Rust,
|
|
multi-region control plane, and recursive auto-spawn (gate it off until policy exists).
|
|
Those are product layers; the four steps above are the engine.
|
|
|
|
---
|
|
|
|
_See [`CAPABILITY-ROUTING.md`](./CAPABILITY-ROUTING.md) for the routing layer the moat rests
|
|
on, [`MCP-INTEGRATION.md`](./MCP-INTEGRATION.md) for the board interface, and
|
|
[`../AGENTS.md`](../AGENTS.md) for the agent matrix._
|