Codex validates the disk-touching + service-install paths (zfs/zpool create,
pw/rc.d service) that can't be exercised off-host. Includes read-only checks,
destructive provisioning steps for a scratch pool, teardown, and acceptance
criteria.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
clawdie chooses storage per host:
- FreeBSD: ZFS required (datasets under the pool)
- Linux with ZFS + a pool: datasets under the pool
- Linux without ZFS: plain-dir fallback, reporting ZFS benefits + spare disks
- --create-pool /dev/DEV runs `zpool create` (needs --pool NAME)
Pool creation is destructive and guarded: refused unless the disk is detected
empty (no partitions/filesystem/mount, not the root disk) or --force is given,
and only with --yes. `discover` lists block devices with candidacy. New
disk-candidacy parser + storage resolver are unit-tested (13 tests).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace inherited env delivery for jailed agent and external MCP spawns with staged launcher/env files under the jail-visible root. Add JailConfig.root_path for named jails that need staged payload delivery.
Tests: pass — cargo fmt --all; cargo test -p colibri-daemon jail_tests -- --nocapture; cargo test -p colibri-mcp -- --nocapture
Adds the restored clawdie installer crate to Cargo.lock and formats AGENTS.md so the repository markdown gate passes after the latest main merges.\n\nChecks: ./scripts/check-format.sh; cargo fmt --check; git diff --check; cargo test -p clawdie --all-targets; cargo test -p colibri-mcp --all-targets; cargo metadata --locked --no-deps --format-version 1
New crates/clawdie binary. Discovers a host's ZFS layout and provisions the
clawdie service, cross-platform via a Platform backend (FreeBSD rc.d + native
ZFS; Linux systemd + ZFS-on-Linux).
- discover: read-only OS + pool/dataset inspection
- plan: render the ZFS layout + service-install steps (dry-run)
- apply: executes the plan, and only with --yes (dry-run otherwise)
apply writes to disk only with --yes. Discovery + plan logic is unit-tested (7);
the disk-touching path must be validated on real hosts.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wires clawdie/layered-soul (the portable identity/context source) into Colibri.
scripts/import-layered-soul.sh reads its reviewed skills/**/*.md into the existing
`skills` catalog (mirrors import-clawdie-skills.sh; idempotent, frontmatter
name/description, category from the skill's parent dir).
Honest scope: only skills are wired. The adapter's "Layered Memory Fabric"
(system_brain / system_ops + a richer system_skills) is design-only
(COLIBRI-SKILLS-PLAN.md), so curated memory is reported-but-not-imported and the
gap is documented in docs/INTEGRATION-LAYERED-SOUL.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Both were written as proposals; the decisions are now working code, so slim them
to plain "how it works" docs (code is the source of truth).
- ADR-agent-harness-consolidation: Proposed -> Accepted/implemented; drop the
migration plan + gates (all shipped), fold in the pi-demotion correction, and
drop the dangling CLAWDIE-AGENT-WIKI reference (deleted in #34). 116 -> ~55 lines.
- COLIBRI-JAILED-AGENT-SPAWN-DESIGN: proposal -> implemented; describe the shipped
spawner (name-vs-path lifecycle, command= syntax, PrivMode mdo/helper, socket
wiring, external-MCP reuse) instead of the original code sketch.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Per cleanup decision: HERDR-HUB-RUNBOOK.md is stale (Herdr is now an optional
Linux UI only, not a hub), and T1.4-CACHE-WARMING-DESIGN.md is superseded (cache
warming is implemented via config flags). Also drops the now-dangling link to the
latter from COLIBRI-TOKENOMICS-TRIFECTA.md.
Kept (still useful): ISO-INTEGRATION-PLAN.md, CLAWDIE-STUDIO-PROPOSAL.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Salvages the non-stale part of docs/colibri-socket-name-cleanup. The daemon's
wire types are ColibriCommand/ColibriResponse (renamed from Herdr* long ago), but
COLIBRI-DAEMON-GLASSPANE-INTEGRATION.md still documented the old Herdr* names.
(The branch's other edit touched docs/CLAWDIE-BUILD.md, which #34 deleted, so it
is dropped.)
Co-authored-by: Sam & Codex (docs/colibri-socket-name-cleanup)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds the canonical ADR referenced by build.cfg and the consolidation work
(from docs/adr-agent-harness-consolidation, which merges clean). Prepends a
dated Update note: the ADR's "remove Pi" guidance is superseded — Pi is DEMOTED
to a spawnable backend (kept on-image, Node stays), zot is the primary harness,
per docs/COLIBRI-JAILED-AGENT-SPAWN-DESIGN.md. Original record preserved.
Co-authored-by: Sam & Claude (original ADR)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Salvages Codex's FreeBSD-validated fix from
fix/jail-spawner-freebsd-command-format, taking ONLY the spawner.rs change onto
current main. (The original branch also re-ran a markdown formatter and would
have re-corrupted the jailed-spawn design doc + README, so those are dropped.)
My merged jail_wrap emitted the ephemeral jail command as two argv tokens
("command", binary), but jail(8) expects a single name=value parameter
(command=<binary>). Without this the `jail -c` ephemeral path fails on FreeBSD.
Fixes the ephemeral builder and the two jail_tests expectations.
Co-authored-by: Sam & Codex (fix/jail-spawner-freebsd-command-format)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
External MCP servers are arbitrary third-party binaries — at least as untrusted
as the agents the spawner already jails — but the #36 prototype spawned them
directly on the host. Close that gap by reusing the existing confinement
primitive instead of growing a second one.
- ExternalMcpServer gains `jail: Option<JailConfig>` (#[serde(default)]).
- ExternalMcpSession::start routes Command::new through
colibri_daemon::spawner::jail_wrap with the shared COLIBRI_JAIL_PRIV_MODE
policy (mdo live / helper deploy). No jail => unchanged. stdio (incl. the
piped JSON-RPC stdin/stdout) flows through jexec/jail/mdo unaffected.
- docs/COLIBRI-EXTERNAL-MCP-PROTOTYPE: document the `jail` field + confinement.
- 3 tests (no-jail passthrough, jexec wrap, registry jail deserialize).
colibri-mcp already depends on colibri-daemon, so no new dep. Build/test/clippy/
fmt green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A prettier-style pass in #36 mangled the jailed-spawn design doc — `mac_do`
became `mac*do` (eating the underscore and opening stray italics) and the
`_which_` / `_not_` emphasis turned into broken `\_which*` / `\_not*`. Restore
the text and wrap `mac_do` in backticks so a future formatter leaves it alone.
Also correct the README status line ("11 crates" → "10 crates") to match the
workspace table; clawdie was removed in #34 and #36 added no new crate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wires JailConfig through the control-plane socket so a jailed agent spawn is
reachable end-to-end:
- ColibriCommand::SpawnAgent gains `jail: Option<JailConfig>` (#[serde(default)],
so existing/raw JSON clients are unaffected).
- socket dispatch + cmd_spawn_agent thread it onto AgentSpawnConfig.jail, where
jail_wrap applies it.
- colibri-client::spawn_agent sets jail: None (signature unchanged); the typed
CLI keeps its own separate Command enum. A client/CLI flag to actually request
a jail is a follow-up — the socket now carries the field for internal callers
(scheduler/supervisor) and any JSON client.
daemon+client build clean; daemon lib tests (58) green; clippy -D warnings clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds stdio external MCP server registry support to colibri-mcp with read-only discovery by default and explicit COLIBRI_MCP_EXTERNAL_CALL gating for proxying external tools. Also smooths the merged jail-spawn formatting/FreeBSD command parameter edge so repository gates pass.\n\nChecks: cargo test -p colibri-mcp --all-targets; cargo fmt --check; ./scripts/check-format.sh; git diff --check; fake stdio MCP server smoke via colibri-mcp --external-config --external-call
Implements the spawner half of docs/COLIBRI-JAILED-AGENT-SPAWN-DESIGN.md so
Colibri can confine a spawned agent (e.g. pi) in a FreeBSD jail. zot untouched.
- PrivMode {Mdo, Helper, None}: how the (unprivileged) daemon gets the root that
jail attach/create needs. Resolved from COLIBRI_JAIL_PRIV_MODE (default mdo —
the live-USB posture); deployed hosts set helper. Only consulted when a spawn
requests a jail.
- JailConfig {name, path, ip4, user}: `name` enters a persistent jail (jexec,
precedence); `path` makes an ephemeral `jail -c command=` that self-cleans on
exit. Neither set = no-op. (Refines the design's `ephemeral` flag into the
clearer name-vs-path choice.)
- jail_wrap(): pure (binary,args)->(program,argv) wrapper. No-op without a jail.
jexec runs without -l so injected COLIBRI_*/provider env is inherited; stdio
flows through mdo/jexec/jail so glasspane ingestion is unchanged.
- AgentSpawnConfig gains `jail: Option<JailConfig>` (#[serde(default)]); spawn()
resolves PrivMode/helper once and routes the command through jail_wrap.
- kill(): documented jail teardown semantics + the in-jail process-group reaping
follow-up.
- 7 jail_wrap unit tests. Full daemon lib suite (58) green; clippy -D warnings clean.
Not wired through the SpawnAgent socket command yet (it builds AgentSpawnConfig
with jail=None) — that protocol field is the next small step.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The `clawdie` crate (Telegram+DeepSeek mini-agent over the control-plane core)
was an experimental operator-lane candidate. Per the agent-harness
consolidation, the live USB runs colibri_daemon + the zot agent, and the
deployed `service clawdie` is a reserved name, not this binary — so the
mini-binary is dead weight. Remove it and its now-orphaned docs.
- delete crates/clawdie (leaf crate; nothing depended on it)
- delete packaging/freebsd/clawdie.in (its rc.d candidate)
- delete docs/CLAWDIE-AGENT-WIKI.md + docs/CLAWDIE-BUILD.md (only described it)
- drop it from workspace members + Cargo.lock; tidy the strip-profile comment
- README: 11 → 10 crates, remove the clawdie row
- COLIBRI-TOKENOMICS-TRIFECTA: drop the stale clawdie-lane scope note
No "relay" existed in this repo (already gone). zot is untouched. The Clawdie
brand, the clawdie operator user, and the reserved deployed `service clawdie`
name are unaffected — this only removes the experimental Rust mini-binary.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Colibri already spawns pi (spawner.rs) and captures its JSONL for glasspane;
this documents adding optional jail confinement to that existing path rather
than touching zot (whose swarm is self-only + no isolation — keeps the mirror
clean).
Covers: JailConfig + jail_wrap at the Command::new site, jail-aware teardown,
and the privilege decision for the root-only jexec step —
- live USB → `mdo -u root` (reuses mac_do; daemon == operator trust domain)
- deployed → setuid/Capsicum helper (narrow root surface on exposed hosts)
mac_do rules are identity-based (gid=0>uid=0), not command-filtered, so mdo
grants the daemon full root; that's acceptable on the single-operator live USB
but not on a deployed/exposed box, hence the split. Selected via PrivMode at
daemon config time so one spawner serves both.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Cleans stale Herdr socket/API naming after the Colibri socket rename, preserves Herdr as an optional Linux/macOS display client, marks the clawdie mini-binary service as experimental rather than ISO/deployed-service contract, and removes old internal session logs.\n\nChecks: ./scripts/check-format.sh; cargo fmt --check; git diff --check; sh -n packaging/freebsd/colibri_daemon.in packaging/freebsd/clawdie.in
The colibri-daemon's own control-plane socket was named after Herdr (the AGPL
Linux supervision tool whose protocol shape it borrowed), which made logs/types
("Herdr socket API listening", HerdrCommand/HerdrResponse) look like a Herdr
dependency. There is none — no herdr crate, process, or network call. zot is the
agent; this is Colibri's control-plane socket.
Renamed Colibri's OWN API only:
- HerdrCommand -> ColibriCommand, HerdrResponse -> ColibriResponse (daemon defs +
socket.rs + colibri-client usages).
- log/doc/Cargo strings: "Herdr socket API"/"operator dashboard"/"Herdr Unix
socket" -> "Colibri control-plane socket" (daemon, clawdie).
Wire-compatible: the JSON `cmd` values come from #[serde(rename=...)] and are
unchanged. Kept legitimate references to Herdr *the tool* (glasspane lineage
"reimplements Herdr's glasspane capability", "Herdr's 5-state model"; client
"display clients (Herdr on Linux…)"; tui "herdr-like").
build + test + clippy -D warnings + fmt --check clean; runtime confirms the
daemon now logs "Colibri control-plane socket listening".
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The daemon already spawns agents and streams stdout JSONL into the glasspane
(cmd_spawn_agent: take_stdout + attach_pane + stream_agent_stdout_to_glasspane),
but the streaming ingestor was Pi-only — zot panes were only *incidentally*
correct (shared lifecycle names) and dropped zot's tool/streaming events to the
default arm.
- PiJsonlIngestor: add a `runtime` field; ingest_line_at normalizes via
zot_event_type for Zot panes (tool_use_* -> tool_execution_*, response
success:false -> error, response/usage -> skipped), raw type for Pi/Local.
- SupervisedPane::new_with_runtime + PaneSupervisor::attach_pane_with_runtime
(existing new/attach_pane_at delegate with Pi — no behavior change).
- socket.rs cmd_spawn_agent: derive runtime from the binary basename
(`zot` -> Zot, else Pi) and attach the pane with it. The stdout streamer is
unchanged — it now ingests with the pane's runtime.
Tests: 34 pass incl. a new runtime-aware test feeding RAW zot lines (tool_use_*,
turn_end) through PaneSupervisor.ingest_line_at -> Working mid tool-loop, Done at
turn_end. clippy -D warnings clean.
Completes the daemon spawn -> glasspane wiring for zot (ADR migration step).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>