Skip to content

feat(agent): let Stacky edit the family's lists, and answer what changed - #61

Merged
arthware-dev merged 10 commits into
mainfrom
feat/memory-history
Aug 3, 2026
Merged

feat(agent): let Stacky edit the family's lists, and answer what changed#61
arthware-dev merged 10 commits into
mainfrom
feat/memory-history

Conversation

@arthware-dev

Copy link
Copy Markdown
Contributor

Stacky could read the family's memory and change almost nothing in it, and could not answer any question about when something happened.

Editing a list. Changing a page died in the tool loop instead of saving, so every edit Stacky made was silently lost. It now edits pages for real: narrow changes (apply_patch) touch only the lines they name and are matched against the page as it currently stands, so an edit made from a copy someone else has since changed is refused by name rather than overwriting them. Whole rewrites (write_file) stay for genuine restructures. Every edit answers with what it actually did, and an edit that drops items names every one.

Asking what changed. The vault has always recorded every version and who wrote it, and nothing read it back. stack memory history answers "what's new this week", "who changed Homer's page", "when did this land on the list" - reading git's own fields, never parsing commit messages. Housekeeping by the bots stays out by default.

History worth reading. Every edit used to be recorded as "updated todos.md". A change now names itself: marge ticked off 1: Wetter checken in camping.

Verified on the demo rig with a real model throughout, not only in tests.

A family's Road-Trip list grew from thirteen items to twenty-seven and never
had a single one ticked off. Nothing was malformed; things went quiet. Each
re-post of the list was re-extracted with fresh wording ("Alternative Dachbox"
came back as suchen, recherchieren, pruefen, besorgen), and because dedup
matches on exact text, every variant landed as a new item.

`stack.list_doc` reads a list page and reports what one edit actually did:
ticked off, reopened, added, moved between headings, reworded, and -- the only
category that means something was destroyed -- removed, always named in full.
A count is not checkable by a family member; "8 items became 7" tells nobody
which one went.

Pure: no git, no Matrix, no I/O. It is what the write path will call to turn an
opaque rewrite into a reviewable one, what a CLI verb would call, and what the
curator needs so the classifier stops replacing the family's words with its own.

Also records the findings and plan in docs/design/brain/write-layer.md so the
reasoning behind all of this outlives the session that produced it.
A family kept one list for a camping trip and re-posted the whole thing
whenever something changed, because that was the only way to say "this is the
current state". Thirteen items became twenty-seven, and not one was ever
ticked off.

Nothing was broken in the merge. The classifier simply never saw the list it
was adding to. Reading each post blind, it re-worded the items every pass --
"Alternative Dachbox" came back as suchen, then recherchieren, then pruefen,
then besorgen -- and because the merge matches on exact text, every variant
landed as a new entry.

So show it the list. A note captured into a topic room now carries that
topic's current todos into the classify prompt, framed as already recorded,
with the point spelled out: an item is not new because it is phrased
differently, and marking something finished is not this field's job.

Verified on the rig against the real list: posting it, posting it again, and
posting it a third time with "-> CHECK" markers all leave the list at fourteen
items. Before this, the third one added "Fenstertasche pruefen" -- the model
understood the marker and had nowhere to put it.
…nged

Reading the vault is fs-shaped: read_file on a path, and it works because
every model is trained on it. Writing had no counterpart, so it grew domain
verbs instead, and a model that can describe the right list perfectly still
cannot perform twenty string-matched calls in a row to produce it.

`stack memory write <path> --by <person>` is the counterpart. One page in, one
page out, attributed. What comes back is not "ok": for a list page it names
what the edit did, and always names in full anything it removed.

  $ stack memory write family/camping/todos.md --by marge
    Wrote family/camping/todos.md (by marge)
      ticked off 2: Heringe mitbringen, Kochloeffel mitbringen

  $ stack memory write family/camping/todos.md --by bart
    Wrote family/camping/todos.md (by bart)
      REMOVED 1: Campingstuehle mitbringen

That report is also the reason a primitive write is safe to hand to a model:
a rewrite that quietly loses six items stops being quiet. Content arrives via
the agent's own data directory rather than argv, because a markdown document
does not survive shlex.
Stacky could read the family's vault and change nothing in it. Changing a list
meant one CLI call per item, matched by substring. Asked to tidy one, it
produced the correct final document in chat, grouped and split exactly as
asked, then failed to perform the twenty calls that would have made it real,
and said it had.

So `write_file` on a vault page now routes to `stack memory write`. Stacky
reads the page, rewrites it whole, and reads back what actually changed
("ticked off 2: ...", or "REMOVED 1: ..."). Ticking off is `- [x]`, splitting a
list in two is a heading. Ordinary markdown, which is what these models are
good at.

`edit_file` on a vault page is refused with instructions rather than
translated: a family list is fifteen lines, whole-document reasoning is the
point, and patching a read-only mount would be the same write with extra ways
to be wrong.

SKILL.md changes with it, or it would keep teaching the verbs this replaces.
It now carries the rules that matter: write the page back in full, keep the
family's words, tick off rather than delete, relay what the write reports, and
never claim a change without having read that report.
Rewriting a page died in the tool loop instead of saving. Every edit the
agent made to a family list was lost, and it had no way to tell.

Editing a page through apply_patch now points at the way that works
rather than failing against a read-only mount.
Asked to reorganise a list, it would strike two unrelated items and
describe a change it never made. It now edits the page instead, and says
so when it cannot.
Changing a list meant replacing the whole page, so an edit made from a
copy that was a few seconds old quietly undid whatever someone else had
just added. Narrow changes now touch only the lines they name, and if
the list moved on in the meantime Stacky is told which line no longer
fits instead of overwriting the change.
Every edit was recorded as "updated todos.md", whoever made it and
whatever it changed, so scrolling the history answered nothing. A change
now names itself: "marge ticked off 1: Wetter checken in camping". Pages
that are not lists say how much text moved, and an edit that lost items
still names every one of them.
The vault has always recorded every version and who wrote it, and nothing
read it back. Now "what's new this week", "who changed Homer's page" and
"when did this land on the list" are one question each, for the family
and for Stacky.
Asked that, Stacky searched four times and guessed from whatever his page
says now. Questions about change have their own answer: what was added,
by whom, when. Housekeeping by the bots stays out of it, so the answer is
what the family did.
@arthware-dev
arthware-dev marked this pull request as ready for review August 3, 2026 18:55
@arthware-dev
arthware-dev merged commit d9ffa76 into main Aug 3, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant