Commit graph

80 commits

Author SHA1 Message Date
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
123kupola
c97b44ad3e feat: add cost discipline — Fast/Smart/Max modes + escalation (Sam & Hermes)
Phase 5: cache-first prompt discipline. New cost module with:
- CostMode enum: Fast (500K/5 turns/4KB tool cap), Smart (2M/20/16KB), Max (8M/100/none)
- escalate() — Fast→Smart→Max, each step logged visibly
- compact_tool_result() — truncate oversized tool outputs with byte annotation
- set-cost-mode socket command + COLIBRI_COST_MODE env var
- 9 unit tests (defaults, thresholds, escalation path, parsing, compaction)
2026-05-27 22:27:30 +02:00
eaa2f27680 feat: add colibri task commands 2026-05-27 22:24:16 +02:00
8d4bb3a916 refactor: rename colibri-ctl binary to colibri (Sam & Claude)
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>
2026-05-27 21:50:36 +02:00
4f81e49983 test: intake-task drains to SQLite via run_loop (Sam & Claude)
Regression guard for the scheduler store deadlock fixed upstream in d760536:
scheduler.tick held a non-reentrant std::sync::Mutex (state.store) across the
match scrutinee, so relocking inside the arm deadlocked the first time any
intake/scheduled task fired.

This test (independently authored on domedog) submits an intake-task over the
real Unix socket, runs run_loop with a fast scheduler tick, and asserts the
task is drained into SQLite. It hangs (>8min) against the pre-fix code and
passes in 0.09s against d760536 — so it cross-validates that fix and guards the
regression. Closes osa-smoke rec #2.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 21:48:47 +02:00