docs: remove stale Herdr hub runbook + T1.4 cache-warming design #42
3 changed files with 0 additions and 260 deletions
|
|
@ -150,5 +150,4 @@ text+image token budgets.
|
|||
- Video: "Agent Specs: The Unreasonable Effectiveness of Useful Tokens"
|
||||
https://www.youtube.com/watch?v=o4KZH_KSqYQ
|
||||
- Colibri T1.4 Prompt Discipline: `docs/T1.4-PROMPT-DISCIPLINE-PLAN.md`
|
||||
- Colibri T1.4 Cache Warming: `docs/T1.4-CACHE-WARMING-DESIGN.md`
|
||||
- Colibri Glasspane Design: `docs/COLIBRI-GLASSPANE-DESIGN.md`
|
||||
|
|
|
|||
|
|
@ -1,124 +0,0 @@
|
|||
# Herdr hub runbook — domedog as the testing hub
|
||||
|
||||
**Goal:** run a Herdr hub on **domedog**, attach **debby** to it over Tailscale,
|
||||
then layer **Colibri** supervision on top. domedog hosts the agents/work; debby
|
||||
is a remote operator console; Colibri derives agent state from the Pi events
|
||||
those agents emit.
|
||||
|
||||
**Verified:** 27.maj.2026 (Herdr 0.6.2, Pi 0.75.5, cargo workspace green @ `5d45a0f`).
|
||||
|
||||
---
|
||||
|
||||
## Topology
|
||||
|
||||
```text
|
||||
Tailscale tailnet (samo.blatnik@)
|
||||
debby ──ssh──▶ domedog (Herdr hub) ──Pi --mode json──▶ Colibri
|
||||
100.66.193.10 100.103.255.41 (glasspane/daemon)
|
||||
remote client herdr server + agents source of truth
|
||||
```
|
||||
|
||||
- **domedog** `100.103.255.41` — Herdr **server** (the hub); agents run here.
|
||||
- **debby** `100.66.193.10` — Herdr **remote client** (`herdr --remote`).
|
||||
- **osa** `100.72.229.63` — FreeBSD; native supervision via `colibri-glasspane`
|
||||
(not a Herdr host — Herdr is Linux/macOS only).
|
||||
|
||||
Herdr's model: whoever runs `herdr --remote <target>` is the viewer/client; the
|
||||
_target_ hosts the server, sessions, panes, and agents.
|
||||
|
||||
---
|
||||
|
||||
## Phase 0 — Hub baseline on domedog ✅ done
|
||||
|
||||
The hub is already up; for the record the steps are:
|
||||
|
||||
```bash
|
||||
herdr status # server: running, protocol 11
|
||||
herdr integration install pi # needs ~/.pi/agent/extensions to exist first:
|
||||
# mkdir -p ~/.pi/agent/extensions
|
||||
herdr integration status # pi: current, claude: current, opencode: current
|
||||
```
|
||||
|
||||
- Server pid runs `herdr server`, sockets in `~/.config/herdr/`:
|
||||
`herdr.sock` (API) + `herdr-client.sock` (protocol).
|
||||
- Pi is installed under nvm node v22 (`~/.nvm/versions/node/v22.22.0/bin/pi`,
|
||||
v0.75.5) — the version glasspane was tested against.
|
||||
- **Gate:** `herdr status` → server running; `herdr integration status` → `pi: current`.
|
||||
|
||||
---
|
||||
|
||||
## Phase 1 — debby attaches in over Tailscale SSH
|
||||
|
||||
**Prereqs (all verified on domedog):**
|
||||
|
||||
- sshd listening on `:22`, reachable at `100.103.255.41` over Tailscale. ✅
|
||||
- debby's key `id_123kupola.pub` (`123kupola@gmail.com`) is already in domedog's
|
||||
`~/.ssh/authorized_keys`, so debby→domedog SSH is authorized. ✅
|
||||
- Herdr server running on domedog. ✅
|
||||
|
||||
**debby-side config (already present in debby `~/.ssh/config`):**
|
||||
|
||||
```sshconfig
|
||||
Host domedog-ts-herdr
|
||||
HostName 100.103.255.41
|
||||
User clawdija
|
||||
IdentityFile ~/.ssh/id_123kupola
|
||||
IdentitiesOnly yes
|
||||
```
|
||||
|
||||
**Remaining gap:** the `herdr` client binary is **not installed on debby**.
|
||||
|
||||
**Steps (run on debby / Hermes):**
|
||||
|
||||
```bash
|
||||
# 1. install the herdr client (same method as domedog; see herdr.dev)
|
||||
# 2. confirm SSH to the hub works:
|
||||
ssh domedog-ts-herdr 'echo ok; whoami' # expect: ok / clawdija
|
||||
# 3. attach to the hub's session:
|
||||
herdr --remote domedog-ts-herdr --session default
|
||||
```
|
||||
|
||||
- **Gate:** domedog `~/.config/herdr/herdr-server.log` logs `client connected`;
|
||||
debby's terminal shows the shared `default` session.
|
||||
|
||||
> Authorizing a new client is just appending its **public** key to domedog's
|
||||
> `~/.ssh/authorized_keys`. Public keys are safe to share/paste/commit. Never
|
||||
> transit a **private** key (the file without `.pub`). Easiest no-paste path,
|
||||
> run from domedog over the existing outbound trust:
|
||||
> `ssh debby-ts-herdr 'cat ~/.ssh/id_123kupola.pub'` then append if not present.
|
||||
|
||||
---
|
||||
|
||||
## Phase 2 — Colibri layered on the hub
|
||||
|
||||
Once debby is attached and agents run in the hub:
|
||||
|
||||
1. Launch a `pi` agent in a Herdr pane on domedog with `--mode json`; capture its
|
||||
JSONL stream.
|
||||
2. `colibri-glasspane` / `colibri-daemon` ingest that JSONL → `GlasspaneSnapshot`
|
||||
(`clawdie.glasspane.snapshot.v1`) served over the daemon Unix socket.
|
||||
3. Operator views agent state read-only via `colibri-harness` (the TUI) /
|
||||
`colibri` (the CLI).
|
||||
|
||||
**Boundary (unchanged):** Colibri daemon = source of truth (scheduling, task
|
||||
ownership, provider logic); Herdr = terminal workspace + display; glasspane =
|
||||
event-derived supervision. No scheduling/ownership in the display layer.
|
||||
|
||||
- **Gate:** a glasspane snapshot shows a pane's state transitioning
|
||||
idle → working → done, derived from _real_ Pi events, while the agent runs
|
||||
inside a Herdr pane.
|
||||
|
||||
---
|
||||
|
||||
## Reference — keys & reachability
|
||||
|
||||
| Host | Tailscale IP | Role | SSH identity used |
|
||||
| ------- | ---------------- | ------------------- | ----------------------------------------------- |
|
||||
| domedog | `100.103.255.41` | Herdr hub / Colibri | `~/.ssh/id_infra` (outbound to Forgejo + debby) |
|
||||
| debby | `100.66.193.10` | remote client | `~/.ssh/id_123kupola` (→ domedog as `clawdija`) |
|
||||
| osa | `100.72.229.63` | FreeBSD, glasspane | — |
|
||||
|
||||
- domedog's Forgejo/Tailscale key is `id_infra`; it authenticates fine — no
|
||||
ssh-agent needed (config points at the file).
|
||||
- Self-hosted Forgejo is `code.smilepowered.org`; SSH git access uses port
|
||||
`2222` via host SSH config. Codeberg is no longer the active push target.
|
||||
|
|
@ -1,135 +0,0 @@
|
|||
# T1.4 PR3b — Cache Warming Design
|
||||
|
||||
## Goal
|
||||
|
||||
Pre-warm the DeepSeek prefix cache on daemon startup so the first real
|
||||
agent task benefits from cached tokens. Reduces latency and cost on
|
||||
cold starts.
|
||||
|
||||
## Design decisions
|
||||
|
||||
### 1. Config-gated, disabled by default
|
||||
|
||||
```env
|
||||
COLIBRI_CACHE_WARMING=0|1 # enable startup warming (default: 0)
|
||||
COLIBRI_CACHE_WARMING_INTERVAL_HOURS=N # re-warm every N hours (default: 0 = disabled)
|
||||
```
|
||||
|
||||
Rationale: cache warming consumes tokens (~3,500 per warm cycle). Until
|
||||
proven beneficial on the ISO target, it stays opt-in.
|
||||
|
||||
### 2. Reuses existing cache probe
|
||||
|
||||
The `colibri-deepseek` crate already has `run_cache_probe()` which:
|
||||
|
||||
1. Sends a warm request with byte-stable STABLE_SYSTEM_PREFIX
|
||||
2. Waits 2s for cache commit
|
||||
3. Sends an identical probe request
|
||||
4. Returns cache_hit_tokens and cache_hit_observed
|
||||
|
||||
We reuse this directly — no new API calls, no new types.
|
||||
|
||||
### 3. Lifecycle
|
||||
|
||||
```
|
||||
Daemon start
|
||||
→ if COLIBRI_CACHE_WARMING=1 AND DEEPSEEK_API_KEY is set
|
||||
→ run_cache_probe()
|
||||
→ log result (hit/miss, tokens)
|
||||
→ record last_warm_at in DaemonState
|
||||
|
||||
Daemon loop (every heartbeat tick, 30s)
|
||||
→ if COLIBRI_CACHE_WARMING_INTERVAL_HOURS > 0
|
||||
→ if now - last_warm_at > interval
|
||||
→ run_cache_probe()
|
||||
→ update last_warm_at
|
||||
|
||||
Daemon shutdown
|
||||
→ no cleanup needed (cache lives on provider side)
|
||||
```
|
||||
|
||||
### 4. Observability
|
||||
|
||||
Cache warming results are:
|
||||
|
||||
- Logged at INFO level on each warm cycle
|
||||
- Exposed in daemon status response: `cache_warming_enabled`, `last_warm_at`,
|
||||
`last_warm_cache_hit`, `last_warm_hit_tokens`
|
||||
- NOT mixed into per-session CacheMetrics (that's for agent API calls)
|
||||
|
||||
### 5. Safety
|
||||
|
||||
- If DeepSeek key is missing or empty, warming is silently skipped
|
||||
- If the probe fails (network, rate limit, balance), it logs a warning
|
||||
and does not retry — the daemon continues normally
|
||||
- Warming failures do not affect daemon startup or agent spawning
|
||||
- On FreeBSD, the key may be in a separate env file — the daemon
|
||||
reads it from the process environment at startup
|
||||
|
||||
### 6. FreeBSD considerations
|
||||
|
||||
- Same code path as Linux — no platform-specific logic
|
||||
- The rc.d service already exports DEEPSEEK_API_KEY via provider.env
|
||||
- OSA validation: check that warming runs on daemon start, produces
|
||||
cache_hit_observed=true, and metrics appear in status
|
||||
|
||||
## Implementation plan
|
||||
|
||||
### Files touched
|
||||
|
||||
| File | Change |
|
||||
| ------------------------------ | ----------------------------------------------------------------------------------------------------- |
|
||||
| `colibri-daemon/src/config.rs` | Add `cache_warming_enabled`, `cache_warming_interval_hours` |
|
||||
| `colibri-daemon/src/daemon.rs` | Add `last_warm_at`, `last_warm_result` to DaemonState; call warm on startup; periodic re-warm in loop |
|
||||
| `colibri-daemon/src/socket.rs` | Expose cache warming fields in cmd_status |
|
||||
| `colibri-deepseek/src/lib.rs` | No changes — reuse existing run_cache_probe() |
|
||||
|
||||
### No changes to
|
||||
|
||||
- `colibri-contracts` — ProviderSmokeResult already has all needed fields
|
||||
- `colibri-store` — no SQLite schema changes (warming is runtime-only)
|
||||
- `colibri-skills`, `colibri-glasspane` — unrelated
|
||||
|
||||
## Test plan
|
||||
|
||||
### Unit tests (Linux, on debby)
|
||||
|
||||
1. `cache_warming_skipped_when_disabled` — config off, no probe runs
|
||||
2. `cache_warming_skipped_when_no_key` — config on but no API key
|
||||
3. `cache_warming_records_last_warm_at` — mock probe result stored
|
||||
4. `cache_warming_periodic_rewarm` — interval triggers re-warm
|
||||
5. `cache_warming_status_includes_metrics` — status response has fields
|
||||
|
||||
### FreeBSD validation (OSA, after merge)
|
||||
|
||||
```sh
|
||||
# Enable warming
|
||||
export COLIBRI_CACHE_WARMING=1
|
||||
export DEEPSEEK_API_KEY=<key>
|
||||
|
||||
# Start daemon, check log
|
||||
cargo run --bin colibri-daemon 2>&1 | grep -i "cache.*warm"
|
||||
|
||||
# Check status via socket
|
||||
echo '{"cmd":"status"}' | nc -U /var/run/colibri/colibri.sock
|
||||
# Verify: cache_warming_enabled=true, last_warm_at is set,
|
||||
# last_warm_cache_hit=true, last_warm_hit_tokens > 0
|
||||
```
|
||||
|
||||
### Acceptance criteria
|
||||
|
||||
- [ ] Warming runs exactly once on startup when enabled + key present
|
||||
- [ ] Warming is skipped when disabled or key missing
|
||||
- [ ] Periodic re-warming fires after interval (if configured)
|
||||
- [ ] Cache hit observed on OSA FreeBSD (real DeepSeek API call)
|
||||
- [ ] Status response includes warming metrics
|
||||
- [ ] Daemon starts normally even if warming fails
|
||||
- [ ] No workspace test regressions
|
||||
|
||||
## Rollout
|
||||
|
||||
1. Hermes implements + tests on Linux (debby), opens PR
|
||||
2. Hermes merges via API after Linux validation
|
||||
3. Codex validates on OSA FreeBSD with real DeepSeek key
|
||||
4. ISO image includes `COLIBRI_CACHE_WARMING=0` default in rc.conf.sample
|
||||
5. Operator enables on FreeBSD after verifying cache hit on their account
|
||||
Loading…
Add table
Reference in a new issue