feat(mother): draft genesis skill — join-the-hive sequence
- Resolve identity: hostname, OS, capability probe - Verify vault: .env exists + contains API key - Register agent: idempotent, safe to re-run - Heartbeat + poll loop: stay alive on the board Platform-specific paths for FreeBSD jail vs Linux container, security invariant documented, cross-linked with HIVE-ONBOARDING and CAPABILITY-ROUTING.
This commit is contained in:
parent
21a630cd93
commit
c62bbd3d7e
1 changed files with 163 additions and 0 deletions
163
skills/mother/SKILL.md
Normal file
163
skills/mother/SKILL.md
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
---
|
||||
name: mother
|
||||
description: Genesis sequence for a new agent joining the Clawdie hive — resolve identity, verify vault provision, register capabilities on the Colibri board, and start the heartbeat/poll loop. Idempotent — safe to re-run on an already-provisioned agent.
|
||||
triggers:
|
||||
- "join the hive"
|
||||
- "mother skill"
|
||||
- "genesis sequence"
|
||||
- "onboard this agent"
|
||||
- "register with colibri"
|
||||
- "first boot"
|
||||
- "new agent setup"
|
||||
- "provision agent"
|
||||
---
|
||||
|
||||
# Mother Skill — Agent Genesis
|
||||
|
||||
Trigger: the agent wakes up in a freshly-provisioned jail (or container) and needs
|
||||
to join the hive. The vault has already written a `.env` into the jail root by the
|
||||
time this skill runs — the agent's job is to verify, register, and start polling.
|
||||
|
||||
## Prerequisites (must already exist before this skill runs)
|
||||
|
||||
- `.env` file present in the agent's home directory (written by `colibri-vault`)
|
||||
- `colibri-daemon` reachable — either on a local Unix socket (osa) or via the TCP
|
||||
bridge over Tailscale (remote hosts)
|
||||
- `colibri` binary in PATH (or at a known location)
|
||||
- The agent knows its own hostname and OS (`hostname`, `uname`)
|
||||
|
||||
## Genesis Sequence
|
||||
|
||||
Run these steps in order. The skill is **idempotent** — if an agent already has an
|
||||
agent_id and is registered, skip the registration step and go straight to polling.
|
||||
|
||||
### 1. Resolve identity
|
||||
|
||||
Determine what this agent IS before registering:
|
||||
|
||||
```bash
|
||||
HOST=$(hostname)
|
||||
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
|
||||
```
|
||||
|
||||
Capability tags are derived from what's actually installed and reachable on this
|
||||
host. Use the Host Matrix as reference (`docs/HOST-MATRIX.md` in layered-soul), but
|
||||
the ground truth is `scripts/verify_facts_probe.py`.
|
||||
|
||||
Minimum base tags every agent should carry:
|
||||
|
||||
| Tag | Source |
|
||||
|-----|--------|
|
||||
| `freebsd` or `linux` | `uname -s` |
|
||||
| `shell` | always present |
|
||||
| `hermes` | if Hermes Agent is installed |
|
||||
| `tailscale` | if `tailscale status` succeeds |
|
||||
|
||||
Additional tags per the Capability Vocabulary in `docs/CAPABILITY-ROUTING.md`:
|
||||
jail isolation (`freebsd-jail`), hardware (`zfs`, `gpu`), runtimes (`python3.12`,
|
||||
`rust`, `node24`), media (`ffmpeg`, `image-render`).
|
||||
|
||||
### 2. Verify vault provision
|
||||
|
||||
Confirm the vault did its job — the `.env` must contain at least one valid API key:
|
||||
|
||||
```bash
|
||||
test -f ~/.env && grep -q '_API_KEY=' ~/.env && echo "vault: provisioned" || echo "vault: MISSING — .env absent or empty"
|
||||
```
|
||||
|
||||
If missing, this agent cannot authenticate to any provider. Report the error and
|
||||
halt — a human operator must re-run `colibri-vault provision`.
|
||||
|
||||
### 3. Register with Colibri
|
||||
|
||||
Check if already registered (by name, not UUID — the daemon enforces UNIQUE on names):
|
||||
|
||||
```bash
|
||||
# Check if agent already exists
|
||||
colibri --socket $COLIBRI_SOCKET list-agents | grep -q "\"$AGENT_NAME\""
|
||||
```
|
||||
|
||||
If NOT registered, register with capabilities derived from Step 1:
|
||||
|
||||
```bash
|
||||
colibri --socket $COLIBRI_SOCKET register-agent "$AGENT_NAME" \
|
||||
--capabilities freebsd,shell,hermes,tailscale,rc.d,pf,zfs
|
||||
```
|
||||
|
||||
The `COLIBRI_SOCKET` path depends on the host:
|
||||
|
||||
| Host | Socket path |
|
||||
|------|-------------|
|
||||
| osa (FreeBSD, local daemon) | `/var/run/colibri/colibri.sock` |
|
||||
| Remote hosts (via socat bridge) | `/tmp/osa-colibri.sock` |
|
||||
|
||||
If registration fails (e.g., name collision), log the error and continue — the agent
|
||||
may already be registered under a different name, or the board may be unreachable.
|
||||
The poller will surface this on its next tick.
|
||||
|
||||
### 4. Start heartbeat and poll loop
|
||||
|
||||
The agent is now a member of the hive. Two recurring jobs keep it alive:
|
||||
|
||||
**Heartbeat** (every 5 min): update agent status on the board so the scheduler knows
|
||||
this agent is still alive and can receive tasks.
|
||||
|
||||
```bash
|
||||
colibri --socket $COLIBRI_SOCKET set-agent-status "$AGENT_NAME" active
|
||||
```
|
||||
|
||||
**Poll loop** (every 2 min): check the board for tasks assigned to this agent.
|
||||
On osa and debby, this runs inside Hermes' internal scheduler — see
|
||||
`colibri/packaging/freebsd/colibri-agent-loop.md` for the Hermes cronjob setup.
|
||||
|
||||
For a bare agent without Hermes cron, a minimal poll loop:
|
||||
|
||||
```bash
|
||||
while true; do
|
||||
colibri --socket $COLIBRI_SOCKET list-tasks --status started \
|
||||
| colibri_poll.py # filters by agent UUID, outputs JSON
|
||||
sleep 120
|
||||
done
|
||||
```
|
||||
|
||||
## Platform-specific notes
|
||||
|
||||
### FreeBSD jail (osa)
|
||||
|
||||
- The vault writes `.env` to `/home/clawdie/.env` inside the jail
|
||||
- The daemon socket is at `/var/run/colibri/colibri.sock` (mounted or shared)
|
||||
- Capabilities include `freebsd-jail`, `zfs` (if zpool is visible), `rc.d`
|
||||
- The jail's `/var/run` is tmpfs — `mkdir -p /var/run/colibri` before connecting
|
||||
|
||||
### Linux container (debby, domedog)
|
||||
|
||||
- The vault writes `.env` to `~/.env`
|
||||
- The socket is a socat bridge at `/tmp/osa-colibri.sock` pointing to osa:9190
|
||||
- Capabilities include `docker` (if Docker socket is mounted), `image-render`
|
||||
(if Pillow/FFmpeg are installed)
|
||||
- Start the socat shim before the poll loop:
|
||||
```bash
|
||||
socat UNIX-LISTEN:/tmp/osa-colibri.sock,fork TCP:${OSA_TS_IP}:9190 &
|
||||
```
|
||||
|
||||
## Idempotency contract
|
||||
|
||||
This skill can be re-run at any time without breaking a live agent:
|
||||
|
||||
| Step | Re-run behavior |
|
||||
|------|-----------------|
|
||||
| Resolve identity | Safe — hostname and OS don't change |
|
||||
| Verify vault | Safe — checks file existence, no side effects |
|
||||
| Register agent | Name collision = benign error (already registered) |
|
||||
| Heartbeat/poll | Safe — daemon ignores duplicate status updates |
|
||||
|
||||
## Security invariant
|
||||
|
||||
The `.env` file is `0600` (written by `colibri-vault` with `Permissions::from_mode(0o600)`).
|
||||
It contains the agent's ONE provider key — never the Vaultwarden org service-account
|
||||
credential. A compromised jail can use its own key but cannot reach another tenant's
|
||||
collection or the vault bootstrap credential.
|
||||
|
||||
_See `docs/HIVE-ONBOARDING.md` for the full onboarding vision,
|
||||
`docs/CAPABILITY-ROUTING.md` for the routing layer, and
|
||||
`colibri/packaging/freebsd/colibri-agent-loop.md` for the Hermes cronjob setup._
|
||||
Loading…
Add table
Reference in a new issue