memoryd (files, the check, edits, journal, index, recall, serving), the memory tools and built-in grants in brokerd, the memory block in loopd, bxctl reindex and memory, and the device checks with memoryd. Each task was built as a reference and gated. Each was replayed on its own at its end state (854 to 936 tests) and mutation-checked. Each skeleton compiles and fails its tests. Every todo comment was read beside its signature. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
83 lines
5.4 KiB
Markdown
83 lines
5.4 KiB
Markdown
# M5a implementation plan: local memory
|
|
|
|
> **For the implementing model:** do not work from this file. The owner gives you one task file at
|
|
> a time (`01-…` to `15-…`). This file is the index for the owner and the reviewer.
|
|
|
|
**Goal:** a new role, `memoryd`, owns the agent's memory: identity (`soul.md`, `memory.md`,
|
|
`user.md`, in every new session's prompt) and experience (`notes.md` and the session logs, found
|
|
with `recall`). The agent writes memory with a `memory` tool without asking; a session that has
|
|
read untrusted content can only take notes. `brokerd` decides both tools under built-in grants and
|
|
hands them to `memoryd`; `loopd` takes the memory block from `memoryd` for each new session.
|
|
|
|
**Architecture:** `brokerd`'s two largest files are split first (01). `proto` gains the tools'
|
|
arguments and eight message kinds (02). `memoryd` is built bottom up: its crate, configuration and
|
|
sockets (03), entries and the check (04), the files and the block (05), notes and the edits (06),
|
|
the journal, undo and review (07), the index (08), `recall` (09), and serving (10). `brokerd`
|
|
gains the two tools and their built-in grants (11), then sends decided memory calls to `memoryd`
|
|
with the session's state, keeping the stricter label (12). `loopd` takes the block and declares
|
|
the two core tools (13); `bxctl` gains `reindex` and `memory` (14). Last, the starter `soul.md`
|
|
and the device checks with `memoryd` running (15).
|
|
|
|
**Spec:** `docs/specs/2026-09-24-m5a-local-memory.md` (approved; P17 to P21 applied to the brief).
|
|
Runbook: task 03 adds `memoryd-start-failed`, task 12 `memoryd-unreachable`, task 13 replaces
|
|
`core-memory-unreadable` with `memory-unavailable` and adds `memory-index-damaged`.
|
|
|
|
**New dependency:** `rusqlite` 0.40.2 with `bundled` (task 03; `deny.toml` gains Zlib for
|
|
`foldhash`). Nothing else.
|
|
|
|
## Global constraints
|
|
|
|
- Everything in `AGENTS.md`, including "Lessons from earlier reviews".
|
|
- Branch `m5a`. One task, one fresh OpenCode session, one commit. Run `cargo fmt --all` before the
|
|
gate. Review happens once, after task 15.
|
|
- **New files** come as skeletons: types, constants and the glue written, `todo!()` bodies with the
|
|
code to write in the comment above. **Existing files** are changed by the exact edits in the
|
|
task, never replaced whole.
|
|
- Some tasks hand over **new versions of given test files**, because the change is in what the
|
|
test must see. Copy them over the old ones as the task says; they are still not to be edited.
|
|
- Only task 15 needs straylight (`make verify-device`). Everything else runs offline against
|
|
temporary directories and fakes.
|
|
|
|
## Tasks
|
|
|
|
Every task had a reference implementation, built in this order from master with the gate at every
|
|
step and replayed on its own (tip T26), its given tests run against it, and mutations of it caught
|
|
by them (tip T28); then the reference was moved off this machine (tip T18). Every skeleton was
|
|
checked to compile at its task's end state and to fail its tests, and every comment above a
|
|
`todo!()` was read beside its signature (tip T29). The three largest functions were split before
|
|
the skeletons were cut (tip T25).
|
|
|
|
| # | File | Delivers | Tests | Check |
|
|
|---|---|---|---|---|
|
|
| 01 | `01-brokerd-split.md` | `policy/` and `ledger/` as modules; no behaviour change | the existing ones | reference |
|
|
| 02 | `02-proto-memory.md` | the tools' arguments, eight message kinds | `memory_args.rs`, `memory_wire.rs`, 8 fixtures | reference; 5 mutations caught |
|
|
| 03 | `03-memoryd-crate.md` | the crate, configuration, `listen`, `rusqlite` | `config.rs`, `socket.rs` | reference; `cargo deny` |
|
|
| 04 | `04-memoryd-entries-check.md` | entries, the check | `entries.rs`, `check.rs` | reference; 8 mutations caught |
|
|
| 05 | `05-memoryd-files.md` | the files, the block | `files.rs` | reference; 6 mutations caught |
|
|
| 06 | `06-memoryd-edits.md` | notes, the five actions, routing by trust | `edit.rs`, `notes.rs` | reference; 11 mutations caught |
|
|
| 07 | `07-memoryd-journal.md` | the journal, undo, review | `journal.rs` | reference; 5 mutations caught |
|
|
| 08 | `08-memoryd-index.md` | the FTS5 index, labels, catch-up, rebuild | `index.rs`, `support/logs.rs` | reference; 8 mutations caught |
|
|
| 09 | `09-memoryd-recall.md` | `recall`, source tags, the recall log | `recall.rs` | reference; 8 mutations caught |
|
|
| 10 | `10-memoryd-serve.md` | the three sockets; `memoryd serve` | `serve.rs` | reference; 10 mutations caught |
|
|
| 11 | `11-brokerd-memory-tools.md` | the two tools, built-in grants | `memory_tools.rs`; `grants.rs` updated | reference; 6 mutations caught |
|
|
| 12 | `12-brokerd-memory-port.md` | calls to `memoryd`, stricter labels | `memory_port.rs`; `rig.rs` updated | reference; 8 mutations caught |
|
|
| 13 | `13-loopd-memory.md` | the block, the core tools, `session_updated` | `memory.rs`; `baseline.rs`, `pointers.rs`, `channel.rs` updated | reference; 6 mutations caught |
|
|
| 14 | `14-bxctl-memory.md` | `bxctl reindex`, `bxctl memory` | `cli_memory.rs` | reference; 5 mutations caught |
|
|
| 15 | `15-soul-and-device.md` | the starter soul; device checks with `memoryd` | `device.rs` updated, `support/memoryd.rs` | reference; `make verify-device` on straylight |
|
|
|
|
At the end of task 15: 936 tests (854 before task 01). Each task's count was checked by running
|
|
the gate at its end state on its own.
|
|
|
|
## Changes during the run
|
|
|
|
None yet.
|
|
|
|
## Running it
|
|
|
|
```sh
|
|
git switch m5a
|
|
BOXMAKER_MODEL=straylight/ornith-1.5-35b-a3b tools/run-plan.sh docs/plans/M5a
|
|
```
|
|
|
|
Keep the OpenCode TUI closed while it runs.
|