Merge pull request 'docs: clarify Herdr as optional Linux display (Sam & Codex)' (#31) from docs/herdr-platform-boundary-cleanup into main
Reviewed-on: #31
This commit is contained in:
commit
773f7294c1
16 changed files with 87 additions and 961 deletions
|
|
@ -1,8 +1,7 @@
|
|||
//! Regression test for the bug the 2026-05-27 osa FreeBSD smoke caught:
|
||||
//! Regression test for the bug a 2026-05-27 osa FreeBSD smoke caught:
|
||||
//! `main.rs` started the socket server but never spawned `daemon::run_loop`, so
|
||||
//! an `intake-task` reported `queued` over the socket yet was never drained into
|
||||
//! the SQLite coordination store. See
|
||||
//! `docs/internal/sessions/2026-05-27-osa-freebsd-daemon-scheduler-smoke.md`.
|
||||
//! the SQLite coordination store.
|
||||
//!
|
||||
//! This proves the full path: socket `intake-task` → `run_loop` scheduler tick →
|
||||
//! persisted SQLite task. If `run_loop` is ever dropped from the wiring again,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// colibri-harness — herdr-like supervision TUI built on Colibri primitives.
|
||||
// colibri-harness — Colibri-native supervision TUI built on Colibri primitives.
|
||||
//
|
||||
// Connects to a colibri-daemon Unix socket, polls GlasspaneSnapshot every 2s,
|
||||
// lets the operator spawn/kill agents, drill into pane details, and cycle
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
# Clawdie Agent — wiki / mindmap
|
||||
|
||||
The **Clawdie agent** is the simplified, operator-friendly face of Colibri: one
|
||||
small Rust binary (`clawdie`) that ships with exactly two things wired up — a
|
||||
Telegram bot and a DeepSeek lane — sitting on top of the proven control-plane
|
||||
core. Everything heavier (cost modes, quotas, multi-provider fallback) is
|
||||
deliberately **lifted**.
|
||||
The **Clawdie agent** mini-binary is an experimental, operator-friendly face of
|
||||
Colibri: one small Rust binary (`clawdie`) that wires a Telegram bot and a
|
||||
DeepSeek lane on top of the control-plane core. It is not the current live-ISO
|
||||
service contract; the FreeBSD live USB runs `colibri_daemon` directly, while
|
||||
`service clawdie` is reserved for a future installed disk/server service once
|
||||
that implementation is chosen.
|
||||
|
||||
This is a mindmap-style wiki page (the format from the Herdr/Colibri capability
|
||||
graph work — see [`HERDR-VS-COLIBRI-GRAPH.md`](./HERDR-VS-COLIBRI-GRAPH.md) and
|
||||
|
|
@ -59,9 +60,9 @@ Two halves of the same daemon, both kept:
|
|||
| **Glasspane** | `colibri-glasspane` + daemon socket | The "radar": agent state, panes, supervision snapshot |
|
||||
| **Coordination** | `colibri-store` + daemon loop | Task board, agent registry, session lifecycle |
|
||||
|
||||
The Clawdie agent reuses these as-is over the Herdr Unix-socket API. It adds the
|
||||
Telegram + DeepSeek front door and **removes** the cost/quota machinery from its
|
||||
own runtime path.
|
||||
The Clawdie mini-binary reuses these as-is over the Colibri control-plane socket.
|
||||
It adds the Telegram + DeepSeek front door and **removes** the cost/quota
|
||||
machinery from its own runtime path.
|
||||
|
||||
## Surface area (the whole product)
|
||||
|
||||
|
|
@ -72,7 +73,7 @@ graph LR
|
|||
ds -->|reply| clawdie
|
||||
clawdie --> gp["glasspane radar"]
|
||||
clawdie --> co["coordination board"]
|
||||
clawdie -. Herdr socket .- ui["operator tools (colibri CLI / TUI)"]
|
||||
clawdie -. Colibri socket .- ui["operator tools (colibri CLI / TUI)"]
|
||||
```
|
||||
|
||||
## Files
|
||||
|
|
@ -95,4 +96,4 @@ graph LR
|
|||
One DeepSeek key serves both the Telegram chat lane and the daemon's own
|
||||
provider routing.
|
||||
|
||||
See [`CLAWDIE-BUILD.md`](./CLAWDIE-BUILD.md) for the build + ISO instructions.
|
||||
See [`CLAWDIE-BUILD.md`](./CLAWDIE-BUILD.md) for experimental build notes.
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
# Clawdie agent — build & ISO instructions
|
||||
# Experimental `clawdie` mini-binary — build notes
|
||||
|
||||
The `clawdie` binary is the simplified Colibri agent (see
|
||||
[`CLAWDIE-AGENT-WIKI.md`](./CLAWDIE-AGENT-WIKI.md)). It is configured almost
|
||||
entirely by **build flags**, so a baked ISO ships ready to run.
|
||||
The `clawdie` binary is an experimental Colibri-side candidate for a future
|
||||
deployed-system service (see [`CLAWDIE-AGENT-WIKI.md`](./CLAWDIE-AGENT-WIKI.md)).
|
||||
It is **not** the current FreeBSD live-ISO service contract. The live USB uses
|
||||
`colibri_daemon`; `service clawdie` remains reserved for an installed disk/server
|
||||
service once that implementation is chosen.
|
||||
|
||||
## 1. Build with baked credentials
|
||||
|
||||
|
|
@ -29,8 +31,8 @@ Build with **no** flags for a "bring your own key" binary — it reads
|
|||
|
||||
## 2. What the binary does out of the box
|
||||
|
||||
- Starts the control-plane core: glasspane supervision + Herdr Unix socket +
|
||||
coordination loop.
|
||||
- Starts the control-plane core: glasspane supervision + Colibri control-plane
|
||||
socket + coordination loop.
|
||||
- If a Telegram token **and** a DeepSeek key are present, runs the Telegram
|
||||
bridge (long-poll → DeepSeek → reply).
|
||||
- No token → headless (control plane only). Token but no key → bridge disabled
|
||||
|
|
@ -39,9 +41,10 @@ Build with **no** flags for a "bring your own key" binary — it reads
|
|||
No cost modes, quotas, context budgets, or provider fallback — those are lifted
|
||||
from this agent on purpose.
|
||||
|
||||
## 3. Run as a service (like Clawdie-AI)
|
||||
## 3. Run as an experimental service
|
||||
|
||||
On FreeBSD, install the rc.d script and enable it:
|
||||
On FreeBSD, install the rc.d script only on a throwaway test host or an explicit
|
||||
deployed-service experiment:
|
||||
|
||||
```sh
|
||||
pw groupadd clawdie
|
||||
|
|
@ -65,18 +68,13 @@ chmod 0600 /usr/local/etc/clawdie/clawdie.env
|
|||
service clawdie restart
|
||||
```
|
||||
|
||||
## 4. ISO integration
|
||||
## 4. ISO status
|
||||
|
||||
The ISO build stages the prebuilt FreeBSD `clawdie` release binary + rc.d (it
|
||||
never compiles Rust while the image is mounted), the same model as the Colibri
|
||||
daemon staging. In `clawdie-iso`:
|
||||
|
||||
- `build.cfg`: `FEATURE_CLAWDIE`, `CLAWDIE_ENABLE`, and the build-flag creds.
|
||||
- `scripts/stage-clawdie-iso.sh`: installs binary + rc.d + rc.conf sample.
|
||||
|
||||
Build the binary on the FreeBSD/OSA host (not Debian/Linux), then run the ISO
|
||||
preflight. **Do not `cargo clean` the colibri checkout** until the ISO build has
|
||||
consumed `target/release/clawdie`.
|
||||
The current `clawdie-iso` baseline does **not** stage this mini-binary or its
|
||||
rc.d script. ISO builds stage `colibri-daemon`, `colibri`, `colibri-smoke-agent`,
|
||||
and preferably `colibri-tui` from this checkout. If a deployed-system
|
||||
`service clawdie` lane is reintroduced later, it should get fresh packaging and
|
||||
acceptance criteria instead of silently treating this experiment as final.
|
||||
|
||||
## 5. Next ISO build — XFCE operator-USB fixes to carry forward
|
||||
|
||||
|
|
@ -84,8 +82,8 @@ The next operator-USB image must retain the XFCE/live-GUI fixes already proven
|
|||
on real hardware (see `clawdie-iso/PLAN-OPERATOR-USB-NEXT.md` and
|
||||
`doc/AMD-ASUS-XFCE-LIVE-USB-FINDINGS.md`). Load-bearing items:
|
||||
|
||||
- **SDDM over LightDM** — LightDM was the silent blocker for live GUI boot on
|
||||
Intel and AMD. SDDM is part of the operator-USB contract; do **not** revert.
|
||||
- **SDDM remains the supported live display manager** — keep it unless an
|
||||
alternative has equivalent real-hardware proof for Intel and AMD GUI boot.
|
||||
- **`clawdie-live-gpu`** — pre-SDDM rc.d service that does a conservative KMS
|
||||
pick (Intel iGPU works out of the box; AMD/NVIDIA picked conservatively)
|
||||
before the display manager starts.
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ crates to be updated in lockstep.
|
|||
│ │
|
||||
│ ┌──────────┐ ┌───────────┐ ┌──────────┐ ┌───────────────┐ │
|
||||
│ │ Spawner │ │ Sessions │ │ Heartbeat │ │ Socket Server │ │
|
||||
│ │ (agents) │ │ (JSONL) │ │ (30s) │ │ (Unix domain) │──┼──► Herdr / web
|
||||
│ └─────┬─────┘ └───────────┘ └─────┬─────┘ └───────┬───────┘ │ board / Zed
|
||||
│ │ (agents) │ │ (JSONL) │ │ (30s) │ │ (Unix domain) │──┼──► Colibri TUI / web
|
||||
│ └─────┬─────┘ └───────────┘ └─────┬─────┘ └───────┬───────┘ │ Zed / optional Herdr Linux
|
||||
│ │ │ │ │
|
||||
│ │ stdout JSONL │ poll_exit() │ query │
|
||||
│ ▼ ▼ ▼ │
|
||||
|
|
@ -47,7 +47,7 @@ matching the existing watchdog convention).
|
|||
|
||||
### Wire types (defined in `colibri-daemon/src/lib.rs`)
|
||||
|
||||
**Inbound: `HerdrCommand`** (tagged by `cmd` field):
|
||||
**Inbound: `ColibriCommand`** (tagged by `cmd` field):
|
||||
|
||||
| `cmd` value | Parameters | Purpose |
|
||||
| -------------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
|
|
@ -59,7 +59,7 @@ matching the existing watchdog convention).
|
|||
| `get-session` | `session_id` | Full session dump (turns + prompt) |
|
||||
| `compact-session` | `session_id` | Compact oldest turns in a session |
|
||||
|
||||
**Outbound: `HerdrResponse`**:
|
||||
**Outbound: `ColibriResponse`**:
|
||||
|
||||
```json
|
||||
{
|
||||
|
|
@ -104,8 +104,8 @@ Server: {"ok":true,"data":{"agent_id":"a1b2-c3d4","status":"running"}}\n
|
|||
|
||||
### Operator CLI smoke helpers
|
||||
|
||||
`colibri-client` also ships two small binaries for manual Herdr/SSH smoke tests
|
||||
without hand-writing socket JSON:
|
||||
`colibri-client` also ships small binaries for manual display-client and SSH
|
||||
smoke tests without hand-writing socket JSON:
|
||||
|
||||
```sh
|
||||
# Inspect daemon state
|
||||
|
|
@ -219,19 +219,19 @@ AgentHandle SupervisedPane Session
|
|||
|
||||
### Daemon lifecycle events → Glasspane AgentState
|
||||
|
||||
| Daemon lifecycle event | Ingested Pi event type | Resulting `AgentState` | Notes |
|
||||
| ------------------------------ | ------------------------------------------------------- | ---------------------- | ------------------------------------------ |
|
||||
| Agent subprocess spawned | _(pane attached, state = `Idle`)_ | `Idle` | `SupervisedPane::new` defaults to `Idle` |
|
||||
| Agent emits `session` header | `session` / `session_started` | `Idle` | Also captures `pi_session_id` and `cwd` |
|
||||
| Agent emits turn/message/tool | `turn_start`, `message_start`, `tool_execution_*`, etc. | `Working` | Any of 14 event types |
|
||||
| Agent emits compaction events | `auto_compaction_*`, `compaction_*` | `Working` | Compaction is active work |
|
||||
| Agent emits retry events | `auto_retry_*` | `Working` | Retry is active work |
|
||||
| Agent awaits steering/approval | `queue_update` | `Blocked` | Operator attention needed (Herdr headline) |
|
||||
| Turn/task complete | `turn_end` / `agent_end` | `Done` | Agent reached a completion point |
|
||||
| Agent emits explicit error | `error` | `Error` | Terminal failure state |
|
||||
| Agent subprocess exits (0) | _daemon injects `agent_end`_ | `Done` | Heartbeat detected normal exit |
|
||||
| Agent subprocess exits (!=0) | _daemon injects `error`_ | `Error` | Heartbeat detected crash/error exit |
|
||||
| Agent killed externally | _daemon injects `error`_ | `Error` | `kill-agent` command |
|
||||
| Daemon lifecycle event | Ingested Pi event type | Resulting `AgentState` | Notes |
|
||||
| ------------------------------ | ------------------------------------------------------- | ---------------------- | ---------------------------------------------- |
|
||||
| Agent subprocess spawned | _(pane attached, state = `Idle`)_ | `Idle` | `SupervisedPane::new` defaults to `Idle` |
|
||||
| Agent emits `session` header | `session` / `session_started` | `Idle` | Also captures `pi_session_id` and `cwd` |
|
||||
| Agent emits turn/message/tool | `turn_start`, `message_start`, `tool_execution_*`, etc. | `Working` | Any of 14 event types |
|
||||
| Agent emits compaction events | `auto_compaction_*`, `compaction_*` | `Working` | Compaction is active work |
|
||||
| Agent emits retry events | `auto_retry_*` | `Working` | Retry is active work |
|
||||
| Agent awaits steering/approval | `queue_update` | `Blocked` | Operator attention needed (dashboard headline) |
|
||||
| Turn/task complete | `turn_end` / `agent_end` | `Done` | Agent reached a completion point |
|
||||
| Agent emits explicit error | `error` | `Error` | Terminal failure state |
|
||||
| Agent subprocess exits (0) | _daemon injects `agent_end`_ | `Done` | Heartbeat detected normal exit |
|
||||
| Agent subprocess exits (!=0) | _daemon injects `error`_ | `Error` | Heartbeat detected crash/error exit |
|
||||
| Agent killed externally | _daemon injects `error`_ | `Error` | `kill-agent` command |
|
||||
|
||||
### State transition diagram
|
||||
|
||||
|
|
@ -446,11 +446,12 @@ let snapshot = state.glasspane.read().await.snapshot_at(
|
|||
|
||||
### Where it is consumed
|
||||
|
||||
| Consumer | Transport | Phase | Purpose |
|
||||
| -------------------- | ------------------ | ----- | -------------------------------- |
|
||||
| Herdr (Linux) | Unix socket | 4 | Operator dashboard display |
|
||||
| Zed / web board | HTTP / SSE | 4 | Web-based supervision view |
|
||||
| colibri-orchestrator | In-memory / socket | 5 | Route/dispatch work across panes |
|
||||
| Consumer | Transport | Phase | Purpose |
|
||||
| ----------------------------- | ------------------ | ----- | -------------------------------------------- |
|
||||
| `colibri` CLI / `colibri-tui` | Unix socket | 4 | Native operator dashboard and smoke surface |
|
||||
| Herdr (Linux/macOS optional) | Unix socket/bridge | 4 | Optional external display client, not source |
|
||||
| Zed / web board | HTTP / SSE | 4 | Web-based supervision view |
|
||||
| colibri-orchestrator | In-memory / socket | 5 | Route/dispatch work across panes |
|
||||
|
||||
### Wire shape (JSON)
|
||||
|
||||
|
|
@ -513,9 +514,10 @@ library crate, not a process — it is compiled into the daemon binary.
|
|||
4. socket::serve(state, shutdown_rx) ← BLOCKING
|
||||
├── Binds Unix socket at config.socket_path
|
||||
├── Accepts connections
|
||||
└── Dispatches HerdrCommand variants
|
||||
└── Dispatches ColibriCommand variants
|
||||
│
|
||||
5. External clients (Herdr, web) connect and send commands
|
||||
5. External clients (colibri CLI/TUI, optional Herdr Linux/macOS, web) connect
|
||||
and send commands
|
||||
```
|
||||
|
||||
### Clean boot checklist (in sequence)
|
||||
|
|
@ -553,6 +555,6 @@ Unix socket path (`DaemonConfig.socket_path`).
|
|||
| `docs/HERDR-VS-COLIBRI-GRAPH.md` | Hybrid boundary: Herdr as Linux display client |
|
||||
| `crates/colibri-daemon/src/socket.rs` | Socket server implementation |
|
||||
| `crates/colibri-daemon/src/daemon.rs` | Daemon background loop + heartbeat |
|
||||
| `crates/colibri-daemon/src/lib.rs` | Wire types: `HerdrCommand`, `HerdrResponse` |
|
||||
| `crates/colibri-daemon/src/lib.rs` | Wire types: `ColibriCommand`, `ColibriResponse` |
|
||||
| `crates/colibri-daemon/src/spawner.rs` | Agent subprocess spawner |
|
||||
| `crates/colibri-glasspane/src/lib.rs` | State machine, supervisor, snapshot contract |
|
||||
|
|
|
|||
|
|
@ -105,14 +105,16 @@ graph LR
|
|||
| `run.manifest` | `build_run_manifest()` → `clawdie.interagent.run-manifest.v1` | run-manifest emitter |
|
||||
|
||||
**Proposed — roadmap, NOT locked** (graph for comparison; names firm up when
|
||||
code lands): supervision `supervise.attach/list/state` (Herdr socket);
|
||||
coordination `board.task(queued→claimed→started→done|failed)`, `skills.*`;
|
||||
code lands): supervision `supervise.attach/list/state` (Colibri source of
|
||||
truth, with optional Herdr-compatible Linux display); coordination
|
||||
`board.task(queued→claimed→started→done|failed)`, `skills.*`;
|
||||
execution `schedule.cron/interval/once`, `remote.*`.
|
||||
|
||||
## 5. Drop candidates (gated)
|
||||
|
||||
Covered by Herdr (supervision, Linux client) or `colibri-deepseek`
|
||||
(provider/cache); remove only after proof gates + per-file caller inventory.
|
||||
Covered by Herdr where a Linux display client is desired, or by
|
||||
`colibri-deepseek` (provider/cache); remove only after proof gates + per-file
|
||||
caller inventory.
|
||||
Snapshot: clawdie-ai `archive/multitenant-claude-pre-divergence`.
|
||||
|
||||
- `tmux-screenshot-command.ts` + glass-pane glue → **Herdr** supervision.
|
||||
|
|
|
|||
|
|
@ -27,6 +27,16 @@ operator/display
|
|||
|
||||
Herdr is not being ported to FreeBSD. On the ISO, the native answer is Colibri daemon + glasspane/TUI/harness.
|
||||
|
||||
## Platform boundary
|
||||
|
||||
| Target | Source of truth | Display/control surface | Claim boundary |
|
||||
| ------------------------- | -------------------------------------- | --------------------------------------- | -------------------------------------------------------------- |
|
||||
| FreeBSD 15 live ISO | `colibri_daemon` + `colibri-glasspane` | `colibri` CLI / `colibri-tui` | Requires FreeBSD build/boot evidence; GUI needs hardware proof |
|
||||
| Linux/macOS operator host | Colibri snapshot/API from the daemon | Optional Herdr, terminal panes, web/Zed | Display-client proof only; does not prove FreeBSD runtime |
|
||||
|
||||
Herdr remains an optional Linux/macOS display client. It must not become a
|
||||
FreeBSD ISO dependency or the source of truth for supervision state.
|
||||
|
||||
## Current baseline
|
||||
|
||||
Already landed and validated:
|
||||
|
|
@ -316,7 +326,7 @@ Required:
|
|||
- Phase 3: task capability matching assigns work to jail workers.
|
||||
- Phase 4: per-task ephemeral jail option if needed.
|
||||
|
||||
### Lane D — Native dashboard / Herdr replacement
|
||||
### Lane D — Native dashboard / optional Herdr display
|
||||
|
||||
1. **FreeBSD-native dashboard**
|
||||
- Continue with `colibri-glasspane-tui` / harness rather than porting Herdr.
|
||||
|
|
|
|||
|
|
@ -191,7 +191,8 @@ Failed: 0 ❌
|
|||
|
||||
### Benefits
|
||||
|
||||
- ✅ Guarantees Linux and FreeBSD behave identically
|
||||
- ✅ Compares Linux and FreeBSD behavior and surfaces platform drift; FreeBSD
|
||||
runtime proof still requires FreeBSD validation
|
||||
- ✅ Catches platform-specific regressions early
|
||||
- ✅ Provides clear evidence matrix for each gate
|
||||
- ✅ Reduces manual "is this working on osa?" checks
|
||||
|
|
|
|||
|
|
@ -1,90 +0,0 @@
|
|||
# Colibri Phase 4 Live Daemon/Client Smoke Report
|
||||
|
||||
**Date:** 27.maj.2026
|
||||
**Host:** osa.smilepowered.org — FreeBSD 15.0-RELEASE-p8 amd64
|
||||
**Repo:** `Clawdie/Colibri`
|
||||
**Commit tested:** `fbcb7e6` — `Add live daemon client smoke with local fake agent`
|
||||
**Status:** PASS
|
||||
|
||||
## Purpose
|
||||
|
||||
Prove that Phase 4 is not only unit-level: a real `colibri-daemon` Unix socket
|
||||
server can run in parallel with existing services, and `colibri-client` can talk
|
||||
to it over the socket without sudo or production paths.
|
||||
|
||||
## Isolation
|
||||
|
||||
The smoke uses a temp data directory and socket under the current user's temp
|
||||
area. It does **not** touch production services, global sockets, or privileged
|
||||
paths.
|
||||
|
||||
No sudo is required.
|
||||
|
||||
## What the smoke covers
|
||||
|
||||
The new integration test:
|
||||
|
||||
```text
|
||||
crates/colibri-client/tests/live_socket_smoke.rs
|
||||
```
|
||||
|
||||
performs this full path:
|
||||
|
||||
1. Creates isolated `DaemonConfig`
|
||||
2. Starts real `socket::serve(...)`
|
||||
3. Creates real `DaemonClient`
|
||||
4. Calls `status`
|
||||
5. Calls `glasspane_snapshot` before spawn and verifies no panes
|
||||
6. Writes a fake local Pi JSONL agent script
|
||||
7. Calls `spawn-agent` with `provider:"local"`
|
||||
8. Verifies Glasspane state transitions via the daemon socket:
|
||||
- `Idle`
|
||||
- `Working`
|
||||
- `Blocked`
|
||||
- `Done`
|
||||
9. Verifies captured `pi_session_id` and `cwd`
|
||||
10. Calls `kill-agent`
|
||||
11. Sends daemon shutdown and removes temp data
|
||||
|
||||
## Local provider behavior added
|
||||
|
||||
`Provider::Local` was added for no-network smoke/local tools:
|
||||
|
||||
- no API key required
|
||||
- no fallback to remote providers
|
||||
- socket `model` field is treated as executable path
|
||||
- no `--mode json` args are injected
|
||||
|
||||
This keeps live daemon/client testing deterministic and independent of Pi,
|
||||
DeepSeek, OpenRouter, Anthropic, or existing agent services.
|
||||
|
||||
## Validation commands
|
||||
|
||||
```sh
|
||||
cargo fmt --check
|
||||
cargo clippy --workspace --all-targets -- -D warnings
|
||||
cargo test --workspace
|
||||
cargo build --workspace --release
|
||||
```
|
||||
|
||||
## Result
|
||||
|
||||
All gates passed on FreeBSD 15.
|
||||
|
||||
```text
|
||||
50 tests passed, 0 failed
|
||||
release build OK
|
||||
```
|
||||
|
||||
## Current conclusion
|
||||
|
||||
Colibri Phase 4 now has a working typed client plus real socket smoke coverage.
|
||||
The daemon/client/glasspane path is proven end-to-end with a local fake Pi JSONL
|
||||
agent, while remaining safe to run in parallel with existing services.
|
||||
|
||||
## Next candidates
|
||||
|
||||
- Add a small CLI wrapper around `colibri-client` for manual operator smoke.
|
||||
- Promote `GlasspaneSnapshot` to `colibri-contracts` once a second external
|
||||
consumer needs standalone deserialization.
|
||||
- Add HTTP/SSE transport later; Unix socket is sufficient for current Phase 4.
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
# OSA FreeBSD `colibri` Task CLI Smoke
|
||||
|
||||
**Date:** 2026-05-27
|
||||
**Host:** osa.smilepowered.org
|
||||
**OS:** FreeBSD 15.0-RELEASE-p8 amd64
|
||||
**Repo:** `Clawdie/Colibri`
|
||||
**Commit:** `f434a89` — `feat: add colibri task commands`
|
||||
**Status:** PASS
|
||||
|
||||
## Scope
|
||||
|
||||
Validated the post-refactor operator CLI task commands, using the renamed binary only:
|
||||
|
||||
```sh
|
||||
colibri create-task
|
||||
colibri list-tasks
|
||||
colibri intake-task
|
||||
```
|
||||
|
||||
No raw Python Unix-socket client was used for task operations.
|
||||
|
||||
## Gates
|
||||
|
||||
```sh
|
||||
cargo fmt --check
|
||||
cargo clippy --workspace --all-targets -- -D warnings
|
||||
cargo test --workspace
|
||||
cargo build --workspace --release
|
||||
```
|
||||
|
||||
Workspace gates were green at `f434a89`.
|
||||
|
||||
## Isolated smoke environment
|
||||
|
||||
```text
|
||||
COLIBRI_DAEMON_DATA_DIR=/tmp/colibri-cli-task-smoke-clawdie-1779913324/data
|
||||
COLIBRI_DAEMON_SOCKET=/tmp/colibri-cli-task-smoke-clawdie-1779913324/colibri.sock
|
||||
COLIBRI_DB_PATH=/tmp/colibri-cli-task-smoke-clawdie-1779913324/colibri.sqlite
|
||||
COLIBRI_HOST=osa-cli-task-smoke
|
||||
```
|
||||
|
||||
## Result
|
||||
|
||||
- `colibri status` connected to the daemon socket.
|
||||
- `colibri create-task --title ... --description ...` created a queued SQLite task.
|
||||
- `colibri list-tasks --status queued` returned the direct task.
|
||||
- `colibri intake-task --title ... --description ... --capability freebsd --capabilities sqlite,scheduler` queued intake successfully.
|
||||
- The daemon scheduler drained intake on the next 30s tick:
|
||||
|
||||
```text
|
||||
FOUND_ON_POLL=31
|
||||
```
|
||||
|
||||
SQLite verification:
|
||||
|
||||
```text
|
||||
tasks 2
|
||||
journal_mode wal
|
||||
```
|
||||
|
||||
Graceful shutdown:
|
||||
|
||||
```text
|
||||
socket exists after stop? no
|
||||
process remains? no
|
||||
```
|
||||
|
||||
The daemon log showed the socket server and background loop exiting cleanly.
|
||||
|
||||
## Verdict
|
||||
|
||||
The renamed `colibri` operator CLI now covers the immediate task workflow:
|
||||
|
||||
```sh
|
||||
colibri create-task --title "..."
|
||||
colibri list-tasks --status queued
|
||||
colibri intake-task --title "..." --capability freebsd
|
||||
```
|
||||
|
||||
The OSA `/tmp` smoke passed without using raw socket helper scripts.
|
||||
|
|
@ -1,243 +0,0 @@
|
|||
# OSA FreeBSD Colibri Daemon + Scheduler Smoke
|
||||
|
||||
**Date:** 27.maj.2026
|
||||
**Host:** osa.smilepowered.org
|
||||
**OS:** FreeBSD 15.0-RELEASE-p9 amd64
|
||||
**Rust:** rustc 1.94.0 (4a4ef493e 2026-03-02)
|
||||
**Repo:** `Clawdie/Colibri`
|
||||
**Commit tested:** `53028a0` — `docs: answer Codex handoff questions — colibri-ctl, scheduler, smoke-agent, WAL`
|
||||
**Status:** PARTIAL PASS — core daemon smoke passed; scheduler runtime wiring gap found
|
||||
|
||||
## Scope
|
||||
|
||||
Prototype-only `/tmp` smoke. No rc.d install, no service takeover, no production paths.
|
||||
|
||||
Test environment:
|
||||
|
||||
```sh
|
||||
COLIBRI_DAEMON_DATA_DIR=/tmp/colibri-osa-smoke-clawdie-1779905501/data
|
||||
COLIBRI_DAEMON_SOCKET=/tmp/colibri-osa-smoke-clawdie-1779905501/colibri.sock
|
||||
COLIBRI_DB_PATH=/tmp/colibri-osa-smoke-clawdie-1779905501/colibri.sqlite
|
||||
COLIBRI_HOST=osa-smoke
|
||||
```
|
||||
|
||||
Build command:
|
||||
|
||||
```sh
|
||||
cargo build --workspace --release
|
||||
```
|
||||
|
||||
Result: release build OK.
|
||||
|
||||
## Core daemon result
|
||||
|
||||
### Start + files
|
||||
|
||||
`colibri-daemon` started successfully with isolated `/tmp` paths.
|
||||
|
||||
Created:
|
||||
|
||||
```text
|
||||
colibri.sock
|
||||
colibri.sqlite
|
||||
colibri.sqlite-shm
|
||||
colibri.sqlite-wal
|
||||
data/sessions/
|
||||
daemon.log
|
||||
```
|
||||
|
||||
SQLite WAL mode is active on FreeBSD:
|
||||
|
||||
```text
|
||||
journal_mode wal
|
||||
```
|
||||
|
||||
### Status
|
||||
|
||||
```json
|
||||
{
|
||||
"agent_list": [],
|
||||
"agents": 0,
|
||||
"daemon": "colibri-daemon",
|
||||
"host": "osa-smoke",
|
||||
"sessions": 0,
|
||||
"version": "0.0.1"
|
||||
}
|
||||
```
|
||||
|
||||
### Snapshot before spawn
|
||||
|
||||
```json
|
||||
{
|
||||
"schema": "clawdie.glasspane.snapshot.v1",
|
||||
"host": "osa-smoke",
|
||||
"observed_at": "2026-05-27T18:11:41.890Z",
|
||||
"panes": []
|
||||
}
|
||||
```
|
||||
|
||||
### Local fake agent spawn
|
||||
|
||||
Command:
|
||||
|
||||
```sh
|
||||
target/release/colibri-ctl --socket "$COLIBRI_DAEMON_SOCKET" \
|
||||
spawn-local /home/clawdie/colibri/target/release/colibri-smoke-agent \
|
||||
--session-id osa-smoke-session
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"agent_id": "d2c5fc74-4085-4731-a0e0-f373df9d007b",
|
||||
"status": "running"
|
||||
}
|
||||
```
|
||||
|
||||
Snapshot after fake agent emitted Pi-compatible JSONL:
|
||||
|
||||
```json
|
||||
{
|
||||
"schema": "clawdie.glasspane.snapshot.v1",
|
||||
"host": "osa-smoke",
|
||||
"observed_at": "2026-05-27T18:11:47.450Z",
|
||||
"panes": [
|
||||
{
|
||||
"id": "d2c5fc74-4085-4731-a0e0-f373df9d007b",
|
||||
"agent": "/home/clawdie/colibri/target/release/colibri-smoke-agent",
|
||||
"state": "done",
|
||||
"pi_session_id": "manual-smoke",
|
||||
"last_event_at": "2026-05-27T18:11:45.897Z",
|
||||
"cwd": "/home/clawdie/colibri"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Kill command succeeded:
|
||||
|
||||
```json
|
||||
{
|
||||
"agent_id": "d2c5fc74-4085-4731-a0e0-f373df9d007b",
|
||||
"status": "stopped"
|
||||
}
|
||||
```
|
||||
|
||||
## Coordination store result
|
||||
|
||||
Direct `create-task` over the Unix socket succeeded and persisted to SQLite:
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"data": {
|
||||
"agent_id": null,
|
||||
"created_at": "2026-05-27T18:11:47.578003651+00:00",
|
||||
"description": "direct socket create-task",
|
||||
"id": "288887de-c82e-46d7-9f2d-2701299266e6",
|
||||
"status": "queued",
|
||||
"title": "osa smoke direct task",
|
||||
"updated_at": "2026-05-27T18:11:47.578003651+00:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
SQLite counts after smoke:
|
||||
|
||||
```text
|
||||
tasks 1
|
||||
agents 0
|
||||
skills 0
|
||||
```
|
||||
|
||||
## Intake-task / scheduler result
|
||||
|
||||
`intake-task` command over the socket returned success:
|
||||
|
||||
```json
|
||||
{"ok":true,"data":{"status":"queued"}}
|
||||
```
|
||||
|
||||
However, an immediate `list-tasks` returned no task from intake:
|
||||
|
||||
```json
|
||||
{"ok":true,"data":[]}
|
||||
```
|
||||
|
||||
The direct `create-task` path then proved the store itself works, so this is not a SQLite failure.
|
||||
|
||||
### Finding
|
||||
|
||||
Scheduler runtime processing is not active in the `colibri-daemon` binary at this commit.
|
||||
|
||||
Evidence:
|
||||
|
||||
- `cmd_intake_task` queues into `state.scheduler` in memory.
|
||||
- `daemon::run_loop` contains the scheduler tick.
|
||||
- `crates/colibri-daemon/src/main.rs` starts the socket server but does **not** spawn `daemon::run_loop`.
|
||||
- Therefore `intake-task` can report `queued`, but queued intake is not drained into SQLite tasks by the running daemon.
|
||||
|
||||
This means T1.3 scheduler unit tests pass, and scheduler code exists, but the live daemon does not yet process intake/scheduled jobs.
|
||||
|
||||
## Restart / teardown behavior
|
||||
|
||||
Graceful interrupt removed the socket:
|
||||
|
||||
```text
|
||||
after stop socket exists? no
|
||||
process remains? no
|
||||
```
|
||||
|
||||
Restarting the daemon against the same `/tmp` DB/socket path also worked:
|
||||
|
||||
```json
|
||||
{
|
||||
"agent_list": [],
|
||||
"agents": 0,
|
||||
"daemon": "colibri-daemon",
|
||||
"host": "osa-smoke-restart",
|
||||
"sessions": 0,
|
||||
"version": "0.0.1"
|
||||
}
|
||||
```
|
||||
|
||||
After restart stop:
|
||||
|
||||
```text
|
||||
restart after stop socket exists? no
|
||||
restart process remains? no
|
||||
```
|
||||
|
||||
The `/tmp` smoke directory was removed after recording this report.
|
||||
|
||||
## Verdict
|
||||
|
||||
### Passed
|
||||
|
||||
- FreeBSD release build
|
||||
- daemon starts with isolated `/tmp` data/socket/DB paths
|
||||
- Unix socket is created and removed on graceful shutdown
|
||||
- status command works
|
||||
- glasspane snapshot command works
|
||||
- SQLite DB + WAL files are created on FreeBSD
|
||||
- `spawn-local colibri-smoke-agent` works
|
||||
- Pi JSONL ingestion produces `done` pane state with `pi_session_id`
|
||||
- direct `create-task` / `list-tasks` store path works
|
||||
- restart against same temp DB/socket path works
|
||||
- prototype rc.d file remains review-only and was not installed
|
||||
|
||||
### Partial / failed
|
||||
|
||||
- `intake-task` returns success but is not processed into a SQLite task because the daemon binary does not start `daemon::run_loop`.
|
||||
- `colibri-ctl` still lacks task/intake helper commands, so task/intake smoke used a small raw Unix-socket Python client.
|
||||
|
||||
## Recommended next fix
|
||||
|
||||
1. Spawn `daemon::run_loop(state.clone(), DaemonLoopConfig::default(), ...)` from `crates/colibri-daemon/src/main.rs` alongside the socket server.
|
||||
2. Add a deterministic integration test proving `intake-task` over the socket becomes a queued SQLite task after a short scheduler tick.
|
||||
3. Add `colibri-ctl` commands for at least:
|
||||
- `list-tasks`
|
||||
- `create-task`
|
||||
- `intake-task`
|
||||
4. Re-run this same FreeBSD `/tmp` smoke.
|
||||
|
|
@ -1,142 +0,0 @@
|
|||
# OSA FreeBSD Intake Scheduler Re-smoke
|
||||
|
||||
**Date:** 27.maj.2026
|
||||
**Host:** osa.smilepowered.org
|
||||
**OS:** FreeBSD 15.0-RELEASE-p9 amd64
|
||||
**Repo:** `Clawdie/Colibri`
|
||||
**Base pulled:** `af8c011` — daemon loop wiring landed
|
||||
**Fix commit:** `d760536` — `fix: avoid scheduler store deadlock on intake drain`
|
||||
**Status:** PASS after follow-up fix
|
||||
|
||||
## What was checked
|
||||
|
||||
Pulled the daemon-loop wiring (`9717ce7`, plus `af8c011`) and ran the full workspace gates:
|
||||
|
||||
```sh
|
||||
cargo fmt --check
|
||||
cargo clippy --workspace --all-targets -- -D warnings
|
||||
cargo test --workspace
|
||||
cargo build --workspace --release
|
||||
```
|
||||
|
||||
Initial gates were green, but a live `/tmp` FreeBSD re-smoke exposed one more runtime bug.
|
||||
|
||||
## Finding during live re-smoke
|
||||
|
||||
With `daemon::run_loop` now started, `intake-task` did reach the scheduler tick and inserted a SQLite task, but a concurrent `list-tasks` socket request timed out.
|
||||
|
||||
Root cause: `Scheduler::tick` used expressions like:
|
||||
|
||||
```rust
|
||||
match state.store.lock().unwrap().create_task(...) {
|
||||
Ok(task) => {
|
||||
state.store.lock().unwrap().list_agents()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `MutexGuard` temporary from the `match` scrutinee can live through the match arm. Relocking `state.store` inside the arm can deadlock the scheduler thread. On FreeBSD this manifested as:
|
||||
|
||||
- SQLite row was created
|
||||
- socket request blocked on the store lock
|
||||
- daemon became unresponsive until killed by the smoke harness timeout
|
||||
|
||||
## Fix
|
||||
|
||||
`d760536` rewrites scheduler store access so every lock is scoped explicitly and dropped before the next lock:
|
||||
|
||||
```rust
|
||||
let create_result = {
|
||||
let store = state.store.lock().unwrap();
|
||||
store.create_task(...)
|
||||
};
|
||||
```
|
||||
|
||||
It also adds a regression test:
|
||||
|
||||
```text
|
||||
scheduler::tests::test_scheduler_tick_drains_intake_without_deadlock
|
||||
```
|
||||
|
||||
## Re-smoke result after fix
|
||||
|
||||
Isolated `/tmp` environment:
|
||||
|
||||
```text
|
||||
COLIBRI_DAEMON_DATA_DIR=/tmp/colibri-osa-resmoke-clawdie-1779908417/data
|
||||
COLIBRI_DAEMON_SOCKET=/tmp/colibri-osa-resmoke-clawdie-1779908417/colibri.sock
|
||||
COLIBRI_DB_PATH=/tmp/colibri-osa-resmoke-clawdie-1779908417/colibri.sqlite
|
||||
COLIBRI_HOST=osa-resmoke
|
||||
```
|
||||
|
||||
`intake-task` response:
|
||||
|
||||
```json
|
||||
{"ok":true,"data":{"status":"queued"}}
|
||||
```
|
||||
|
||||
The scheduler drained intake on the 30s tick:
|
||||
|
||||
```text
|
||||
FOUND_ON_POLL=30
|
||||
```
|
||||
|
||||
`list-tasks` then returned the queued task:
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"data": [
|
||||
{
|
||||
"agent_id": null,
|
||||
"created_at": "2026-05-27T19:00:47.360062420+00:00",
|
||||
"description": "prove scheduler loop drains intake",
|
||||
"id": "c3dab9df-8a37-47b1-854b-d956fd796d41",
|
||||
"status": "queued",
|
||||
"title": "osa resmoke intake",
|
||||
"updated_at": "2026-05-27T19:00:47.360062420+00:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
SQLite verification:
|
||||
|
||||
```text
|
||||
tasks 1
|
||||
journal_mode wal
|
||||
```
|
||||
|
||||
Graceful shutdown:
|
||||
|
||||
```text
|
||||
socket exists after stop? no
|
||||
process remains? no
|
||||
```
|
||||
|
||||
Daemon log included both task loops exiting cleanly:
|
||||
|
||||
```text
|
||||
daemon background loop started ... scheduler_secs=30
|
||||
received interrupt signal, initiating graceful shutdown
|
||||
socket server received shutdown signal
|
||||
daemon loop received shutdown signal
|
||||
daemon background loop exited
|
||||
Herdr socket API shut down
|
||||
colibri-daemon shut down cleanly
|
||||
```
|
||||
|
||||
## Final verdict
|
||||
|
||||
The daemon loop wiring is valid after `d760536`.
|
||||
|
||||
Validated on FreeBSD:
|
||||
|
||||
- daemon starts with `/tmp` data/socket/DB paths
|
||||
- background daemon loop starts beside the socket server
|
||||
- `intake-task` over Unix socket becomes a queued SQLite task on the scheduler tick
|
||||
- `list-tasks` remains responsive after the tick
|
||||
- SQLite WAL works
|
||||
- graceful shutdown removes socket and exits both socket + loop tasks
|
||||
|
||||
The smoke directory was removed after recording this report.
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
# Colibri Scheduler / FreeBSD Store Isolation Finding
|
||||
|
||||
**Date:** 27.maj.2026
|
||||
**Repo:** `Clawdie/Colibri`
|
||||
**Finding commit:** `ceaeaee` — scheduler T1.3 landed
|
||||
**Fix commit:** `a48afa1` — `fix: harden scheduler tests and FreeBSD store isolation`
|
||||
**Status:** Fixed and verified
|
||||
|
||||
## Finding
|
||||
|
||||
After pulling `ceaeaee`, the Linux-side direction was good, but FreeBSD validation exposed a real test-isolation bug:
|
||||
|
||||
```text
|
||||
failed to open coordination store at "/var/db/colibri/colibri.sqlite":
|
||||
I/O error: Permission denied (os error 13)
|
||||
```
|
||||
|
||||
Root cause: `daemon::tests::test_daemon_state_creation` used `DaemonConfig::from_env()`, which on FreeBSD resolves the default production/service SQLite path:
|
||||
|
||||
```text
|
||||
/var/db/colibri/colibri.sqlite
|
||||
```
|
||||
|
||||
Unit tests must not require production service paths or root permissions.
|
||||
|
||||
## Fix
|
||||
|
||||
`test_daemon_state_creation` now overrides:
|
||||
|
||||
- `data_dir`
|
||||
- `socket_path`
|
||||
- `db_path`
|
||||
|
||||
with an isolated temp directory before constructing `DaemonState`.
|
||||
|
||||
## Additional hardening
|
||||
|
||||
While reviewing the scheduler, the follow-up also hardened edge cases:
|
||||
|
||||
- cron fields accept leading-zero forms such as `00 12 01 06 01`
|
||||
- cron schedules fire at most once per matching minute, even with a 30s daemon tick
|
||||
- `pick_agent` no longer assigns required-capability tasks to zero-match agents
|
||||
- empty required-capability tasks can still select a general available agent
|
||||
|
||||
## Verification
|
||||
|
||||
Commands run after the fix:
|
||||
|
||||
```sh
|
||||
cargo fmt --check
|
||||
cargo clippy --workspace --all-targets -- -D warnings
|
||||
cargo test --workspace
|
||||
cargo build --workspace --release
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```text
|
||||
89 tests passed, 0 failed
|
||||
release build OK
|
||||
```
|
||||
|
||||
## Conclusion
|
||||
|
||||
T1.3 scheduler remains accepted, but `a48afa1` is the correct green baseline after FreeBSD-safe test isolation and scheduler edge-case hardening.
|
||||
|
|
@ -1,115 +0,0 @@
|
|||
# Colibri Baseline — main @ d360dde
|
||||
|
||||
**Date:** 2026-05-31
|
||||
**Commit:** `d360dde` — Merge PR #4 (T1.4 PR2: trimming + auto-escalation)
|
||||
**Status:** All 4 merged PRs validated on Linux + FreeBSD
|
||||
|
||||
## Merged PRs
|
||||
|
||||
| PR | Title | Content | Tests |
|
||||
| --- | ------------------------------------- | ---------------------------------------------------- | -------- |
|
||||
| #1 | PromptAssembly + CacheMetrics structs | Structural wrapper, no behavior change | 5 golden |
|
||||
| #2 | colibri-skills scaffold | Read-only skill consumer crate, 12 tests | 12 |
|
||||
| #3 | zot runtime event normalization | AgentRuntime enum, zot event mapper, 16 tests | 16 |
|
||||
| #4 | cost-aware trimming + auto-escalation | trim_to_budget(), EscalationTrigger, auto_escalate() | 11 |
|
||||
|
||||
## Validation
|
||||
|
||||
### Linux (debby, Debian 13)
|
||||
|
||||
```
|
||||
rustc: 1.94.0 (via rustup)
|
||||
cargo fmt --check ✓
|
||||
cargo clippy --workspace --all-targets -- -D warnings ✓
|
||||
cargo test --workspace ✓
|
||||
git diff --check HEAD ✓
|
||||
```
|
||||
|
||||
### FreeBSD (osa, FreeBSD 15.0-RELEASE)
|
||||
|
||||
```
|
||||
host: osa.smilepowered.org
|
||||
rustc: 1.94.0
|
||||
cargo: 1.94.0
|
||||
freebsd-version -k: 15.0-RELEASE-p9
|
||||
freebsd-version -u: 15.0-RELEASE-p9
|
||||
uname -r: 15.0-RELEASE-p8 (kernel p9 installed, pending reboot)
|
||||
|
||||
cargo fmt --check ✓
|
||||
cargo clippy --workspace --all-targets -- -D warnings ✓
|
||||
cargo test --workspace ✓
|
||||
git diff --check HEAD ✓
|
||||
```
|
||||
|
||||
### Test counts
|
||||
|
||||
```
|
||||
colibri-daemon: 51 unit + 7 glasspane integration + 1 scheduler integration
|
||||
colibri-contracts: golden tests
|
||||
colibri-glasspane: 33 unit (17 Pi + 16 zot)
|
||||
colibri-skills: 12 unit
|
||||
colibri-store: integration
|
||||
Workspace total: all passed, no failures
|
||||
```
|
||||
|
||||
### Workspace crates (9)
|
||||
|
||||
```
|
||||
colibri-contracts, colibri-deepseek, colibri-runtime,
|
||||
colibri-glasspane, colibri-daemon, colibri-client,
|
||||
colibri-glasspane-tui, colibri-store, colibri-skills
|
||||
```
|
||||
|
||||
## Known caveats
|
||||
|
||||
- OSA kernel is p8 running but p9 installed — reboot needed for kernel update.
|
||||
Does not affect Rust validation.
|
||||
- `colibri-skills` and `zot-runtime-event-adapter` are scaffold-only (Phase 1).
|
||||
No IO, no SQLite, no daemon integration yet.
|
||||
- `PromptAssembly::trim_to_budget()` is implemented but not yet wired into
|
||||
the scheduler or session append path — PR 3 (scheduler injection) pending.
|
||||
- `CacheMetrics` struct exists but is not populated by any API call path yet.
|
||||
- API token (`FORGEJO_API_TOKEN`) stored in `~/.hermes/.env` with 0600 perms.
|
||||
Enables Hermes to create/merge PRs via Forgejo API without web UI.
|
||||
|
||||
## Key files added/changed this session
|
||||
|
||||
```
|
||||
docs/T1.4-PROMPT-DISCIPLINE-PLAN.md (new — T1.4 implementation plan)
|
||||
docs/COLIBRI-CUTOVER-PLAN.md (link to T1.4 plan)
|
||||
crates/colibri-daemon/src/session.rs (PromptAssembly, CacheMetrics,
|
||||
trim_to_budget, golden tests)
|
||||
crates/colibri-daemon/src/cost.rs (EscalationTrigger, auto_escalate)
|
||||
crates/colibri-glasspane/src/lib.rs (AgentRuntime, zot_event_type,
|
||||
apply_zot_event, 16 tests)
|
||||
crates/colibri-skills/ (new crate — structs, 12 tests)
|
||||
doc/COLIBRI-SKILLS-PLAN.md → docs/ moved (skills plan)
|
||||
```
|
||||
|
||||
## Next recommended steps
|
||||
|
||||
In priority order for USB/ISO target:
|
||||
|
||||
1. **Real Pi spawn path proof** — validate that Colibri can spawn a Pi agent
|
||||
and consume its JSONL events on both Linux and FreeBSD.
|
||||
|
||||
2. **ISO service hardening** — Colibri as an `rc.d` service on FreeBSD,
|
||||
status visibility, firstboot integration.
|
||||
|
||||
3. **T1.4 PR3 — scheduler prompt injection** — wire trim_to_budget() into
|
||||
the scheduler's spawn-agent path, cost-aware prompt assembly.
|
||||
|
||||
4. **T1.4 PR4 — startup cache warming** — warm DeepSeek prefix cache on
|
||||
daemon startup, config-gated. Separate from PR3 because of lifecycle/cost
|
||||
concerns.
|
||||
|
||||
## Branch hygiene
|
||||
|
||||
```
|
||||
main: d360dde (baseline, all merged)
|
||||
t14-pr2-trimming: merged → can delete
|
||||
t14-pr1-clean: merged → can delete
|
||||
docs/t14-prompt-discipline-plan: merged → can delete
|
||||
feat/colibri-skills-scaffold: merged → can delete
|
||||
feat/zot-runtime-event-adapter: merged → can delete
|
||||
```
|
||||
|
|
@ -1,156 +0,0 @@
|
|||
# OSA real Pi binary spawn proof
|
||||
|
||||
**Date:** 2026-05-31
|
||||
**Host:** `osa.smilepowered.org`
|
||||
**Colibri commit:** `44865f3` — main after PR #8
|
||||
**Pi binary:** `/home/clawdie/.npm-global/bin/pi`, version `0.76.0`
|
||||
|
||||
## Verdict
|
||||
|
||||
Real Pi binary spawn path was proven on OSA through `colibri-daemon`.
|
||||
|
||||
The daemon spawned a local executable wrapper, the wrapper executed the real
|
||||
`pi` binary in JSON mode, Colibri streamed Pi JSONL stdout into glasspane, and
|
||||
the pane reached `done` with a captured Pi session id.
|
||||
|
||||
This proves the runtime path:
|
||||
|
||||
```text
|
||||
colibri-daemon spawn-local
|
||||
→ wrapper executable
|
||||
→ real pi --mode json --no-tools --no-context-files --no-session -p ...
|
||||
→ Pi JSONL stdout
|
||||
→ colibri glasspane ingestion
|
||||
→ snapshot state=done + pi_session_id captured
|
||||
```
|
||||
|
||||
## Environment
|
||||
|
||||
```text
|
||||
host: osa.smilepowered.org
|
||||
rustc: rustc 1.94.0 (4a4ef493e 2026-03-02) (built from a source tarball)
|
||||
cargo: cargo 1.94.0 (85eff7c80 2026-01-15) (built from a source tarball)
|
||||
freebsd-version -k: 15.0-RELEASE-p9
|
||||
freebsd-version -u: 15.0-RELEASE-p9
|
||||
uname: FreeBSD osa.smilepowered.org 15.0-RELEASE-p8 FreeBSD 15.0-RELEASE-p8 releng/15.0-n281036-53054229dcb3 GENERIC amd64
|
||||
```
|
||||
|
||||
Caveat: OSA has p9 installed, but the running kernel is still p8 pending
|
||||
operator reboot.
|
||||
|
||||
## Direct Pi smoke
|
||||
|
||||
Before the daemon proof, direct Pi JSON mode was verified:
|
||||
|
||||
```sh
|
||||
pi --version
|
||||
# 0.76.0
|
||||
|
||||
pi --mode json --no-tools --no-context-files --no-session -p 'Reply with exactly: OK'
|
||||
```
|
||||
|
||||
Result: exit status 0, JSONL emitted, including:
|
||||
|
||||
- `session`
|
||||
- `agent_start`
|
||||
- `turn_start`
|
||||
- `message_start` / `message_update` / `message_end`
|
||||
- `turn_end`
|
||||
- `agent_end`
|
||||
|
||||
## Daemon proof setup
|
||||
|
||||
A temporary daemon instance was started with temp-only paths:
|
||||
|
||||
```sh
|
||||
COLIBRI_DAEMON_DATA_DIR=/tmp/colibri-real-pi-daemon-...
|
||||
COLIBRI_DAEMON_SOCKET=/tmp/colibri-real-pi-daemon-.../colibri.sock
|
||||
COLIBRI_DB_PATH=/tmp/colibri-real-pi-daemon-.../colibri.sqlite
|
||||
COLIBRI_HOST=osa-real-pi-proof
|
||||
target/debug/colibri-daemon
|
||||
```
|
||||
|
||||
The local spawn target was a temporary wrapper script:
|
||||
|
||||
```sh
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
WORKDIR="${TMPDIR:-/tmp}/colibri-real-pi-work-$$"
|
||||
mkdir -p "$WORKDIR"
|
||||
cd "$WORKDIR"
|
||||
exec pi --mode json --no-tools --no-context-files --no-session -p 'Reply with exactly: OK'
|
||||
```
|
||||
|
||||
Then Colibri CLI spawned it through the daemon:
|
||||
|
||||
```sh
|
||||
target/debug/colibri --socket "$SOCKET" spawn-local "$WRAPPER" --session-id real-pi-osa-proof
|
||||
```
|
||||
|
||||
Spawn response:
|
||||
|
||||
```json
|
||||
{
|
||||
"agent_id": "f8d07954-b66d-4008-9da2-783818935b22",
|
||||
"status": "running"
|
||||
}
|
||||
```
|
||||
|
||||
## Observed state transitions
|
||||
|
||||
Polling `colibri snapshot` showed:
|
||||
|
||||
```text
|
||||
poll 1: idle None None
|
||||
poll 2: idle None None
|
||||
poll 3: working 019e7e95-cc0b-751a-8c0b-e6fd3ffab08f None
|
||||
poll 4: working 019e7e95-cc0b-751a-8c0b-e6fd3ffab08f None
|
||||
poll 5: done 019e7e95-cc0b-751a-8c0b-e6fd3ffab08f None
|
||||
```
|
||||
|
||||
Final snapshot excerpt:
|
||||
|
||||
```json
|
||||
{
|
||||
"schema": "clawdie.glasspane.snapshot.v1",
|
||||
"host": "osa-real-pi-proof",
|
||||
"panes": [
|
||||
{
|
||||
"id": "f8d07954-b66d-4008-9da2-783818935b22",
|
||||
"agent": "/tmp/colibri-real-pi-daemon-.../run-real-pi.sh",
|
||||
"state": "done",
|
||||
"pi_session_id": "019e7e95-cc0b-751a-8c0b-e6fd3ffab08f",
|
||||
"cwd": "/tmp/colibri-real-pi-work-62462"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## What this proves
|
||||
|
||||
- OSA has a working `pi` binary.
|
||||
- `pi --mode json` emits JSONL that Colibri glasspane can ingest.
|
||||
- `colibri-daemon` can spawn an executable that runs real Pi.
|
||||
- JSONL stdout streaming from real Pi reaches glasspane.
|
||||
- Glasspane captures Pi session id separately from Colibri pane id.
|
||||
- The pane reaches `done` after a real Pi turn completes.
|
||||
|
||||
## Remaining limitations
|
||||
|
||||
- This used a wrapper because `spawn-local` currently treats `model` as a single
|
||||
executable path and does not pass argv.
|
||||
- This did not prove a first-class Pi provider command shape in the daemon.
|
||||
- This did not prove a long-running interactive Pi session, only one noninteractive
|
||||
JSON-mode turn.
|
||||
- This did not prove cache warming or scheduler injection behavior with real Pi.
|
||||
|
||||
Suggested follow-up if needed:
|
||||
|
||||
- add first-class argv support for `spawn-local`, or
|
||||
- add a dedicated Pi provider path that invokes:
|
||||
|
||||
```text
|
||||
pi --mode json --no-tools --no-context-files --no-session -p <prompt>
|
||||
```
|
||||
|
||||
with deterministic prompt/config handling.
|
||||
|
|
@ -1,6 +1,10 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# clawdie — FreeBSD rc.d service for the simplified Colibri agent.
|
||||
# clawdie — experimental FreeBSD rc.d service candidate.
|
||||
#
|
||||
# The supported live-ISO service is colibri_daemon. This script is kept for
|
||||
# explicit deployed-service experiments only; do not treat it as the final
|
||||
# installed-system service contract without fresh acceptance criteria.
|
||||
#
|
||||
# Operator-friendly by design: enable it and start it. The two credentials
|
||||
# (Telegram bot token + DeepSeek key) are normally baked into the binary at
|
||||
|
|
@ -101,7 +105,7 @@ clawdie_prestart()
|
|||
|
||||
clawdie_poststart()
|
||||
{
|
||||
# Wait for the Herdr socket to appear (daemon forks, child binds socket).
|
||||
# Wait for the Colibri control-plane socket to appear (daemon forks, child binds socket).
|
||||
local timeout=10
|
||||
local waited=0
|
||||
while [ ! -S "${clawdie_socket}" ] && [ $waited -lt $timeout ]; do
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue