Skip to content

deliberate and background writes

nate
Jul 9, 20263 min read1 read

deliberate and background writes

ong-term agent memory gets written two ways, and mature systems end up with both. evidence throughout from three systems: letta, the memgpt-lineage agent-memory runtime; phi, a bluesky agent; and the slack bot that lives in the examples of marvin, an llm toolkit.

  • deliberate: the agent calls a tool — letta's replace-core-memory, phi's save_memory, the marvin slack bot's store_facts_about_user. legible in the transcript, but only fires when the model thinks of it.
  • background: a pipeline writes without being asked — letta's asynchronous episodic memory, phi's extraction → reconciliation pass and its end-of-run residue synthesis. catches what the agent wouldn't have saved, at the cost of a second system to keep honest.

phi and letta arrived at this same split independently, which is decent evidence the split is real rather than one vendor's framing.

keeping background writes clean

a background pipeline that only appends will rot. phi's write path (two haiku-class calls per batch):

  1. an extractor proposes facts about the user from recent conversation. it never sees existing memory, so a bad stored fact can't steer new extraction.
  2. each proposal is embedded and matched against the 3 most similar stored observations; a reconciler returns ADD / UPDATE / DELETE / NOOP.
  3. updates supersede in place: old row marked status: superseded with a back-link, reads filter to active rows, history stays queryable. an UPDATE unions the old row's source references (a refinement keeps its evidence); a DELETE-and-replace starts fresh (a correction shouldn't inherit the evidence of the claim it overturns).

what reaches the prompt carries its pedigree: llm summaries inject as "trust: low", extracted observations as "trust: medium (N sources, age)", verbatim transcripts as "trust: high".

adopting a background runtime is a reliability decision

the marvin slack bot spent one day (2025-12-09) on letta's agentic-learning SDK: adopted at 13:32, committed to by 15:15 ("remove home-rolled TurboPuffer-based user facts system... automatically extracts and injects memories without needing explicit tool calls"), reverted at 23:20 when the SDK's async context manager awaited tasks in __aexit__ after the event loop closed, crashing the bot. read narrowly — an SDK lifecycle bug, no information about the memory model. the durable lesson is about integration surface: background memory that wraps your request path makes its bugs your outages, so it has to clear a higher reliability bar than a store you call explicitly. phi keeps its background passes outside the request path for the same reason: each prompt block returns empty on error, and a dead memory store means a thinner prompt instead of a crash.

sources

  • botsrc/bot/memory/, src/bot/core/residue.py, docs/memory.md
  • marvin — commits 30aed2de, 36da4c1a, 47da4ce6, a593d2b3 (the letta day); examples/slackbot/src/slackbot/assets.py
  • letta — the memgpt lineage; two-memory-type framing via cameron.stream

Did you enjoy this article?

Recommend it — Standard Reader surfaces well-loved writing to more readers across the network.

Across the AtmosphereDiscussions