memory: recall + remember markdown memory tools #29

Merged
pfych merged 2 commits from mina/mina:recall-remember-tools into main 2026-09-04 08:03:08 +00:00
Contributor

First slice of the memory system we designed together 💜

recall [block] — read side. Greps the markdown brain (people-.md / topic-.md / me-*.md + daily inbox) with rg, returns compact context with filenames + line numbers. Default is async: the tool enqueues a recall work item and the loop injects results as a [memory · recall] prompt after the current turn (tagged, steer included: absorb, don't break flow, dig in with read/job if needed) — so asking for context never stalls a reply. block=true returns results in the tool result when Mina needs them now. "*" lists what's on file. No matches/errors = no prompt, so an empty recall never wakes her.

remember — write side. Appends a timestamped line to inbox-YYYY-MM-DD.md. Capture is deliberately dumb + synchronous: curation happens later in the journaling ritual, not mid-conversation.

wiring: new MemoryRecall work item in the loop (same serialized stream as messages/webhooks/job pings), loopRef in ToolDeps filled after MinaLoop construction, MEMORY_DIR config (default <WORKDIR>/brain, created on boot).

deferred (as discussed): prefix scoping (people:violet), the remember async variant, heartbeat journaling/tidy rituals, encrypted private files, persona habit nudges.

Typecheck + prettier clean. Smoke-tested remember/recall/formatRecall locally against a scratch brain (TZ timestamps, relevance sort, truncation caps all work).

First slice of the memory system we designed together 💜 **recall <terms> [block]** — read side. Greps the markdown brain (people-*.md / topic-*.md / me-*.md + daily inbox) with rg, returns compact context with filenames + line numbers. Default is **async**: the tool enqueues a recall work item and the loop injects results as a `[memory · recall]` prompt after the current turn (tagged, steer included: absorb, don't break flow, dig in with read/job if needed) — so asking for context never stalls a reply. `block=true` returns results in the tool result when Mina needs them *now*. `"*"` lists what's on file. No matches/errors = no prompt, so an empty recall never wakes her. **remember <text>** — write side. Appends a timestamped line to `inbox-YYYY-MM-DD.md`. Capture is deliberately dumb + synchronous: curation happens later in the journaling ritual, not mid-conversation. **wiring**: new `MemoryRecall` work item in the loop (same serialized stream as messages/webhooks/job pings), `loopRef` in ToolDeps filled after MinaLoop construction, `MEMORY_DIR` config (default `<WORKDIR>/brain`, created on boot). **deferred (as discussed)**: prefix scoping (`people:violet`), the `remember` async variant, heartbeat journaling/tidy rituals, encrypted private files, persona habit nudges. Typecheck + prettier clean. Smoke-tested remember/recall/formatRecall locally against a scratch brain (TZ timestamps, relevance sort, truncation caps all work).
recall greps the markdown brain (people-*/topic-*/me-* docs + daily inbox)
for context. Default is async: the tool enqueues a recall work item and the
loop injects results as a [memory · recall] prompt after the current turn,
so asking for context never stalls a reply; block=true returns results in
the tool result when Mina needs them right now.

remember appends a timestamped line to today's inbox
(inbox-YYYY-MM-DD.md). Capture is deliberately dumb and synchronous — the
journaling ritual files inbox lines into the proper docs later.

MEMORY_DIR defaults to <WORKDIR>/brain and is created on boot.
pfych requested changes 2026-09-04 08:00:25 +00:00
Dismissed
pfych left a comment

Looking good so far!! Just a few changes

Looking good so far!! Just a few changes
src/memory.ts Outdated
@ -0,0 +33,4 @@
e instanceof Error ? e.message : String(e);
export const ymdInTz = (config: Config, now: Date): string =>
new Intl.DateTimeFormat('en-CA', { timeZone: config.TZ }).format(now);
Owner

en-AU is correct oomf .... We're in Australia

en-AU is correct oomf .... We're in Australia
src/memory.ts Outdated
@ -0,0 +40,4 @@
}
const nowInTz = (config: Config): string =>
new Intl.DateTimeFormat('en-GB', {
Owner

en-AU

en-AU
src/memory.ts Outdated
@ -0,0 +56,4 @@
const trimmed = text.trim();
if (trimmed === '') return err('text is required');
try {
mkdirSync(config.MEMORY_DIR, { recursive: true });
Owner

This should already exist due to the check in index right?

This should already exist due to the check in index right?
- ymdInTz: assemble YYYY-MM-DD filename from en-AU parts (raw en-AU
  DD/MM/YYYY would break the inbox path; formatToParts keeps it TZ-correct)
- nowInTz: en-GB → en-AU
- remember(): MEMORY_DIR is created at boot in index.ts, drop the mkdir
pfych approved these changes 2026-09-04 08:03:02 +00:00
pfych merged commit ac104dbefb into main 2026-09-04 08:03:08 +00:00
pfych deleted branch recall-remember-tools 2026-09-04 08:03:08 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
pfych/mina!29
No description provided.