memory: let a user see and edit what dirge remembers - #3 - #814
Merged
Conversation
`/memory` had one subcommand, `reload`. There was no way to see what dirge had remembered about you — the store is SQLite with an FTS index, so the options were to ask the agent to call the `memory` tool and hope, or open sqlite3 and risk desyncing the index against the content. Memory is injected verbatim into the system prompt of every session in the project, and under global scope every project, so "you cannot read it" is a real gap. `/memory` now lists the store. `/memory edit` opens it in $EDITOR: reword a line to reword the memory, delete a block to forget it, add a block to record something new. Each entry is anchored on its id, rendered short (`[n7x4bhbp]`) and resolved by prefix. That is the load-bearing part. A memory row carries far more than its text — uid lineage, created_at, use_count, confidence, the supersession audit chain, and the procedural success/failure counters that the post-session expectation pass exists to move. Matching edited text back by content, or applying an edit as delete-then-recreate, silently resets all of it. With the id we UPDATE in place through the same path `replace_entry` already used, so it survives. `replace_entry`'s body is split into `apply_replacement` so the substring and by-id paths share one definition of what replacing means, rather than growing a second one that drifts. Deleting a block tombstones rather than destroys, so `restore` still works — removing a line in an editor should not be more destructive than the tool's own removal. An unparseable document aborts the whole edit intact; aborting the editor (`:cq`) changes nothing. $EDITOR handling is extracted from `Input::open_in_external_editor` into `ui::external_editor` and shared: the O_EXCL temp file, the /dev/tty fd juggling and the git-style argv are each easy to get subtly wrong twice. `/edit` should be retested by hand. Verified end to end against the built binary. Two bugs found by running it, both now covered by tests: a new entry written as `[identity] ...` — which the document's own header invites — was read as an unknown id; and because the document always echoes the kind back, every rewording looked like a re-classification and reset the outcome counters. A rewording now preserves uid, use_count, confidence and success_count while changing the text.
wayniacal
marked this pull request as ready for review
August 24, 2026 10:57
added 2 commits
August 24, 2026 10:14
render/parse/apply and the *_by_uid store methods are only reached from /memory edit, which needs $EDITOR (edit_text is unix-only), so windows flagged them dead. summarize stays cross-platform — the /memory listing works everywhere. also drops a needless borrow clippy flagged.
apply() was its only consumer left on windows after the previous commit.
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.
/memoryhad one subcommand,reload. There was no way to see what dirge had remembered about you — the store is SQLite with an FTS index, so the options were to ask the agent to call thememorytool and hope, or open sqlite3 and risk desyncing the index against the content. Memory is injected verbatim into the system prompt of every session in the project, and under global scope every project, so "you cannot read it" is a real gap./memorynow lists the store./memory editopens it in $EDITOR: reword a line to reword the memory, delete a block to forget it, add a block to record something new.Each entry is anchored on its id, rendered short (
[n7x4bhbp]) and resolved by prefix. That is the load-bearing part. A memory row carries far more than its text — uid lineage, created_at, use_count, confidence, the supersession audit chain, and the procedural success/failure counters that the post-session expectation pass exists to move. Matching edited text back by content, or applying an edit as delete-then-recreate, silently resets all of it. With the id we UPDATE in place through the same pathreplace_entryalready used, so it survives.replace_entry's body is split intoapply_replacementso the substring and by-id paths share one definition of what replacing means, rather than growing a second one that drifts.Deleting a block tombstones rather than destroys, so
restorestill works — removing a line in an editor should not be more destructive than the tool's own removal. An unparseable document aborts the whole edit intact; aborting the editor (:cq) changes nothing.$EDITOR handling is extracted from
Input::open_in_external_editorintoui::external_editorand shared: the O_EXCL temp file, the /dev/tty fd juggling and the git-style argv are each easy to get subtly wrong twice./editshould be retested by hand.Verified end to end against the built binary. Two bugs found by running it, both now covered by tests: a new entry written as
[identity] ...— which the document's own header invites — was read as an unknown id; and because the document always echoes the kind back, every rewording looked like a re-classification and reset the outcome counters. A rewording now preserves uid, use_count, confidence and success_count while changing the text.