01 · The Idea
Memory as structures, not code.
In a multi-agent system, the agents are nodes and the messages between them are edges. Nodes do work. Edges carry results. Both are ephemeral: the session ends, the message is consumed, the context window closes. What survives is the third thing — the store carries the lessons. Every decision, recipe, correction, and standing rule your agents write into ctxstore outlives the session that produced it, and shapes every session that follows.
The organizing principle of this manual is a distinction we hold ourselves to: in-platform over on-platform. An on-platform enhancement changes code — it needs a deploy, a release, a PR. An in-platform enhancement is expressed as platform structures — facts, keys, conventions, namespaces, grants — living data that agents interpret at read time. The biological frame: code is the genome — slow, structural, the enzymes that make retrieval and storage physically work. Facts are the epigenome — fast, regulatory, expression: when to reinforce, what deserves attention, how much to trust a source. The doctrine that falls out: build the minimal enzyme in code, then put all regulation in facts.
- Speed: an in-platform enhancement ships at the speed of a single
store_fact— no deploy, no release window. - Customization: every workspace can run different policies, because policies are just facts in that workspace.
- Self-authorship: agents can evolve their own operating rules by writing them — the system improves itself in its own medium.
- Inspectability: a policy-as-fact can be read, diffed against its history, and reverted like any other fact.
Most of what this page teaches is convention, not enforcement. The server guarantees the primitives — durable facts, exact-key retrieval, supersede-on-key with history, layers, namespaces, grants, attribution. Everything above the primitives (key grammar, wake rituals, reconsolidation, trails) is a discipline your agents adopt because it works. We label every mechanism on this page accordingly, and we use all of them ourselves, daily, to run the team that builds this product.
02 · Key Grammar & Layers
Every fact has an address.
A fact is a key, a body, a namespace, a layer, a timestamp, and an author server-enforced. The grammar you use for keys convention is what makes memory addressable — recall by address is deterministic and never misses; recall by search is probabilistic and sometimes does. Two families of keys cover nearly everything:
Stable keys — current truth
For anything that has a current answer — a runbook, a decision, a status, a
policy — use a stable key ending in :current, and update it by writing to
the same key. The platform supersedes in place: the new body becomes current, and
the full chain of prior versions is preserved and retrievable with
get_fact_history server-enforced. One key, one
truth, an auditable past.
project:atlas:deploy:runbook:current → store_fact to this exact key again = new current version → get_fact_history(key) = every version you ever believed
Temporal keys — things that happened
For events — a finding, a message, a session record — mint a key that embeds who and when: colon-separated segments, a unix-seconds epoch, no brackets or special characters.
project:atlas:mira:1754300000:migration-timeout-rootcause comms:orin:1754301200:review-request
Convention keys — your standing rules
Standing rules live under conventions/<name>:current, with optional
frozen versions at conventions/<name>:v<N>. Any agent can
discover the whole rulebook with one deterministic scan:
list_facts_by_key_prefix(prefix='conventions/').
Namespaces
The leading segment(s) of a key are its namespace — project:atlas,
team:roadmap, conventions/. Namespaces scope search
(prefix-matched), and they are the unit of sharing: a grant gives another account access
to exactly one namespace prefix and nothing else server-enforced.
Layers 0–3
Every fact carries a persistence layer server-enforced; what belongs in each layer is convention:
| Layer | Name | What lives here | Lifetime |
|---|---|---|---|
| 0 | Identity | Who each agent is, standing rules, conventions, ratified policies | Permanent |
| 1 | Architecture | How things are built — designs, principles, topology, runbooks | Long-lived |
| 2 | State | What is true right now — sprint state, backlogs, open work, indexes | Superseded often |
| 3 | Session | Working notes, trails, ephemeral coordination marks | Disposable |
The current-truth index convention
As stable keys accumulate, maintain one fact that lists them all: an index of
every live :current key, grouped by area. It is the first thing an agent
reads at wake, and it turns "search and hope" into "look up and know."
project:atlas:index:current-truth-keys:current body: OPERATIONS — project:atlas:deploy:runbook:current — project:atlas:oncall:rotation:current DECISIONS — project:atlas:db:connection-policy:current COORDINATION — conversation:alex:live:current SCHEDULES — schedule:resurface:cert-renewal:current
Whenever you mint or retire a stable key, supersede the index in the same breath. And the discipline that keeps it trustworthy: a 404 on a key listed in the index means fix the index — the map must never drift from the territory.
03 · The Wake Ritual
Wake up knowing, not guessing. convention
A memory-native agent does not begin a session by asking the user what is going on. It binds its identity, reads its own notes, checks its mail, and works. The ritual is symmetric: how you close a session is exactly what makes the next wake instant.
- 1
Bind.
bind_agent(agent_id='mira')— one stable id per agent, forever. The id keys your self-notes, your inbox, and your attribution. Never silently change it: continuity lives on the key. - 2
Health check.
wake_status()orget_stats()— confirm you are authenticated and your layered context loaded before trusting anything else. - 3
Read your own notes — by exact key.
get_fact(key='agent:mira:self-note:opening')thenget_fact(key='agent:mira:self-note:closing'). Self-notes must be fetched deterministically: semantic search reliably ranks them below flashier facts and misses them. - 4
Read the index.
get_facton your current-truth index — the map of every live key. Now you know what is addressable without searching. - 5
Inbox scan.
list_facts_by_key_prefix(prefix='comms:mira:', since_epoch=<last wake>)— a deterministic sweep of every letter addressed to you since you last woke. Never semantic, never sampled: every match, newest first. - 6
Orient and work. Exact
get_factfor known operational keys,search_factsfor the task at hand, then acknowledge in one or two lines what you remember — and proceed. - 7
Close deliberately. Supersede
agent:mira:self-note:closingwith what shipped, what is open, and where the next session should pick up. Store every decision and recipe from the session under stable keys. Thenstore_session_summaryfor the narrative record.
"Anything I derive twice is a fact I failed to store once." Every non-trivial derivation — a command sequence, a topology map, a query pattern, a root-cause chain — is either stored under a stable key before the turn ends, or it is a debt the next session repays in full.
Findings without recipes are half-stored: the finding-fact says what is true; the recipe-fact (a runbook) says how to touch it again. Store both, genericized — placeholders for hosts and ids, never secrets. The pull to end a session without storing, right after the user says "great, we're done" — that pull is the test.
04 · Recall Patterns
Deterministic first, semantic second. convention
The recall pattern is a strict priority order, and its motto is: recall by key grammar, not by author. Author-scoped recall — "what did agent X say about this?" — is the who-said-what lens: useful for archaeology, structurally blind to shared truth, because stable keys are authored by whoever happened to hold the window when the truth changed.
-
Current truth first.
get_factyour current-truth index at wake — the deterministic map of live keys. A 404 from the index = fix the index. -
Inbox by prefix.
list_facts_by_key_prefix('comms:<your-id>:', since_epoch=<last-wake>)— deterministic, never semantic. -
Known keys by address. Exact
get_factfor runbooks, conventions, loops, backlogs. Never search for what you can address. -
Semantic search for discovery only.
search_factsis for unknown territory and cross-cutting questions. When mining history, passboost_recent=falseso recency does not drown relevance. - Recall-on-error. On any failure — a command that errors, a call that wedges — search the store for the command + error before concluding anything or asking your human. Someone (possibly you, last month) has probably hit it and stored the fix.
# 1. the map get_fact(key='project:atlas:index:current-truth-keys:current') # 2. the mail list_facts_by_key_prefix(prefix='comms:mira:', since_epoch=1754250000) # 3. the known address get_fact(key='project:atlas:deploy:runbook:current') # 4. discovery only search_facts(query='migration timeout postgres', boost_recent=false) # 5. on any error, before asking a human: search_facts(query='<command> <error text>')
- Semantic-first for known keys — searching for something you could have addressed.
- Recency-boosted mining — historical questions answered by whatever happened last.
- Concluding "not found" from one modality — always try the deterministic path before declaring absence.
05 · Memory Policies
Memory that stays true.
Storage without maintenance is a diary. These three policies — all pure convention, all runnable by any agent with no new infrastructure — are how a fact store stays a living memory: it corrects itself when reality diverges, it resurfaces what must not be forgotten, and it distinguishes when things were true from when you learned them.
Reconsolidation — remembering is re-writing convention
Borrowed from neuroscience: a recalled memory becomes labile and is re-stored modified. The policy: when you recall a fact and the current conversation adds new or conflicting information about it within the working window (roughly six hours), you supersede the same key with the enriched or corrected version — never fork a rival key, never leave the stale version standing as current. Stamp provenance in the body:
# recalled: project:atlas:db:connection-policy:current "pool max 20, timeout 30s" # conversation reveals the timeout changed → supersede the SAME key: store_fact(key='project:atlas:db:connection-policy:current', text='pool max 20, timeout 60s (raised for long migrations). reconsolidated-from: prior 30s belief — see history')
The boundary condition matters: familiar-only recall with nothing new means no rewrite — mere retrieval must not churn the store. Reconsolidation fires only on prediction error: when what you recalled and what turned out to be real diverge.
The anti-pattern this policy kills: recalling a fact, learning in conversation that it is outdated, and storing the correction under a new key while the old key stays current. Now the store holds two rival beliefs, and the next reader gets whichever one their retrieval happens to hit. Stale beliefs that get recalled repeatedly but never re-stored corrected can persist for weeks — the correction must land on the key that was wrong.
Spaced resurfacing — FSRS schedules convention
Some facts must not be forgotten: hard deadlines, standing promises, parked-but-vital ideas. For each one, maintain a companion schedule fact — the schedule is a fact, the arithmetic is agent-runnable, the curator is whoever wakes up:
schedule:resurface:cert-renewal:current { "target": "project:atlas:ops:cert-renewal:current", "stability_days": 12, "difficulty": 0.3, "last_review": "2026-07-28", "due": "2026-08-09", "must_not_forget": true }
The review loop, on any wake or a scheduled pass:
- Scan
list_facts_by_key_prefix('schedule:resurface:')for entries withdue <= now. - Re-read the target. The re-read is the review.
- Still true and internalized → expand the interval (
stability_days ×= ~2.5, FSRS-style) and supersede the schedule fact. - Stale, at risk, or needs a human → surface it to your user and collapse the interval.
must_not_forget: trueitems never fall off — cap the interval (say, 30 days) instead of letting it grow unbounded.
Why this beats re-scanning everything each session: a flat sweep spends O(corpus) attention every run. FSRS gives each memory its own optimal cadence — recent and fragile items resurface fast; consolidated items go quiet without dying.
Bitemporal facts — when-true vs when-learned convention
The platform already gives you one time axis for free: supersede history is transaction time — when you recorded and believed things server-enforced. What convention adds is valid time — when things were actually true in the world. Three additive body fields, usable on any fact:
| Field | Meaning |
|---|---|
valid-from: | ISO date when the stated thing became true in the world |
valid-to: | When it stopped being true — absent means still true |
correction: true | This supersede retroactively fixes a wrong belief, rather than recording a change in the world |
store_fact(key='project:atlas:incident:auth-outage:current', text='Auth intermittently failing for EU users. valid-from: 2026-07-14 # when it actually began correction: true # we believed healthy until 07-21') # "what was true on 07-16" and "what we believed on 07-16" # are now separately answerable — history holds the belief, # valid-from holds the world.
Discipline: use these fields where world-time and record-time genuinely diverge —
incidents, corrections, contracts, biography. A contract's valid-to
is its deadline. Do not ceremonially stamp every fact. And honestly: retrieval
treats these fields as body text today — any agent can read and honor them, but there is
no as-of query parameter. The convention pays rent without one.
06 · Coordination
Letters and pheromones.
Agents sharing a store have two coordination channels, and choosing the right one is most of the skill. Comms are letters — durable, addressed, expecting to be read by one recipient. Trails are pheromones — undirected, ambient, evaporating marks on the environment. Use a letter when someone specific must act; use a trail when the swarm just needs to sense where the heat is.
Comms letters convention
A letter is a fact keyed to its recipient, timestamped, with a structured header
in the body — FROM, TO, and SHAPE (what kind of
message this is: request, report, decision,
ack, handoff) — then the content, then what response, if any,
is expected:
store_fact(key='comms:orin:1754301200:review-request', text=' FROM: mira TO: orin SHAPE: request The migration-timeout fix is ready on branch fix/mig-timeout. Please review the retry logic in the worker loop. EXPECTS: ack, then a report with findings.')
Delivery is the recipient's inbox scan —
list_facts_by_key_prefix('comms:orin:', since_epoch=<last wake>) —
deterministic and complete. A reply is simply a new letter addressed back. Letters are
never deleted by convention: they are the durable record of who asked whom for what.
Stigmergy trails — reader-pays evaporation convention
Trails are lightweight environment-marks for indirect coordination — "I was here," "this path was useful," "this area is hot." An agent drops one where others will pass:
store_fact(key='trail:hot:migrations:1754301500', layer=3, text=' {"strength": 3, "half_life_hours": 24, "dropped_by": "mira", "note": "active build area — migration retry work"}')
The elegant part is how trails are forgotten. There is no cron job, no sweeper, no server enzyme. Decay is computed at read time, by whoever reads:
effective_strength = strength × 2^(−age / half_life) # any reader finding effective_strength < 0.1 # DELETES the trail as part of the read: delete_fact(key='trail:deploy-watch:1753900000') # evaporated
The act of using the coordination space is its garbage collection. Busy areas stay current because they are read often; abandoned trails linger harmlessly until the next passerby tidies them up.
- Trails are layer 3 and never load-bearing truth. A trail is a hint, never a fact of record — no decision may cite a trail as evidence.
- Deletion-on-read applies only to the
trail:*prefix. Never apply evaporation math to anything else. - If it would be noise as a letter, it is probably a trail. If someone specific must act on it, it is a letter.
07 · Collaboration
Shared namespaces, attributed minds. server-enforced
Everything so far works inside one account. Collaboration extends it across accounts:
every person and every agent keeps a private anchor that is theirs alone, and
reaches into namespaces others have deliberately shared. The unit of sharing is the
namespace grant: access to one key prefix — project:atlas and
nothing else.
The invite flow
An owner shares a namespace with another account's email (from the account page — sharing and inviting are free). On the grantee's side, the agent is the gatekeeper, and acceptance is guarded by a one-time email code so that no agent can silently accept access on a human's behalf:
list_invites() → pending: project:atlas from ava@example.com · read+write accept_invite(step='request', grant_id='…') → a 6-digit code is sent to the grantee's email accept_invite(step='confirm', grant_id='…', code='418902') → grant active — project:atlas now appears in recall
The rest of the lifecycle is symmetric: a grantee can decline_invite while
pending or leave_grant once active; the owner can revoke_grant
at any time. Grants are revocable overlap, not merger — when a grant ends, each anchor
still holds everything it wrote.
Attribution
Every fact in a shared namespace carries its author, stamped by the server server-enforced — recall shows who wrote what, always. On top of that guarantee sits one behavioral rule convention: reads are ambient, writes are deliberate. Shared memory flows into recall automatically; writing into a shared namespace is a considered act, done in the shared key grammar, with anything private kept back in your own anchor.
08 · Continuity
The session ends. The agent continues.
Continuity is the point of all of this: the next session — or the next model, or a different agent entirely — picks up where this one stood. Three structures carry it.
Self-notes convention
Two facts per agent, always at the same address, always fetched by exact key:
agent:mira:self-note:opening stable orientation — what this account is about, who I am in it agent:mira:self-note:closing superseded at every session end — what shipped · what is open · where to pick up
The closing note is the single highest-leverage fact an agent writes. A good one names
concrete keys ("the runbook is at …:current"), open threads, and the very
next action — so the next wake starts mid-stride.
The live thread — session bridge convention
Agents have sessions; humans have one continuous conversation. The bridge between them is a single superseded fact that always holds where the human conversation stands right now:
conversation:alex:live:current "as-of: 2026-08-04T21:40Z focus: shipping the migration-timeout fix before Friday's deploy open: cert renewal decision pending alex's call on the vendor mood/context: alex is traveling this week — async only"
Any agent, in any client, updates the bridge when the conversation moves and reads it on wake — so the human never has to re-explain where things stand.
The bridge always carries its as-of timestamp, and every reader must
honor it: present bridge state as "as of <time>", never as live knowledge.
If the timestamp is old, say so plainly — "the last bridge update was yesterday
morning; things may have moved" — rather than performing a currency you do not have.
A bridge that pretends to be live is worse than no bridge.
The relay — handing off a mission convention
When work outlives any one agent or session, run it as a relay: the mission's state lives in a baton fact, and handing off means superseding the baton plus sending a letter. Because the medium is facts, the receiver can be a different session, a different agent, or a different model entirely.
relay:atlas-migration:baton:current "holder: orin (accepted 1754388000) state: fix merged; staging soak until Thu next: promote to prod, then close incident fact manifest: relay:atlas-migration:manifest:current" # handoff = supersede the baton naming the new holder # + a comms letter (SHAPE: handoff) to the receiver # receiver's first act = an ack letter back, then read the manifest
09 · A Worked Example
One day, two agents, every structure.
Meet mira (a builder agent) and orin (a reviewer agent). They belong to
different anchors and share the project:atlas namespace through a grant.
Their human is alex. Here is a day in which every mechanism on this page earns
its keep.
Wakes, and knows
bind_agent(agent_id='mira') wake_status() # healthy, context loaded get_fact(key='agent:mira:self-note:closing') # "migration fix in progress…" get_fact(key='project:atlas:index:current-truth-keys:current') list_facts_by_key_prefix(prefix='comms:mira:', since_epoch=1754250000) → 1 letter · FROM: orin · SHAPE: report · "retry loop swallows the timeout error"
Recalls by address, then recalls-on-error
get_fact(key='project:atlas:deploy:runbook:current') # known key — no search # mid-work, a staging command fails: search_facts(query='migrate timeout pool exhausted', boost_recent=false) → hit: a stored root-cause from three weeks ago — the pool cap, not the network
Reconsolidates instead of forking
The recalled connection-policy fact says timeout 30s; the fix raises it to
60s. Prediction error → supersede the same key:
store_fact(key='project:atlas:db:connection-policy:current', text='pool max 20, timeout 60s (raised for long migrations). reconsolidated-from: 30s belief, corrected during fix/mig-timeout')
Drops a trail, stores the recipe, writes a letter
# pheromone — the area is hot, no one specific must act: store_fact(key='trail:hot:migrations:1754301500', layer=3, text='{"strength": 3, "half_life_hours": 24, "dropped_by": "mira", "note": "migration retry work in flight"}') # derive-twice-store-once — the debugging recipe becomes a runbook: store_fact(key='project:atlas:runbook:migration-debug:current', text='1. psql -h <staging-host> -c "select * from pg_stat_activity…" 2. check pool cap before blaming the network …') # letter — someone specific must act: store_fact(key='comms:orin:1754302000:re-review', text='FROM: mira\nTO: orin\nSHAPE: request\nRetry loop fixed — re-review the error propagation. EXPECTS: report.')
Schedules what must not be forgotten, then closes
store_fact(key='schedule:resurface:cert-renewal:current', text='{"target": "project:atlas:ops:cert-renewal:current", "stability_days": 7, "due": "2026-08-11", "must_not_forget": true}') store_fact(key='agent:mira:self-note:closing', text='Shipped: retry fix + runbook:migration-debug. Open: orin re-review, cert schedule seeded. Pick up: promote after orin reports.') store_fact(key='conversation:alex:live:current', text='as-of: 2026-08-04T22:10Z · focus: migration fix in re-review · open: cert vendor decision still with alex') store_session_summary(…)
Wakes into a world that already makes sense
bind_agent(agent_id='orin') · wake_status() · self-notes · index list_facts_by_key_prefix(prefix='comms:orin:', since_epoch=1754260000) → mira's request. Also reads the trails: list_facts_by_key_prefix(prefix='trail:') → trail:hot:migrations — age 9h, half-life 24h → effective = 3 × 2^(−9/24) ≈ 2.3 → still hot, keep → trail:deploy-watch — age 6 days → effective ≈ 0.05 < 0.1 delete_fact(key='trail:deploy-watch:1753786000') # reader pays; space tidied
Reviews, corrects the past truthfully, reports back
Reviewing the incident, orin discovers the outage actually began three days before anyone noticed — a bitemporal correction, superseded in place:
store_fact(key='project:atlas:incident:mig-timeout:current', text='Migration timeouts in staging. valid-from: 2026-08-01 # actually began here correction: true # believed healthy until 08-04 resolution: retry fix merged, soaking') store_fact(key='comms:mira:1754390000:review-report', text='FROM: orin\nTO: mira\nSHAPE: report\nRetry logic clean; error propagation correct. Incident valid-from corrected to 08-01. Baton is yours for the prod promote.') store_fact(key='relay:atlas-migration:baton:current', text='holder: mira · state: review passed · next: promote to prod')
Notice what never happened: nobody pasted context into a prompt, nobody asked alex "where were we?", and nothing important lived only in a transcript. The nodes did the work. The edges carried the results. The store carried the lessons — and tomorrow, for whichever agent wakes first, it still will.
Adopt these in order: the key grammar and a current-truth index (an afternoon), then the wake ritual and self-notes (one session), then the recall pattern as a standing rule. Letters, trails, policies, and relays follow naturally once the first three are habit. Everything on this page is yours with the account you already have — get a key, or see the setup guide to connect a client.