The owner's hosts (titan, talos) run 1.98.1; nixos-26.05's Rust is 1.95.0, so builds and lints differed by host. The flake gains a second input, oxalica's rust-overlay (following our nixpkgs, so host configs can still follow theirs), and both the package build and the dev shell use its stable 1.98.1 with clippy and rustfmt. The workspace's rust-version rises to 1.98 to match; AGENTS.md, docs/dependencies.md and the M5c-1 plan follow. Checked on straylight: nix build gives all seven binaries; the dev shell has rustc, cargo and clippy 1.98.1, rustfmt 1.9.0, cargo-deny 0.19.6; make gate in it passes with 1122 tests, as on titan. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
88 lines
5.6 KiB
Markdown
88 lines
5.6 KiB
Markdown
# M5c-1 implementation plan: Honcho, the write 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:** finished turns and memory writes reach Honcho: turns to the agent's trusted or untrusted
|
|
workspace by the session's state at the turn's end (never a `secret` session's), trusted memory
|
|
writes mirrored as conclusions at once, untrusted notes to the fleet workspace as messages, all
|
|
through an append-only ledger that is also the outbox.
|
|
|
|
**Architecture:** `bxcore` gains the speaker on a turn, the turn number on `SessionUpdated`, and a
|
|
session-state question; `loopd`, `gatewayd` and `bxctl chat` carry the speaker; `brokerd` answers
|
|
the question on a new socket; `memoryd` gains a `honcho` module (configuration, ledger, decision,
|
|
`roncho` clients, a sync worker, mirrored memory writes) and `bxctl memory sync` shows its state.
|
|
|
|
**Tech stack:** Rust 1.98, edition 2024; `roncho` 1.0.0 (`default-features = false, features =
|
|
["blocking"]`), added by the design model in task 00; no other new crate.
|
|
|
|
**Spec:** `docs/specs/2026-09-27-m5c-honcho.md` (approved 2026-09-27), sections 3 to 7 and 10 to
|
|
13. The read path (`recall` over the fleet, `ask_memory`) is M5c-2, a later plan.
|
|
|
|
## Global constraints
|
|
|
|
- Roles depend on `bxcore` only; `memoryd` also on `roncho` (task 00). No `unsafe`, no async
|
|
runtime.
|
|
- Every `roncho` client is built with `.without_config_file()` (spec 6).
|
|
- Nothing is logged that holds memory text or a key: `roncho` errors are logged by kind and
|
|
status only (spec 6).
|
|
- Nothing above `private` is written, and never a `secret` session's turn (spec 3).
|
|
- No file the implementer reads holds a chat-template tag whole (T33); no fake key whole.
|
|
- Every path a given test creates is removed by a guard (T44); every process a test starts has a
|
|
deadline.
|
|
- Every fail-closed state has a runbook entry, added by the task that adds its pointer (T49's
|
|
lesson from M5b: the gate needs the entry with the pointer).
|
|
- Commit trailer from the driver; gate with a 600000 ms timeout.
|
|
|
|
## Tasks (outline, for the owner's review)
|
|
|
|
| # | Delivers | Crates |
|
|
|---|---|---|
|
|
| 00 | (the design model, before the run) `roncho` added: workspace dependency, `docs/dependencies.md`, `docs/egress.md` (rift), `cargo deny`, the Nix build on straylight; saved Honcho responses for the fake server (below) | all |
|
|
| 01 | Wire: `Turn.speaker`, `LogRecord::User.speaker` (optional, absent in old logs), `SessionUpdated.turn`, `SessionState` → `SessionStateReply`; fixtures | bxcore |
|
|
| 02 | `loopd` logs the speaker on the `User` record and sends the turn number in `SessionUpdated` | loopd |
|
|
| 03 | `gatewayd` sets the speaker: the Mattermost username when every post of the burst is from one person, else none | gatewayd |
|
|
| 04 | `bxctl chat --speaker NAME`, opt-in, no default | bxctl |
|
|
| 05 | `brokerd` serves `run/memory-broker/state.sock` from its state store; runbook `broker-state-unavailable` | brokerd |
|
|
| 06 | `memoryd`'s `[honcho]` section and its keys, checked at start; runbook `honcho-config-invalid` | memoryd |
|
|
| 07 | The ledger, `memory/honcho.jsonl`: its records, append, read-through, and the outbox | memoryd |
|
|
| 08 | The decision for a turn (a pure function: state, labels, speaker, text) | memoryd |
|
|
| 09 | On `SessionUpdated`: ask `brokerd`, read the labels, decide, record; undecided turns retried | memoryd |
|
|
| 10 | `roncho` clients per workspace, and creating workspaces, peers and sessions (names, the agent unobserved, the fleet with reasoning, summaries and dreaming off, the `-2` sessions); the fake Honcho server | memoryd |
|
|
| 11 | The sync worker for turns: messages in parts of 25,000, neutralised; backoff; outage logged once; refused sends and keys; runbooks `honcho-unreachable`, `honcho-send-refused`, `honcho-key-refused` | memoryd |
|
|
| 12 | Memory writes mirrored: each journalled edit decided by spec 4's table (conclusions, fleet messages, retractions, undo) | memoryd |
|
|
| 13 | The sync worker for memory writes: conclusions created and deleted, fleet messages | memoryd |
|
|
| 14 | `bxctl memory sync`: decided, sent, waiting, failed | memoryd, bxctl |
|
|
|
|
After task 14, the design model runs the M5c-1 device check (spec 13) on straylight, rift and the
|
|
owner's Mattermost.
|
|
|
|
## The owner's answers (2026-09-27)
|
|
|
|
1. **`bxctl chat`'s speaker is opt-in: `--speaker NAME`, with no default.** Console turns are
|
|
mostly tests, and Honcho can neither forget them nor be shared without them; a `bxctl chat` turn
|
|
without the flag has no speaker and is not synced (spec 4). Task 04.
|
|
2. **Saved Honcho responses** for the fake server: the design model records real responses from
|
|
rift in task 00, in a throwaway workspace, `boxmaker-plan-probe`, that it creates and deletes.
|
|
It touches no other workspace on rift, in any way (not even a read): rift has no keys yet, so
|
|
the rule is ours to keep.
|
|
|
|
## 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 reference moved to straylight as a bundle
|
|
before the run. Task files name their log row (T47); a scanner-like function gets a golden file
|
|
(T46); a request through another role is counted against its limits (T49).
|
|
|
|
## Running it
|
|
|
|
```sh
|
|
git switch -c m5c1 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/M5c1 01
|
|
```
|
|
|
|
(Or titan's Ornith, `titan/…` and `http://127.0.0.1:8081/…`, once its GPU is free.)
|