colibri/docs/wiki/runtime-inventory.md
clawdie 7f0f06d36a
Some checks are pending
CI / rust (push) Waiting to run
CI / markdown (push) Waiting to run
CI / port (push) Waiting to run
CI / agent-jail-pkgs (push) Waiting to run
refactor: rename golden tests → fixtures (consistent positive framing) (#267)
2026-06-28 10:22:17 +02:00

88 lines
4.2 KiB
Markdown

# Runtime inventory and host status
← [index](./index.md)
Colibri discovers the host in two complementary ways:
1. **Runtime inventory** — a one-shot probe that reports versions installed on
the machine (`node`, `npm`, `pi`, `zot`, package manager, OS, etc.).
2. **Watchdog host status** — a read-only, newline-framed Unix-socket call to
the Clawdie watchdog that returns live health metrics.
Both are intentionally additive: they read from Clawdie, they do not change
it. This page records the design of those read-only integrations.
## Runtime inventory probe
The `colibri-runtime-inventory` binary (`src/bin/runtime_inventory.rs`) emits a
single JSON object matching the `clawdie.runtime-version-inventory.v1` schema
from `crates/colibri-contracts/src/lib.rs`.
### Detection strategy
| Field | How it is detected |
| ----------------- | ------------------------------------------------------------------------------------------------------ |
| `host` | `COLIBRI_HOST``HOSTNAME``hostname` command → `"unknown"` |
| `os` | `uname -sr` + target architecture; falls back to `std::env::consts` |
| `node` | `node --version` |
| `npm` | `npm --version` |
| `npm_prefix` | `npm config get prefix` |
| `package_manager` | `pkg` on FreeBSD, otherwise `apt` / `dnf` / `brew` |
| `pi` | `PI_BIN``~/.npm-global/bin/pi``pi --version` → package.json of `@earendil-works/pi-coding-agent` |
| `zot` | `ZOT_BIN``zot --version` across PATH and candidate locations |
### Why this shape
- `pi` is an npm package installed in `node_modules`, so version detection must
fall back to reading its package manifest when `--version` is missing.
- `zot` is a single Go binary, so a plain `--version` probe is correct.
- `pi`/`zot` are optional; a host that only runs one agent runtime should
still produce a valid inventory.
## Watchdog host status
`crates/colibri-runtime/src/lib.rs` implements the watchdog reader. It connects
over a Unix domain socket, sends `{"cmd":"status"}\n`, reads back one
newline-terminated JSON line, and normalizes the response into `HostStatus`.
### Socket path resolution
The search order lets operators, services, and test harnesses override the
socket location without recompiling:
1. `COLIBRI_WATCHDOG_SOCKET` (explicit override)
2. `COLIBRI_SERVICE_NAME` (default `clawdie`) → `{service}-watchdog.sock`
3. `TMP_IPC_DIR/{service}-watchdog.sock`
4. `AGENT_TMP_DIR/ipc/{service}-watchdog.sock` or
`CLAWDIE_TMP_DIR/ipc/{service}-watchdog.sock`
5. `$HOME/clawdie-ai/tmp/ipc/{service}-watchdog.sock`
6. `tmp/ipc/{service}-watchdog.sock` (final fallback)
### Wire protocol
- Framing: one line, newline-terminated.
- Request: `{"cmd":"status"}\n`.
- Expected response: `{"ok": true, "data": { ... watchful host fields ... }}`.
- Timeout: 2 seconds by default, overridable in `WatchdogReadOptions`.
### Normalization rules
`normalize_watchdog_status()` in `crates/colibri-runtime/src/lib.rs` is defensive:
- Missing fields default to `"unknown"` for strings, `0` for counters, and
`false` for booleans.
- `controlplane_status` is lifted from `controlplane.overallStatus`.
- The original raw object is preserved under `HostStatus.raw` so callers can
access fields Colibri does not yet model.
## Golden fixtures
`crates/colibri-contracts/tests/fixtures.rs` parses committed inventory and
host-status manifests in `manifests/` and round-trips them through the Rust
structs. Those fixtures come from real hosts (`osa`, `domedog`, `debby`, the
operator USB) and are treated as cross-platform source material.
## See also
- [contracts](./contracts.md) — stable schemas for inventory and host-status.
- [cost-model](./cost-model.md) — how runtime inventory feeds cost decisions.