From d75c64672ea9b26c9d74d306c7e6377f6f800248 Mon Sep 17 00:00:00 2001 From: "K. Isom" Date: Mon, 28 Sep 2026 15:58:53 -0700 Subject: [PATCH] M5c-2 plan: outline for the owner's review Co-Authored-By: Claude Opus 5.5 (1M context) --- docs/plans/M5c2/README.md | 105 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 docs/plans/M5c2/README.md diff --git a/docs/plans/M5c2/README.md b/docs/plans/M5c2/README.md new file mode 100644 index 0000000..8a9bbff --- /dev/null +++ b/docs/plans/M5c2/README.md @@ -0,0 +1,105 @@ +# M5c-2 implementation plan: Honcho, the read path + +> For the implementer: each task file is one closed task for one fresh session. Read `AGENTS.md`, +> then the task file, and do exactly that task. The driver is `tools/run-plan.sh`. + +**Goal:** the agent reads what the fleet knows. `recall` searches the other agents' trusted +workspaces and the fleet workspace alongside the local index, each source on its own limit, and +a new core tool, `ask_memory`, asks Honcho's dialectic about one or two workspaces. What comes back +is labelled, and taints the session, as a local `recall` hit does. + +**Architecture:** `bxcore` gains `ask_memory`'s arguments; `brokerd` runs it as a built-in memory +tool with its own wait; `loopd` declares it as a core tool with its own wait; `memoryd` gains +read-only Honcho clients, turns Honcho's messages and conclusions into `recall` items, runs its +Honcho sources and chats outside its state lock, and answers `ask_memory`. + +**Tech stack:** Rust 1.98.1, edition 2024; `roncho` 1.0.0 (already a dependency of `memoryd`, +`features = ["tls"]`); no new crate. + +**Spec:** `docs/specs/2026-09-27-m5c-honcho.md`, sections 3, 8, 9, 10 and 13, as amended on +2026-09-28 (`8e56261`). + +## The owner's decisions (2026-09-28) + +1. **Queries from any session.** `recall` searches Honcho, and `ask_memory` asks it, from a + session of any class, `secret` included: Honcho stores no query, and on rift a query reaches + only the owner's hosts. It is an assumption about rift's configuration, written into the spec + (section 8) and `docs/egress.md`. A query holding a known-prefix secret is refused before + anything is sent. +2. **Two workspaces per `ask_memory` call**, both asked at once, so both answer inside + `brokerd`'s wait; the model asks again for more. +3. **New recordings from rift** for the fake server (task 00), in a throwaway workspace deleted + afterwards, as in M5c-1. + +## What the code already has, and what it lacks + +- A session keeps the tools array it was created with (`loopd`'s baseline is saved at the start + and sent on every request): `ask_memory` appears in sessions started after deployment, and no + epoch code is needed. +- `brokerd` waits 30 s for any memory tool (`memory_port.rs`, `MEMORY_WAIT`), and `loopd` 120 s for + any tool (`[broker] timeout_ms`). Neither has a per-tool wait; `ask_memory` needs 170 s and 180 s + (spec 9). +- `memoryd` holds its one state lock for the whole of a `recall`. Honcho searches (5 s) and chats + (150 s) must run outside it, or every `memory` call waits behind them. +- M5c-1's `Clients` are the sync worker's, for writes, and move into its thread. Reading needs + its own clients: one per `[[honcho.read]]` workspace, the fleet, and the agent's own two (for + `ask_memory`). +- `roncho`'s blocking client has what is needed: `search_workspace`, `query_conclusions` (it + requires the observer and the observed) and `workspace_chat`. + +## Global constraints + +- Roles depend on `bxcore` only; `memoryd` also on `roncho`. No `unsafe`, no async runtime. +- Every `roncho` client is built with `.without_config_file()`; keys come from + `bxcore::secrets` and are never logged; errors are logged by kind and status only. +- Text from Honcho is neutralised on arrival and capped like a local `recall` snippet (600 + characters); a result's labels raise the session as a local hit's do. +- No Honcho call runs under `memoryd`'s state lock. +- Without a `[honcho]` section, `recall` is exactly M5b's and `ask_memory` answers that Honcho is + not configured. +- No file the implementer reads holds a chat-template tag whole (T33), nor a fake key whole. +- Every path a given test creates is removed by a guard (T44); every process a test starts has a + deadline. +- Each task gives its baseline and its gate count with what the count includes (T50, T53); the + branch line is a check, never `git switch` (T51); import changes are single added lines (T54); + whitespace-checked literals are marked on every edit (T55); the task's table of `roncho`'s API + is complete, and the Cargo registry is off limits (T56). + +## Tasks (outline, for the owner's review) + +| # | Delivers | Crates | +|---|---|---| +| 00 | (the design model, before the run) recordings from rift: workspace search with a limit, conclusion queries for two peers, chat at `minimal` and `low`, and what a missing workspace answers | — | +| 01 | Wire: `AskMemoryArgs { question, workspaces, reasoning }`, its name and its checks (question at most 2,000 characters; one or two workspace names, no repeats; `minimal` or `low`); fixtures | bxcore | +| 02 | `brokerd`: `ask_memory` as a built-in memory tool (grant, parsing, routing to `memoryd`); a per-tool wait on `memoryd`, 170 s for `ask_memory` and 30 s for the others | brokerd | +| 03 | `loopd`: `ask_memory`'s schema as a core tool in a new registry; a per-tool wait on `brokerd`, 180 s for `ask_memory` and `[broker] timeout_ms` for the others; the system prompt's line on memory tools | loopd | +| 04 | `memoryd`: read clients, one per `[[honcho.read]]` workspace, the fleet and the agent's own two, with a 5 s limit for searches and 150 s for chat | memoryd | +| 05 | `memoryd`, pure: Honcho messages and conclusions as `recall` items (tag, source name, class, neutralised, capped), interleaved with the local hits to `k`, the local index first | memoryd | +| 06 | `memoryd`: `recall`'s Honcho sources, each on its own thread with its own limit, after the local search and outside the lock; `: unavailable`; a query holding a secret sends nothing | memoryd | +| 07 | `memoryd`: `ask_memory`: workspace names checked against `[honcho]`, both chats at once, each answer tagged and capped, labels, `: unavailable`; a question holding a secret sends nothing | memoryd | +| 08 | `memoryd` serves `ask_memory` beside `recall` and `memory`, outside the lock; `bxctl`'s usage and the runbook where a new message needs a pointer | memoryd, bxctl | + +After task 08, the design model runs the M5c-2 device check (spec 13) on straylight, rift and the +owner's Mattermost: a second `memoryd` under its own name writes a fleet note that `recall` finds, +tagged `memory-tainted`, turning the session untrusted; `ask_memory` answers from the agent's own +trusted workspace within its limit; with rift down, `recall` answers from the local index with +`unavailable` lines. The baseline is measured again against the 3,000-token budget +(`make verify-device`). + +## Before hand-over + +Every task is worked through `docs/plans/CHECKLIST.md` with a reference in a scratch worktree +with its own build directory, replayed from its task text; mutations; `/tmp` compared around a +gate run; scratch files in the worktree's `.state/`; the whole workspace stressed under load +(T52); the reference moved to straylight as a bundle before the run. Task files name their log +row (T47). For every class or trust rule, each path that reads from Honcho gets a test at the +forbidden label (T58). + +## Running it + +```sh +git switch -c m5c2 master +OPENCODE_MODEL=straylight/ornith-1.5-35b-a3b RESUME=1 \ + SLOTS_URL='http://straylight:11434/slots?model=ornith-1.5-35b-a3b' \ + tools/run-plan.sh docs/plans/M5c2 01 +```