Skip to content
Registry

memory

v0.2.18

Durable cross-session agent memory — named banks of always-injected markdown rules and auto-extracted memories, hybrid BM25 + entity recall, pinning, and supersede-never-delete history. Plain files on disk; every operation is a traced function.

license: Apache-2.0agentbm25contextmemoryragrecall

Install

bash
iii trigger compose::add worker=memory@next

Run in your project with the iii engine running. Exact versions are immutable and digest-pinned.

Agent-ready brief for v0.2.18
Install, config, dependencies, readme, skills and API reference, all in one place. Fetch as agent-context.md for an LLM to consume.
The same content rendered as discrete blocks below is exposed as a single markdown document at /registry/workers/memory.md?version=next. Paste it into an LLM prompt or pipe it through curl from a worker.

Install

iii trigger compose::add worker=memory@0.2.18

Dependencies

Readme

README.md

memory

Durable cross-session agent memory. Named banks hold two kinds of content: rules (markdown documents injected whole into the system prompt) and memories (auto-extracted records recalled on demand). Everything is a plain file you can open, a function you can call, and an event you can watch: memory that acts visibly, not magically.

Install

iii trigger compose::add worker=memory

The default bank main materializes on first use. No configuration required; without llm-router extraction degrades to explicit memory::save calls, and without the harness the worker still serves its full RPC surface.

Quickstart

Save something, then see exactly what a turn on that topic would be given:

iii trigger memory::save text="User publishes blog posts on Tuesday mornings" pinned=true tags=blog
iii trigger memory::recall query="when do I publish articles"

Give the bank a standing instruction — injected into the system prompt of every session using it:

iii trigger memory::rule::set name=style content="# Style\nFormal register. No em-dashes."

With the harness running there is nothing else to wire: chat normally and memory captures in the background. Say "never start replies with the word Certainly" in a conversation and it lands in the bank's auto-managed learned rule; state something durable and it appears as a memory after the turn. If memory seems absent, iii trigger memory::doctor runs a real save→recall roundtrip and names what is degraded.

Configuration

All fields hot-reload through the configuration worker and are editable in the worker's explicit form in the Console's global Settings modal; data_dir reopens the store on the fly. Fields: data_dir, default_bank, inject_rules, inject_memories, recall_limit, recall_budget_tokens, extraction_enabled, extraction_model, extraction_window, extraction_timeout_ms, max_memories_per_turn, rule_learning_enabled, max_rule_chars, decay_half_life_days (default 60; installs that predate MOT-5385 keep their stored 30 — set 60 in Settings to adopt the tuned recall curve), embeddings_enabled, embedding_model.

Why this shape

  • Files are the source of truth. rules/*.md and memories.jsonl under the data dir. Edit them in any editor; memory::reload (or a restart) picks the edits up. The search index is a RAM-only cache rebuilt from the files at boot, so store and index can never diverge across restarts.
  • Crash-safe by construction. Every mutation appends one fsynced JSONL line before touching RAM. There is no shutdown flush to get wrong. An unwritable data dir is boot-fatal: this worker never silently runs in RAM.
  • Supersede, never delete. Updates append revisions; deletes append tombstones; trashed banks move to .trash/. Any state is recoverable.
  • Pinning. A pinned memory ranks higher in recall and is untouchable by every automatic path.
  • Tags. Topical labels WITHIN a bank ("iii", "billing") for filtering — organization, not ranking. Set them on save/update, extraction suggests them automatically, and memory::list/memory::recall take a tag filter.
  • One LLM call per turn, zero at query time. Extraction runs in the background after a turn completes. It sees what the bank already holds about the conversation: a restatement (same text, or a close rewording) reinforces the known memory instead of duplicating it, and a correction supersedes the memory it corrects (a recoverable tombstone; pinned memories are never touched). Facts about the person talking are written as "The user …" with the user entity, so first-person questions reach all of them. Recall is BM25 over the query's content words (English stopwords dropped) + entity match + corroboration + recency, plus a semantic signal when router::embed is available: sub-millisecond at this scale.
  • Rules learn from corrections. Extraction classifies standing instructions (style directives, workflow corrections) separately from memories and appends them to the bank's auto-managed learned rule — correcting the agent in chat reaches every later turn (new sessions in the system prompt, running ones as an appended rules update). Hand-authored rules are never touched; dedup by content fingerprint; rule_learning_enabled turns it off.
  • Secrets are redacted, deterministically. Known key and token shapes (provider API keys, bearer tokens, JWTs, private key blocks, credentialed URLs, password=-style assignments) become [REDACTED: before anything is stored — memory text, entities, tags, and rules, on every write path — and before the transcript excerpt reaches the extraction model. The item-changed event names what was redacted (reason), never the value. A denylist of shapes: an unknown format passes, so the extraction prompt still forbids secrets.
  • Time-aware. Extraction reads each message with its own date and writes dated events ("tomorrow", "next Friday") as absolute dates; every injected memory carries its last-updated date, and the block names the day it was recalled.
  • Honest health. memory::doctor runs a real save→recall→trash roundtrip and reports sibling reachability. memory::recall names the retrieval mode it ran. Degradation is explicit, never silent.

How it hooks into the harness

Seam What happens
harness::hook::pre-generate (fail-open, priority 100) Injects the session bank's rules into the system prompt once per session (sent verbatim after that; a later rule change arrives as one appended update message, so the prefix stays append-only) and, on each turn's first step, up to recall_limit recalled memories as one appended message, minus any the window already carries from an earlier turn's block (a block compaction dropped no longer counts, so its memories can return). Whether an update is due is read from the window the step sends (its newest message, else the frozen section), so a lost or compacted-away update is sent again and a delivered one never is
harness::turn-completed Queues one background router::complete extraction pass over the turn's new user/assistant messages (at most extraction_window), into the bank the turn was injected with. A failed or cancelled turn is extracted too (its own bank, not the next turn's); a sub-agent's turn never is

Bank selection, one resolver for injection, extraction and agent calls: turn metadata memory_bank → session metadata memory_bank (session::set-meta) → the parent turn's bank, else the parent session's (a sub-agent works in its parent's bank, walked up) → configured default_bank. A memory::* call without bank inside a turn acts on that turn's bank; outside a session (CLI, console, other workers) it uses default_bank. An invalid name, a deleted bank other than the default, or a parent session that no longer exists means no memory for the session — never another bank — and extraction never brings a deleted bank back. A session-lookup failure injects nothing new (the section the session already has stays) and makes extraction retry. An unknown bank gets the ambient header while extraction is on (extraction creates the bank after a turn) and nothing while it is off.

Switching a running session's bank does not rewrite what it already saw: the new bank's section arrives as an appended update that overrides the frozen one, while the earlier bank's section and recalled memories stay visible in the transcript. Start a new session when the two contexts must not mix. Turning inject_rules and inject_memories both off works the same way: a running session keeps its section and is told once that no memory section applies.

All seam bindings are one-shot at startup and rely on the engine's recoverable triggers (iii #1962, engine ≥ 0.21.8): bound before the owning sibling (harness, session-manager, queue) is up, they park as pending intents and activate when the trigger type registers. On older engines the binds are silently dropped.

Functions

Function Purpose
memory::bank::create / list / delete Banks as first-class named scopes ("blog" vs "coding" vs "personal"); delete moves to .trash/
memory::save Explicit save ("remember this"): fingerprinted, reinforces on repeat
memory::get / list / update / delete / pin Memory CRUD; delete tombstones; update bumps a revision in the log
memory::recall The exact scorer the hook uses: preview what a turn would be given; tag narrows to one label; mode: lexical | semantic returns one raw arm (plain BM25 over the content words, or cosine) for callers that fuse arms themselves
memory::tags Distinct tags across a bank's live memories with counts (the filter source)
memory::preview Full injection dry-run for a hypothetical chat message: rules section (budgets applied), memories post ambient floor and token budget, appended message verbatim — the hook's exact code path
memory::rule::list / set The always-injected markdown rules; empty content removes
memory::supersede Retire one memory in favor of another (tombstone + pointer) — the consolidation seam; reinforce makes it a merge (a non-pinned survivor absorbs the retired record's observations), reason rides the events
memory::doctor End-to-end self-test (roundtrip + sibling reachability)
memory::reload Reload every bank from disk after hand-editing files

Custom trigger types

Bind live views here instead of polling; both are filterable by bank in the binding config, delivery is fire-and-forget, at-least-once, unordered.

  • memory::item-changed — a memory was created / updated / superseded / deleted. Payload: {event_type, bank, memory, reason?} (reason on consolidation changes).
  • memory::bank-changed — a bank was created / trashed, or its rules changed. Payload: {event_type, bank}.

Storage layout

Compose stores this tree under III_COMPOSE_DIR. A standalone worker uses its process current directory for the same relative default.

<III_COMPOSE_DIR>/data/memory/
  main/
    bank.yaml          # description
    rules/style.md     # always-injected markdown
    memories.jsonl     # append-only memory log (full records, last-wins by id)
    vectors.jsonl      # derived embedding sidecar (rebuildable)
  .trash/              # trashed banks, timestamped

Recall quality eval

tests/recall_quality.rs scores the production Bank::recall over a synthetic golden bank (tests/recall_quality/golden.json: one persona, 76 memories including 4 paraphrase duplicates, 62 English/Portuguese queries across lexical, paraphrase, identity, temporal-update, dated-event and durable-old categories). It runs in three modes:

  • lexical;
  • hybrid, with cached text-embedding-3-small vectors;
  • hybrid-consolidated, which first replays the semantic consolidation tier's recorded decisions (tests/recall_quality/consolidation.json, from memory-consolidate's judge eval) and scores expectations carried to the survivors.

It reports hit@1/3, MRR@10, nDCG@10 and recall@10 per category and language. It also counts traps, where a superseded memory outranks the current one, and duplicate pollution, a query whose top 10 holds both members of a dup_of pair. The committed snapshot tests/golden/recall_quality.json makes it a PR gate. The metric conventions follow Hindsight's retrieval eval.

cargo test --test recall_quality -- --nocapture                # report
UPDATE_GOLDENS=1 cargo test --test recall_quality              # re-baseline after an intended change
III_NAMESPACE=<ns> cargo test --test recall_quality -- --ignored embed_golden_set   # re-embed after editing golden.json

Permissions

Suggested defaults ship in iii-permissions.yaml: agents get memory::recall, memory::save, memory::get, memory::list, memory::update, memory::delete, memory::pin; the hook/pipeline internals are denied, and bank/rule writes plus memory::reload are human-owned surfaces (console, REST, CLI) by default.

The memory family

Like llm-router and its provider workers, memory is a family of narrow siblings rather than one grown monolith — this worker owns the store, per-turn injection, capture, and recall, and stays deliberately small:

Worker Role Status
memory (this) Banks, rules, memories: storage, harness injection, background capture, hybrid recall, live trigger types shipped
memory-consolidate Background hygiene on a schedule: deterministic dedup of near-duplicate memories, catch-up-on-boot scheduling. Supersede-only through memory::supersede, never touches pinned records; every change lands as a memory::item-changed event shipped

The split is the point: consolidation can be installed, stopped, or removed without touching stored memory, and this worker never grows a scheduler.

Boundaries

Context-manager compresses one history for one turn; this worker is the durable cross-session sibling its spec reserves (see tech-specs/2026-06-agentic/memory.md). Recall fuses BM25 with a semantic signal when router::embed has an embed-capable provider; memory::recall.retrieval names the mode either way. Consolidation belongs to the memory-consolidate sibling, not here.

Skills

API reference (JSON)

agent-api-reference.json
{
  "functions": [
    {
      "description": "Create a named memory bank: an isolated scope of rules and memories, e.g. one per project or persona. Idempotent; sessions select it via metadata `memory_bank`.",
      "metadata": {},
      "name": "memory::bank::create",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "description": {
            "default": null,
            "description": "Human description shown in listings and the console.",
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "description": "Bank name, `[a-z0-9][a-z0-9_-]{0,63}` (it becomes a folder name).",
            "type": "string"
          }
        },
        "required": [
          "name"
        ],
        "title": "BankCreateRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "BankInfo": {
            "description": "Summary row for `memory::bank::list` and the console page.",
            "properties": {
              "description": {
                "default": "",
                "type": "string"
              },
              "memories": {
                "description": "Live memory (memory) count.",
                "format": "uint",
                "minimum": 0,
                "type": "integer"
              },
              "name": {
                "type": "string"
              },
              "pinned": {
                "format": "uint",
                "minimum": 0,
                "type": "integer"
              },
              "rules": {
                "description": "Rule (always-injected markdown) count.",
                "format": "uint",
                "minimum": 0,
                "type": "integer"
              }
            },
            "required": [
              "memories",
              "name",
              "pinned",
              "rules"
            ],
            "type": "object"
          }
        },
        "properties": {
          "bank": {
            "$ref": "#/definitions/BankInfo"
          },
          "created": {
            "description": "False when the bank already existed (create is idempotent).",
            "type": "boolean"
          }
        },
        "required": [
          "bank",
          "created"
        ],
        "title": "BankCreateResponse",
        "type": "object"
      }
    },
    {
      "description": "Delete a memory bank: the folder moves to the store's .trash, recoverable by hand.",
      "metadata": {},
      "name": "memory::bank::delete",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "name": {
            "type": "string"
          }
        },
        "required": [
          "name"
        ],
        "title": "BankDeleteRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "trashed_to": {
            "description": "Where the bank folder was moved (under the store's `.trash/`).",
            "type": "string"
          }
        },
        "required": [
          "ok",
          "trashed_to"
        ],
        "title": "BankDeleteResponse",
        "type": "object"
      }
    },
    {
      "description": "List every memory bank with memory/rule/pin counts.",
      "metadata": {},
      "name": "memory::bank::list",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "title": "BankListRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "BankInfo": {
            "description": "Summary row for `memory::bank::list` and the console page.",
            "properties": {
              "description": {
                "default": "",
                "type": "string"
              },
              "memories": {
                "description": "Live memory (memory) count.",
                "format": "uint",
                "minimum": 0,
                "type": "integer"
              },
              "name": {
                "type": "string"
              },
              "pinned": {
                "format": "uint",
                "minimum": 0,
                "type": "integer"
              },
              "rules": {
                "description": "Rule (always-injected markdown) count.",
                "format": "uint",
                "minimum": 0,
                "type": "integer"
              }
            },
            "required": [
              "memories",
              "name",
              "pinned",
              "rules"
            ],
            "type": "object"
          }
        },
        "properties": {
          "banks": {
            "items": {
              "$ref": "#/definitions/BankInfo"
            },
            "type": "array"
          }
        },
        "required": [
          "banks"
        ],
        "title": "BankListResponse",
        "type": "object"
      }
    },
    {
      "description": "Delete a memory (tombstone: sets invalid_at). It leaves recall immediately but stays on disk, readable with include_superseded.",
      "metadata": {},
      "name": "memory::delete",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "bank": {
            "default": null,
            "description": "Bank; omitted: the calling session's bank, else the configured default.",
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "type": "string"
          }
        },
        "required": [
          "id"
        ],
        "title": "DeleteRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "Confidence": {
            "description": "How a memory entered the store.",
            "oneOf": [
              {
                "description": "Stated directly in the source conversation.",
                "enum": [
                  "extracted"
                ],
                "type": "string"
              },
              {
                "description": "Derived by the extraction model rather than stated verbatim.",
                "enum": [
                  "inferred"
                ],
                "type": "string"
              },
              {
                "description": "Saved explicitly by an agent or a human (highest trust).",
                "enum": [
                  "stated"
                ],
                "type": "string"
              }
            ]
          },
          "Memory": {
            "description": "One memory item. Serialized whole as a `memories.jsonl` line; replay is last-wins by `id`, so an update appends a full record with a bumped `revision` and a delete appends a tombstoned record (`invalid_at` set) — history is never destroyed, only superseded.",
            "properties": {
              "confidence": {
                "$ref": "#/definitions/Confidence"
              },
              "corroboration": {
                "default": 0,
                "description": "Times this memory was independently re-observed. Boosts recall rank.",
                "format": "uint32",
                "minimum": 0,
                "type": "integer"
              },
              "created_at": {
                "description": "Milliseconds since epoch.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "entities": {
                "default": [],
                "description": "Entity handles used as an exact-match retrieval signal.",
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "id": {
                "description": "Content fingerprint (`fp` + FNV-1a of the normalized text), so re-ingesting the same source reinforces instead of duplicating.",
                "type": "string"
              },
              "invalid_at": {
                "description": "Set when the memory stopped being true (superseded or deleted). The record stays on disk and remains queryable with `include_superseded: true`.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "pinned": {
                "default": false,
                "description": "Pinned memories are never touched by any automatic path (consolidation, decay); only an explicit `memory::pin`/`memory::update` changes them.",
                "type": "boolean"
              },
              "revision": {
                "default": 0,
                "description": "Bumped on every appended revision of this id; replay keeps the highest.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "source": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/Provenance"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "stated_at": {
                "description": "When the fact was last STATED (created, re-observed, text edited). Unlike `updated_at`, pin/tag/entity edits never bump it, so consolidation can order \"which statement is current\" by it. Legacy records load as None.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "superseded_by": {
                "description": "Memory id that replaced this one, when superseded by content.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "tags": {
                "default": [],
                "description": "Topical labels for filtering WITHIN a bank (\"iii\", \"workers\", \"billing\") — organization, not ranking. Normalized lowercase, capped like entities. Old records without the field load as untagged.",
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "text": {
                "type": "string"
              },
              "updated_at": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              }
            },
            "required": [
              "confidence",
              "created_at",
              "id",
              "text",
              "updated_at"
            ],
            "type": "object"
          },
          "Provenance": {
            "description": "Where a memory came from. Every extracted memory points back into session-manager; nothing in memory duplicates the transcript store.",
            "properties": {
              "agent": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "entry_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "session_id": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "type": "object"
          }
        },
        "description": "Shared response for update/delete/pin.",
        "properties": {
          "memory": {
            "$ref": "#/definitions/Memory"
          }
        },
        "required": [
          "memory"
        ],
        "title": "MemoryResponse",
        "type": "object"
      }
    },
    {
      "description": "Self-test memory end to end: data-dir writability, a scratch-bank write/read/trash roundtrip, and sibling reachability (router, session-manager). Reports degraded states explicitly, not a bare process-up health.",
      "metadata": {},
      "name": "memory::doctor",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "title": "DoctorRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "DoctorCheck": {
            "properties": {
              "detail": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "ok": {
                "type": "boolean"
              }
            },
            "required": [
              "detail",
              "name",
              "ok"
            ],
            "type": "object"
          }
        },
        "properties": {
          "checks": {
            "items": {
              "$ref": "#/definitions/DoctorCheck"
            },
            "type": "array"
          },
          "ok": {
            "description": "True only when every REQUIRED check passed (sibling reachability is reported but advisory).",
            "type": "boolean"
          }
        },
        "required": [
          "checks",
          "ok"
        ],
        "title": "DoctorResponse",
        "type": "object"
      }
    },
    {
      "description": "Internal: queue-delivered extraction job — errors propagate so the queue retries and dead-letters instead of losing the pass.",
      "metadata": {
        "internal": true
      },
      "name": "memory::extract-job",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "One durable extraction job (the `data` of a queue message).",
        "properties": {
          "bank": {
            "description": "The bank the turn was injected with. Absent: resolved when the job runs (the worker never saw the turn, or the job predates this).",
            "type": [
              "string",
              "null"
            ]
          },
          "session_id": {
            "type": "string"
          },
          "skip": {
            "description": "The turn ran without memory (an invalid or deleted bank): the job only steps the cursor past it.",
            "type": "boolean"
          },
          "until": {
            "description": "The turn's last user/assistant entry: the pass reads no further.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "session_id"
        ],
        "title": "ExtractJobInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "ok": {
            "type": "boolean"
          }
        },
        "required": [
          "ok"
        ],
        "title": "AckResponse",
        "type": "object"
      }
    },
    {
      "description": "Fetch one memory by id, including superseded/tombstoned records.",
      "metadata": {},
      "name": "memory::get",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "bank": {
            "default": null,
            "description": "Bank; omitted: the calling session's bank, else the configured default.",
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "type": "string"
          }
        },
        "required": [
          "id"
        ],
        "title": "GetRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "Confidence": {
            "description": "How a memory entered the store.",
            "oneOf": [
              {
                "description": "Stated directly in the source conversation.",
                "enum": [
                  "extracted"
                ],
                "type": "string"
              },
              {
                "description": "Derived by the extraction model rather than stated verbatim.",
                "enum": [
                  "inferred"
                ],
                "type": "string"
              },
              {
                "description": "Saved explicitly by an agent or a human (highest trust).",
                "enum": [
                  "stated"
                ],
                "type": "string"
              }
            ]
          },
          "Memory": {
            "description": "One memory item. Serialized whole as a `memories.jsonl` line; replay is last-wins by `id`, so an update appends a full record with a bumped `revision` and a delete appends a tombstoned record (`invalid_at` set) — history is never destroyed, only superseded.",
            "properties": {
              "confidence": {
                "$ref": "#/definitions/Confidence"
              },
              "corroboration": {
                "default": 0,
                "description": "Times this memory was independently re-observed. Boosts recall rank.",
                "format": "uint32",
                "minimum": 0,
                "type": "integer"
              },
              "created_at": {
                "description": "Milliseconds since epoch.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "entities": {
                "default": [],
                "description": "Entity handles used as an exact-match retrieval signal.",
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "id": {
                "description": "Content fingerprint (`fp` + FNV-1a of the normalized text), so re-ingesting the same source reinforces instead of duplicating.",
                "type": "string"
              },
              "invalid_at": {
                "description": "Set when the memory stopped being true (superseded or deleted). The record stays on disk and remains queryable with `include_superseded: true`.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "pinned": {
                "default": false,
                "description": "Pinned memories are never touched by any automatic path (consolidation, decay); only an explicit `memory::pin`/`memory::update` changes them.",
                "type": "boolean"
              },
              "revision": {
                "default": 0,
                "description": "Bumped on every appended revision of this id; replay keeps the highest.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "source": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/Provenance"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "stated_at": {
                "description": "When the fact was last STATED (created, re-observed, text edited). Unlike `updated_at`, pin/tag/entity edits never bump it, so consolidation can order \"which statement is current\" by it. Legacy records load as None.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "superseded_by": {
                "description": "Memory id that replaced this one, when superseded by content.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "tags": {
                "default": [],
                "description": "Topical labels for filtering WITHIN a bank (\"iii\", \"workers\", \"billing\") — organization, not ranking. Normalized lowercase, capped like entities. Old records without the field load as untagged.",
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "text": {
                "type": "string"
              },
              "updated_at": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              }
            },
            "required": [
              "confidence",
              "created_at",
              "id",
              "text",
              "updated_at"
            ],
            "type": "object"
          },
          "Provenance": {
            "description": "Where a memory came from. Every extracted memory points back into session-manager; nothing in memory duplicates the transcript store.",
            "properties": {
              "agent": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "entry_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "session_id": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "type": "object"
          }
        },
        "properties": {
          "memory": {
            "$ref": "#/definitions/Memory"
          }
        },
        "required": [
          "memory"
        ],
        "title": "GetResponse",
        "type": "object"
      }
    },
    {
      "description": "Internal: harness pre-generate hook — injects the session bank's rules into the system prompt and recalled memories as one appended message. Never denies.",
      "metadata": {
        "internal": true
      },
      "name": "memory::hook::pre-generate",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "GenerateInput": {
            "properties": {
              "messages": {
                "default": null,
                "description": "Transcript messages as assembled so far — the window this step sends, persisted notices (earlier rules updates included) replayed in place (schema-free: shapes belong to the router)."
              },
              "system_prompt": {
                "default": "",
                "type": "string"
              }
            },
            "type": "object"
          }
        },
        "description": "Envelope the harness posts to `pre-generate` hooks. Only the fields this worker reads are typed; everything else is ignored.",
        "properties": {
          "generate": {
            "anyOf": [
              {
                "$ref": "#/definitions/GenerateInput"
              },
              {
                "type": "null"
              }
            ]
          },
          "metadata": {
            "default": null,
            "description": "Turn metadata (`harness::send` options.metadata); `memory_bank` here overrides the session-level selection for this turn."
          },
          "session_id": {
            "default": "",
            "type": "string"
          },
          "step": {
            "default": 0,
            "description": "Step within the turn; 0 is the step that opens it.",
            "format": "uint64",
            "minimum": 0,
            "type": "integer"
          },
          "turn_id": {
            "default": null,
            "description": "The turn this step belongs to; its bank is recorded under it.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "title": "PreGenerateInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "Mutations": {
            "properties": {
              "append_messages": {
                "items": true,
                "type": "array"
              },
              "system_prompt": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "append_messages"
            ],
            "type": "object"
          }
        },
        "description": "Hook reply: `continue` with optional mutations (never deny — memory is an enrichment, not a gate).",
        "properties": {
          "annotations": {
            "additionalProperties": true,
            "type": [
              "object",
              "null"
            ]
          },
          "decision": {
            "type": "string"
          },
          "mutations": {
            "anyOf": [
              {
                "$ref": "#/definitions/Mutations"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "decision"
        ],
        "title": "HookResponse",
        "type": "object"
      }
    },
    {
      "description": "List a bank's memories page by page, newest first. `include_superseded` shows history too.",
      "metadata": {},
      "name": "memory::list",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "bank": {
            "default": null,
            "description": "Bank; omitted: the calling session's bank, else the configured default.",
            "type": [
              "string",
              "null"
            ]
          },
          "include_superseded": {
            "default": null,
            "description": "Include superseded/tombstoned records (the history view).",
            "type": [
              "boolean",
              "null"
            ]
          },
          "limit": {
            "default": null,
            "description": "Page size, default 50, max 500.",
            "format": "uint",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          },
          "offset": {
            "default": null,
            "format": "uint",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          },
          "tag": {
            "default": null,
            "description": "Only memories carrying this tag.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "title": "ListRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "Confidence": {
            "description": "How a memory entered the store.",
            "oneOf": [
              {
                "description": "Stated directly in the source conversation.",
                "enum": [
                  "extracted"
                ],
                "type": "string"
              },
              {
                "description": "Derived by the extraction model rather than stated verbatim.",
                "enum": [
                  "inferred"
                ],
                "type": "string"
              },
              {
                "description": "Saved explicitly by an agent or a human (highest trust).",
                "enum": [
                  "stated"
                ],
                "type": "string"
              }
            ]
          },
          "Memory": {
            "description": "One memory item. Serialized whole as a `memories.jsonl` line; replay is last-wins by `id`, so an update appends a full record with a bumped `revision` and a delete appends a tombstoned record (`invalid_at` set) — history is never destroyed, only superseded.",
            "properties": {
              "confidence": {
                "$ref": "#/definitions/Confidence"
              },
              "corroboration": {
                "default": 0,
                "description": "Times this memory was independently re-observed. Boosts recall rank.",
                "format": "uint32",
                "minimum": 0,
                "type": "integer"
              },
              "created_at": {
                "description": "Milliseconds since epoch.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "entities": {
                "default": [],
                "description": "Entity handles used as an exact-match retrieval signal.",
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "id": {
                "description": "Content fingerprint (`fp` + FNV-1a of the normalized text), so re-ingesting the same source reinforces instead of duplicating.",
                "type": "string"
              },
              "invalid_at": {
                "description": "Set when the memory stopped being true (superseded or deleted). The record stays on disk and remains queryable with `include_superseded: true`.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "pinned": {
                "default": false,
                "description": "Pinned memories are never touched by any automatic path (consolidation, decay); only an explicit `memory::pin`/`memory::update` changes them.",
                "type": "boolean"
              },
              "revision": {
                "default": 0,
                "description": "Bumped on every appended revision of this id; replay keeps the highest.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "source": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/Provenance"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "stated_at": {
                "description": "When the fact was last STATED (created, re-observed, text edited). Unlike `updated_at`, pin/tag/entity edits never bump it, so consolidation can order \"which statement is current\" by it. Legacy records load as None.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "superseded_by": {
                "description": "Memory id that replaced this one, when superseded by content.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "tags": {
                "default": [],
                "description": "Topical labels for filtering WITHIN a bank (\"iii\", \"workers\", \"billing\") — organization, not ranking. Normalized lowercase, capped like entities. Old records without the field load as untagged.",
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "text": {
                "type": "string"
              },
              "updated_at": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              }
            },
            "required": [
              "confidence",
              "created_at",
              "id",
              "text",
              "updated_at"
            ],
            "type": "object"
          },
          "Provenance": {
            "description": "Where a memory came from. Every extracted memory points back into session-manager; nothing in memory duplicates the transcript store.",
            "properties": {
              "agent": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "entry_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "session_id": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "type": "object"
          }
        },
        "properties": {
          "memories": {
            "items": {
              "$ref": "#/definitions/Memory"
            },
            "type": "array"
          },
          "total": {
            "format": "uint",
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "memories",
          "total"
        ],
        "title": "ListResponse",
        "type": "object"
      }
    },
    {
      "description": "Internal: hot-reload memory from the authoritative configuration when it changes — reopens the store on a data_dir change and swaps the per-call tuning snapshot otherwise.",
      "metadata": {
        "internal": true,
        "trace_hidden": true
      },
      "name": "memory::on-config-change",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "Internal `memory::on-config-change` trigger payload. The handler re-fetches the authoritative configuration (trusting `new_value` from a discoverable bus function would let any caller inject config).",
        "properties": {
          "id": {
            "default": null,
            "description": "Configuration id that changed (advisory; the handler re-fetches).",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "title": "OnConfigChangeEvent",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "ok": {
            "type": "boolean"
          }
        },
        "required": [
          "ok"
        ],
        "title": "OnConfigChangeResponse",
        "type": "object"
      }
    },
    {
      "description": "Internal: session::deleted handler — drops the session's extraction cursor.",
      "metadata": {
        "internal": true,
        "trace_hidden": true
      },
      "name": "memory::on-session-deleted",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "`session::deleted` payload (the field this worker reads).",
        "properties": {
          "session_id": {
            "default": "",
            "type": "string"
          }
        },
        "title": "SessionDeletedInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "ok": {
            "type": "boolean"
          }
        },
        "required": [
          "ok"
        ],
        "title": "AckResponse",
        "type": "object"
      }
    },
    {
      "description": "Internal: harness turn-completed handler — enqueues one durable extraction job (a single router::complete call) for the finished turn; inline fallback without a queue.",
      "metadata": {
        "internal": true
      },
      "name": "memory::on-turn-completed",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "`harness::turn-completed` payload (the fields this worker reads).",
        "properties": {
          "parent": {
            "default": null,
            "description": "Set on a sub-agent's turn (its live parent link)."
          },
          "parent_session_id": {
            "default": null,
            "description": "Set on a parentless spawn's turn (its display parent).",
            "type": [
              "string",
              "null"
            ]
          },
          "session_id": {
            "default": "",
            "type": "string"
          },
          "turn_id": {
            "default": null,
            "type": [
              "string",
              "null"
            ]
          }
        },
        "title": "TurnCompletedInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "ok": {
            "type": "boolean"
          }
        },
        "required": [
          "ok"
        ],
        "title": "AckResponse",
        "type": "object"
      }
    },
    {
      "description": "Pin or unpin a memory. Pinned memories rank higher in recall and are untouchable by every automatic path.",
      "metadata": {},
      "name": "memory::pin",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "bank": {
            "default": null,
            "description": "Bank; omitted: the calling session's bank, else the configured default.",
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "type": "string"
          },
          "pinned": {
            "type": "boolean"
          }
        },
        "required": [
          "id",
          "pinned"
        ],
        "title": "PinRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "Confidence": {
            "description": "How a memory entered the store.",
            "oneOf": [
              {
                "description": "Stated directly in the source conversation.",
                "enum": [
                  "extracted"
                ],
                "type": "string"
              },
              {
                "description": "Derived by the extraction model rather than stated verbatim.",
                "enum": [
                  "inferred"
                ],
                "type": "string"
              },
              {
                "description": "Saved explicitly by an agent or a human (highest trust).",
                "enum": [
                  "stated"
                ],
                "type": "string"
              }
            ]
          },
          "Memory": {
            "description": "One memory item. Serialized whole as a `memories.jsonl` line; replay is last-wins by `id`, so an update appends a full record with a bumped `revision` and a delete appends a tombstoned record (`invalid_at` set) — history is never destroyed, only superseded.",
            "properties": {
              "confidence": {
                "$ref": "#/definitions/Confidence"
              },
              "corroboration": {
                "default": 0,
                "description": "Times this memory was independently re-observed. Boosts recall rank.",
                "format": "uint32",
                "minimum": 0,
                "type": "integer"
              },
              "created_at": {
                "description": "Milliseconds since epoch.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "entities": {
                "default": [],
                "description": "Entity handles used as an exact-match retrieval signal.",
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "id": {
                "description": "Content fingerprint (`fp` + FNV-1a of the normalized text), so re-ingesting the same source reinforces instead of duplicating.",
                "type": "string"
              },
              "invalid_at": {
                "description": "Set when the memory stopped being true (superseded or deleted). The record stays on disk and remains queryable with `include_superseded: true`.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "pinned": {
                "default": false,
                "description": "Pinned memories are never touched by any automatic path (consolidation, decay); only an explicit `memory::pin`/`memory::update` changes them.",
                "type": "boolean"
              },
              "revision": {
                "default": 0,
                "description": "Bumped on every appended revision of this id; replay keeps the highest.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "source": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/Provenance"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "stated_at": {
                "description": "When the fact was last STATED (created, re-observed, text edited). Unlike `updated_at`, pin/tag/entity edits never bump it, so consolidation can order \"which statement is current\" by it. Legacy records load as None.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "superseded_by": {
                "description": "Memory id that replaced this one, when superseded by content.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "tags": {
                "default": [],
                "description": "Topical labels for filtering WITHIN a bank (\"iii\", \"workers\", \"billing\") — organization, not ranking. Normalized lowercase, capped like entities. Old records without the field load as untagged.",
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "text": {
                "type": "string"
              },
              "updated_at": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              }
            },
            "required": [
              "confidence",
              "created_at",
              "id",
              "text",
              "updated_at"
            ],
            "type": "object"
          },
          "Provenance": {
            "description": "Where a memory came from. Every extracted memory points back into session-manager; nothing in memory duplicates the transcript store.",
            "properties": {
              "agent": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "entry_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "session_id": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "type": "object"
          }
        },
        "description": "Shared response for update/delete/pin.",
        "properties": {
          "memory": {
            "$ref": "#/definitions/Memory"
          }
        },
        "required": [
          "memory"
        ],
        "title": "MemoryResponse",
        "type": "object"
      }
    },
    {
      "description": "Preview the memory injection for a hypothetical chat message: the exact system-prompt memory section a new session gets (rules, budgets, truncation markers; running sessions receive changes as an appended update), the memories the turn would be handed (post ambient floor and token budget), and the appended message verbatim. Runs the pre-generate hook's own code.",
      "metadata": {},
      "name": "memory::preview",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "bank": {
            "default": null,
            "description": "Bank to preview; omitted: the calling session's bank, else the configured default.",
            "type": [
              "string",
              "null"
            ]
          },
          "query": {
            "description": "The hypothetical user message (what someone would type in chat).",
            "type": "string"
          }
        },
        "required": [
          "query"
        ],
        "title": "PreviewRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "Confidence": {
            "description": "How a memory entered the store.",
            "oneOf": [
              {
                "description": "Stated directly in the source conversation.",
                "enum": [
                  "extracted"
                ],
                "type": "string"
              },
              {
                "description": "Derived by the extraction model rather than stated verbatim.",
                "enum": [
                  "inferred"
                ],
                "type": "string"
              },
              {
                "description": "Saved explicitly by an agent or a human (highest trust).",
                "enum": [
                  "stated"
                ],
                "type": "string"
              }
            ]
          },
          "Memory": {
            "description": "One memory item. Serialized whole as a `memories.jsonl` line; replay is last-wins by `id`, so an update appends a full record with a bumped `revision` and a delete appends a tombstoned record (`invalid_at` set) — history is never destroyed, only superseded.",
            "properties": {
              "confidence": {
                "$ref": "#/definitions/Confidence"
              },
              "corroboration": {
                "default": 0,
                "description": "Times this memory was independently re-observed. Boosts recall rank.",
                "format": "uint32",
                "minimum": 0,
                "type": "integer"
              },
              "created_at": {
                "description": "Milliseconds since epoch.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "entities": {
                "default": [],
                "description": "Entity handles used as an exact-match retrieval signal.",
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "id": {
                "description": "Content fingerprint (`fp` + FNV-1a of the normalized text), so re-ingesting the same source reinforces instead of duplicating.",
                "type": "string"
              },
              "invalid_at": {
                "description": "Set when the memory stopped being true (superseded or deleted). The record stays on disk and remains queryable with `include_superseded: true`.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "pinned": {
                "default": false,
                "description": "Pinned memories are never touched by any automatic path (consolidation, decay); only an explicit `memory::pin`/`memory::update` changes them.",
                "type": "boolean"
              },
              "revision": {
                "default": 0,
                "description": "Bumped on every appended revision of this id; replay keeps the highest.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "source": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/Provenance"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "stated_at": {
                "description": "When the fact was last STATED (created, re-observed, text edited). Unlike `updated_at`, pin/tag/entity edits never bump it, so consolidation can order \"which statement is current\" by it. Legacy records load as None.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "superseded_by": {
                "description": "Memory id that replaced this one, when superseded by content.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "tags": {
                "default": [],
                "description": "Topical labels for filtering WITHIN a bank (\"iii\", \"workers\", \"billing\") — organization, not ranking. Normalized lowercase, capped like entities. Old records without the field load as untagged.",
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "text": {
                "type": "string"
              },
              "updated_at": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              }
            },
            "required": [
              "confidence",
              "created_at",
              "id",
              "text",
              "updated_at"
            ],
            "type": "object"
          },
          "PreviewMemory": {
            "properties": {
              "memory": {
                "$ref": "#/definitions/Memory"
              },
              "score": {
                "description": "Recall score; 0.0 for memories added by the ambient floor.",
                "format": "float",
                "type": "number"
              }
            },
            "required": [
              "memory",
              "score"
            ],
            "type": "object"
          },
          "Provenance": {
            "description": "Where a memory came from. Every extracted memory points back into session-manager; nothing in memory duplicates the transcript store.",
            "properties": {
              "agent": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "entry_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "session_id": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "type": "object"
          }
        },
        "properties": {
          "bank": {
            "type": "string"
          },
          "memories": {
            "description": "Memories the turn would be handed, post ambient floor and token budget, in injection order.",
            "items": {
              "$ref": "#/definitions/PreviewMemory"
            },
            "type": "array"
          },
          "message": {
            "description": "The appended `<memory>` message body, verbatim; absent when no memory fits the budget.",
            "type": [
              "string",
              "null"
            ]
          },
          "retrieval": {
            "description": "Retrieval mode that ran (`bm25-entity` or `bm25-entity-semantic`; `none` when memories are not injected).",
            "type": "string"
          },
          "rules": {
            "description": "Rules included, and whether any were cut by `max_rule_chars`.",
            "format": "uint",
            "minimum": 0,
            "type": "integer"
          },
          "rules_truncated": {
            "type": "boolean"
          },
          "system_prompt_section": {
            "description": "The memory section appended to the system prompt (ambient header + rules), exactly as injected — truncation markers included.",
            "type": "string"
          }
        },
        "required": [
          "bank",
          "memories",
          "retrieval",
          "rules",
          "rules_truncated",
          "system_prompt_section"
        ],
        "title": "PreviewResponse",
        "type": "object"
      }
    },
    {
      "description": "Search a bank's memories relevant to a query (BM25 + entities + corroboration + recency; no LLM). The same scorer the pre-generate hook uses — call it to preview an injection. mode lexical/semantic returns one raw arm (plain BM25, or cosine).",
      "metadata": {},
      "name": "memory::recall",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "RecallMode": {
            "enum": [
              "hybrid",
              "lexical",
              "semantic"
            ],
            "type": "string"
          }
        },
        "properties": {
          "bank": {
            "default": null,
            "description": "Bank to search; omitted: the calling session's bank, else the configured default.",
            "type": [
              "string",
              "null"
            ]
          },
          "include_superseded": {
            "default": null,
            "description": "Also rank superseded/tombstoned records (the history view).",
            "type": [
              "boolean",
              "null"
            ]
          },
          "limit": {
            "default": null,
            "description": "Max memories returned (default: the configured recall_limit).",
            "format": "uint",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          },
          "mode": {
            "allOf": [
              {
                "$ref": "#/definitions/RecallMode"
              }
            ],
            "description": "`hybrid` (default) is the fused scorer the hook uses. `lexical` and `semantic` return ONE raw arm (plain BM25, or cosine as the score) for callers that fuse arms themselves — consolidation interleaves both so a near-duplicate is never buried by the fused rank."
          },
          "query": {
            "type": "string"
          },
          "tag": {
            "default": null,
            "description": "Only rank memories carrying this tag.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "query"
        ],
        "title": "RecallRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "Confidence": {
            "description": "How a memory entered the store.",
            "oneOf": [
              {
                "description": "Stated directly in the source conversation.",
                "enum": [
                  "extracted"
                ],
                "type": "string"
              },
              {
                "description": "Derived by the extraction model rather than stated verbatim.",
                "enum": [
                  "inferred"
                ],
                "type": "string"
              },
              {
                "description": "Saved explicitly by an agent or a human (highest trust).",
                "enum": [
                  "stated"
                ],
                "type": "string"
              }
            ]
          },
          "Memory": {
            "description": "One memory item. Serialized whole as a `memories.jsonl` line; replay is last-wins by `id`, so an update appends a full record with a bumped `revision` and a delete appends a tombstoned record (`invalid_at` set) — history is never destroyed, only superseded.",
            "properties": {
              "confidence": {
                "$ref": "#/definitions/Confidence"
              },
              "corroboration": {
                "default": 0,
                "description": "Times this memory was independently re-observed. Boosts recall rank.",
                "format": "uint32",
                "minimum": 0,
                "type": "integer"
              },
              "created_at": {
                "description": "Milliseconds since epoch.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "entities": {
                "default": [],
                "description": "Entity handles used as an exact-match retrieval signal.",
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "id": {
                "description": "Content fingerprint (`fp` + FNV-1a of the normalized text), so re-ingesting the same source reinforces instead of duplicating.",
                "type": "string"
              },
              "invalid_at": {
                "description": "Set when the memory stopped being true (superseded or deleted). The record stays on disk and remains queryable with `include_superseded: true`.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "pinned": {
                "default": false,
                "description": "Pinned memories are never touched by any automatic path (consolidation, decay); only an explicit `memory::pin`/`memory::update` changes them.",
                "type": "boolean"
              },
              "revision": {
                "default": 0,
                "description": "Bumped on every appended revision of this id; replay keeps the highest.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "source": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/Provenance"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "stated_at": {
                "description": "When the fact was last STATED (created, re-observed, text edited). Unlike `updated_at`, pin/tag/entity edits never bump it, so consolidation can order \"which statement is current\" by it. Legacy records load as None.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "superseded_by": {
                "description": "Memory id that replaced this one, when superseded by content.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "tags": {
                "default": [],
                "description": "Topical labels for filtering WITHIN a bank (\"iii\", \"workers\", \"billing\") — organization, not ranking. Normalized lowercase, capped like entities. Old records without the field load as untagged.",
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "text": {
                "type": "string"
              },
              "updated_at": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              }
            },
            "required": [
              "confidence",
              "created_at",
              "id",
              "text",
              "updated_at"
            ],
            "type": "object"
          },
          "Provenance": {
            "description": "Where a memory came from. Every extracted memory points back into session-manager; nothing in memory duplicates the transcript store.",
            "properties": {
              "agent": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "entry_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "session_id": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "type": "object"
          },
          "ScoredMemory": {
            "properties": {
              "memory": {
                "$ref": "#/definitions/Memory"
              },
              "score": {
                "format": "float",
                "type": "number"
              }
            },
            "required": [
              "memory",
              "score"
            ],
            "type": "object"
          }
        },
        "properties": {
          "bank": {
            "type": "string"
          },
          "memories": {
            "items": {
              "$ref": "#/definitions/ScoredMemory"
            },
            "type": "array"
          },
          "retrieval": {
            "description": "Retrieval mode actually used — degradation is explicit, never silent. `hybrid`: `bm25-entity`, or `bm25-entity-semantic` when the query was embedded through `router::embed`. `lexical`: `lexical`. `semantic`: `semantic`, or `semantic-unavailable` (empty result — NOT \"no matches\") when the query could not be embedded.",
            "type": "string"
          }
        },
        "required": [
          "bank",
          "memories",
          "retrieval"
        ],
        "title": "RecallResponse",
        "type": "object"
      }
    },
    {
      "description": "Drop all in-RAM state and reload every bank from disk — the recovery hatch after editing bank files by hand.",
      "metadata": {},
      "name": "memory::reload",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "title": "ReloadRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "banks": {
            "format": "uint",
            "minimum": 0,
            "type": "integer"
          },
          "ok": {
            "type": "boolean"
          }
        },
        "required": [
          "banks",
          "ok"
        ],
        "title": "ReloadResponse",
        "type": "object"
      }
    },
    {
      "description": "List a bank's rules (markdown, injected whole into the system prompt on every turn). Stored as plain files under the bank's rules/ folder; editing them by hand is equivalent.",
      "metadata": {},
      "name": "memory::rule::list",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "bank": {
            "default": null,
            "description": "Bank whose rules to list; omitted: the calling session's bank, else the configured default.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "title": "RuleListRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "Rule": {
            "description": "One markdown rule: always injected whole into the system prompt for sessions using its bank. Stored as `rules/<name>.md` — open it in any editor.",
            "properties": {
              "content": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "updated_at": {
                "description": "Milliseconds since epoch (file mtime).",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              }
            },
            "required": [
              "content",
              "name",
              "updated_at"
            ],
            "type": "object"
          }
        },
        "properties": {
          "bank": {
            "type": "string"
          },
          "rules": {
            "items": {
              "$ref": "#/definitions/Rule"
            },
            "type": "array"
          }
        },
        "required": [
          "bank",
          "rules"
        ],
        "title": "RuleListResponse",
        "type": "object"
      }
    },
    {
      "description": "Create or replace one rule (atomic write; empty content removes it). Rules are plain markdown files under the bank's rules/ folder.",
      "metadata": {},
      "name": "memory::rule::set",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "bank": {
            "default": null,
            "description": "Bank to write into; omitted: the calling session's bank, else the configured default. Created on first use.",
            "type": [
              "string",
              "null"
            ]
          },
          "content": {
            "description": "Markdown content. Empty removes the rule.",
            "type": "string"
          },
          "name": {
            "description": "Rule name, `[a-z0-9][a-z0-9_-]{0,63}` (it becomes `<name>.md`).",
            "type": "string"
          }
        },
        "required": [
          "content",
          "name"
        ],
        "title": "RuleSetRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "exists": {
            "description": "False when the empty content removed the rule.",
            "type": "boolean"
          },
          "ok": {
            "type": "boolean"
          }
        },
        "required": [
          "exists",
          "ok"
        ],
        "title": "RuleSetResponse",
        "type": "object"
      }
    },
    {
      "description": "Save one memory explicitly. Content-fingerprinted: re-saving the same text reinforces the existing memory instead of duplicating it. Use when the user says `remember this`.",
      "metadata": {},
      "name": "memory::save",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "bank": {
            "default": null,
            "description": "Target bank; omitted: the calling session's bank, else the configured default.",
            "type": [
              "string",
              "null"
            ]
          },
          "entities": {
            "default": [],
            "description": "Entity handles (people/projects/tools) used as a retrieval signal.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "pinned": {
            "default": false,
            "type": "boolean"
          },
          "session_id": {
            "default": null,
            "description": "Provenance session, when saved on behalf of a conversation.",
            "type": [
              "string",
              "null"
            ]
          },
          "tags": {
            "default": [],
            "description": "Topical labels for filtering within the bank (organization, not ranking).",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "text": {
            "description": "The memory, one self-contained sentence.",
            "type": "string"
          }
        },
        "required": [
          "text"
        ],
        "title": "SaveRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "Confidence": {
            "description": "How a memory entered the store.",
            "oneOf": [
              {
                "description": "Stated directly in the source conversation.",
                "enum": [
                  "extracted"
                ],
                "type": "string"
              },
              {
                "description": "Derived by the extraction model rather than stated verbatim.",
                "enum": [
                  "inferred"
                ],
                "type": "string"
              },
              {
                "description": "Saved explicitly by an agent or a human (highest trust).",
                "enum": [
                  "stated"
                ],
                "type": "string"
              }
            ]
          },
          "Memory": {
            "description": "One memory item. Serialized whole as a `memories.jsonl` line; replay is last-wins by `id`, so an update appends a full record with a bumped `revision` and a delete appends a tombstoned record (`invalid_at` set) — history is never destroyed, only superseded.",
            "properties": {
              "confidence": {
                "$ref": "#/definitions/Confidence"
              },
              "corroboration": {
                "default": 0,
                "description": "Times this memory was independently re-observed. Boosts recall rank.",
                "format": "uint32",
                "minimum": 0,
                "type": "integer"
              },
              "created_at": {
                "description": "Milliseconds since epoch.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "entities": {
                "default": [],
                "description": "Entity handles used as an exact-match retrieval signal.",
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "id": {
                "description": "Content fingerprint (`fp` + FNV-1a of the normalized text), so re-ingesting the same source reinforces instead of duplicating.",
                "type": "string"
              },
              "invalid_at": {
                "description": "Set when the memory stopped being true (superseded or deleted). The record stays on disk and remains queryable with `include_superseded: true`.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "pinned": {
                "default": false,
                "description": "Pinned memories are never touched by any automatic path (consolidation, decay); only an explicit `memory::pin`/`memory::update` changes them.",
                "type": "boolean"
              },
              "revision": {
                "default": 0,
                "description": "Bumped on every appended revision of this id; replay keeps the highest.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "source": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/Provenance"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "stated_at": {
                "description": "When the fact was last STATED (created, re-observed, text edited). Unlike `updated_at`, pin/tag/entity edits never bump it, so consolidation can order \"which statement is current\" by it. Legacy records load as None.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "superseded_by": {
                "description": "Memory id that replaced this one, when superseded by content.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "tags": {
                "default": [],
                "description": "Topical labels for filtering WITHIN a bank (\"iii\", \"workers\", \"billing\") — organization, not ranking. Normalized lowercase, capped like entities. Old records without the field load as untagged.",
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "text": {
                "type": "string"
              },
              "updated_at": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              }
            },
            "required": [
              "confidence",
              "created_at",
              "id",
              "text",
              "updated_at"
            ],
            "type": "object"
          },
          "Provenance": {
            "description": "Where a memory came from. Every extracted memory points back into session-manager; nothing in memory duplicates the transcript store.",
            "properties": {
              "agent": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "entry_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "session_id": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "type": "object"
          }
        },
        "properties": {
          "created": {
            "description": "False when the text fingerprint matched an existing memory (it was reinforced instead).",
            "type": "boolean"
          },
          "memory": {
            "$ref": "#/definitions/Memory"
          }
        },
        "required": [
          "created",
          "memory"
        ],
        "title": "SaveResponse",
        "type": "object"
      }
    },
    {
      "description": "Retire one memory in favor of another: tombstone with a superseded_by pointer, never a plain delete. The consolidation seam; pinned memories cannot be superseded. reinforce makes it a merge (the non-pinned survivor absorbs the retired record's observations); reason is carried on the item-changed events.",
      "metadata": {},
      "name": "memory::supersede",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "bank": {
            "default": null,
            "description": "Bank; omitted: the calling session's bank, else the configured default.",
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "description": "Memory to retire.",
            "type": "string"
          },
          "reason": {
            "default": null,
            "description": "Why — carried on the `memory::item-changed` events this call emits (not persisted on the record). Trimmed, capped at 500 chars.",
            "type": [
              "string",
              "null"
            ]
          },
          "reinforce": {
            "default": false,
            "description": "Merge semantics: the survivor absorbs the retired record's observations (corroboration += retired + 1) in the same call. A pinned survivor is never written. Default false (a state change: the new record replaces the old, nothing to absorb).",
            "type": "boolean"
          },
          "superseded_by": {
            "description": "Live memory that replaces it.",
            "type": "string"
          }
        },
        "required": [
          "id",
          "superseded_by"
        ],
        "title": "SupersedeRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "Confidence": {
            "description": "How a memory entered the store.",
            "oneOf": [
              {
                "description": "Stated directly in the source conversation.",
                "enum": [
                  "extracted"
                ],
                "type": "string"
              },
              {
                "description": "Derived by the extraction model rather than stated verbatim.",
                "enum": [
                  "inferred"
                ],
                "type": "string"
              },
              {
                "description": "Saved explicitly by an agent or a human (highest trust).",
                "enum": [
                  "stated"
                ],
                "type": "string"
              }
            ]
          },
          "Memory": {
            "description": "One memory item. Serialized whole as a `memories.jsonl` line; replay is last-wins by `id`, so an update appends a full record with a bumped `revision` and a delete appends a tombstoned record (`invalid_at` set) — history is never destroyed, only superseded.",
            "properties": {
              "confidence": {
                "$ref": "#/definitions/Confidence"
              },
              "corroboration": {
                "default": 0,
                "description": "Times this memory was independently re-observed. Boosts recall rank.",
                "format": "uint32",
                "minimum": 0,
                "type": "integer"
              },
              "created_at": {
                "description": "Milliseconds since epoch.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "entities": {
                "default": [],
                "description": "Entity handles used as an exact-match retrieval signal.",
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "id": {
                "description": "Content fingerprint (`fp` + FNV-1a of the normalized text), so re-ingesting the same source reinforces instead of duplicating.",
                "type": "string"
              },
              "invalid_at": {
                "description": "Set when the memory stopped being true (superseded or deleted). The record stays on disk and remains queryable with `include_superseded: true`.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "pinned": {
                "default": false,
                "description": "Pinned memories are never touched by any automatic path (consolidation, decay); only an explicit `memory::pin`/`memory::update` changes them.",
                "type": "boolean"
              },
              "revision": {
                "default": 0,
                "description": "Bumped on every appended revision of this id; replay keeps the highest.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "source": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/Provenance"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "stated_at": {
                "description": "When the fact was last STATED (created, re-observed, text edited). Unlike `updated_at`, pin/tag/entity edits never bump it, so consolidation can order \"which statement is current\" by it. Legacy records load as None.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "superseded_by": {
                "description": "Memory id that replaced this one, when superseded by content.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "tags": {
                "default": [],
                "description": "Topical labels for filtering WITHIN a bank (\"iii\", \"workers\", \"billing\") — organization, not ranking. Normalized lowercase, capped like entities. Old records without the field load as untagged.",
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "text": {
                "type": "string"
              },
              "updated_at": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              }
            },
            "required": [
              "confidence",
              "created_at",
              "id",
              "text",
              "updated_at"
            ],
            "type": "object"
          },
          "Provenance": {
            "description": "Where a memory came from. Every extracted memory points back into session-manager; nothing in memory duplicates the transcript store.",
            "properties": {
              "agent": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "entry_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "session_id": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "type": "object"
          }
        },
        "properties": {
          "memory": {
            "allOf": [
              {
                "$ref": "#/definitions/Memory"
              }
            ],
            "description": "The retired record."
          },
          "reinforced": {
            "description": "True when the survivor was reinforced (`reinforce` asked and the survivor is not pinned).",
            "type": "boolean"
          }
        },
        "required": [
          "memory",
          "reinforced"
        ],
        "title": "SupersedeResponse",
        "type": "object"
      }
    },
    {
      "description": "List the tags across a bank's live memories with usage counts, most used first — the filter source for tag-scoped list/recall.",
      "metadata": {},
      "name": "memory::tags",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "bank": {
            "default": null,
            "description": "Bank; omitted: the calling session's bank, else the configured default.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "title": "TagsRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "TagCount": {
            "properties": {
              "count": {
                "format": "uint",
                "minimum": 0,
                "type": "integer"
              },
              "tag": {
                "type": "string"
              }
            },
            "required": [
              "count",
              "tag"
            ],
            "type": "object"
          }
        },
        "properties": {
          "bank": {
            "type": "string"
          },
          "tags": {
            "items": {
              "$ref": "#/definitions/TagCount"
            },
            "type": "array"
          }
        },
        "required": [
          "bank",
          "tags"
        ],
        "title": "TagsResponse",
        "type": "object"
      }
    },
    {
      "description": "Serve the memory worker's injected console UI assets (content function for its console:script / console:style / console:module triggers).",
      "metadata": {
        "internal": true
      },
      "name": "memory::ui-content",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "Input of the content function: the console asks for one asset by path.",
        "properties": {
          "path": {
            "description": "The asset path from the trigger config (e.g. `state/page.js`).",
            "type": "string"
          }
        },
        "required": [
          "path"
        ],
        "title": "UiContentInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "Output of the content function.",
        "properties": {
          "content": {
            "description": "The asset source, verbatim.",
            "type": "string"
          },
          "content_type": {
            "description": "MIME type the console should serve the asset with.",
            "type": "string"
          }
        },
        "required": [
          "content",
          "content_type"
        ],
        "title": "UiContentResult",
        "type": "object"
      }
    },
    {
      "description": "Revise a memory's text, entities, or pin flag in place (same id, bumped revision; the prior revision stays in the on-disk log).",
      "metadata": {},
      "name": "memory::update",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "bank": {
            "default": null,
            "description": "Bank; omitted: the calling session's bank, else the configured default.",
            "type": [
              "string",
              "null"
            ]
          },
          "entities": {
            "default": null,
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "id": {
            "type": "string"
          },
          "pinned": {
            "default": null,
            "type": [
              "boolean",
              "null"
            ]
          },
          "tags": {
            "default": null,
            "description": "Replace the tag set (empty list clears).",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "text": {
            "default": null,
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id"
        ],
        "title": "UpdateRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "Confidence": {
            "description": "How a memory entered the store.",
            "oneOf": [
              {
                "description": "Stated directly in the source conversation.",
                "enum": [
                  "extracted"
                ],
                "type": "string"
              },
              {
                "description": "Derived by the extraction model rather than stated verbatim.",
                "enum": [
                  "inferred"
                ],
                "type": "string"
              },
              {
                "description": "Saved explicitly by an agent or a human (highest trust).",
                "enum": [
                  "stated"
                ],
                "type": "string"
              }
            ]
          },
          "Memory": {
            "description": "One memory item. Serialized whole as a `memories.jsonl` line; replay is last-wins by `id`, so an update appends a full record with a bumped `revision` and a delete appends a tombstoned record (`invalid_at` set) — history is never destroyed, only superseded.",
            "properties": {
              "confidence": {
                "$ref": "#/definitions/Confidence"
              },
              "corroboration": {
                "default": 0,
                "description": "Times this memory was independently re-observed. Boosts recall rank.",
                "format": "uint32",
                "minimum": 0,
                "type": "integer"
              },
              "created_at": {
                "description": "Milliseconds since epoch.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "entities": {
                "default": [],
                "description": "Entity handles used as an exact-match retrieval signal.",
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "id": {
                "description": "Content fingerprint (`fp` + FNV-1a of the normalized text), so re-ingesting the same source reinforces instead of duplicating.",
                "type": "string"
              },
              "invalid_at": {
                "description": "Set when the memory stopped being true (superseded or deleted). The record stays on disk and remains queryable with `include_superseded: true`.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "pinned": {
                "default": false,
                "description": "Pinned memories are never touched by any automatic path (consolidation, decay); only an explicit `memory::pin`/`memory::update` changes them.",
                "type": "boolean"
              },
              "revision": {
                "default": 0,
                "description": "Bumped on every appended revision of this id; replay keeps the highest.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "source": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/Provenance"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "stated_at": {
                "description": "When the fact was last STATED (created, re-observed, text edited). Unlike `updated_at`, pin/tag/entity edits never bump it, so consolidation can order \"which statement is current\" by it. Legacy records load as None.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "superseded_by": {
                "description": "Memory id that replaced this one, when superseded by content.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "tags": {
                "default": [],
                "description": "Topical labels for filtering WITHIN a bank (\"iii\", \"workers\", \"billing\") — organization, not ranking. Normalized lowercase, capped like entities. Old records without the field load as untagged.",
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "text": {
                "type": "string"
              },
              "updated_at": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              }
            },
            "required": [
              "confidence",
              "created_at",
              "id",
              "text",
              "updated_at"
            ],
            "type": "object"
          },
          "Provenance": {
            "description": "Where a memory came from. Every extracted memory points back into session-manager; nothing in memory duplicates the transcript store.",
            "properties": {
              "agent": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "entry_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "session_id": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "type": "object"
          }
        },
        "description": "Shared response for update/delete/pin.",
        "properties": {
          "memory": {
            "$ref": "#/definitions/Memory"
          }
        },
        "required": [
          "memory"
        ],
        "title": "MemoryResponse",
        "type": "object"
      }
    }
  ],
  "triggers": [
    {
      "description": "A memory bank was created or trashed. Payload: { event_type, bank }.",
      "invocation_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "description": "Config accepted by both trigger types.",
        "properties": {
          "bank": {
            "description": "Only deliver events for this bank.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "title": "BindingConfig",
        "type": "object"
      },
      "metadata": {},
      "name": "memory::bank-changed",
      "return_schema": {}
    },
    {
      "description": "A memory was created, updated, superseded, or deleted in a memory bank. Payload: { event_type, bank, memory, reason? } (reason on consolidation changes, and `redacted: <labels>` when secrets were redacted on save/update). Bind console/live views here.",
      "invocation_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "description": "Config accepted by both trigger types.",
        "properties": {
          "bank": {
            "description": "Only deliver events for this bank.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "title": "BindingConfig",
        "type": "object"
      },
      "metadata": {},
      "name": "memory::item-changed",
      "return_schema": {}
    }
  ]
}

Search the registry

Find workers, kits and executables, or jump to a page.