Memory

July 26, 2026 ยท View on GitHub

Memory is the part that compounds. Most agents forget you the moment the context window fills โ€” 131k tokens goes fast. Iva files everything into a plain-markdown vault, reorganizes it while you sleep, and pulls back only what each question needs. You talk, it files.

Iva's memory tree: daily transcripts as leaves, rolled-up summaries as branches, CORE.md and typed cards as the trunk

The memory tree

Iva means willow, and the memory is shaped like one:

LayerWhat lives therePath
๐Ÿƒ Leavesthe word-for-word transcript of each day, Iva's replies includeddaily/YYYY-MM-DD.md
๐ŸŒฟ Branchessummaries folded upward: day โ†’ week โ†’ month โ†’ yearsummaries/daily/, weekly/, monthly/, yearly/
๐Ÿชต TrunkCORE.md (โ‰ค1200 chars, in every prompt) + typed cards: contacts, projects, decisions, ideas, notesCORE.md, cards/

CORE.md rides in every system prompt; everything else comes in per question through ranked search. A weekly summary costs about 1/35th of its seven raw days, so recall stays cheap as the vault grows.

Nightly rollup

One script, four timers, server-local time. scripts/memory/rollup.ts drives the running agent through eve/client:

TimerWhenReadsWrites
daily04:00yesterday's raw transcriptcards, daily summary, CORE.md
weeklySun 04:157 daily summariesweekly summary
monthly1st, 04:20the month's weekliesmonthly summary
yearlyJan 1, 04:25the year's monthliesyearly summary

Daily and weekly runs post a report to Telegram; monthly and yearly run silent.

The daily pass extracts entities through write_card โ€” a tool whose type and status enums come from the vault's schema.json, so the model cannot invent card types. Every fact gets one operation:

  • โž• ADD โ€” a new card, or a new line on an existing one.
  • ๐Ÿ” SUPERSEDE โ€” the card is rewritten to the new truth; the old value moves to an append-only ## History as a dated line (- 2026-03โ†’06: TDI Group).
  • โญ๏ธ NOOP โ€” already known, nothing written.

Facts carry a confidence: tag โ€” EXTRACTED (you said it) or INFERRED (Iva deduced it) โ€” so later answers assert the first and hedge the second. Decisions are the payoff: a decision card holds what you chose, when and why, and its History records every reversal with dates. You always see what is true now, plus the trail of how it got there.

The same pass resolves conflicts flagged in .graph/supersede-candidates.json and rewrites CORE.md: durable facts, standing preferences, at most 3 active goals โ€” plus dated behavioral lessons from exchanges you corrected, so a mistake made twice doesn't become a habit.

memory_search runs on Node 24's built-in node:sqlite: BM25 over an FTS5 full-text index. Zero external dependencies โ€” no vector database, no search server, nothing extra on a $5 VPS. Hits are reranked by link distance in .graph/vault-graph.json โ€” cards that reference each other surface together โ€” and weighted by IDF coverage, so ranking stays language-agnostic: Russian, Uzbek and English all work.

For fuzzy or cross-language semantics, switch on hybrid mode (MEMORY_SEARCH_MODE=hybrid plus one embedding key โ€” every variable in configuration.md). Dense results are fused with BM25 via reciprocal rank fusion; the nightly doctor rebuilds the embedding sidecar.

Doctor

At 05:00 scripts/memory/doctor.ts runs mechanical maintenance โ€” no LLM, all deterministic โ€” executing the autograph scripts from scripts/autograph/ via uv:

  1. enforce โ€” schema backstop: coerces type aliases, fixes invalid statuses, backfills system fields on cards written outside write_card
  2. graph.health โ€” rebuilds the link graph, appends a 0โ€“100 health score to history
  3. decay โ€” updates relevance tiers so stale cards sink
  4. moc.generate โ€” regenerates the MOC topic indexes
  5. supersede, dedup, link_cleanup โ€” dry-run scans; findings queue for the next rollup, never auto-applied

Then it commits and pushes the vault. No remote yet? It creates a private iva-vault GitHub repo through gh. It pings you on Telegram only when a human is needed: a failed maintenance step, a health-score drop, CORE.md past its 1200-char cap, or a failed push (including when there's no remote and gh isn't logged in).

Vault layout

The vault is initialized from vault-template/ as its own private git repo, separate from the Iva checkout:

vault/
โ”œโ”€โ”€ CORE.md          # always-on core
โ”œโ”€โ”€ MOC.md           # topic index, regenerated nightly
โ”œโ”€โ”€ cards/           # contacts/ projects/ decisions/ ideas/ notes/
โ”œโ”€โ”€ daily/           # raw transcripts, one per day
โ”œโ”€โ”€ summaries/daily/ # day summaries
โ”œโ”€โ”€ weekly/ monthly/ yearly/
โ”œโ”€โ”€ attachments/     # originals, by date
โ”œโ”€โ”€ schema.json      # the vault schema โ€” types, domains, decay
โ””โ”€โ”€ .graph/          # machine-owned graph + scan results

The vault is pure data: the maintenance code and the processing prompts live in the Iva repo (scripts/autograph/, scripts/memory/instructions/), so an update ships them to every install at once. Vaults created before 0.3.3 also carry a legacy .claude/ folder โ€” dead weight, no longer read, safe to keep or delete.

Everything is plain markdown. Cards, summaries and CORE.md are safe to edit by hand โ€” enforce re-canonicalizes the frontmatter the next night. Leave MOC.md and .graph/ alone (both are regenerated) and treat daily/ as an append-only log. To browse, open the vault folder in Obsidian: wikilinks, backlinks and the graph view work as-is.

Background & prior art

Memory is the part I've worked on longest: first agent-second-brain, a Telegram-to-Obsidian pipeline; then autograph, the typed-graph schema engine Iva now ships and runs over the vault; Iva gathers both. The core idea โ€” keep the verbatim record, compress upward, never lose the trail โ€” follows the LCM: Lossless Context Management paper (Ehrlich & Blackman, 2026), with the card graph, SUPERSEDE semantics and doctor loop on top.