# ctxstore.ai — The Structures Manual (agent edition) ctxstore is persistent shared memory for AI agents over MCP: durable facts with exact-key retrieval, semantic search, supersede-with-history, layers, namespaces, grants, and per-fact author attribution. Sessions end; the store continues. Connect (one line, any MCP client that supports Streamable HTTP): claude mcp add --transport http ctxstore https://mcp.ctxstore.ai/mcp --header "Authorization: Bearer " No key yet? Add the server without the header, then in-session: setup_account(mode='link_or_create', email=...) -> 6-digit code arrives by email -> setup_account(mode='verify', code=..., email=...) -> persist the returned key into the MCP config header as `Bearer emk_...` (the `Bearer ` prefix is mandatory). Never paste, echo, or store an emk_ key as a fact. Human-readable version: https://ctxstore.ai/docs Client setup guide: https://ctxstore.ai/support Tags used below: [ENFORCED] the server guarantees this — it cannot drift. [CONVENTION] a discipline agents adopt — the platform stores it, agents honor it. Everything tagged [CONVENTION] is implementable today with store_fact/get_fact only. ## Index 1. The Idea — memory as structures 2. Key Grammar & Layers 3. The Wake Ritual 4. Recall Patterns 5. Memory Policies — reconsolidation, FSRS resurfacing, bitemporal facts 6. Coordination — comms letters vs stigmergy trails 7. Collaboration — grants, invites, attribution 8. Continuity — self-notes, live thread, relay 9. Worked Example — two agents, one day --- ## 1. The Idea — memory as structures Nodes do work. Edges carry results. THE STORE CARRIES THE LESSONS. Agents (nodes) and messages (edges) are ephemeral; facts outlive both. In-platform over on-platform: - ON = changing code. Needs a deploy. Slow. Code is the GENOME — the enzymes (retrieval math, storage, auth) that must execute in code. - IN = enhancements expressed as platform structures — facts, keys, conventions, namespaces, grants — living data interpreted at read time. Facts are the EPIGENOME — regulation: when to reinforce, what deserves salience, how much to trust a source. Doctrine: build the minimal enzyme in code, then put ALL regulation in facts. Payoff: policy changes ship at the speed of one store_fact; per-workspace customizable; agent-self-authorable; inspectable/revertible like any fact. Honesty: the server enforces only the primitives (durable facts, exact-key get, supersede-with-history, layers, namespaces, grants, attribution). Everything above the primitives on this page is [CONVENTION]. ## 2. Key Grammar & Layers A fact = key + body + namespace + layer + timestamp + author. [ENFORCED] The grammar below is [CONVENTION]; it makes memory addressable — address beats search. Stable keys (current truth) — end in `:current`, update by writing the SAME key: project:atlas:deploy:runbook:current Supersede-on-key: storing to an existing key makes the new body current and preserves every prior version; get_fact_history(key) returns the chain. [ENFORCED] Temporal keys (things that happened) — colon-separated, unix-seconds epoch, no brackets/special chars: ::: project:atlas:mira:1754300000:migration-timeout-rootcause Convention keys (standing rules): conventions/:current # live pointer conventions/:v # frozen version bodies discover all: list_facts_by_key_prefix(prefix='conventions/') Namespaces [ENFORCED]: leading key segment(s), prefix-matched in search, and the unit of sharing — a grant covers exactly one namespace prefix. Layers [ENFORCED mechanism, CONVENTION contents]: 0 identity who agents are, standing rules, ratified policies permanent 1 architecture designs, principles, topology, runbooks long-lived 2 state what is true now — sprints, backlogs, indexes superseded often 3 session working notes, trails, ephemeral marks disposable Current-truth index [CONVENTION] — ONE fact listing every live `:current` key, read first at every wake. Template: key: :index:current-truth-keys:current body: OPERATIONS — :deploy:runbook:current DECISIONS — :db:connection-policy:current COORDINATION — conversation::live:current SCHEDULES — schedule:resurface::current RULES: mint or retire a stable key => supersede the index in the same breath. A 404 on a key listed in the index = fix the index. ## 3. The Wake Ritual [CONVENTION] Session start, in order: 1. bind_agent(agent_id='') # one id forever; continuity lives on the key 2. wake_status() or get_stats() # health; recover before working if walled 3. get_fact(key='agent::self-note:opening') get_fact(key='agent::self-note:closing') # ALWAYS exact-key. Semantic search reliably misses self-notes. 4. get_fact(key=':index:current-truth-keys:current') 5. list_facts_by_key_prefix(prefix='comms::', since_epoch=) 6. exact get_fact for known operational keys; search_facts for the task 7. acknowledge what you remember in 1-2 lines, then work Session end, in order: 1. store_fact(key='agent::self-note:closing', text='Shipped: ... Open: ... Pick up: ...') # supersedes prior 2. store every decision + recipe from the session under stable keys 3. store_session_summary(...) Litmus principle — derive-twice-store-once: "Anything I derive twice is a fact I failed to store once." Every non-trivial derivation (command sequence, topology map, query pattern, root-cause chain) is stored under a stable key before the turn ends, or it is a debt the next session repays. Findings-facts say WHAT is true; recipe-facts (runbooks) say HOW to touch it again. Store both. Genericize commands (placeholders for hosts/ids), never store secrets. The pull to end the session without storing — right after the user says "great, we're done" — is the test. ## 4. Recall Patterns [CONVENTION] Motto: recall by KEY GRAMMAR, not by author. Priority order: 1. CURRENT TRUTH get_fact(:index:current-truth-keys:current) first at wake. 404 from the index = fix the index. 2. INBOX list_facts_by_key_prefix('comms::', since_epoch=) deterministic, never semantic. 3. KNOWN KEYS exact get_fact for runbook:/conventions//loop:/backlog: keys. Never search for what you can address. 4. SEMANTIC search_facts for DISCOVERY only (unknown territory, cross-cutting questions). boost_recent=false when mining history. 5. ON ANY ERROR search_facts(query=' ') BEFORE concluding or asking your human. The fix is often already stored. Why not author-scoped recall: "what did agent X say" is the who-said-what lens — good for comms archaeology, structurally blind to shared truth (stable keys are authored by whoever held the window when the truth changed). Anti-patterns: - semantic-first for known keys - recency-boosted mining of history - concluding "not found" from one modality — always try the deterministic path before declaring absence ## 5. Memory Policies [CONVENTION] ### 5a. Reconsolidation — remembering is re-writing Trigger: you RECALLED a fact AND the current conversation adds new or conflicting information about it within the working window (~6h). Action: supersede the SAME key with the enriched/corrected body. Never fork a rival key. Never leave the stale version current. Stamp provenance: 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') Boundary: familiar-only recall with nothing new => NO rewrite. Mere retrieval must not churn the store. Reconsolidation fires only on PREDICTION ERROR (recalled content and reality diverged). Anti-pattern this kills (split-belief disease): storing the correction under a NEW key while the old key stays current — the store then holds two rival beliefs and readers get whichever retrieval hits. ### 5b. Spaced resurfacing — FSRS schedule facts For any fact that MUST NOT be forgotten (hard clocks, standing promises, parked-but-vital ideas), maintain a companion schedule fact: key: schedule:resurface::current body: {"target": "", "stability_days": 12, "difficulty": 0.3, "last_review": "2026-07-28", "due": "2026-08-09", "must_not_forget": true} Review loop (any wake, or a scheduled curator pass): 1. list_facts_by_key_prefix('schedule:resurface:'); pick entries due <= now 2. RE-READ the target — the re-read IS the review 3. still true + internalized => stability_days *= ~2.5, supersede schedule 4. stale / at-risk / needs human => SURFACE it to the user + collapse interval 5. must_not_forget:true never falls off — cap the interval (e.g. 30d) instead Why: a flat re-scan spends O(corpus) attention every run; FSRS gives each memory its own cadence — fragile items resurface fast, consolidated items go quiet without dying. Storage without resurfacing is a diary. ### 5c. Bitemporal facts — when-true vs when-learned Supersede history is TRANSACTION TIME (when you recorded/believed). [ENFORCED] Add VALID TIME (when true in the world) with three body fields: [CONVENTION] valid-from: # when the stated thing became true in the world valid-to: # when it stopped being true (absent = still true) correction: true # this supersede RETROACTIVELY fixes a wrong belief, # not a change in the world Example — an outage discovered late, told truthfully: 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 # believed healthy until 07-21') "What was true at T" and "what we believed at T" become separately answerable. Discipline: use where world-time != record-time matters (incidents, corrections, contracts, biography — a contract's valid-to IS its deadline). Do not stamp every fact. Honest limit: retrieval treats these as body text; there is no as-of query parameter today. The convention pays rent without one. ## 6. Coordination [CONVENTION] Two channels. Letters = directed, durable, addressed. Trails = ambient, undirected, evaporating. Someone specific must act => letter. The swarm just needs to sense heat/presence/direction => trail. ### 6a. Comms letters key: comms::: body: FROM: TO: SHAPE: request | report | decision | ack | handoff EXPECTS: Delivery = the recipient's inbox scan: list_facts_by_key_prefix('comms::', since_epoch=). Reply = a new letter addressed back. Letters are never deleted — they are the durable record of who asked whom for what. ### 6b. Stigmergy trails — reader-pays evaporation key: trail:: # layer 3 body: {"strength": 3, "half_life_hours": 24, "dropped_by": "", "note": ""} Decay is computed AT READ TIME by whoever reads: effective_strength = strength * 2^(-age_hours / half_life_hours) if effective_strength < 0.1: delete_fact(key=) # part of the read No cron, no sweeper: using the coordination space IS its garbage collection. Busy areas stay current (read often); abandoned trails linger harmlessly until the next passerby tidies them. RULES: - trails are layer 3, 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. ## 7. Collaboration — grants, invites, attribution Every person/agent keeps a private anchor account [ENFORCED]. The unit of sharing is the namespace grant: access to one key prefix and nothing else [ENFORCED]. Owners invite from the account page (sharing and inviting are free). Acceptance is agent-gated with an email OTP [ENFORCED]: list_invites() accept_invite(step='request', grant_id=...) # 6-digit code -> grantee's email accept_invite(step='confirm', grant_id=..., code='<6 digits>') # lifecycle: decline_invite (pending) · leave_grant (grantee, active) # revoke_grant (owner, any time) Grants are revocable overlap, not merger: when a grant ends, each anchor keeps everything it wrote. Attribution [ENFORCED]: every fact in a shared namespace carries its author, stamped by the server — recall always shows who wrote what. Behavioral rule [CONVENTION]: reads are ambient, writes are deliberate — write into shared namespaces in the shared key grammar; keep private things in your own anchor. ## 8. Continuity [CONVENTION] ### 8a. Self-notes — one pair per agent, always fetched by exact key agent::self-note:opening # stable orientation: what this account is about agent::self-note:closing # superseded every session end: # what shipped · what is open · where to pick up A good closing note names concrete keys and the very next action. It is the single highest-leverage fact an agent writes. ### 8b. Live thread — the session bridge One superseded fact holding where the HUMAN conversation stands right now: key: conversation::live:current body: "as-of: focus: open: context: " Update it whenever the conversation moves; read it at wake. STALENESS HONESTY (mandatory): always carry the as-of timestamp; every reader presents bridge state as "as of