The Memory Model
Previously has no database and no vector store. Memory is plain Markdown files in a git repository, organized by time. Three timelines run through the product, and only one of them is shared:
- Your life — everything you lived. Most of it was only ever experienced by you; Previously does not see it.
- The shared record — every conversation, every decision, every unspoken moment that got remembered. This is what Previously stores, as a timeline of episodic slices.
- Its thinking — the agent's own cognition while it worked: what it recalled, what it reasoned, what it concluded. This is recorded too, alongside each slice.
The memory model is how these lines are kept: an immutable identity bundled at build time, a lossless episodic timeline at runtime, a compact user card that distills the timeline into who you are — and an evolution data layer that records how the system itself should change.
L0: The Identity Constitution
The deepest layer is not data at all — it is who the agent is. identity/agent/SOUL.md and identity/agent/DIRECTIVES.md hold the agent's constitution: its character and its standing rules.
At build time, both files are compiled into a generated TypeScript module, so the constitution is frozen into the deployment. It is never read from disk at runtime, and its source sits outside the tool whitelist — the agent cannot rewrite its own soul, and neither can a bad edit to the repo change the live prompt.
The Episodic Layer: Slices on a Timeline
Every conversation burst becomes a time slice — a directory on your personal timeline whose path encodes exactly when it happened:
memory/episodic/slices/2026/08/10/2130/
timeline/
core.md -- the shared record: YAML frontmatter + conversation turns
agent.md -- its thinking: the agent's cognition log for this slice
previously.md -- a snapshot of the user card as of this slice
Note the two files under timeline/: core.md is the shared record (what was said, with structured metadata — focus, summary, open_loops, decisions, tags, emotional_tone, status, start/end), while agent.md is the agent's own line — its thinking at the time, mechanically extracted. A slice opens when you start talking and closes by pure time rules (a slice-age cap, context loss, or a turn-count safety valve). There is no topic-shift rule: slicing is purely time-driven, so the timeline stays a lossless autobiography. See Time Slices for the full lifecycle.
Strands are the thin semantic index over that timeline: a keyword like wedding-speech or running woven through every slice that carries it, stored in memory/episodic/strands.json as a strand-to-slice-paths mapping. A slice is what happened; a strand is what it was about. See Strands.
Key takeaway: slices are the single source of truth. Everything else — the strand index, the timeline catalog, the user card, the playbooks — is a derived, rebuildable projection over the slice files.
The Timeline Index
Reading a hundred slices to answer one question wastes context, so Previously maintains a derived index over the whole history:
memory/episodic/timeline/index.json— the canonical structured catalog: one entry per slice with itsfocus,summary,tags,strands,open_loops,decisions, and aneeds_markingflag for slices whose semantics haven't been filled yet.memory/episodic/timeline.md— a Markdown projection of the same catalog, grouped by month and day, readable by the agent (and by you).
Both are rebuilt by deterministic reconciliation — enumerate the slice files, diff, reconcile — with zero model calls. A fresh slice is upserted into the catalog the turn it is created; any entry flagged needs_marking gets its focus/summary backfilled later, at slice-close boundaries, never on the conversation's critical path.
The index is a map, not an answer source: each line carries enough texture to judge relevance, but correctness always comes from opening the raw slice. That drill-down is the recall colleague's job — it navigates the catalog, the strands, and the slices itself, and quotes the originals. See Recall and The Timeline.
The User Card
memory/episodic/current-previously.md is the living distillation of the timeline — a compact card that answers who you are, refined after slice boundaries. It is the difference between an agent that stores your history and one that arrives already knowing you: it is what makes an arrival briefing possible.
The card has four sections:
| Section | Contents |
|---|---|
| Identity | Structured head: name, how to address you, aliases |
| Past | A rolling third-person profile paragraph, updated in place, plus anchor facts — durable dates, decisions, and red lines that will still be true in years |
| Now | Current-state hooks, not narratives — mechanically expired after 7 days |
| Horizon | Future-facing commitments and deadlines, each with a by: date; overdue items are flagged, never silently dropped |
Every entry carries refs pointers back to the slices that evidence it, so any claim can be drilled down to the raw record. The card is never rewritten wholesale and never touched by the generic write tool: the evolution agent edits it through validated per-entry mutations (addNow, updatePastProfile, resolveHorizon, …), and over-limit writes are rejected with compression instructions. Hard caps keep the whole card under roughly 8 KB, so it stays cheap to inject into every prompt. See The User Card for the full format.
The Evolution Data Layer
Next to the episodic layer sits a second, smaller data layer — the state of the self-evolution loop itself:
memory/evolution/
direction.md -- the learned user portrait: Portrait + Hypotheses pool
fitness.json -- bounded store of scored events + mechanical signals
memory/agent-playbooks/
recall.md -- evolved behavioral brief for the recall colleague
search.md -- ... for webSearch
thinkdeep.md -- ... for thinkDeep
- direction.md — the loop's learned model of who you are: a Portrait of confirmed, cross-context traits (descriptive, never imperative, evidence in trailing
— refs:tails) plus a bounded pool of falsifiable hypotheses with a code-enforced TTL. This is the loop's environment; the card and playbooks are only its products. - fitness.json — the selection pressure's ledger. Events are per-slice, per-bucket (
card/recall/search/thinkdeep/interaction) ordinal deltas (−2…+1) with user-verbatim evidence attached — an evidence-less score is force-zeroed structurally on write. Alongside them sit mechanical signals (recall verify/rework/repeat, regenerate/stop) recorded by instrumentation, not by any model. The store is deliberately bounded: it is the current generation's pressure gauge, never an archive of record. - agent-playbooks/ — one short brief per sub-agent, injected into its user prompt at call time. A missing playbook is a normal state: the injection is simply skipped.
The evolvable surface is data; the contracts are code. Direction, playbooks, and the card under memory/ are what the evolution loop may rewrite. The sub-agent schemas, tool sets, budgets, trigger math, and acceptance rules stay in the code — deliberately outside the loop's reach, so the protocol that governs evolution cannot itself be evolved. See The Evolution Loop.
The Whitelist Boundary
Agent tools are confined to three writable directories:
memory/ tasks/ sessions/
The source tree is agent-read-only — no tool may modify it. Path validation normalizes inputs first — decoding URI components, converting backslashes to forward slashes, resolving ./ and ../, stripping leading slashes — then rejects empty and absolute paths before matching against the allowed prefixes.
Within the whitelist, system-managed paths are readable but write-blocked for the generic write tool:
memory/episodic/— slices, indexes, and the user card are system-owned- Any
_index.jsonfile - Any
strands.jsonfile
The evolution layer's protection is of a different kind: not a path pattern but tool ownership. Only the evolution agent holds the writes to memory/evolution/ and memory/agent-playbooks/ — recall, webSearch, and thinkDeep are read-only reporters — so the acceptance rules and the evidence chain have exactly one place to hold.
This keeps the episodic timeline and its structural indexes safe from accidental or malicious corruption; the card and the evolution files change only through their dedicated, validated paths.
Context Assembly: Frozen with the Slice
There is no ever-growing prompt window, and no prompt re-assembled from scratch each turn either. The system prompt is layered, and anchored to the slice's start: the identity constitution, the user card, the slice head (where the evolution_summary is replayed verbatim), the timeline and strands brief — byte-identical for the whole life of a slice.
This is a deliberate caching decision: provider prompt caches match byte prefixes, and a prompt that doesn't move within a slice keeps hitting its prefix cache. Anything that genuinely changes per turn stays out of the system prompt — when the model needs the precise time, it reads it itself through the currentTime tool.
Deep context is never stuffed into the prompt by default either — the main agent asks the recall colleague, which searches the timeline itself and answers with anchored quotes. See Recall.
Why Plain Markdown + YAML
Every piece of memory is a Markdown file with YAML frontmatter. This choice is deliberate:
- Portable —
git cloneanywhere, read on any device, no server needed. - Git-diffable — every change to a slice, the card, or the direction is tracked in version history. You can see what Previously learned, and when.
- Human-editable — open any file in your editor, fix a summary, add a tag. No admin UI, no SDK.
- Any tool reads it — Previously writes, Claude Code reads, Codex extends. No lock-in, no integration tax, no schema migration.
Files are the interface.
Related
- Recall — the colleague who works the timeline at inference time
- The User Card — the living distillation of you, and the loop that evolves it
- The Evolution Loop — the full story of direction, fitness, and triggers
- The Scribe — how conversations from other tools enter this timeline
- The Only Way In — the acceptance-gated entry point for outside content