memory: confirm writes before storing them - #2 - #815
Merged
Conversation
wayniacal
marked this pull request as ready for review
August 24, 2026 10:59
Collaborator
|
Thanks, that makes sense. |
dirge decides what is worth remembering on its own. The agent writes mid-session, and after an idle session the background review and memory curator write more. All of it lands in the system prompt of every later session in the project — and under global scope, every project. Nobody approves any of it, a wrong or trivial memory persists silently, and something the human knows matters is never recorded unless the model happened to notice it. `memory.confirm_writes` (default off) puts a human in that loop. An `add` is queued instead of stored; `/memory review` opens the queue in $EDITOR. The file is the desired final state of the batch, not a diff — so reject (delete the block), reword (edit the text) and add (type a new one) are one operation, and recording what the model missed is a first-class action rather than an afterthought. Accepted entries go in through the normal add_entry path, so a memory you typed is indistinguishable from one the model proposed. A queued entry rides on `status = 'pending'`. Every read path already filters `status = 'active'` — the snapshot, `view`, and the FTS join in `search` — so a proposal is inert everywhere with no new filtering and no migration. It also skips hot-tier compaction: a merely proposed memory must not demote an accepted one before anyone agreed to keep it. Only `add` is gated. `replace`/`supersede`/`remove` act on entries a human already accepted, and `supersede` usually fires because the user just corrected the agent. An aborted edit (`:cq`) changes nothing, which is why `edit_text` returns None rather than an empty document — confusing the two would reject the whole queue. An unparseable file aborts the apply intact rather than half-applying. $EDITOR handling is extracted from `Input::open_in_external_editor` into `ui::external_editor` and shared, rather than copied: the O_EXCL temp file, the /dev/tty fd juggling and the git-style argv are all easy to get subtly wrong twice. Verified end to end against the built binary: writes queue as pending; the agent's own `view` and `search` report zero entries; review rewords one entry, rejects another and adds a third, leaving exactly that in the store with an empty queue; an editor exiting non-zero leaves queue and store untouched; and with the gate off writes go straight through as before.
collect/render/parse/apply and PendingEntry/list_pending/clear_pending are only reached from /memory review, which needs $EDITOR, so windows flagged them dead. notify_if_queued and add_pending stay cross-platform: the queue itself is written and counted everywhere. clippy wanted the indent-continuation if collapsed.
yogthos
force-pushed
the
feat/memory-review
branch
from
August 24, 2026 14:40
35b315a to
5ff6e9d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
dirge decides what is worth remembering on its own. The agent writes mid-session, and after an idle session the background review and memory curator write more. All of it lands in the system prompt of every later session in the project — and under global scope, every project. Nobody approves any of it, a wrong or trivial memory persists silently, and something the human knows matters is never recorded unless the model happened to notice it.
memory.confirm_writes(default off) puts a human in that loop. Anaddis queued instead of stored;/memory reviewopens the queue in $EDITOR.The file is the desired final state of the batch, not a diff — so reject (delete the block), reword (edit the text) and add (type a new one) are one operation, and recording what the model missed is a first-class action rather than an afterthought. Accepted entries go in through the normal add_entry path, so a memory you typed is indistinguishable from one the model proposed.
A queued entry rides on
status = 'pending'. Every read path already filtersstatus = 'active'— the snapshot,view, and the FTS join insearch— so a proposal is inert everywhere with no new filtering and no migration. It also skips hot-tier compaction: a merely proposed memory must not demote an accepted one before anyone agreed to keep it.Only
addis gated.replace/supersede/removeact on entries a human already accepted, andsupersedeusually fires because the user just corrected the agent.An aborted edit (
:cq) changes nothing, which is whyedit_textreturns None rather than an empty document — confusing the two would reject the whole queue. An unparseable file aborts the apply intact rather than half-applying.$EDITOR handling is extracted from
Input::open_in_external_editorintoui::external_editorand shared, rather than copied: the O_EXCL temp file, the /dev/tty fd juggling and the git-style argv are all easy to get subtly wrong twice.Verified end to end against the built binary: writes queue as pending; the agent's own
viewandsearchreport zero entries; review rewords one entry, rejects another and adds a third, leaving exactly that in the store with an empty queue; an editor exiting non-zero leaves queue and store untouched; and with the gate off writes go straight through as before.note: this should merge after my previous memory browse does since they both extract ui::external_editor, so it will require a rebase