Commit graph

84 commits

Author SHA1 Message Date
0d872f199b fix(test): handle serve() Result in live_socket_check (unbreak clippy on main) (#78)
Some checks are pending
CI / rust (push) Waiting to run
CI / markdown (push) Waiting to run
2026-06-15 17:56:47 +02:00
4517e13935 fix(daemon): fail closed when socket ownership is unsafe (Sam & Codex)
Some checks failed
CI / rust (pull_request) Has been cancelled
CI / markdown (pull_request) Has been cancelled
Return an error from the socket server when another daemon owns the Unix socket or bind setup fails, and broadcast shutdown so the daemon does not stay alive without a control socket. Also format the PR docs.\n\nChecks: cargo fmt --check; ./scripts/check-format.sh; git diff --check; cargo test -p colibri-daemon clear_stale_socket -- --nocapture; cargo test -p colibri-daemon --test sigterm_shutdown -- --nocapture.
2026-06-15 09:08:56 +02:00
Sam & Claude
b32c3acaed fix(daemon): handle SIGTERM + liveness-aware socket cleanup (Sam & Claude)
Some checks failed
CI / rust (pull_request) Has been cancelled
CI / markdown (pull_request) Has been cancelled
The rc.d "rm stale socket on prestart" fix (07e4660) was a band-aid over
two daemon-side defects that surfaced on the live FreeBSD host:

1. colibri-daemon never handled SIGTERM. main.rs awaited only ctrl_c()
   (SIGINT), so `service stop`/`restart` — which sends SIGTERM via
   daemon(8) to the child — killed it on the default disposition with no
   cleanup. The graceful path (socket removal, agent reaping) never ran,
   leaking the socket file and orphaning spawned agents across restarts.
   Now wait_for_shutdown_signal() selects on SIGTERM or SIGINT, so the
   same graceful path runs on a normal service stop. New integration test
   (tests/sigterm_shutdown.rs) spawns the binary, sends SIGTERM, and
   asserts the socket is removed.

2. Stale-socket cleanup had no liveness check — both the daemon
   (socket.rs) and the rc prestart would unconditionally rm the socket
   before bind, which could delete a *running* instance's socket if
   rc.subr's pid detection misfires and starts a second daemon. Cleanup
   now probes first (clear_stale_socket): connect succeeds -> refuse to
   start; refused/dead -> remove and bind. Unit-tested for absent, stale,
   and live cases.

With the daemon owning safe socket cleanup, the rc prestart no longer
removes the socket (only stale pidfiles), eliminating the restart-time
clobber hazard. This also makes the SIGTERM shutdown described in
ISO-SERVICE-LAYOUT.md (PR #75) actually true.

Gates: cargo fmt --check, clippy -D warnings, cargo test --workspace all
green on Linux; sh -n on the rc script OK. FreeBSD runtime validation
still pending per FREEBSD-BUILD-LANE-HANDOFF.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 08:37:06 +02:00
9891d06144 feat(rc): rename test agent and load provider env (Sam & Codex)
Rename the local deterministic launch helper from colibri-smoke-agent to colibri-test-agent, update CLI/TUI/tests/docs, and teach the FreeBSD rc.d service to source /usr/local/etc/colibri/provider.env plus set a service PATH for local spawns.\n\nChecks: cargo fmt --check; ./scripts/check-format.sh; git diff --check; cargo check -p colibri-daemon -p colibri-client -p colibri-glasspane-tui; cargo check -p colibri-client --bins; cargo test -p colibri-client --test live_socket_check -- --nocapture.
2026-06-15 07:35:44 +02:00
Sam & Claude
9d443a498c feat: wire cost mode enforcement + poll_tasks spawn path (Sam & Hermes)
Some checks failed
CI / rust (pull_request) Has been cancelled
CI / markdown (pull_request) Has been cancelled
Priority 3 — Cost mode enforcement:
- Removed session_max_bytes/max_uncompacted_turns from DaemonConfig; cost
  mode string is now the single source of truth for all thresholds
- maybe_compact_or_rollover() derives thresholds from CostMode, not static
  config fields
- compact_oldest_turns() takes a keep parameter (derived from cost mode)
- compact_tool_result() wired into build_prompt_messages() — tool results
  are truncated when cost mode says to compact
- trim_to_budget() called in build_prompt_assembly()
- auto_escalate() wired into session_rotation() — escalates cost mode
  when compaction is insufficient
- set-cost-mode socket command now updates runtime cost_mode (RwLock on
  DaemonState) instead of just acknowledging

Priority 2 — Pi spawn path end-to-end:
- poll_tasks() now queries claimed tasks, spawns the configured agent
  binary (COLIBRI_AGENT_BINARY), creates a session, wires stdout to
  glasspane, and transitions the task to Started
- stream_agent_stdout_to_glasspane made pub for cross-module access
- poll_tasks called from scheduler_tick_fn after the scheduler runs
- New integration test: poll_tasks_spawns_agent_for_claimed_task validates
  the full path: create task → claim → poll_tasks spawns → glasspane
  observes Idle → Working → Blocked → Done lifecycle

Gates: fmt/clippy/test all green (207 tests, 0 failures).
2026-06-14 17:25:11 +02:00
9593348df7 Test staged-env shell-quoting helpers; rescope ISO priority 1 to boot validation (#66)
Some checks are pending
CI / rust (push) Waiting to run
CI / markdown (push) Waiting to run
2026-06-14 15:07:47 +02:00
Sam & Claude
7abe8c4d4c docs: purge all Herdr references, consolidate into AGENTS.md + README (Sam & Hermes)
Some checks failed
CI / markdown (pull_request) Has been cancelled
CI / rust (pull_request) Has been cancelled
Deleted 8 stale docs (~1,700 lines) and merged their essential intent into
AGENTS.md and README.md:

Merged into AGENTS.md:
- Architecture Roles section (zot=agent, Colibri=control plane, pi=backend)
- ISO Takeover Gates table (Gates 1-5 with status)

Merged into README.md:
- glasspane row names zot/pi (not just Pi)
- architecture diagram names zot/pi JSONL
- removed Herdr dependency reference

Deleted (content merged or obsolete):
- docs/HERDR-VS-COLIBRI-GRAPH.md (migration artifact)
- docs/ADR-agent-harness-consolidation.md (merged into AGENTS.md)
- docs/COLIBRI-GLASSPANE-DESIGN.md (merged into README, rest in code)
- docs/COLIBRI-DAEMON-GLASSPANE-INTEGRATION.md (code is source of truth)
- docs/MULTIAGENT-WORKFLOW-IMPROVEMENTS.md (already in AGENTS.md)
- docs/T1.4-PROMPT-DISCIPLINE-PLAN.md (gaps tracked in priority handoff #3)
- docs/ISO-INTEGRATION-PLAN.md (gates merged into AGENTS.md)
- .hermes/plans/2026-05-27-colibri-cutover.md (old plan, superseded)

Also cleaned Herdr references from Rust doc comments in
colibri-glasspane/src/lib.rs and colibri-client/src/lib.rs.

Result: 18 docs → 11 docs, 66 Herdr references → 0.
Gates: fmt/clippy/test all green.
2026-06-14 14:04:49 +02:00
83abd586c3 Merge pull request 'feat(daemon): headroom compression sidecar (hardened)' (#57) from fix/headroom-sidecar-quality into main
Some checks are pending
CI / rust (push) Waiting to run
CI / markdown (push) Waiting to run
2026-06-14 01:35:53 +02:00
34929a6a53 fix(headroom): harden sidecar protocol and timeout (Sam & Codex)
Some checks failed
CI / rust (pull_request) Has been cancelled
CI / markdown (pull_request) Has been cancelled
Keep the Python sidecar connection open for multiple newline-delimited requests, add daemon-side request timeout/fallback tests, and document the opt-in Headroom sidecar contract.\n\nChecks: ./scripts/check-format.sh; cargo fmt --check; python3 -m py_compile scripts/headroom-sidecar.py; git diff --check; cargo test -p colibri-daemon cost -- --nocapture; cargo test -p colibri-daemon session:: -- --nocapture; cargo test -p colibri-daemon --all-targets; cargo check -p colibri-daemon; manual sidecar two-request smoke using a headroom-capable Python env.
2026-06-14 01:30:45 +02:00
Sam & Claude
0b364ac36d fix(spawner): allow too_many_arguments on prepare_spawn_command
Some checks failed
CI / rust (pull_request) Has been cancelled
CI / markdown (pull_request) Has been cancelled
Unbreaks the workspace clippy gate: prepare_spawn_command has 8 args (8/7), so
clippy::too_many_arguments fails under -D warnings on main.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 01:30:31 +02:00
edc1a5cdbf feat(daemon): headroom-ai compression sidecar for tool results
Some checks failed
CI / rust (pull_request) Has been cancelled
CI / markdown (pull_request) Has been cancelled
- scripts/headroom-sidecar.py: Unix socket server (from headroom import compress)
- cost.rs: HeadroomSidecar struct with connect/compress methods
- session.rs: build_prompt_messages() now accepts optional sidecar
- daemon.rs: spawns sidecar on startup if COLIBRI_HEADROOM_ENABLED=true
- config.rs: headroom_enabled + headroom_socket_path config fields
- socket.rs: cmd_status reports headroom status, cmd_get_session uses sidecar
- All test fixtures updated with new DaemonConfig fields

40-50% token savings on tool outputs with zero accuracy loss.
Disabled by default (COLIBRI_HEADROOM_ENABLED=false).
Works identically on Linux and FreeBSD.
2026-06-14 01:15:52 +02:00
4abc2c5294 fix(clawdie): harden FreeBSD installer plan (Sam & Codex)
Use the clawdie service user in the generated FreeBSD rc.d script, chown state directories after the user is created, and reject unknown existing ZFS pools before rendering/applying a plan. Update the FreeBSD validation handoff to cover these checks.\n\nFreeBSD checks: cargo fmt --check; ./scripts/check-format.sh; git diff --check; cargo test -p clawdie -- --nocapture; cargo clippy -p clawdie --all-targets -- -D warnings; cargo build -p clawdie --release; target/release/clawdie discover; target/release/clawdie plan; target/release/clawdie apply --pool zroot (dry-run); target/release/clawdie plan --pool does-not-exist (expected error).
2026-06-14 00:42:43 +02:00
Sam & Claude
325951be5c feat(clawdie): ZFS-aware storage strategy + optional pool creation
Some checks failed
CI / rust (pull_request) Has been cancelled
CI / markdown (pull_request) Has been cancelled
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>
2026-06-14 00:32:21 +02:00
56c405904d fix(spawner): stage jailed env payloads (Sam & Codex)
Some checks failed
CI / rust (pull_request) Has been cancelled
CI / markdown (pull_request) Has been cancelled
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
2026-06-13 23:28:19 +02:00
Sam & Claude
c902f75813 feat(clawdie): host installer/deployer crate (FreeBSD + Linux)
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>
2026-06-13 22:55:23 +02:00
Sam & Claude
c38f6e5a73 fix(spawner): use FreeBSD jail command=<binary> parameter syntax
Some checks failed
CI / rust (pull_request) Has been cancelled
CI / markdown (pull_request) Has been cancelled
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>
2026-06-13 21:29:39 +02:00
3ce2840823 Merge pull request 'feat(mcp): confine external MCP servers in a jail (reuse spawner primitive)' (#38) from feat/jail-external-mcp into main
Some checks are pending
CI / markdown (push) Waiting to run
CI / rust (push) Waiting to run
Reviewed-on: #38
2026-06-13 20:35:26 +02:00
Sam & Claude
87c075d6ba feat(mcp): confine external MCP servers in a jail (reuse spawner primitive)
Some checks failed
CI / rust (pull_request) Has been cancelled
CI / markdown (pull_request) Has been cancelled
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>
2026-06-13 20:08:24 +02:00
Sam & Claude
c2f631b53c feat(socket): accept jail on the spawn-agent command
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>
2026-06-13 20:01:02 +02:00
5ce93206b2 feat(mcp): prototype external MCP host tools (Sam & Codex)
Some checks failed
CI / rust (pull_request) Has been cancelled
CI / markdown (pull_request) Has been cancelled
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
2026-06-13 19:53:21 +02:00
Sam & Claude
66cbc76a5b feat(spawner): JailConfig + jail_wrap for jailed agent spawn
Some checks failed
CI / rust (pull_request) Has been cancelled
CI / markdown (pull_request) Has been cancelled
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>
2026-06-13 19:31:09 +02:00
Sam & Claude
1f2377d4dd cleanup: drop the experimental clawdie mini-binary
Some checks failed
CI / markdown (pull_request) Has been cancelled
CI / rust (pull_request) Has been cancelled
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>
2026-06-13 19:19:07 +02:00
Sam & Claude
21800a8775 feat(mcp): add colibri-mcp crate — MCP bridge for editor integration (Sam & Claude)
Some checks failed
CI / rust (pull_request) Has been cancelled
CI / markdown (pull_request) Has been cancelled
- 7 Phase 1 tools: status, snapshot, list_tasks, list_skills,
  create_task, intake_task, set_cost_mode
- Write tools gated behind COLIBRI_MCP_WRITE=1 (default read-only)
- stdio JSON-RPC server for MCP protocol compliance
- 10 integration tests with mock Unix socket server
- Uses ColibriCommand/ColibriResponse (post-rename from PR #30)
- Design doc: docs/CLAWDIE-STUDIO-PROPOSAL.md
2026-06-13 12:53:43 +02:00
6e78ea630d docs: clarify Herdr as optional Linux display (Sam & Codex)
Some checks failed
CI / rust (pull_request) Has been cancelled
CI / markdown (pull_request) Has been cancelled
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
2026-06-13 12:29:11 +02:00
Sam & Claude
b11bff2b00 refactor: rename the daemon socket API Herdr* -> Colibri* (Sam & Claude)
Some checks failed
CI / rust (pull_request) Has been cancelled
CI / markdown (pull_request) Has been cancelled
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>
2026-06-13 11:07:58 +02:00
Sam & Claude
6c6420ff2a feat(glasspane): runtime-aware ingestion so zot panes parse precisely (Sam & Claude)
Some checks failed
CI / rust (pull_request) Has been cancelled
CI / markdown (pull_request) Has been cancelled
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>
2026-06-13 10:48:21 +02:00
Sam & Claude
813ace9237 fix(daemon): make the Herdr socket group-writable (0770) (Sam & Claude)
Re-landed on current main (the earlier branch never merged — main moved under
it). Operators hit "permission denied" connecting to the colibri daemon from
colibri-tui / the `clawdie` helper: socket.rs binds the Unix socket but never
sets its mode, so it stays at the umask default (0755 = owner-only write).
Connecting needs WRITE perm, so a colibri-group member (clawdie) gets EACCES.
chmod the socket to 0770 after bind. Shared socket::serve, so it covers both
colibri-daemon and the clawdie agent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 10:53:01 +02:00
fd0d83e053 fmt: format current main Rust sources (Sam & Codex) 2026-06-04 20:59:20 +02:00
454c23db34 fix(colibri): add ListSkills + RegisterSkill to Command enum (Hermes)
The colibri CLI's parse_args and run handler referenced Command::ListSkills
and Command::RegisterSkill, but both variants were missing from the enum
definition. This caused a build failure on Linux (rustc 1.95.0).

Added the missing variants with their fields (name, description, category
for RegisterSkill). Build + test + format gate verified green.

Co-Authored-By: Hermes Agent <hermes@clawdie.si>
2026-06-04 20:17:58 +02:00
Clawdie Operator
c422f16697 Add USB live runtime inventory golden test
Manifest captured from the clawdie-iso operator USB:
- FreeBSD 15.0-RELEASE, Node v24.14.1, pi 0.78.0
- Validates the RuntimeInventory contract parses live USB data
2026-06-04 12:46:34 +00:00
Clawdie Operator
6e7c4c022b Add list-skills + register-skill to colibri CLI
- DaemonClient: list_skills() and register_skill() methods
- CLI: list-skills and register-skill subcommands
- Parsing: --description and --category options for register-skill
- Usage text and examples updated

The daemon socket already had ListSkills and RegisterSkill commands;
this exposes them through the colibri CLI binary.
2026-06-04 12:12:19 +00:00
Sam & Claude
25c7f16600 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	Cargo.toml
2026-06-02 09:26:46 +02:00
Sam & Claude
aea2fbe60e feat: add clawdie — simplified operator agent in one small binary (Sam & Claude)
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>
2026-06-02 08:31:59 +02:00
123kupola
24c1fbfd13 fix: restore PR11 Linux preflight 2026-05-31 17:36:35 +02:00
b06d244e85 feat: cache warming on daemon startup + periodic re-warm (T1.4 PR3b)
Disabled by default. Enables DeepSeek prefix cache warming:
- Fire-and-forget probe on daemon startup
- Optional periodic re-warming (COLIBRI_CACHE_WARMING_INTERVAL_HOURS)
- Cache warming metrics exposed in daemon status
- Fix: Box<dyn Error> -> Box<dyn Error + Send + Sync> in deepseek crate

Config: COLIBRI_CACHE_WARMING=0|1, COLIBRI_CACHE_WARMING_INTERVAL_HOURS=N
Status: cache_warming.enabled, .last_warm_at, .last_warm_cache_hit,
        .last_warm_hit_tokens

Build: pass | Tests: workspace green | Fmt: clean
2026-05-31 17:33:53 +02:00
a42e6b76ff feat: add local_args to spawn-agent for argv-capable Pi spawn
Adds local_args field to HerdrCommand::SpawnAgent, enabling the
Local provider to pass argv to the agent binary without a wrapper
script. Backward-compatible — local_args defaults to None.

Real Pi spawn on FreeBSD is now:
  spawn-agent provider=local model=pi local_args=['--mode','json','--no-tools','-p','task']

Previously required a wrapper script because only an executable
path was accepted. This closes the OSA wrapper caveat from PR #9.

Build: pass | Tests: workspace green
2026-05-31 17:21:25 +02:00
1f550a4b5c feat: scheduler prompt injection (T1.4 PR3a)
When scheduler_prompt_injection is enabled and a session_id is
provided on spawn-agent, the daemon builds a PromptAssembly from
the session, serializes it as COLIBRI_SESSION_CONTEXT env var,
and passes COLIBRI_COST_MODE to the spawned agent process.

Config-gated (default: disabled) via COLIBRI_SCHEDULER_PROMPT_INJECTION.
No cache warming — that's PR3b (separate).

Build: pass | Tests: workspace green | Clippy: clean | Fmt: clean
2026-05-31 17:05:32 +02:00
3c10fc098e test: add Pi spawn path proof integration test
Validates: Colibri spawns agent process (fake-pi-agent.py) → reads
JSONL stdout → glasspane ingests → snapshot shows Done state with
correct session ID.

Uses scripts/fake-pi-agent.py which emits the colibri-pi-events
JSONL taxonomy (session, agent_start, turn_start, turn_end,
agent_end). Proves the spawn→ingest→glasspane pipeline without
requiring the real pi binary.

The real Pi binary path (when installed) follows the same pattern:
pi --mode json is spawned with identical spawner code.

Build: pass | Tests: 1/1 green | Workspace: all green
2026-05-31 16:23:11 +02:00
79c15cd4df feat: cost-aware trimming + auto-escalation (T1.4 PR 2)
Behavior changes for cache-first prompt discipline:

- PromptAssembly::trim_to_budget(CostMode): trims volatile scratch
  first, then oldest appendable log entries, to fit within cost mode
  budget. Prefix is never trimmed. Returns count of items removed.

- EscalationTrigger enum: BudgetExceeded + CompactionInsufficient
  variants for auto-escalation decisions.

- auto_escalate(): returns Some(next_mode) if trigger warrants
  escalation, None if already at ceiling or trigger doesn't apply.

- 11 new tests: trim budget scenarios (under/over/deterministic/
  prefix-preserved), escalation chain (fast→smart→max→ceiling),
  compaction triggers.

No scheduler injection, no cache warming — PR 3 follows.

Build: pass | Tests: 51/51 green | Clippy: clean | Fmt: clean
2026-05-31 16:13:11 +02:00
880da14662 Merge pull request 'feat: add zot runtime event normalization scaffold' (#3) from feat/zot-runtime-event-adapter into main 2026-05-31 16:03:51 +02:00
65e304a1e0 Merge pull request 'feat: scaffold colibri-skills crate — split-brain read consumer' (#2) from feat/colibri-skills-scaffold into main 2026-05-31 16:03:12 +02:00
7c1a9d886a feat: add PromptAssembly + CacheMetrics structs (T1.4 PR 1)
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
2026-05-31 15:30:38 +02:00
b0e94fd514 feat: add zot runtime event normalization scaffold
Phase 1 of zot agent harness integration. Adds:

- AgentRuntime enum (Pi, Zot, Local) with serde support
- zot_event_type() — parse zot RPC NDJSON lines to normalized
  Colibri event types. Permissive: handles tool_use_start,
  tool_use_args, tool_use_end in addition to documented events.
- apply_zot_event() / fold_zot_events() — state transitions
  reusing the existing apply_pi_event() logic via normalization.
- Critical: assistant_message does NOT end the pane (zot may
  emit them during tool loops). Only turn_end/done signals
  completion.
- 16 new tests using real captured zot RPC event lines, including
  tool call sequences and error/success response handling.
- PiJsonlIngestor and existing tests unchanged (33/33 green).

No spawner, socket, or process changes — this is the event
taxonomy foundation only. Wrapper + daemon integration follow
in Phase 2.

Build: pass | Tests: 33/33 green | Clippy: clean | Fmt: clean
2026-05-31 15:03:39 +02:00
1da49eac4f fix: satisfy clippy for skill status default (Sam & Codex)
Validation: cargo fmt --check; cargo clippy -p colibri-skills --all-targets -- -D warnings; cargo test -p colibri-skills.
2026-05-31 14:38:28 +02:00
5267f97f52 feat: scaffold colibri-skills crate — split-brain read consumer
Phase 1: structs + type system + 12 tests. No IO, no SQLite yet.
Compiles against full workspace (9 crates now, up from 8).

The colibri-skills crate is the read-only runtime consumer for
skill artifacts authored in Clawdie-AI. It does NOT store or author
skills — it indexes committed, reviewed skill bundles.

Seeded from the astro-howto artifact (PR #6 in clawdie-ai):
  - Skill, SkillManifest, SkillArtifact, SkillChunk structs
  - ArtifactType classifier (document, image, script, transcript, etc.)
  - ImportSummary + SearchResult types
  - SQLite schema documented in doc/COLIBRI-SKILLS-PLAN.md

Build: pass | Tests: 12/12 green | Clippy: pending
2026-05-31 14:36:43 +02:00
123kupola
6f957d3d72 test: add Slovenian multibyte truncation test (Sam & Hermes)
"Cene že še češnje je" — š/č/ž are 2-byte UTF-8, same family as
German umlauts. Complements the existing CJK+umlaut test. Ensures
compact_tool_result never panics on Slavic diacritics in FreeBSD
locale output, pkg descriptions, and agent logs.
2026-05-27 23:22:10 +02:00
0dd7cf70af fix: UTF-8-safe truncation in compact_tool_result
cost.rs:124 sliced at a raw byte boundary which panics on multibyte
UTF-8 characters (ä, ö, ü, CJK, etc). FreeBSD tool output and agent
logs regularly contain non-ASCII.

Fix: use str::floor_char_boundary() to round down to the nearest valid
char boundary before slicing. This never panics and produces valid
UTF-8 output at or below the requested byte limit.

Added test: multibyte truncation with CJK + umlaut input.
2026-05-27 23:09:34 +02:00
123kupola
0b24a7c7d1 feat: richer status + cost thresholds in session rotation (Sam & Hermes)
ISO-ready improvements:
- cmd_status now returns paths, cost mode/thresholds, task counts
  by status, pane count, scheduler interval
- session_rotation reads CostMode thresholds instead of static
  DaemonConfig fields — Fast/Smart/Max affect compaction now
- Debug log includes active cost_mode
2026-05-27 22:48:42 +02:00
2883151b5f fix: keep cost mode changes clippy-clean 2026-05-27 22:31:31 +02:00
123kupola
ffee0c655a docs: note set-cost-mode is runtime-only for T1.4 (Sam & Hermes) 2026-05-27 22:29:09 +02:00