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>
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>
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
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
Remove the transition-era docs that no longer guide anyone and just pollute
context: MIGRATION-INVENTORY, CALLER-INVENTORY, GATE5-MIGRATION-GRAPH,
COLIBRI-CUTOVER-PLAN, and the rolling .agent-handoff.md. (History stays in git.)
Fix references in kept docs: drop the cutover/caller pointers (README,
COLIBRI-DAEMON-GLASSPANE-INTEGRATION), and repoint handoff mentions (AGENTS,
tools/README, MULTIAGENT-WORKFLOW-IMPROVEMENTS) to the ephemeral per-task
`doc/<FEATURE>-HANDOFF.md` convention. Dated session logs left as historical
record. Markdown gate green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
colibri had no Prettier config or gate, so its markdown drifted freely (22/31
files failed Prettier). Mirror the clawdie-iso gate so docs stay consistent:
- .prettierrc: same as clawdie-iso — proseWrap=preserve, printWidth=80, and
embeddedLanguageFormatting=off for *.md so fenced code (JSON/mermaid/shell in
the graph + design docs) is left exactly as written.
- .prettierignore: target/, scratch dirs, CHANGELOG.
- scripts/check-format.sh: `prettier@3 --check '**/*.md'` (run before pushing).
- AGENTS.md: "Markdown Formatting Gate" section documenting the workflow.
- One-shot `prettier --write` across all markdown. Pure formatting — only
emphasis-marker (*x* -> _x_), list-bullet, table-padding, and blank-line
normalization; no prose/command/code-fence content changed.
Gate now green (`./scripts/check-format.sh` → all matched files pass).
Docs-only + tooling — no Rust touched, no rebuild.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Run Prettier on the PR #15 tokenomics doc after the clawdie scope and model-name fixes.\n\nChecks: npx --yes prettier@3 --check docs/COLIBRI-TOKENOMICS-TRIFECTA.md; cargo fmt --check; git diff --check.
Per Claude review: the tokenomics doc implied cost-modes/metering as
universal Colibri behaviour, but the clawdie lane deliberately strips
all of it. Added explicit scope block referencing CLAWDIE-AGENT-WIKI.md.
Also aligned example model name deepseek-v4-flash with harness docs.
New `clawdie` crate: the operator-friendly face of Colibri. One small Rust
binary that reuses the proven control-plane core (glasspane supervision +
Herdr Unix-socket API + coordination loop — the "split brain") and puts a
DeepSeek-backed Telegram bot in front of it. That is the entire out-of-the-box
surface.
Deliberately lifted vs. the full control plane: cost modes, quota accounting,
context budgets, multi-provider fallback (OpenRouter/Anthropic), per-user
limits. One DeepSeek key serves both the chat lane and the daemon routing.
- crates/clawdie: main (core + bridge wiring), telegram (long-poll bridge),
deepseek (minimal one-key chat), build.rs (bakes CLAWDIE_TG_TOKEN +
CLAWDIE_DEEPSEEK_KEY build flags; runtime env overrides).
- packaging/freebsd/clawdie.in: rc.d service, daemon(8)-supervised, restart on
crash, dedicated clawdie user — starts as a service like Clawdie-AI.
- release profile strips symbols (binary ~7.6 MB stripped).
- docs/CLAWDIE-AGENT-WIKI.md (mindmap), docs/CLAWDIE-BUILD.md (build + ISO +
next-build XFCE USB fixes), README workspace table.
Build/clippy/fmt green; headless start smoke-tested (socket + sessions bind).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Hardens the FreeBSD service for production readiness:
- rc.d: post-start socket health check (waits up to 10s), post-stop
socket cleanup, 'health' extra command that probes socket with
a status command via nc.
- newsyslog: log rotation at 1MB, 7 compressed archives,
colibri:colibri ownership.
- staging: copies newsyslog config into image root, updated
staging report to list all installed files.
- docs/ISO-SERVICE-LAYOUT.md: filesystem layout, boot/shutdown
behavior, startup validation commands, config knobs, secrets
policy, log rotation details.
Shell syntax: sh -n clean on both scripts.
Workspace tests: all green.
Linux + FreeBSD validation green. All 4 PRs merged.
Known caveats: OSA kernel p8 running / p9 pending reboot,
colibri-skills and zot harness are scaffold-only.
Structural only — no behavior change. Introduces:
- PromptAssembly: named 3-region wrapper around build_prompt_messages()
with to_messages(), immutable_prefix, appendable_log, volatile_scratch,
total_bytes, estimated_tokens.
- CacheMetrics: per-session cache-hit tracking with hit_rate() and
record().
- Session::build_prompt_assembly() wraps existing build_prompt_messages()
with no logic change.
- 5 golden tests: assembly structure, empty volatile, hit rate
calculations, record accumulation.
- Linked T1.4-PROMPT-DISCIPLINE-PLAN.md from COLIBRI-CUTOVER-PLAN.md.
No trimming, no escalation, no scheduler changes — PR 2 and 3 follow.
Parked branches (colibri-skills, zot harness) untouched.
Build: pass | Tests: 41/41 green (+5 new) | Clippy: clean | Fmt: clean
Proposal for a unified Colibri + Zed experience where the operator
can edit docs/code while simultaneously running and observing agents,
tasks, and scheduler from one visual surface.
Three integration levels:
1. Near-term: Zed as visual shell over colibri-daemon socket
(sidebar extension, one-app experience, not one binary)
2. Mid-term: colibri-mcp MCP bridge (highest leverage)
- Zed already supports MCP natively
- Reuses colibri-client crate directly
- Editor-agnostic (works with any MCP-capable editor)
- 7 Phase-1 tools defined (status, snapshot, tasks, intake, etc.)
3. Long-term: true single binary (not recommended now)
- Colibri must run headless at boot even when editor is closed
Product shape:
colibri-daemon (service) + colibri-mcp (bridge) + colibri-studio
(launcher) + Zed extension. Two new thin binaries, no existing
crates change.
Estimated: ~1 week of focused agent time for MCP Phase 1 + launcher.
The operator CLI was already a subcommand dispatcher; drop the -ctl suffix so
it reads `colibri status` / `colibri snapshot` / `colibri spawn-local …` — one
`colibri` entrypoint (same single-binary-with-subcommands shape as just, but a
control plane). Renames the bin + its source file, updates usage strings, and
points the forward-looking docs at `colibri`. Dated session/handoff records
are left as historical. (Task-board subcommands intake/create/list are the
follow-up T1.3c slice.)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
packaging/freebsd/colibri_daemon.in: FreeBSD rc.d service file
for review only, not installed. Uses /var/db/colibri,
/var/run/colibri, COLIBRI_DB_PATH. /tmp smoke test comes first.
Flesh out Decision #1 (SQLite-first) with the operational surface and make
Lane 2 explicitly non-blocking for core correctness:
- Storage surface (proposed defaults): DB file path (FreeBSD /var/db/colibri,
Linux XDG, COLIBRI_DB_PATH override); WAL + synchronous=NORMAL, local FS only;
backup via VACUUM INTO + JSON contract export; authoritative (task/agent/
scheduling) vs mirrored (Pi events, watchdog host-status, inventory).
- Postgres-escalation criterion: one concrete rule — only if Lane 4 dual-run
parity proves SQLite insufficient for required cross-host shared state.
- Failure mode: DB corrupt/unavailable => fail safe, no takeover; watchdog/hostd
and local FreeBSD safety stay authoritative.
- Lane 2: gates IMG deployment only, never Colibri core correctness.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- COLIBRI-CUTOVER-PLAN.md: resolve Open Decision #1 — Colibri owns its own
store, embedded SQLite first, Postgres adapter only if parity/integration
proves the need (do not default to reusing clawdie-ai system_ops). Reaffirm
the Herdr boundary. Update Lane 1 T1.2 + Next actions accordingly.
- .agent-handoff.md: relay to Hermes — 0925939 is the shared verified plan,
the .hermes draft is superseded where it conflicts, storage decided. FYI,
not a debate.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Verified, shared version of the cutover orchestration plan in docs/,
correcting the .hermes/plans draft against the actual repos:
- Kill the fabricated clawdie-ai crates/colibri-daemon (no crates/ dir
exists there; the real daemon is Unix-socket in the colibri repo, not
axum/HTTP).
- Fix baseline to 160dd11 (65 tests pass/0 fail, clippy -D warnings clean);
eb37784 was not clippy-clean.
- Reaffirm the Herdr boundary: Linux/macOS display/remote plane, no Herdr
on FreeBSD; colibri-glasspane is the native answer (Lane 2 reframed).
- Correct ownership: Claude=domedog=Linux, Codex=osa=FreeBSD, Hermes=debby=Linux.
- Surface the Postgres coupling as an explicit open decision, not a given.
- Downgrade the overclaimed debby<->domedog herdr smoke test to "not yet done."
Leaves the .hermes draft untouched; marked DRAFT/PROPOSED pending ratification.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Operator runbook for standing up domedog as the Herdr testing hub, attaching
debby as a remote client over Tailscale SSH, then layering Colibri supervision.
Records verified state: hub running (Herdr 0.6.2), pi integration installed,
debby's key already authorized + ssh config present, remaining gap = herdr
client not yet installed on debby. Includes the key-safety note (public keys
safe; never transit private keys) and the IPv6/Codeberg retry tip.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Make the Herdr boundary explicit now that Herdr-Linux-remote and
Colibri-FreeBSD are validated as separate planes:
- Herdr FreeBSD port is parked, not a migration blocker. The exploratory
FreeBSD build findings are kept for the record but framed as a parked
experiment, not a pending task.
- Herdr stays a Linux/macOS display/remote plane behind the socket contract;
colibri-glasspane is the native FreeBSD supervision answer.
Tighten stale status so it stops rotting:
- Replace the fixed "31 passed, 0 failed" count with "all gates green as of
b325c38" plus the clippy clean note.
- Anchor the top-level status line to commit b325c38.
Doc-only; no code or test changes.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>