| title | Memory |
|---|---|
| description | How an agent remembers across events — four categories, four tools, when to use each. |
Memory is what an agent learned from prior events that lets it behave like a teammate who's been here before, instead of one that showed up this morning. An agent writes facts via memory_store and reads them back via memory_recall on the next event.
Memory is always on — no setup, no flag.
| Category | Scope | Lifetime | Use for |
|---|---|---|---|
core |
agent | durable; evicted last at the entry cap | Learned facts about durable entities — customers, accounts, preferences. |
daily |
agent | 72h auto-prune | Time-bounded follow-ups, open tickets, scheduled reminders. |
conversation |
event | dies with the run | Within-run scratch — checkpoint findings during a long incident. |
workspace |
workspace | durable | Facts shared across every agent in the workspace. |
Pick core for "would I want a future event to know this?" Pick daily for "this should expire on its own." Pick conversation only for staging during a long run. Pick workspace only when multiple agents need the same fact.
The agent calls these from inside a run; the runtime wires them to the memory backend.
| Tool | Shape | Purpose |
|---|---|---|
memory_store(key, category, content, tags?) |
upsert | Write a distilled fact. |
memory_recall(key) |
one entry or empty | Exact lookup by key. |
memory_list(filter) |
matching entries | Filter by category / tags / recency. |
memory_forget(key) |
delete | Remove or correct a fact. |
There is no vector search. Pre-filter with tags + categories + recency, then let the model reason over the candidate set.
The two memory touchpoints are at the start of a run (memory_recall before deciding) and at the end (memory_store after deciding what was learned). Anything writing to memory in the middle is probably scratch — that belongs in conversation.
flowchart LR
Start([run opens]) --> Recall["memory_recall<br/>pull prior context"]
Recall --> Reason[agent reasons + acts]
Reason --> Store["memory_store<br/>write what was learned"]
Store --> End([run closes])
Hydration (what an agent sees at run start) and eviction (what the platform deletes at the per-agent entry cap) are both category-pinned: core wins.
- Hydration fills a fixed byte budget: every
coreentry that fits loads first (newest first), then the newest non-core entries fill the remainder. Acorefact written once — an owner, a deploy target, a customer's plan — is still in context at entry 1001, even after a noisy month ofdailywrites. - Eviction at the entry cap deletes the coldest non-core entries first. A
coreentry is deleted only when nothing else remains. - Custom categories (and anything the platform doesn't recognise) are windowed by recency — never silently pinned.
Selection is deterministic — same entries, same budget, same result — so "why does my agent remember X but not Y?" always has a checkable answer: X was core; Y was windowed, or too big for the budget.
Four habits make selection work for you instead of against you:
- Store load-bearing facts as
core. If a future event must know it, it'score. Everything windowed ages out of hydration. - Reuse stable keys. Re-storing a key refreshes the entry instead of duplicating it —
deploy_target, notdeploy_target_jun12. - Forget what's stale.
memory_forgetbeats letting eviction pick the victim. Hoarding everything ascoredefeats the pinning: an all-coreset over the cap evicts your coldestcorefacts. - Keep entries small. The hydration budget is bytes, not entries — snapshot conclusions, not transcripts.
Memory is stored in Postgres but exports as markdown for human review.
---
key: customer_bob_chen_acme
category: core
tags: [customer, plan_pro]
---
Bob Chen, Acme. Pro since Jan 15. API user (not dashboard), webhooks → Slack.
Prefers technical responses. Prior: Feb 3 signature issue (NTP).Frontmatter is structured metadata; the body is the distilled prose the agent wrote.
To remove or fix a fact, the agent itself calls memory_forget(key) followed by memory_store(...) with the corrected entry — typically driven from a steer message:
zombiectl steer zmb_2041 "forget customer_bob_chen_acme; Bob is now on the Enterprise plan"The next event uses the corrected memory.
Every memory operation is scoped by zombie_id. Agent A cannot read Agent B's memory. The memory store is a separate Postgres database, not a shared filesystem — even an agent with shell or file tools can't reach it through the wrong protocol.
My agent keeps re-asking the user for the same info.
Either memory_store isn't being called at the end of the previous event, or memory_recall isn't being called at the start of the next one. Audit your SKILL.md — recall must happen before the reasoning step.
My agent remembers something stale.
The underlying system changed but memory didn't. Steer the agent to call memory_forget(key) and re-store the corrected entry. For systems-of-record that change frequently, build a sync job into the agent's prose.
Should I use core or conversation for this?
conversation only for run-scoped scratch (e.g. checkpointing tool-call findings during a long incident — see How long does a run take?). Everything else is core or daily.
| Symptom | Cause | Fix |
|---|---|---|
| Recall returns nothing on a known entity | Inconsistent key convention | Use a stable, deterministic key derivation in SKILL.md (e.g. customer_<email-slug>). |
| Memory grows forever | core has no time-based pruning; at the entry cap, coldest core entries are evicted when no non-core entries remain |
Steer the agent to call memory_forget on stale keys, or move time-bounded entries to daily. |
UZ-MEM-003 on store |
Memory backend unavailable | Re-run the trigger; if persistent, file an issue. |
UZ-MEM-001 on store |
Memory scope denied (cross-agent access attempt) | Memory is per-agent. Use workspace-category writes if you need to share facts across agents. |