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>
colibri-daemon runs in the foreground and writes no pidfile, so the previous
`command=/usr/local/bin/colibri-daemon` would hang `service start` and leave
status/stop unable to track it. Run it under daemon(8): -P supervisor pidfile,
-r restart on crash, -u colibri privilege drop, -o logfile for the tracing
stdout. start_precmd recreates the colibri-owned /var/run/colibri (tmpfs),
/var/db/colibri, and the log dir each start. Still review-only / not installed;
needs an on-FreeBSD `service` test (osa-smoke rec #4).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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>
Two improvements to Hermes' run_loop wiring (9717ce7):
1. Add scheduler_secs to the daemon loop startup log — the most
important interval for the OSA re-smoke was missing from the
heartbeat/rotation/handoff log line.
2. Replace tokio::select! with tokio::join! in main.rs — select!
returned when the first task finished, leaving the other dangling.
join! waits for both the socket server and the daemon loop to
complete before proceeding to shutdown.
89 tests pass, clippy clean.
The scheduler tick was wired into daemon::run_loop but main.rs only
started the socket server, never the background loop. intake-task
commands queued into the scheduler's in-memory queue were never
processed. Fix: spawn daemon::run_loop as a second tokio task
alongside the socket server.
packaging/freebsd/colibri_daemon.in: FreeBSD rc.d service file
for review only, not installed. Uses /var/db/colibri,
/var/run/colibri, COLIBRI_DB_PATH. /tmp smoke test comes first.
Flesh out Decision #1 (SQLite-first) with the operational surface and make
Lane 2 explicitly non-blocking for core correctness:
- Storage surface (proposed defaults): DB file path (FreeBSD /var/db/colibri,
Linux XDG, COLIBRI_DB_PATH override); WAL + synchronous=NORMAL, local FS only;
backup via VACUUM INTO + JSON contract export; authoritative (task/agent/
scheduling) vs mirrored (Pi events, watchdog host-status, inventory).
- Postgres-escalation criterion: one concrete rule — only if Lane 4 dual-run
parity proves SQLite insufficient for required cross-host shared state.
- Failure mode: DB corrupt/unavailable => fail safe, no takeover; watchdog/hostd
and local FreeBSD safety stay authoritative.
- Lane 2: gates IMG deployment only, never Colibri core correctness.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- COLIBRI-CUTOVER-PLAN.md: resolve Open Decision #1 — Colibri owns its own
store, embedded SQLite first, Postgres adapter only if parity/integration
proves the need (do not default to reusing clawdie-ai system_ops). Reaffirm
the Herdr boundary. Update Lane 1 T1.2 + Next actions accordingly.
- .agent-handoff.md: relay to Hermes — 0925939 is the shared verified plan,
the .hermes draft is superseded where it conflicts, storage decided. FYI,
not a debate.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Verified, shared version of the cutover orchestration plan in docs/,
correcting the .hermes/plans draft against the actual repos:
- Kill the fabricated clawdie-ai crates/colibri-daemon (no crates/ dir
exists there; the real daemon is Unix-socket in the colibri repo, not
axum/HTTP).
- Fix baseline to 160dd11 (65 tests pass/0 fail, clippy -D warnings clean);
eb37784 was not clippy-clean.
- Reaffirm the Herdr boundary: Linux/macOS display/remote plane, no Herdr
on FreeBSD; colibri-glasspane is the native answer (Lane 2 reframed).
- Correct ownership: Claude=domedog=Linux, Codex=osa=FreeBSD, Hermes=debby=Linux.
- Surface the Postgres coupling as an explicit open decision, not a given.
- Downgrade the overclaimed debby<->domedog herdr smoke test to "not yet done."
Leaves the .hermes draft untouched; marked DRAFT/PROPOSED pending ratification.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Operator runbook for standing up domedog as the Herdr testing hub, attaching
debby as a remote client over Tailscale SSH, then layering Colibri supervision.
Records verified state: hub running (Herdr 0.6.2), pi integration installed,
debby's key already authorized + ssh config present, remaining gap = herdr
client not yet installed on debby. Includes the key-safety note (public keys
safe; never transit private keys) and the IPv6/Codeberg retry tip.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The Tab / BackTab key arms wrapped their whole body in
`if !app.sessions.is_empty()`. clippy (-D warnings) flagged both as
collapsible_match; lift the guard onto the match arm. Empty `sessions` now
falls through to the catch-all — same no-op as before, behavior unchanged.
Gates on c2655d1 + this: build ok, cargo test --workspace 65 passed/0 failed,
cargo clippy --workspace --all-targets -- -D warnings clean, cargo fmt --check clean.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Make the Herdr boundary explicit now that Herdr-Linux-remote and
Colibri-FreeBSD are validated as separate planes:
- Herdr FreeBSD port is parked, not a migration blocker. The exploratory
FreeBSD build findings are kept for the record but framed as a parked
experiment, not a pending task.
- Herdr stays a Linux/macOS display/remote plane behind the socket contract;
colibri-glasspane is the native FreeBSD supervision answer.
Tighten stale status so it stops rotting:
- Replace the fixed "31 passed, 0 failed" count with "all gates green as of
b325c38" plus the clippy clean note.
- Anchor the top-level status line to commit b325c38.
Doc-only; no code or test changes.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
read_manifest used a loose `filename.contains(manifest_type)` substring
match, so for host=osa type=watchdog-host-status it nondeterministically
grabbed either `…watchdog-host-status.json` (correct, has `.status`) or its
sibling `…watchdog-host-status-run-manifest.json` (no `.status`). When the
run-manifest won the read_dir race, source/mode read as "unknown" and the
FreeBSD watchdog-socket-read row failed (11/12).
Match the exact `<host>-<manifest_type>.json` suffix and pick the lexically
greatest (most-recent dated) filename, so selection is deterministic and the
run-manifest sibling is excluded. The underlying watchdog data was always
correct; this was a false failure from loose fixture matching.
cargo test --workspace: all green. cargo clippy --all-targets -D warnings: clean.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1. Terminal cleanup on all exit paths: move disable_raw_mode +
LeaveAlternateScreen to main() with a restore_terminal() helper,
install a panic hook so raw mode is never left active on panic or
io::Error early-return from run().
2. Safe observed_at slice: replace &snap.observed_at[..19] (panics on
short strings) with .get(..19).unwrap_or(&snap.observed_at).
3. Stalled state unified in icon column: state_color() and state_icon()
now accept a stalled bool — stalled panes show magenta ⚠ in the icon
cell instead of a green/yellow primary state icon, so the eye lands on
a single column. Separate Stalled column kept for redundancy.
4. Footer j/k navigation hint added alongside q and r.
---
Build: pass | Tests: pass — 50 passed