Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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 istools/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.95, 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
bxcoreonly;memorydalso onroncho(task 00). Nounsafe, no async runtime. - Every
ronchoclient is built with.without_config_file()(spec 6). - Nothing is logged that holds memory text or a key:
ronchoerrors are logged by kind and status only (spec 6). - Nothing above
privateis written, and never asecretsession'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 |
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.
Two points for the owner
bxctl chat's speaker is a flag,--speaker NAME. The spec says "from its configuration", butbxctlhas none; without the flag abxctl chatturn has no speaker and is not synced, which is the spec's rule for an unknown speaker.- Saved Honcho responses. The fake server in the tests answers from fixtures. Written from
the OpenAPI document alone they could be wrong in the ways the
ronchoreview found (the evidence fields). The design model would record real responses from rift in task 00, in a throwaway workspace (boxmaker-plan-probe) that it deletes afterwards: creating a workspace, peers, a session, messages and conclusions, and deleting a conclusion. This writes to your Honcho; nothing else on rift is touched.
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
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.)