Skip to content

feat(memory): keep every household list in one format - #195

Merged
arthware-dev merged 17 commits into
feature/rc2from
feat/lists
Oct 12, 2026
Merged

arthware-dev merged 17 commits into
feature/rc2from
feat/lists

Conversation

@arthware-dev

Copy link
Copy Markdown
Contributor

Summary

  • Every household list (groceries, a store, the todos of a topic or a trip) is one file under <bucket>/lists/, with sections in walking order, people, due and done dates in the Obsidian Tasks format, and stack memory list to show and change it; the agent's list_edit tool uses the same commands.
  • Ticked items leave the list the night after into a monthly archive, which also tells list add where a known item was last bought; topic todos.md files move to lists on the next stack up memory, and the old todo commands are gone.
  • The archivist puts a record's action items on its topic's list once, linked back to it, and takes todos only from a note in the writer's own words, so pasted text no longer adds its author's suggestions.

Nine commits that each stand alone, so this is meant for a rebase merge. Wiki rendering of lists (overview page, person pages, schedule) follows in a separate PR.

Refs: #194

arthware-dev and others added 17 commits October 12, 2026 09:45
Groceries, a store, the things to do for a trip: every list becomes
one file, `<bucket>/lists/<slug>.md`, with a title, a description,
the topics it belongs to and its sections in walking order.

Every item is one checkbox line with its fields at the end:

- a relative link to someone in `people/` assigns it, several links
  assign it to several people;
- any other link into the vault names the record it came from;
- `📅` is the day it is due and `✅` the day it was ticked, the fields
  of the Obsidian Tasks plugin.

`stack.lists` reads and writes the format. It adds an item at the end
of its section and creates a missing heading in the order of
`sections`; every other line, including notes the family wrote in
Obsidian or Forgejo, stays as it is. The commands, the archivist and
the wiki move onto it next.

Refs: #194
`stack memory list` works on every list in `<bucket>/lists/`, the same
verbs for groceries, a store or the todos for a trip:

- `show` names every list with its open items counted, or shows one
  list's items under their sections; `--all` adds the ticked ones.
- `create` starts a list with a title, a description, its topics and
  its sections in walking order.
- `add` puts one or more items into a section, with `--for` for the
  people it is assigned to and `--due` for a day.
- `tick`, `untick` and `remove` change items by name; a tick records
  the day.
- `move` takes an item to another list, keeping its people and dates.
- `reset` reopens every ticked item, for a list used again and again.

The caller names the item, never the line, and the rest of the file
stays as it is. A name that fits several items, a section the list
does not have, a person the family never declared or a list that does
not exist is refused with the choices there are. An item bought and
needed again is on the list twice under one name; a tick then means
the open one, an untick the ticked one.

Every change commits to Forgejo as the person given with `--as`, which
is required, and every answer and commit names the list it changed:
`chore(lists): homer ticked off Milch on Einkaufsliste`.

`stack memory write` refuses a rewrite that drops or reopens an item
on these files, as it already does for `todos.md`.

Refs: #194
A topic's todos lived in `<bucket>/<topic>/todos.md`, apart from every
other list and in a format of their own. They become lists:

- The next `stack up memory` moves each `todos.md` to
  `<bucket>/lists/<topic>.md` in one commit, keeping every line and
  tick and turning the old due date into a `📅` field. A topic that
  already has a list gains only the items it is missing.
- The archivist puts the action items of a document or note on its
  topic's list, linked back to the record, and starts the list when
  the topic has none, with a description in the household language
  ("Was für Utility noch zu tun ist"). A record's items go on the list
  once: a refile adds none, so what the family ticked, reworded or
  removed stays as they left it, and when a refile renames the record
  its items link to the new path.
- A record's summary lists its action items without checkboxes: the
  list holds whether they are done, and Obsidian no longer counts the
  record's copy as a second open task.
- Topic pages show the open items of every list that names the topic,
  and the agent's brief names those lists and how to read one.
- `/go/topic/<topic>/todo` links already posted in chat open the
  topic's list; `/go/list/<slug>` opens any list by name.
- `lists` is no longer taken for a topic name.

Refs: #194
The agent's `list_edit` tool now names a list by its slug and runs
`stack memory list`, so it reaches every list, not only a topic's
`todos.md`:

- `add` can put an item in one of the list's sections, assign it to
  family members and give it a due day; `move` takes items to another
  list.
- The skill tells the agent where lists live, to use only a list's own
  sections, to assign people or dates only when someone says so, and to
  retry once with the choices a refusal names.
- A room's greeting mentions what is open on the topic's lists.

Refs: #194
`stack memory list` covers what they did, for every list:

- `stack memory topic <topic> todo` and its `add`, `strike` and
  `unstrike` verbs are gone; `stack memory topic <topic>` still shows
  the topic's overview, and `stack memory topic <topic> todo` says
  where the todos went: `stack memory list show <topic>`.
- `stack memory list-edit <page>` is gone; the agent's tool runs
  `stack memory list`.
- The agent's API no longer needs a rule refusing the topic todo verbs.

Refs: #194
A list should show what is still to do or to buy. A ticked item now
stays on its list for the rest of the day ("did we get eggs?") and
moves to the list's archive on the nightly sweep:

- The archive is one file per list and month,
  `<bucket>/lists/archive/<slug>/<YYYY-MM>.md`, in the same format,
  with each item's section, people and dates kept.
- A tick made by hand in Obsidian or Forgejo, without a date, gets the
  day's date first and leaves the night after.
- A list created with `--recurring` (a packing list, the weekly
  chores) keeps its ticks until `stack memory list reset`.
- Everything moves in one commit by the memory bot, against the
  version of each file it read, so a tick made meanwhile is never lost.

Refs: #194
Saying "we need eggs" should not require naming a store. `stack memory
list add` now takes the list as optional:

- An item the household had before, open on a list or in an archive,
  goes to the list it is open on, otherwise to the one it was last
  ticked on, in the section it had there and spelled as before.
  Items known on different lists go to each, one commit per list.
- `--topic` keeps the choice inside one topic's lists, such as the
  stores of a shopping topic.
- An item no list has had is refused with every list and its
  description, so the caller picks one. A list that is named always
  wins.

The agent's `list_edit` tool may leave the list out when adding and
pass the room's topic instead.

Refs: #194
Asked for "Schrauben vom Baumarkt" with no list for that store, the
agent put the items on the closest-sounding list. `list_edit` now has
a `create` operation with a title, a description of what goes on the
list (`about`), the room's topic and a store's sections, and the skill
tells the agent to start a list when none fits. The `topic` parameter
says plainly that it takes the room's topic, never a list's name.

`stack memory list create` takes the slug as optional and makes it
from the title the way a topic's folder is (`Baumarkt` makes
`baumarkt`), because a family names a list, not a slug.

The test stand-in for nanobot takes the keywords the real schema
builder takes, so a tool parameter that collides with one of them
(`description` did) fails in the unit lane, not on the agent.

Refs: #194
Every note was asked for action items: a typed reminder, a voice
message, but also text copied from somewhere else, whose author's
suggestions ("try this framework") then landed on the family's list.

The archivist now decides before the model is asked. A voice message
counts as the speaker's own words; a typed message counts when it reads
like one: a single paragraph, no link, at most 300 characters. Anything
else yields no todos, and a link, a file, an email or a refile never
does. A long note with a task in it is left to the agent: "put it on
the list".

The prompt for what passes is the one before due dates were added: on
the household's model, asking for a due date as well merged a shopping
list into one item or dropped it, so a deadline stays in the item's
words ("Take out the trash by Friday").

The archivist also shows the model the topic's list from `lists/`
again; it still read the old `todos.md`.

Refs: #194
A list could only be described when it was created. `stack memory list
set <list>` now changes what is given and keeps the rest:

- `--title` and `--description`;
- `--topic`, repeatable, the topics the list belongs to, which is how
  a list joins a topic room after the fact (`--topic ""` for none);
- `--section`, repeatable, the new walking order: the list's sections
  move with their items into that order, and a section it does not
  name goes after them.

The agent's `list_edit` tool has the same operation, so "die
Einkaufsliste gehört in diesen Raum" can be done in chat.

Refs: #194
The agent took a room's topic from its name, but only knew the English
"Topic:" prefix and dropped every non-ASCII letter, so a room called
"Thema: Einkauf" became `thema-einkauf` and matched nothing. It also
needed the topic's wiki page, which a room kept only for lists does not
have.

The agent now derives the topic the way the archivist binds it (both
prefixes, "ä" folded to "a"), held to the archivist's answers by a
test, and knows a topic that has a page or a list naming it. The brief
offers the topic's overview only when there is one.

Refs: #194
"Ich habe den Erlaubniszettel unterschrieben" says nothing about the
Education list the archivist put the item on, and `tick` needed the
list. `tick`, `untick` and `remove` now take it as optional, as `add`
does: without one, each item is looked up on every list.

- An item found on one list is changed there, and the answer names it.
- Items on different lists are each changed on theirs.
- An item open on one list and ticked on another is the one the verb
  would change.
- An item still on several lists is refused with each list and its
  matches, so the caller names the list.

The agent's `list_edit` tool leaves the list out when nobody said
which.

Refs: #194
The agent added groceries by rewriting the list page instead of
calling `list_edit`, which skips what the list commands do: Joghurt
landed on the list twice, coffee under bread, and a following tick
caught only one of the two.

`stack memory write`, whole page or patch, now refuses a change to a
list page that adds or ticks off items and points to `list_edit`.
Writing a list page stays the way to restructure it: rewording an
item, moving it under another heading, renaming a section.

Refs: #194
In a test with the family's phrasing the agent read list files to show
them, so link markup and every old tick reached the chat in a format
that changed from answer to answer; it removed an item the family said
they would buy elsewhere instead of moving it; and with two ticket
items on a list it ticked one without asking.

The skill now shows lists through `stack memory list show`, reads
"ich hole X lieber auf dem Markt" as a move, asks when two items fit,
and names the list and the item when it confirms a change.

Refs: #194
A change whose sentence did not fit a commit subject was recorded as
"marge changed family/lists/einkaufsliste.md". The subject now counts
the items and names the list ("marge ticked off 3 items on
Einkaufsliste"), with the full sentence in the body.

Refs: #194
A list the archivist started for a topic was titled from the topic's
slug, so "Haus & Garten" became "Haus Garten". It now takes the topic's
name as the document was classified with it.

Refs: #194
The user guide named neither lists nor Stacky, so a family member could
not learn from it that lists exist or how to keep them. A "Lists"
section says how to start a list in walking order, add and tick items
by chat without naming the list, move items, put a name and a day on
one, use a recurring list, what letters and notes add, how a list
belongs to a topic room, and what Stacky cannot do yet.

Refs: #194
@arthware-dev
arthware-dev changed the base branch from main to feature/rc2 October 12, 2026 16:05
@arthware-dev
arthware-dev merged commit 93d2873 into feature/rc2 Oct 12, 2026
2 checks 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