Skip to main content
Glama
Cloto-dev

CPersona

Official
by Cloto-dev

cpersona

Servidor de memoria MCP

Dale a Claude memoria persistente entre sesiones. Un solo archivo SQLite. 21 herramientas. Sin dependencia de LLM.

License: MIT Python Tests

Inicio rápido · Características · Arquitectura · Todas las herramientas · Libro en Zenn (JP)


Repositorio independiente — Esta es la versión independiente para usar con Claude Desktop, Claude Code y cualquier cliente MCP. Si eres usuario de ClotoCore, utiliza la versión en cloto-mcp-servers en su lugar.

El problema

Claude olvida todo entre sesiones. Cada conversación empieza desde cero: no hay contexto sobre tu proyecto, tus preferencias o lo que discutiste ayer.

cpersona soluciona esto. Es un servidor MCP que almacena recuerdos en un archivo SQLite local y los recupera mediante búsqueda híbrida. Claude te recuerda.

Related MCP server: mcp-memory-graph

Inicio rápido

Requisitos previos: Python 3.10+, Git

1. Instalar cpersona

git clone https://github.com/Cloto-dev/cpersona.git
cd cpersona
python -m venv .venv

# Windows
.venv\Scripts\activate
# macOS / Linux
# source .venv/bin/activate

pip install .

2. Configurar el servidor de embeddings (Recomendado)

La búsqueda híbrida de cpersona funciona mejor con un servidor de embeddings para la similitud vectorial. Recomendamos usar cloto-mcp-servers/embedding con el modelo jina-v5-nano (33M parámetros, 768d, se ejecuta localmente en la CPU):

git clone https://github.com/Cloto-dev/cloto-mcp-servers.git
cd cloto-mcp-servers/servers
pip install ./embedding

Sin un servidor de embeddings, cpersona recurre únicamente a la búsqueda FTS5 + palabras clave. La búsqueda vectorial (la capa de recuperación más potente) estará desactivada.

3. Configurar tu cliente MCP

Claude Desktop — añadir a claude_desktop_config.json:

{
  "mcpServers": {
    "embedding": {
      "command": "/path/to/.venv/bin/python",
      "args": ["/path/to/servers/embedding/server.py"],
      "env": {
        "EMBEDDING_PROVIDER": "onnx_jina_v5_nano",
        "EMBEDDING_HTTP_PORT": "8401"
      }
    },
    "cpersona": {
      "command": "/path/to/.venv/bin/python",
      "args": ["/path/to/cpersona/server.py"],
      "env": {
        "CPERSONA_DB_PATH": "/home/you/.claude/cpersona.db",
        "CPERSONA_EMBEDDING_MODE": "http",
        "CPERSONA_EMBEDDING_URL": "http://127.0.0.1:8401/embed"
      }
    }
  }
}

Windows: usa .venv/Scripts/python.exe y C:/Users/tu_usuario/.claude/cpersona.db

Claude Code:

claude mcp add-json embedding '{"type":"stdio","command":"/path/to/.venv/bin/python","args":["/path/to/servers/embedding/server.py"],"env":{"EMBEDDING_PROVIDER":"onnx_jina_v5_nano","EMBEDDING_HTTP_PORT":"8401"}}' -s user

claude mcp add-json cpersona '{"type":"stdio","command":"/path/to/.venv/bin/python","args":["/path/to/cpersona/server.py"],"env":{"CPERSONA_DB_PATH":"/home/you/.claude/cpersona.db","CPERSONA_EMBEDDING_MODE":"http","CPERSONA_EMBEDDING_URL":"http://127.0.0.1:8401/embed"}}' -s user

Eso es todo. Claude ahora tiene memoria persistente. Pídele que store (almacene) algo y recall (recupere) en una sesión posterior.

Características

Búsqueda híbrida — Tres estrategias de recuperación independientes se ejecutan en paralelo y fusionan los resultados mediante Reciprocal Rank Fusion (RRF):

Capa

Método

Fortaleza

Vectorial

Similitud de coseno (jina-v5-nano, 768d)

Significado semántico

FTS5

Búsqueda de texto completo en SQLite con tokenizador trigrama

Términos exactos, nombres, IDs

Palabras clave

Coincidencia de patrones de respaldo

Casos extremos, coincidencias parciales

Tipos de memoria:

  • Memoria declarativa — Hechos individuales, decisiones, instrucciones almacenadas mediante store

  • Memoria episódica — Resúmenes de conversaciones archivados mediante archive_episode

  • Memoria de perfil — Atributos de usuario/proyecto acumulados mediante update_profile

Puntuación de confianza — Cada recuerdo recuperado obtiene una puntuación de confianza que combina:

  • Similitud de coseno (relevancia semántica)

  • Decaimiento temporal dinámico (se adapta al rango temporal del corpus: un corpus de 1 año y uno de 1 día usan curvas de decaimiento diferentes)

  • Impulso de recuperación (los recuerdos frecuentemente útiles aparecen más fácilmente, con un desvanecimiento natural)

  • Factor de finalización (los temas resueltos decaen más rápido)

Sin dependencia de LLM — cpersona es un servidor de datos puro. Nunca llama a un LLM internamente. Todo el resumen y la extracción los realiza el agente que realiza la llamada. Esto significa cero costes de API por parte de cpersona, comportamiento determinista y sin latencia oculta.

Capacidades adicionales:

  • Aislamiento de espacio de nombres del agente: múltiples agentes comparten una base de datos sin interferencias

  • Cola de tareas en segundo plano: procesamiento asíncrono persistente en BD y recuperable tras fallos

  • Exportación/importación JSONL: portabilidad total de memoria entre entornos

  • Fusión de memoria entre agentes: copia/movimiento atómico con deduplicación

  • Autocalibración: ajuste estadístico del umbral mediante puntuación z de distribución nula (no se necesitan etiquetas)

  • Comprobación de salud: 16 detecciones automatizadas con autorreparación (contaminación, duplicados, desincronización FTS, datos no válidos, tareas obsoletas, contenido vacío, fuentes no válidas)

  • Comprobación profunda: análisis de calidad de datos semánticos (recuperación de fuentes anónimas, contenido corto, perfiles obsoletos, episodios huérfanos)

  • Protección de memoria: bloquear/desbloquear para evitar la eliminación o edición accidental

  • Penalización de recuperación reciente: suprime el efecto de cámara de eco para recuerdos recuperados frecuentemente

  • Transporte stdio + HTTP transmitible

  • SQLite de archivo único: no requiere base de datos externa

Arquitectura

                         ┌─────────────────────────────────────┐
                         │            MCP Host                 │
                         │   (Claude Desktop / Claude Code)    │
                         └──────────────┬──────────────────────┘
                                        │ MCP (JSON-RPC)
                         ┌──────────────▼──────────────────────┐
                         │           cpersona                  │
                         │         (server.py)                 │
                         │                                     │
                         │  ┌─────────┐  ┌─────────┐          │
                         │  │  store   │  │ recall  │  ...     │
                         │  └────┬────┘  └────┬────┘          │
                         │       │             │               │
                         │  ┌────▼─────────────▼────────────┐  │
                         │  │         SQLite DB              │  │
                         │  │                                │  │
                         │  │  memories    (content + embed) │  │
                         │  │  episodes    (summaries)       │  │
                         │  │  profiles    (attributes)      │  │
                         │  │  memories_fts (FTS5 index)     │  │
                         │  │  episodes_fts (FTS5 index)     │  │
                         │  │  task_queue   (async jobs)     │  │
                         │  └────────────────────────────────┘  │
                         │                                      │
                         └──────────────┬───────────────────────┘
                                        │ HTTP
                         ┌──────────────▼──────────────────────┐
                         │       Embedding Server              │
                         │  (jina-v5-nano ONNX, 768d)          │
                         └─────────────────────────────────────┘

Flujo de recuperación (modo RRF):

Query → ┌── Vector search (cosine similarity)  ──┐
        ├── FTS5 search (episodes + memories)    ──┼── RRF merge → Confidence scoring → Top-K
        └── Keyword fallback                     ──┘

Benchmarks

Probado en LMEB (Long-term Memory Evaluation Benchmark, resultados) — 22 tareas de evaluación que miden la calidad de la recuperación de memoria:

Modelo de Embedding

Parámetros

Dimensiones

NDCG@10 medio

MiniLM-L6-v2

22M

384

36.88

e5-small

33M

384

46.36

jina-v5-nano

33M

768

54.14

jina-v5-nano logra una mejora del +47% sobre la línea base de MiniLM.

Todas las herramientas

Herramienta

Descripción

store

Almacenar un mensaje en la memoria del agente

recall

Recuperar recuerdos relevantes (vectorial + FTS5 + palabras clave, fusión RRF)

get_profile

Obtener el perfil actual del agente

update_profile

Guardar el perfil del agente precalculado

archive_episode

Archivar episodio de conversación con resumen y palabras clave

list_memories

Listar recuerdos recientes

list_episodes

Listar episodios archivados

delete_memory

Eliminar un solo recuerdo (se aplica la propiedad)

delete_episode

Eliminar un solo episodio (se aplica la propiedad)

delete_agent_data

Eliminar todos los datos de un agente

calibrate_threshold

Autocalibrar el umbral de búsqueda vectorial mediante puntuación z

export_memories

Exportar a JSONL (recuerdos, episodios, perfiles)

import_memories

Importar desde JSONL (idempotente mediante deduplicación msg_id)

merge_memories

Fusionar los datos de un agente en otro (atómico, con deduplicación)

get_queue_status

Estado de la cola de tareas en segundo plano

recall_with_context

Recuperar con contexto de conversación externo (autodeduplicación)

update_memory

Actualizar contenido de memoria (rechaza si está bloqueado)

lock_memory

Bloquear memoria para evitar eliminación/edición

unlock_memory

Desbloquear memoria para permitir eliminación/edición

check_health

Comprobación de salud de base de datos de 16 puntos con autorreparación

deep_check

Análisis de calidad de datos semánticos profundos con autorreparación

Configuración

Todos los ajustes mediante variables de entorno con valores predeterminados razonables:

Variable

Predeterminado

Descripción

CPERSONA_DB_PATH

./cpersona.db

Ruta de la base de datos SQLite

CPERSONA_EMBEDDING_MODE

http

Modo de embedding (http o disabled)

CPERSONA_EMBEDDING_URL

http://127.0.0.1:8401/embed

URL del servidor de embedding

CPERSONA_VECTOR_SEARCH_MODE

remote

Modo de búsqueda vectorial

CPERSONA_SEARCH_MODE

rrf

Estrategia de búsqueda (rrf o cascade)

CPERSONA_RRF_K

60

Parámetro de suavizado RRF

CPERSONA_CONFIDENCE_ENABLED

false

Incluir metadatos de confianza en los resultados

CPERSONA_AUTO_CALIBRATE

false

Autocalibrar al iniciar

CPERSONA_TASK_QUEUE_ENABLED

false

Habilitar cola de tareas en segundo plano

CPERSONA_RECENT_RECALL_PENALTY

0.7

Penalización para recuerdos recuperados recientemente

CPERSONA_RECENT_RECALL_WINDOW_MIN

5

Ventana (minutos) para la penalización de recuperación reciente

Estadísticas

  • ~3,500 líneas de código Python (archivo único, server.py)

  • 117 pruebas en 12 módulos de prueba

  • Esquema v8 (automigración)

  • Licencia MIT

Funciona con

cpersona es un servidor MCP: funciona con cualquier host compatible con MCP:

Parte de ClotoCore

cpersona es la capa de memoria de ClotoCore, una plataforma de agentes de IA de código abierto escrita en Rust. Aunque cpersona es totalmente independiente (licencia MIT), fue diseñada para dar a los agentes de IA una memoria persistente y buscable dentro del ecosistema ClotoCore.

Más información

Licencia

MIT: uso gratuito desde cualquier host MCP sin restricciones.

Available Tools

34 tools
archive_episodeA

Archive a conversation episode with pre-computed summary, keywords, and resolved status. All LLM processing is performed by the caller. A summary that runs past the embedding window adds nodes:{status:'queued'} to the response, as on store.

ParametersJSON Schema
NameRequiredDescriptionDefault
channelNov2.4.22 conversation-channel tag (e.g. a Discord channel id). Default '' (= unscoped). Channel-scoped recall returns episodes whose channel matches; this powers the per-channel episodic loop.
historyNoOriginal conversation messages (used for start/end timestamp extraction; the episode embedding is computed from summary)
summaryYesEpisode summary (pre-computed by caller)
agent_idYesAgent identifier
keywordsNoSpace-separated keywords (pre-computed by caller)
resolvedNoWhether the topic was completed/concluded
project_idNov2.4.17 isolation axis. Omit or pass '' for the global pool. v2.5.1: pass '@auto' to resolve this agent's default from the server's operating context (the resolution is echoed as resolved_project_id; an unmapped agent yields operating_context_warning). bug-186: resolution requires a configured operating context. With none — the default, and equally the outcome of a sidecar that fails to parse — the sentinel is NOT resolved: it is stored and filtered as the literal project_id '@auto', resolved_project_id echoes '@auto', and no warning is raised. Read resolved_project_id before relying on the resolution.
session_keyNoOpaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnlyHint=false, idempotentHint=false, destructiveHint=false). The description adds genuine value beyond that: it discloses the caller-side LLM contract and the specific overflow behavior (nodes:{status:'queued'} when the summary exceeds the embedding window). It stops short of describing persistence semantics or auth requirements.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences with no waste; the core purpose is front-loaded and the caller-processing constraint and queue behavior follow immediately. Nothing is redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description usefully covers the one notable return-value shape (the queued node) and the caller-processing contract. For an 8-parameter mutation tool this is largely sufficient, though it could say more about persistence/dedup behavior.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all 8 parameters in detail — including the complex project_id '@auto' resolution semantics. The description adds the summary/embedding-window interaction but no syntax or meaning for the remaining parameters, so the baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (archive) and resource (conversation episode) plus the key inputs (summary, keywords, resolved status). It implicitly separates itself from the sibling `store` by saying the queued behavior is 'as on store', which signals this is the episode-specific archive path rather than the generic store.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'All LLM processing is performed by the caller' does imply the usage contract (caller must pre-compute the summary/keywords), but it never states when to choose this over siblings like store, list_episodes, or delete_episode. Usage is implied rather than explicitly routed.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

calibrate_thresholdA

Auto-calibrate the vector search threshold from the null (random-pair) cosine distribution. Samples random memory pairs and places the threshold ABOVE the null mean so unrelated pairs are rejected. method='separation' (default) learns the operating point from two populations — null pairs vs temporally-adjacent same-session positives (nearest-neighbour fallback when too few exist); method='percentile' uses a quantile of the null distribution (robust to anisotropic models such as bge-m3); method='zscore' uses mean + z*std. No labels used, purely statistical. Adapts to both embedding model and corpus characteristics.

ParametersJSON Schema
NameRequiredDescriptionDefault
methodNo'separation' (default; two-population — learns the operating point from null pairs vs temporally-adjacent same-session positives, falling back to nearest-neighbour when too few exist), 'percentile', or 'zscore'
agent_idYesAgent ID whose memories to sample
z_factorNoZ-score multiplier for method='zscore' (default: 1.0, higher = stricter)
percentileNoNull-distribution quantile for method='percentile' (default: 0.95, higher = stricter)
sample_sizeNoNumber of embeddings to sample (default: 200)
session_keyNoOpaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare readOnlyHint=false and non-idempotent, and the description says the calibration is 'purely statistical' with no labels, adding algorithmic transparency. However, it does not disclose operational behavior: whether the computed threshold is persisted to the agent, whether it overwrites a prior threshold, the cost of sampling 200 embeddings, or any auth requirement.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose is front-loaded in the first sentence, followed by method semantics. It is a bit dense with parenthetical detail, but nearly every clause (null mean placement, no-labels, model/corpus adaptation) carries information an agent needs.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 6-parameter, no-output-schema tool, the description thoroughly explains the calibration algorithm and method choices, which is the core complexity. It leaves minor gaps (persistence of the resulting threshold, response shape), which keeps it from a 5.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds genuine value beyond the schema by explaining the tradeoffs between the method enum values (separation's two-population learning, percentile's robustness to anisotropic models like bge-m3, zscore's mean+z*std), which helps an agent pick the right value.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Auto-calibrate the vector search threshold from the null (random-pair) cosine distribution.' An agent immediately understands the operation. It does not, however, name or contrast with any sibling tool (e.g. set_recall_precision), so it stops short of a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives guidance on which of the three methods to choose (percentile for anisotropic models like bge-m3), which is useful, but it never states when to call this tool versus alternatives such as set_recall_precision, nor any precondition like requiring existing memories. Usage is implied rather than explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

check_healthA

Check memory database health (37-check registry, each issue tagged critical/warn/info): contamination, duplicates, oversized content, embeddings, FTS and schema integrity, SQLite file integrity, naming, JSON and timestamp drift, stale tasks, profiles and sources. Returns storage stats with project_id/channel distributions. The verdict is status (healthy / degraded / unhealthy, from severity counts; info never degrades). Read it as a verdict on what is IN the database, not on whether the pipeline that fills it is working: a corpus whose every embedding is NULL scores healthy while semantic recall is dead. Nothing contacts the embedding backend unless fix=true, so on a report-only run the liveness findings cannot appear and their absence is not evidence the backend answered; the null_embedding finding says why its repair cannot run. checks runs a subset: an unknown name is rejected (ok=false), and every response echoes checks_run. fix=true repairs, agent-scoped and locked-safe, except dedup_msg_id_index: its repair blanks colliding msg_id values under every agent because the UNIQUE index it restores is global, so under an ACL it needs read-write on '*'; exclude it via checks to stay agent-scoped. critical file-integrity findings are report-only. Two repairs are lossy and irreversible: oversized memories are cut to CPERSONA_MAX_CONTENT_LENGTH (default 16000) and the profile to CPERSONA_MAX_PROFILE_LENGTH (default 2000), keeping the start, and lowering a cap shortens rows that fit the old one. Some repairs are bounded per run (source canonicalisation classifies at most 10000 rows): a fix response with remaining > 0 has NOT converged; run fix again until remaining stops decreasing.

ParametersJSON Schema
NameRequiredDescriptionDefault
fixNoAuto-fix detected issues
checksNoRegistry check names to run (empty = all). See cpersona.checks.HEALTH_CHECK_NAMES.
agent_idNoAgent ID to check (empty = all agents)
session_keyNoOpaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Only readOnlyHint=false is provided, yet the description discloses behavior far beyond it: agent-scoping and lock-safe repairs, the global UNIQUE-index caveat requiring read-write on '*', two lossy irreversible repairs with their caps, bounded per-run repairs and `remaining` semantics, and the fact that the embedding backend is untouched unless fix=true. This is exactly the kind of context annotations cannot carry.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the purpose and verdict semantics before operational caveats, and almost every sentence carries non-obvious information. It is a dense single block with several long clauses, so it is informative rather than wasteful, but could be broken up for scanability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description still explains the return shape: `status` as a severity-derived verdict, `checks_run` echo, storage stats with distributions, and `remaining` for non-converged fixes. It also warns how to interpret results (a healthy verdict says nothing about pipeline liveness), so an agent has what it needs to call and read it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: it explains that fix triggers repair (and what that repairs/destroys), that `checks` echoes `checks_run` and rejects unknown names, and that critical file-integrity findings remain report-only. Only `agent_id` and `session_key` gain little beyond the schema text.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Check memory database health') and immediately enumerates the 37-check registry and the domains covered (contamination, duplicates, embeddings, FTS/schema and SQLite integrity, drift, stale tasks, profiles/sources). An agent knows exactly what this tool inspects and can distinguish it from a general-purpose diagnostic call without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear operational context: fix=true repairs, `checks` runs a subset and rejects unknown names, exclude dedup_msg_id_index to stay agent-scoped, and re-run fix until `remaining` stops decreasing. However, it never names the obvious alternative (deep_check) or states when to prefer this tool over it, so the when-vs-alternative guidance is absent.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

check_updateA

Report whether a newer release of this server exists, and — only if you ask — install it. The check itself runs ONCE per process start, in a background task that nothing waits on, and its verdict is cached for 24h (CPERSONA_UPDATE_CHECK_INTERVAL_SECONDS) in a file beside the database; a bare call here reads that verdict and reaches neither the network nor the disk. state is one of: ok (running the newest release) / newer (a newer final release exists — pre-releases are never proposed) / yanked (every file of the RUNNING version has been withdrawn on PyPI; reason carries the publisher's text) / unlisted (this version is not on the index at all — a development checkout; not a defect) / unknown (no check has completed, e.g. no network) / disabled. install names how this process was installed (uvx / pip / checkout / unknown) and the exact command that would update it. refresh=true performs the fetch now (3s budget) and updates the cache. apply=true runs that command as an argv list (never a shell), returning exit_code and the last 40 lines of output — supported for pip and checkout installs only; under uvx the environment is a cache entry keyed by the launch arguments, so the update belongs in your client's config (uvx cpersona@latest), and an install here would be discarded on the next launch. A checkout parked at a tag (detached HEAD) is likewise refused before anything runs, and answers with the git fetch --tags && git checkout <tag> form to use instead. Updating is NEVER automatic and never a side effect of any other call. A RESTART IS ALWAYS REQUIRED afterwards: this process keeps serving the old code until it is replaced. Unaffected by pause_persistence — an install writes no memory row, so a no-persist session can still repair a withdrawn version. Set CPERSONA_UPDATE_CHECK=false to disable the feature entirely: no fetch, no cache, no notice on recall or check_health, and this tool answers state=disabled.

ParametersJSON Schema
NameRequiredDescriptionDefault
applyNoRun the detected update command (pip / checkout installs only). Off by default; a restart is required afterwards.
refreshNoFetch the package index now instead of reading the cached verdict (3s budget; a failure answers state=unknown).

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description extensively discloses behavior beyond the minimal readOnlyHint:false annotation: the once-per-process background check, 24h cache, no network/disk on bare calls, exact state meanings, restart requirement, no automatic updates, install-method constraints, and independence from pause_persistence. This is exemplary transparency for a tool with side-effecting capabilities.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The content is dense and every major point is relevant, but it is delivered as one long monolithic paragraph with no bullets or headings, making it harder to parse. It is somewhat longer than necessary, with minor repetitions around 'never automatic' and 'only if you ask'.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description fully covers the return contract: state values, reason, install command, exit_code, and output truncation. It also addresses edge cases such as detached HEAD, uvx cache behavior, and the CPERSONA_UPDATE_CHECK disable path, so an agent has everything needed to invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, but the description adds substantial meaning: refresh has a 3s budget and failure yields state=unknown; apply returns exit_code and last 40 lines, never uses a shell, and is restricted to pip/checkout installs. The description enriches both boolean parameters well beyond their schema definitions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a precise verb and resource: 'Report whether a newer release of this server exists' and explicitly scopes the install capability as opt-in. It clearly separates check, refresh, and apply behaviors, making the tool's purpose unambiguous even among many siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context for when a bare call, refresh=true, and apply=true are appropriate, and explicitly states when apply is refused (checkout at tag, uvx). It does not explicitly name alternative sibling tools, but the usage boundaries are otherwise detailed enough for an agent to decide correctly.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

declare_associationsA
DestructiveIdempotent

Declare associative memory after the fact: entities with aliases, and subject–predicate–object relations, recorded verbatim and walked by reconstruct. The server extracts nothing and infers nothing — coverage is exactly what was declared. anchor_ref names the record (mem:<id> / ep:<id>) the declaration is evidenced by: every entity named is recorded as mentioned by it and every relation carries it. Malformed items are reported in dropped and skipped; nothing else in the call is refused for them. retract removes relations by id and mentions by {entity, ref} — the only way a declaration leaves the store. Response: {ok, result:'declared', entities:[{id, name, created}], mentions, relations:[ids], dropped:[{item, reason}], retracted?:{relations, mentions}}. Under pause_persistence nothing is written (result:'skipped', persisted:false).

ParametersJSON Schema
NameRequiredDescriptionDefault
channelNoMemory channel the declaration belongs to. Default: '' (shared).
retractNoDeclarations to remove: {relations: [relation ids], mentions: [{entity: <entity id>, ref: 'mem:<id>'}]}. Only this agent's rows are touched.
agent_idYesAgent identifier
anchor_refNoThe record this declaration is evidenced by: 'mem:<id>' or 'ep:<id>' of this agent. Optional.
project_idNoProject the declaration belongs to. Optional — omit or pass '' for the global pool. v2.5.1: pass '@auto' to resolve this agent's default from the server's operating context (the resolution is echoed as resolved_project_id; an unmapped agent yields operating_context_warning). bug-186: resolution requires a configured operating context. With none — the default, and equally the outcome of a sidecar that fails to parse — the sentinel is NOT resolved: it is stored and filtered as the literal project_id '@auto', resolved_project_id echoes '@auto', and no warning is raised. Read resolved_project_id before relying on the resolution.
session_keyNoOpaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.
associationsNoThe entities and relations to declare. Malformed items are reported in `dropped` and skipped.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations (destructiveHint=true, idempotentHint=true) by disclosing that nothing is inferred or extracted, that malformed items land in `dropped` while the rest of the call proceeds, that retract is the only path by which a declaration leaves the store, and that pause_persistence causes a skip with persisted:false.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose and behavior, and the response shape is compressed into one line. It is dense and long, but nearly every clause conveys a distinct behavioral fact rather than restating the schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, yet the description supplies the full response envelope and the retraction/pause variants. Combined with the 100%-documented schema, an agent has everything needed to invoke and interpret the call.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds meaning the schema does not: anchor_ref's propagation to every named entity and relation, and the retract/response contract. It does not fully re-explain the deeply documented project_id/session_key fields, which the schema already carries.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise verb (declare) and resource (associative memory: entities with aliases plus subject-predicate-object relations) and distinguishes itself from siblings by noting coverage is verbatim and read back via reconstruct. An agent can tell this apart from store/recall/reconstruct without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Frames the use case ('declare after the fact') and points to reconstruct as the consumer of what is declared, and to retract as the removal path. It does not explicitly contrast with store or recall, so the when-not guidance is implied rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

deep_checkA

Deep heuristic analysis of memory data quality. Detects issues requiring recovery or judgment (anonymous sources, short/trivial content, stale profiles, orphaned episodes, stale threshold calibration, embedding-space near-duplicate pairs as merge candidates). fix=true applies repairs for: anonymous_source, short_content. Report-only (fix is accepted and ignored): stale_profile, orphaned_episodes, calibration_staleness, near_duplicate, unnormalized_content, embedding_norm — apply those decisions via merge_memories / delete_memory / calibrate_threshold / update_profile. Use checks parameter to select specific checks.

ParametersJSON Schema
NameRequiredDescriptionDefault
fixNoApply repairs (default: dry-run preview only)
checksNoChecks to run (empty = all). Options: anonymous_source, short_content, stale_profile, orphaned_episodes, calibration_staleness, near_duplicate, unnormalized_content, embedding_norm
agent_idYesAgent ID to check (required)
session_keyNoOpaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.

TDQS

A4.2/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well past the readOnlyHint=false annotation by disclosing the exact mutation semantics: fix defaults to dry-run preview, and fix=true only affects two of the eight checks while the rest ignore it. This partial-write behavior is the single most important thing an agent must know before setting fix=true and it is stated plainly.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose, then a parenthetical inventory of issue types, then the fix/report-only split, then follow-up tools. Dense but every clause carries information; the parenthetical enumeration pushes it toward a run-on sentence.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a four-parameter tool with no output schema, the description covers what it detects, what it mutates, what it ignores, and where to route unresolved issues. The main omission is any indication of the report shape or findings structure an agent should expect back.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3 and the schema already documents fix, checks options, and session_key. The description still adds real meaning by mapping checks to their fix behavior and clarifying that an empty checks list runs everything. It does not, however, expand on the unusual session_key partitioning hint beyond what the schema says.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb+resource: 'Deep heuristic analysis of memory data quality' with an enumerated set of detected issue classes (anonymous sources, stale profiles, orphaned episodes, near-duplicate pairs). An agent immediately knows this is a diagnostics/repair pass. It never explicitly contrasts itself with the sibling check_health, so sibling differentiation is only implicit via the check list.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Strong routing guidance: it states which checks are auto-repairable (anonymous_source, short_content) and, for each report-only check, names the sibling to apply the decision (merge_memories / delete_memory / calibrate_threshold / update_profile). No explicit 'when to call this vs check_health' statement, so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_agent_dataA
DestructiveIdempotent

Delete ALL data (memories, profiles, episodes) for a specific agent. Used by kernel during agent deletion.

ParametersJSON Schema
NameRequiredDescriptionDefault
agent_idYesAgent ID whose data should be purged
session_keyNoOpaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true and idempotentHint=true, so the safety profile is covered. The description adds genuine value by enumerating exactly what is destroyed (memories, profiles, episodes) and the scope (single agent), which the annotations do not convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences with zero padding; the destructive scope is front-loaded before the caller-context note. Every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For an irreversible bulk-delete tool, the description pairs the destructive scope with annotations that flag destructiveness, and no output schema exists to explain. It could state irreversibility or permission requirements, but nothing critical for correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and both parameters carry detailed schema descriptions, including a lengthy note on session_key semantics, so the schema does the heavy lifting. The description adds no parameter-level meaning, making the baseline 3 correct.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Delete) plus resource scope (ALL data for a specific agent) and enumerates what is covered: memories, profiles, episodes. This distinguishes it from the finer-grained delete_memory and delete_episode siblings, though it never names them explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

"Used by kernel during agent deletion" gives context about who calls it and when, but provides no guidance for an agent choosing between this and delete_memory/delete_episode/archive_episode, and no when-not-to-use condition or prerequisites.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_episodeA
DestructiveIdempotent

Delete a single episode by ID. Ownership is enforced when agent_id is provided.

ParametersJSON Schema
NameRequiredDescriptionDefault
agent_idNoAgent ID for ownership verification (injected by kernel)
episode_idYesEpisode ID to delete
session_keyNoOpaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.

TDQS

A3.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already declare destructiveHint=true, idempotentHint=true, and readOnlyHint=false, covering the safety profile. The description adds meaningful context by stating that ownership is enforced only when agent_id is provided, which affects authorization behavior. It does not explain cascading effects, but this is a valuable addition beyond structured fields.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences with zero waste. The core action and ownership condition are front-loaded and concise.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive single-resource deletion with rich annotations and full schema coverage, the description provides the key ownership condition. Minor gaps exist, such as no guidance on choosing archive_episode over deletion or on data cascade, but these are not critical given the tool's complexity and the available structured data.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all three parameters thoroughly. The description restates the episode_id and agent_id ownership concept but adds no syntax, format, or constraint details beyond the schema. The session_key parameter is not mentioned in the description at all, though it is fully documented in the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('Delete') and resource ('a single episode by ID'), making the action clear. It implies scoping to one episode, which helps distinguish it from sibling operations like delete_agent_data or archive_episode, but it does not explicitly name any sibling for differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no explicit guidance on when to use this tool versus alternatives such as archive_episode or delete_agent_data. The word 'single' weakly implies a non-bulk operation, but no routing conditions or exclusions are stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_memoryB
DestructiveIdempotent

Delete a single memory by ID. Ownership is enforced when agent_id is provided.

ParametersJSON Schema
NameRequiredDescriptionDefault
agent_idNoAgent ID for ownership verification (injected by kernel)
memory_idYesMemory ID to delete
session_keyNoOpaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.

TDQS

B3.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true, idempotentHint=true, and readOnlyHint=false, so the safety profile is covered structurally. The description adds useful authorization context ('Ownership is enforced when agent_id is provided'), but does not state that the deletion is permanent/irreversible or what happens to associated data.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, front-loaded with the core action and followed by the ownership condition. Efficient with no padding, though minimally terse.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive mutation with strong annotations and full schema coverage, the description covers the core action and one behavioral constraint. It omits irreversibility, cascade effects, and failure/error behavior when ownership check fails, leaving meaningful gaps for a delete tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so all three parameters (agent_id, memory_id, session_key) are already documented in the schema, including the ownership-verification note on agent_id. The description restates the ownership rule but adds no syntax or format detail beyond the schema. Baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb+resource (delete a single memory by ID), which distinguishes it from siblings like delete_agent_data and delete_episode. However, it does not explicitly name those siblings or scope the difference beyond the singular 'single memory'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No when-to-use or when-not-to-use guidance, and no alternatives named. The only conditional is about ownership enforcement, which is behavioral rather than a usage rule.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

export_memoriesA
Destructive

Export memories, episodes, and profiles to a JSONL file for backup or portability.

ParametersJSON Schema
NameRequiredDescriptionDefault
agent_idYesAgent identifier (empty string to export all agents)
output_pathYesFile path for the JSONL output
include_embeddingsNoInclude embedding BLOBs as base64 (default false, usually not needed)

TDQS

A3.5/5.0
Behavior1/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description describes an export operation, which is typically non-destructive. However, annotations set destructiveHint to true, implying the tool may have destructive side effects (e.g., file overwrite). The description does not disclose this, contradicting the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, straightforward sentence with no wasted words. It is front-loaded with the action and purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description mentions the data types exported (memories, episodes, profiles) and the format (JSONL), but does not address potential side effects like file overwriting despite the destructiveHint annotation. Given no output schema, more detail on the return value or behavior would improve completeness.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema covers all three parameters (agent_id, output_path, include_embeddings) with descriptions. The tool description does not add additional meaning beyond what the schema provides, so baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool exports memories, episodes, and profiles to a JSONL file for backup or portability. It uses a specific verb and resource, and distinguishes from siblings like import_memories.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides context for when to use the tool (backup or portability) but does not explicitly state when not to use it or mention alternatives. Sibling list makes the purpose clear enough.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_contentsA
Read-only

Fetch full, untrimmed content for recall preview refs. Use after a preview-tier recall to expand only the rows that matter instead of opting the whole recall out with full_content=true. Bounded twice: at most 20 refs per call, and a 40,000-character budget across the batch (2.5.4a2) that does not move when CPERSONA_MAX_CONTENT_LENGTH does. Rows are never cut to fit — when the budget is spent the remaining refs come back in deferred (absent otherwise) alongside budget_chars; re-fetch them in a second call. A single row larger than the budget is still returned in full, because this tool is the only path back to a row's complete text. RANGES: a ref may instead be an object that names part of its record -- {ref, node: i} or {ref, node: [first, last]} (inclusive) for overflow-tree nodes, e.g. the node.index of a reconstruct quote and its neighbours, or {ref, span: [start, end]} for characters. Offsets are in the stored text (a memory's content, an episode's summary without the '[Episode] ' label). The item then carries that slice as content and range = {span, content_len, and node + of when nodes were named, or block + of when blocks were}; a span end past the text is clamped and range.span says what was served. A ref may also carry revision, the digest a reconstruct quote's expand hands out for the text its offsets were measured in: a record rewritten since refuses rather than serving different characters under the same numbers. A range that cannot be served exactly is never widened to the whole row: it comes back in unresolved (absent otherwise) as {ref, reason}, reason one of invalid_range, no_current_nodes (the record has no complete node set -- short records have none, and a new long one gets them shortly after store), node_out_of_range, span_out_of_range, no_current_blocks, block_out_of_range, stale_revision. Only the slice counts against the budget.

ParametersJSON Schema
NameRequiredDescriptionDefault
refsYesRefs from recall messages ('mem:<id>' / 'ep:<id>'), or range objects such as {'ref': 'mem:<id>', 'node': [2, 3]} / {'ref': 'ep:<id>', 'span': [0, 800]} / {'ref': 'mem:<id>', 'block': 4, 'revision': '<from an expand>'} (max 20 per call). At most one of node / span / block
agent_idYesAgent identifier (ownership check — another agent's refs come back in `missing`)

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations carry only readOnlyHint=true; the description shoulders the rest and does so richly: two hard bounds (20 refs, 40,000-char budget), the deliberate non-truncation policy with `deferred`/`budget_chars`, the oversized-single-row exception, staleness refusal via `revision`, and enumerated `unresolved` reasons. Nothing here contradicts the read-only annotation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is long, but the tool's surface genuinely is large (ranges, node vs block vs span, revisions, deferral), and the purpose is front-loaded before the mechanics. The version tag and env-var mention are minor noise, keeping this just under a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description must explain returns — and it does: `deferred`, `budget_chars`, `unresolved` with enumerated reasons, `range` contents, `missing` for foreign refs, and the oversized-row pass-through. An agent has everything needed to call and interpret results correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Although schema coverage is 100%, the description adds substantially more than the schema: concrete ref formats ('mem:<id>' / 'ep:<id>'), example range objects, offset semantics (offsets are in stored text; episode summary excludes the '[Episode] ' label), the clamp behavior for spans past the end, and the meaning of `revision`. This far exceeds the schema's 'At most one of node / span / block' note.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Fetch full, untrimmed content for recall preview refs') and positions itself relative to sibling behaviors: it expands preview-tier rows rather than opting the whole recall out with full_content=true. An agent can distinguish this from recall and reconstruct without inspecting schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly names the trigger ('after a preview-tier recall') and the anti-pattern it replaces (setting full_content=true on the whole recall), steering the agent toward 'expand only the rows that matter.' The alternative path and the condition selecting it are stated, not implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_operating_contextA
Read-only

Read the server-served operating context (v2.5.1): the operator-owned doctrine distributed to every connected client. Without arguments returns the preview tier — context_revision, instructions_summary, project_id registry (+ enforce mode), @auto defaults, and doctrine section names. Pass section to fetch one section's full body. Read-only: the context is edited by the operator on the filesystem (~/.cpersona/operating-context.toml), never via MCP.

ParametersJSON Schema
NameRequiredDescriptionDefault
sectionNoDoctrine section name to fetch in full (from doctrine_sections). Empty = preview tier.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description not only aligns with the readOnlyHint annotation but adds significant context: the context is edited on the filesystem (~/.cpersona/operating-context.toml), never via MCP. This discloses the source of truth and mutation path, which annotations alone do not provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three concise sentences, front-loaded with the core purpose, followed by mode details and behavioral note. No wasted words. Structure is logical: what, how, important note.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given one optional parameter, no output schema, and full annotations, the description covers all necessary aspects: return types (preview tier components, full section body), usage modes, and behavioral constraints (read-only, filesystem editing). It is sufficient for an AI agent to correctly invoke this tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with a description for the 'section' parameter. The description adds value by explaining the default behavior (preview tier) and that the section is from 'doctrine_sections'. It clarifies the parameter's effect beyond the schema's own description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool reads the 'server-served operating context' with a specific version (v2.5.1). It identifies the resource and its nature as 'operator-owned doctrine'. This is specific and distinct from sibling tools like 'get_profile' or 'get_contents'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly states the two modes: without arguments returns the preview tier, and with a 'section' argument returns the full body. It mentions read-only and that editing is done via filesystem, not MCP. While it doesn't contrast with siblings, it provides clear usage context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_profileC
Read-only

Get the current profile for an agent.

ParametersJSON Schema
NameRequiredDescriptionDefault
agent_idYesAgent identifier

TDQS

C2.9/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Description aligns with readOnlyHint by stating 'Get', but adds no further behavioral details such as error handling for missing agents, return format, or scope of the profile.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Single sentence, concise and front-loaded. Could include more detail without being overly long, but the brevity aids readability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Adequate for a simple 1-parameter tool with no output schema. However, lack of return value description may leave the agent uncertain about the output format.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with a clear description for 'agent_id'. The tool description does not add any additional meaning beyond the schema, so baseline score applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description 'Get the current profile for an agent' clearly states the action (get) and resource (profile) with specifier 'for an agent'. It distinguishes from sibling 'update_profile' but is slightly redundant with the tool name.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to use this tool vs alternatives, no prerequisites or limitations mentioned. The only implicit guidance is from the readOnlyHint annotation.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_queue_statusA
Read-only

Get the status of the background task queue (pending tasks, retry config).

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, so the description's addition of 'pending tasks, retry config' provides some context. However, it could be more transparent about the return format or any other behavioral traits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, front-loaded sentence of 13 words. Every word is purposeful and concise.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple, parameterless tool with readOnlyHint annotation, the description is fairly complete. It could benefit from specifying the output structure, but given no output schema, it's adequate.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has zero parameters, so baseline is 4. The description does not add parameter details, which is acceptable since there are none.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states a specific verb 'Get' and resource 'background task queue status', and mentions what is included (pending tasks, retry config). This distinguishes it from sibling tools like check_health or list_episodes.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage for checking queue status but provides no explicit guidance on when to use it versus alternatives, nor when not to use it. No sibling comparisons mentioned.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_recall_precisionA
Read-only

Read an agent's effective recall precision (knob 3) — the read-back companion to set_recall_precision. Returns the resolved specificity weight (beta) and its named precision level (strict / balanced / lenient, or 'custom' for a raw beta), and flags whether the value is a per-agent override or the global CPERSONA_RECALL_PRECISION default (overridden + global_precision / global_beta). Read-only: it never recalibrates and never persists, so a UI can load the current setting, let the user edit it, and write it back instead of the control being write-only.

ParametersJSON Schema
NameRequiredDescriptionDefault
agent_idYesAgent whose precision to read

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true. The description goes further by stating it never recalibrates or persists, and details the returned fields (beta, precision level, override flags). This adds behavioral context beyond the annotation, though it doesn't cover all edge cases.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single paragraph that front-loads the main purpose and then provides additional details. It is reasonably concise, though some sentences could be tightened. Every sentence adds value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the simple input (1 param, no output schema), the description thoroughly explains the return value and its relationship to the global default and override behavior. It is complete for a read-only tool of this complexity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema covers the single required parameter (agent_id) with a description. The tool description does not add meaning beyond that, but since schema coverage is 100%, a baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool reads an agent's effective recall precision, identifies it as the read-back companion to set_recall_precision, and specifies it is read-only. This distinguishes it from its sibling and provides a specific verb-resource combination.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explains when to use this tool (as a read-back companion to set_recall_precision, for UI loading before editing) and implies it should be used before writing. However, it does not explicitly mention alternatives or when not to use it, though the sibling set tool is clearly the counterpart.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_session_findingsA
Read-only

Pull the storage-integrity findings on demand (the SuperAuditor pull contract, docs/SUPERAUDITOR_STANDARD.md) instead of reading them off check_health: the same detector as check_health(fix=false) over the WHOLE database. Read-only, never repairs. Each finding carries kind (a check registry name, or an escalation tier this seam mints for a runner that grades its own severity, e.g. null_embedding_pipeline_down — a tier is NOT a registry name), check (the registry name that produced it: check_health(checks=[finding['check']]) re-runs exactly that probe) and a static per-kind severity (critical = the read contract is broken now / warn = two stored facts contradict / info = an observation). check_health's own verdict rides along as health_severity; a probe that raised is reported as kind check_crashed instead of failing the pull. NOT free: the registry runs unfiltered, including two whole-database reads (the FTS5 integrity-check over both indexes and PRAGMA quick_check), so every pull is O(database); budget it by call frequency. There is deliberately no cheap subset. Findings are NOT filtered by agent_id or project_id: slicing them by the caller's bucket would hide exactly the forgotten rows (scope a repair with check_health(agent_id=...)). Honest caps: findings holds at most per_kind_limit rows per kind, capped_kinds names every kind that had more, and total and the counts describe the RETURNED set only. summary restates it in prose (include_summary=false skips it). Without a session_key on a shared remote transport the response carries identity_shared: true; _meta.server_version identifies the running instance.

ParametersJSON Schema
NameRequiredDescriptionDefault
session_keyNoOpaque client-declared session identity (partition hint, not authentication). Empty on a non-stdio transport marks the response identity_shared.
per_kind_limitNoMaximum findings returned per kind (default 5, minimum 1). Kinds that hit it are listed in capped_kinds.
include_summaryNoInclude the human-readable `summary` rendering (default true). It restates `findings` in prose — set false when machine-reading.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only supply readOnlyHint=true, yet the description adds substantial behavior: never repairs, cost is O(database) with two named whole-database reads, findings are unfiltered by agent_id/project_id, hard caps with capped_kinds, and identity_shared on shared transports. This is far beyond what the annotation conveys.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Core purpose and the read-only contract are front-loaded, and nearly every sentence carries load-bearing detail on return fields and cost. It is nonetheless dense and heavy on capitalized emphasis and parentheticals, so it is slightly longer than strictly necessary for a three-parameter tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description carries the full burden and does so: it defines kind, check, severity tiers, health_severity, the check_crashed case, findings, capped_kinds, total, summary, identity_shared and _meta.server_version. An agent has everything needed to interpret the return.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all three params, setting a baseline of 3. The description goes further by tying session_key empty-on-shared-transport to identity_shared, per_kind_limit to capped_kinds, and include_summary to prose output, adding real semantic context.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Pull the storage-integrity findings on demand') and immediately disambiguates from the sibling check_health, noting it is 'the same detector as check_health(fix=false) over the WHOLE database'. An agent can distinguish this from check_health without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly routes usage: use this 'instead of reading them off check_health', but scope a repair with check_health(agent_id=...). It also gives a budgeting rule ('budget it by call frequency') and warns there is deliberately no cheap subset, covering when not to use it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

import_memoriesA
DestructiveIdempotent

Import memories, episodes, and profiles from a JSONL file. Idempotent: memories deduplicate on msg_id (and on content within a project/channel), episodes on their summary within a project/channel.

ParametersJSON Schema
NameRequiredDescriptionDefault
dry_runNoCount records without writing to DB (preview mode)
input_pathYesPath to the JSONL file to import
session_keyNoOpaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.
target_agent_idNoRemap all records to this agent ID (empty to use original agent_id from file)

TDQS

A3.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare write (readOnlyHint=false), idempotentHint=true, and destructiveHint=true, so the safety profile is covered. The description adds the actual deduplication mechanism (msg_id, and content within project/channel for memories; summary for episodes), which is genuinely useful behavioral detail beyond the annotations. It does not disclose what the destructive aspect overwrites, but the idempotency disclosure is the valuable part.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with purpose then idempotency detail, with zero filler. Each sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, but the description plus 100%-covered parameters and safety annotations give an agent enough to call this correctly. Minor gaps remain around conflict/overwrite behavior and auth, but the core operation and idempotency contract are covered.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the parameters (input_path, dry_run, session_key, target_agent_id) are documented in detail in the schema itself, including the opaque session_key semantics. The description adds no parameter-level meaning, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Import) plus the exact resources (memories, episodes, profiles) and the source format (JSONL file), which clearly distinguishes it from export_memories by direction. It never names a sibling explicitly, but the operation is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives no when-to-use, prerequisites, or alternative routing (e.g., vs store, migrate_channel_axis, or export_memories). The idempotency note is behavioral, not usage guidance, so an agent gets no help deciding when this tool is the right choice.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_episodesA
Read-only

List archived episodes for an agent (for dashboard display). bug-385: limit is clamped to 200 rows. When the caller asked for more and rows past the cap exist, the response carries budget_rows (the cap), so a capped listing can be told from one that reached the end of the data — reach the rest through export_memories or a narrower filter, not a larger limit. bug-255: within that cap the response holds an 800,000-character budget across summary and keywords together, with the same degradation and ceiling semantics as list_memories — rows past the budget that exceed the preview cap carry pure prefixes plus summary_truncated/summary_len and keywords_truncated/keywords_len; budget_chars appears iff at least one row was degraded. Their ref expands the summary via get_contents (under the row's own agent_id); a full keywords string is only available through export_data.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMax episodes to return
agent_idNoAgent identifier (empty for all agents)
project_idNov2.4.17 γ filter. Same semantics as list_memories. v2.5.1: pass '@auto' to resolve this agent's default from the server's operating context (the resolution is echoed as resolved_project_id; an unmapped agent yields operating_context_warning). bug-186: resolution requires a configured operating context. With none — the default, and equally the outcome of a sidecar that fails to parse — the sentinel is NOT resolved: it is stored and filtered as the literal project_id '@auto', resolved_project_id echoes '@auto', and no warning is raised. Read resolved_project_id before relying on the resolution.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint annotation, the description discloses the 200-row limit clamp, the budget_rows cap signal, an 800,000-character budget across summary+keywords, conditional budget_chars emission, and per-field truncation markers (summary_truncated/summary_len, keywords_truncated/keywords_len). These are non-obvious behaviors an agent could not infer from structured fields.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is front-loaded with purpose before the behavioral detail, and every sentence carries actionable information. The single dense paragraph and inline bug-ticket tags make it heavier to parse than ideal, but there is little waste.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the full burden of explaining return values, and it does so thoroughly: budget_rows, budget_chars, the truncation flags and their paired length fields, plus how to recover the truncated content. Nothing needed to call or interpret the result is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds meaningful parameter-relevant meaning: limit is silently clamped to 200 and a bigger value does not help, and project_id's '@auto' resolution caveat (bug-186) is reinforced. This is genuine added value beyond the schema text.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ("List archived episodes for an agent") plus intended scope ("for dashboard display"), so the agent immediately knows the operation and its context. It is distinguishable from the neighboring list_memories, whose truncation semantics it references as a parallel case.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It routes the agent to alternatives for specific goals: reach truncated rows via export_memories or a narrower filter rather than a larger limit, expand a ref via get_contents, and get a full keywords string only through export_data. It stops short of an explicit when-to-use-this-vs-list_memories rule, so it earns a 4.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_memoriesA
Read-only

List recent memories for an agent (for dashboard display). bug-385: limit is clamped to 500 rows. When the caller asked for more and rows past the cap exist, the response carries budget_rows (the cap), so a capped listing can be told from one that reached the end of the data — reach the rest through export_memories or a narrower filter, not a larger limit. bug-255: within that cap the response holds a 1,000,000-character content budget. Rows are returned newest-first and none is dropped by the budget; once it is spent, later rows LONGER than the preview cap (CPERSONA_RECALL_PREVIEW_CHARS, default 500) degrade to a pure prefix with content_truncated/content_len and a ref that get_contents expands under the row's own agent_id (in an all-agents listing, pair the ref with the row's agent_id field). budget_chars appears iff at least one row was degraded. The effective ceiling is the budget plus one whole row plus the degraded rows' prefixes, so it scales with the preview cap; preview cap 0 disables trimming and the budget with it.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMax memories to return
agent_idNoAgent identifier (empty for all agents)
project_idNov2.4.17 γ filter. Omit → no filter; '' → global pool only; 'X' → 'X' ∪ global pool. v2.5.1: pass '@auto' to resolve this agent's default from the server's operating context (the resolution is echoed as resolved_project_id; an unmapped agent yields operating_context_warning). bug-186: resolution requires a configured operating context. With none — the default, and equally the outcome of a sidecar that fails to parse — the sentinel is NOT resolved: it is stored and filtered as the literal project_id '@auto', resolved_project_id echoes '@auto', and no warning is raised. Read resolved_project_id before relying on the resolution.

TDQS

A4.2/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With only readOnlyHint available, the description carries the full behavioral burden and does so in depth: a 500-row clamp, a 1,000,000-character content budget, newest-first ordering, no row dropped, prefix degradation of long rows past the preview cap, and the conditions that populate budget_rows/budget_chars. This is far beyond what annotations convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose is front-loaded, but the body is a dense wall of bug-tagged clauses (bug-385, bug-255, resolved_project_id, preview cap) that is hard to scan. Content is largely non-redundant, yet the run-on sentences and inline parentheticals hurt readability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description fully enumerates the response fields that matter (budget_rows, budget_chars, content_truncated, content_len, ref) and their triggering conditions. An agent has enough to interpret a capped or degraded listing correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3, but the description adds real meaning: `limit` is clamped to 500, and the `ref` must be paired with the row's own `agent_id` in all-agents listings. `project_id` sentinel/resolution behavior is covered by the schema itself, so the description's added value is concentrated on `limit`.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('List recent memories for an agent') plus scope hint (dashboard display). It partially differentiates from siblings by routing extra data to export_memories, but does not clearly separate itself from recall/recall_with_context, which also return memories.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly warns against raising `limit` past the cap and names alternatives ('reach the rest through export_memories or a narrower filter'). This gives clear when-not and alternative guidance, though it never states when list_memories beats recall for a plain retrieval.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lock_memoryA
Idempotent

Lock a memory to prevent deletion and editing. Ownership enforced when agent_id provided.

ParametersJSON Schema
NameRequiredDescriptionDefault
agent_idNoAgent ID for ownership verification
memory_idYesMemory ID to lock
session_keyNoOpaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=false, idempotentHint=true and destructiveHint=false, so the safety profile is covered. The description adds genuine context beyond them: the ownership verification behavior triggered when agent_id is supplied, which is a conditional authorization rule not expressed in the schema. It omits failure modes (already locked, non-owner caller), keeping it from a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, zero waste, with the primary effect front-loaded ahead of the conditional ownership note. Nothing could be trimmed without losing information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple 3-parameter, 1-required mutation tool with annotations carrying the safety profile and no output schema, the description covers the essential state change and the conditional authorization rule. What is missing is error/edge behavior, such as what happens if the memory is already locked or the caller is not the owner.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description adds a small amount of meaning for agent_id by tying it to enforced ownership, but says nothing extra about memory_id or the unusual session_key partition semantics, so it does not rise above baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a specific verb and resource ('Lock a memory') and states the concrete effect ('prevent deletion and editing'), so the agent knows exactly what state change results. It does not, however, name or contrast with the obvious sibling unlock_memory, so differentiation is left implicit.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The intended use is implied by the effect clause — call this when you want a memory protected from modification — but there is no explicit when-to-use framing, no prerequisite conditions, and no mention of unlock_memory as the inverse operation. Adequate but with clear gaps.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

merge_memoriesA
DestructiveIdempotent

Merge memories, episodes, and profiles from one agent into another. Atomic one-shot equivalent of export→import without intermediate files. Strategy 'skip' deduplicates by msg_id (memories) and summary (episodes).

ParametersJSON Schema
NameRequiredDescriptionDefault
modeNoMerge mode: 'copy' (preserve source) or 'move' (delete source after merge)copy
dry_runNoPreview merge without writing to DB
strategyNoMerge strategy: 'skip' (default) — skip duplicates, keep target's versionskip
session_keyNoOpaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.
source_agent_idYesAgent ID to merge FROM
target_agent_idYesAgent ID to merge INTO

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare write (readOnlyHint=false), idempotent, and destructive behavior, so the bar is lower. The description adds meaningful non-annotation context: atomicity, no intermediate files, and the deduplication key (msg_id for memories, summary for episodes). It does not detail what 'move' destroys beyond what the schema states, but it meaningfully supplements the safety profile.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences, front-loaded with the core action, then the differentiating equivalence, then the dedup semantics. Zero filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive, multi-entity merge with a fully documented schema and no output schema, the description covers purpose, atomicity, and dedup rules adequately. Minor gaps remain around recommended usage context (dataset size, ordering, permission prerequisites), which keeps it just short of complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description goes beyond the schema's terse 'skip duplicates' by specifying that dedup is by msg_id (memories) and summary (episodes). This adds real semantic meaning for the strategy parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource (merge memories, episodes, and profiles from one agent into another) and explicitly distinguishes itself from siblings by framing it as the 'atomic one-shot equivalent of export→import'. An agent can tell it apart from export_memories/import_memories without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides clear context for when to prefer this over the export→import alternative ('without intermediate files'), which routes the agent between siblings. However it gives no explicit when-not conditions or prerequisites (e.g. permissions, same-namespace constraints).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

migrate_channel_axisA

Re-channel bridge-type memories to their concrete channel (knob2 v2 default flip prep). Memories the kernel filed under the bridge type ('discord') are rewritten to the concrete channel recovered from the stored session_id ('{channel_id}:{user_id}:{chunk}' | '{channel_id}:shared' → channel_id), so per-channel recall can match them. Non-destructive (only the channel column changes) and idempotent (re-running is a no-op once moved). dry_run=true (default) reports the recoverable count, the channels that would be recovered, and an unrecoverable bucket (channel='discord' rows with no snowflake session_id) without mutating. globalize_unrecoverable=true moves the unrecoverable bucket to channel='' (global, matched by every channel-scoped recall) so the flip orphans nothing; default false (report only).

ParametersJSON Schema
NameRequiredDescriptionDefault
dry_runNoPreview counts only, no mutation (default: true)
agent_idNoAgent ID to migrate (empty = all agents)
session_keyNoOpaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.
globalize_unrecoverableNoAlso move channel='discord' rows with no snowflake session_id to channel='' (global). Default false.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only give readOnlyHint=false; the description carries the rest and does it well, disclosing non-destructiveness ('only the channel column changes'), idempotence ('re-running is a no-op'), the default dry_run preview, and precisely what globalize_unrecoverable alters. This is exactly the mutation context an agent needs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action, then progressively the mechanics, safety properties, and the two flag behaviors. Sentences are dense and jargon-heavy ('snowflake session_id', '{channel_id}:shared'), but every clause conveys information about behavior or defaults rather than filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description compensates by describing what dry_run returns (recoverable count, recovered channels, unrecoverable bucket) and what the two flags do. For a 4-param mutation tool with safety annotations, nothing an agent needs to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3, but the description adds real meaning: it explains that dry_run=true (default) reports recoverable count, channels, and an unrecoverable bucket without mutating, and that globalize_unrecoverable=true moves the unrecoverable bucket to channel='' (global). That clarifies the effect of both booleans beyond their terse schema text.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('re-channel bridge-type memories to their concrete channel') and explains the underlying mechanism (session_id '{channel_id}:{user_id}:{chunk}' parsing). No sibling tool shares this migration purpose, so the agent can immediately tell it apart from recall/store/profile tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Frames the when ('knob2 v2 default flip prep' so per-channel recall can match) and explains the default dry_run=true preview mode as the safe entry point. It doesn't name an explicit alternative tool or state when-not-to-use, but no plausible sibling overlaps, so the guidance is effectively complete.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pause_persistenceA
Idempotent

Pause write operations on this MCP server for an opt-in TTL window (default 1800 seconds, at most 86400). While paused, every write tool — store, declare_associations, archive_episode, update_memory, delete_memory, delete_episode, delete_agent_data, lock_memory, unlock_memory, update_profile, import_memories, merge_memories, calibrate_threshold, set_recall_precision — returns a no-op response carrying persisted: false, dry_run: true and a reason (with the TTL remaining) instead of writing. Branch on persisted: false, not on an id: an id reads "no-persist" (store, archive_episode), and the action-specific id keys (deleted_id / updated_id / locked_id / unlocked_id / episode_id) are null. migrate_channel_axis is instead forced to dry_run and reports repairs_skipped, with no persisted key; check_health and deep_check downgrade to fix=false (repairs_skipped: true). Read tools answer normally, but recall does not bump recall_count / last_recalled_at. Blast radius follows session_key (response scope). Pass the same session_key here and on your write calls and the pause covers that key alone (scope: "session"): a session that sends a different key is neither silenced by it nor able to clear it. The key is a partition hint, not a credential, so anyone who sends the same string shares the pause. Omit it and you arm the bucket every keyless caller shares (scope: "process") — on a streamable-HTTP deployment one process serves every client, so a keyless pause silences writes for every other keyless session until resume or TTL elapse, and those sessions get no signal. Under stdio (one process per client) that bucket is the session. This affects only cpersona; pause cscheduler separately.

ParametersJSON Schema
NameRequiredDescriptionDefault
session_keyNoOpaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.
ttl_secondsNoTTL until automatic resume. Min 1, max 86400 (clamped). Default 1800.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Far exceeds annotations: it discloses the exact no-op response contract (persisted:false, dry_run:true, reason, "no-persist" id), the special-cased behavior of migrate_channel_axis/check_health/deep_check, and the recall side effect. The detailed blast-radius discussion (session vs process bucket, shared keyless bucket on streamable-HTTP, no signal to silenced sessions) is behavioral context the readOnly/idempotent/destructive hints cannot convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose and the affected-tool list, then layers the response contract and blast radius. The bolded blast-radius paragraph is dense and the asterisked emphasis is heavy for prose, but each section carries distinct, non-redundant information rather than restating the name.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex gating tool with no output schema, the description covers the return shape, the scope partitioning, the cross-server caveat (cscheduler paused separately), and the read-tool behavior. Nothing essential for calling it correctly is missing, aside from not naming resume_persistence directly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds genuine meaning beyond the schema by tying session_key to scope semantics ("scope: session" vs "scope: process") and the partition-not-credential caveat, and reiterating the ttl default/max. The extra meaning lifts it above baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("Pause write operations on this MCP server") plus the scoping mechanism (opt-in TTL window), and enumerates the exact write tools affected. An agent can distinguish this from sibling pause/status tools like resume_persistence and persistence_status without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explains the conditions that select behavior for the key parameter (pass session_key for a per-session pause vs omit for the shared process bucket) and gives an explicit when-to-care warning about blast radius. It lacks an explicit pointer to alternatives such as resume_persistence for ending the pause early or persistence_status for checking, so routing is implied rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

persistence_statusA
Read-only

Report whether persistence is currently paused and the TTL remaining (in seconds). It reports the bucket session_key selects (response scope), not the server as a whole: with a session_key it answers for your session only, so paused: false here does not mean no other session is paused. Without one it reflects the bucket every keyless caller shares, which on a streamable-HTTP deployment means paused: true may have been armed by a different keyless session.

ParametersJSON Schema
NameRequiredDescriptionDefault
session_keyNoOpaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, so the safety profile is covered. Beyond that, the description adds valuable behavioral context: what the `scope` response reflects, and the non-obvious caveat that `paused: false` for your session does not imply no other session is paused, including the keyless-HTTP scenario.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core purpose in the first sentence, then spends the remaining text on the genuinely useful scoping caveats. It is dense but every sentence carries weight; no filler or repetition of the schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description correctly enumerates what is returned (paused flag, TTL, scope). For a single-parameter read tool with nuanced scoping, the description supplies everything an agent needs to interpret the result correctly, including the keyless-bucket edge case.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the schema already documents session_key in depth (opaque partition hint, default, maxLength). The description reinforces which bucket it selects but adds no syntax or format detail beyond the schema, so the baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (report) and resource (persistence paused state) plus the returned value (TTL in seconds). It also distinguishes itself from the broader system by clarifying it reports the session-scoped bucket rather than the server as a whole.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description thoroughly explains the two usage modes (with vs. without session_key) and their differing semantics, which is genuine guidance. However, it never names the natural alternatives (pause_persistence, resume_persistence) or states explicitly when to call this tool versus them, leaving routing to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

recallA
Read-only

Recall memories by multi-strategy search (vector + FTS5 + keyword). To answer a question from memory, prefer reconstruct: it returns items that quote the rows supporting them, within a character budget. Rows come in ascending order of relevance: the LAST row is the best match (docs/behavior-contracts.md section 1). gate_fallback: true (absent otherwise) means every candidate fell below the quality gate and the below-gate lexical matches were returned instead of an empty result: treat them as low-confidence. suggestion (absent otherwise, at most once per session) is something only the user can decide: that this scope has outgrown the scan window with no coarse index for a time cue to search the rest. Relay its message, and run its fix only if the user agrees. Content is a preview of the record's start by default. A row the preview cut also carries excerpt, the part of the record that matched the query (at most 800 characters, CPERSONA_RECALL_EXCERPT_CHARS; passages joined by ' … ' in text order), and excerpt_basis (blocks / lexical / start). Read the excerpt before expanding a row with get_contents(refs). full_content=true returns whole rows, capped at 200,000 characters per response: rows past it fall back to the preview and the response carries full_content_budget_chars. Each scored row carries match_reason {signal, score, ...}: signal is the branch the quality gate keyed on (rsf > cosine > rrf), the other keys are the per-retriever contributions, and prior is the age weight when one ordered the row. An enabled confidence score is returned beside each row but neither orders nor gates it (unless CPERSONA_CONFIDENCE_ORDERING=legacy). Unscored rows (cascade FTS/keyword) have no match_reason.

ParametersJSON Schema
NameRequiredDescriptionDefault
deepNoDeep recall — halves the quality gate (and the calibrated fused gate), so weaker matches are admitted. It also disables time and completion decay, which are inert unless CPERSONA_CONFIDENCE_ENABLED=true, and it does NOT widen the scan window (CPERSONA_MAX_MEMORIES) — deep is about how weak a match may be, not how far back the search reaches.
limitNoPer-retriever search depth, not a pure response cap: the value is handed to each retrieval channel (vector / episode FTS / keyword) as its top-K, so lowering it shrinks the candidate pool itself — rows beyond the depth are unreachable at any gate value, and score normalization / autocut operate on the smaller pool, which can also reorder what remains. Fewer rows than this may be returned. (Agent-facing cap; the library layer accepts up to the scan window for direct callers.)
queryYesSearch query (empty returns recent memories)
traceNo2.6 recall trace: true adds `trace` to the response — which rows each stage (retrieval arms, fusion, quality gate, autocut, final order, count cut, reserved seats) kept, dropped or reordered, and why, with ranks and scores. It carries references only, never stored text, and is not stored on the server. trace_version identifies its shape. False (the default) returns the response unchanged.
channelNoFilter memories by channel (e.g. 'chat', 'discord'). Default: '' (all channels).
agent_idYesAgent identifier
time_cueNo2.6: when the answer was stored, as far as you remember. Give after and/or before (a date YYYY-MM-DD, which includes that whole day, or an ISO-8601 timestamp), or ago, plus confidence. The server also searches that period. Among the rows it returns anyway, one found there moves up by at most 3 / 2 / 1 places (sure / likely / vague), and as many extra seats (3 / 2 / 1) hold the best records that search found which the answer does not already hold: one no other search reached, or one the count cut. The returned rows are those of a recall without the cue, reordered, plus at most those seats: no row is removed or re-scored, and which rows pass the quality gate does not change. If the period holds nothing it is widened once, one confidence step. likely widens the period by half its length on each side, vague by its whole length. The response then carries time_cue: the period searched, whether it was widened, how many rows moved and how many seats were used, and remainder when the period held more records than the vector search reads and no coarse index could search the rest. Pass it only when the request itself says when (a date, a month, "last week", "in the spring"); omit it when the request names no time, and never fill it with today's date or a guess. A cue whose own period starts within the last 24 hours (today, or later) is not used: the rows are those of a recall without a cue, and time_cue in the response says ignored. A cue that cannot be read returns an error and no messages.
source_idNov2.4.20 per-user source filter. Empty (default) = no filter. Non-empty = prefix match against json_extract(source, '$.id'), e.g. 'discord:12345' to restrict to one Discord user, or 'discord:' to scope to all Discord-sourced memories. Episodes carry no per-user source tagging, so they are skipped when this is set — UNLESS channel is also set, which scopes episodes to one conversation and re-admits them.
project_idNov2.4.17 γ filter. Omit → no filter (all projects). '' → global pool only. 'X' → 'X' bucket ∪ global pool. Threaded through cascade / RRF / vector / FTS / keyword paths. v2.5.1: pass '@auto' to resolve this agent's default from the server's operating context (the resolution is echoed as resolved_project_id; an unmapped agent yields operating_context_warning). bug-186: resolution requires a configured operating context. With none — the default, and equally the outcome of a sidecar that fails to parse — the sentinel is NOT resolved: it is stored and filtered as the literal project_id '@auto', resolved_project_id echoes '@auto', and no warning is raised. Read resolved_project_id before relying on the resolution.
session_keyNoOpaque session identity you declare — a partition hint, NOT authentication. It scopes this process's per-session state: the degraded-recall advisory's "already told you" memory, and which no-persist pause applies to this call. It does NOT filter stored data (use agent_id / project_id / channel for that), and it never reaches the database. Omit it to share one bucket with every other caller that omits it, which is the behaviour that predates this parameter.
full_contentNov2.5.0 preview tier opt-out. By default message content longer than the preview cap (CPERSONA_RECALL_PREVIEW_CHARS, default 500) is returned as a pure prefix with content_truncated/content_len markers; each message's `ref` expands via get_contents. true returns full text.
exclude_contentsNoNormalized content strings to exclude from results (starts-with match). Used to prevent duplication with conversation context already known to the caller. bug-399: the starts-with rule holds only at or above 32 characters. A shorter entry has to EQUAL the stored content (after the normalization this parameter already asks for: stripped and lower-cased) — a short prefix would otherwise suppress every memory beginning with it, inside the retrievers and with nothing in the response reporting the exclusion. Size entries at or above that length when you mean a prefix.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With only readOnlyHint=true from annotations, the description carries the behavioral load well: it explains gate_fallback (below-gate low-confidence rows), suggestion semantics and when to run its fix, the 200,000-char full_content budget and its fallback, excerpt/excerpt_basis, match_reason signal ordering (rsf > cosine > rrf), and that confidence scores neither order nor gate. No contradiction with readOnlyHint.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose, but then becomes a dense wall of parenthetical edge cases, version tags, and file references. Each sentence carries real information, yet the sheer length and nesting make it harder to scan than it needs to be for a tool with a 100%-covered schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 12 parameters, nested time_cue objects, and no output schema, the description covers the response surface (gate_fallback, suggestion, excerpt, match_reason, full_content_budget_chars, time_cue echo) unusually thoroughly. The remaining gap is minor — a few filter params are left to the schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description earns above that by adding cross-parameter and response interplay the schema does not state, such as reading `excerpt` before expanding a row with get_contents(refs), and the full_content budget behavior. It does not add much for the filter parameters (channel, project_id, source_id), which live entirely in the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb and mechanism ('Recall memories by multi-strategy search (vector + FTS5 + keyword)'), and explicitly names the sibling `reconstruct` as the preferred tool for answering questions from memory. An agent can distinguish this from recall_with_context and reconstruct from the first two sentences.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a clear routing rule ('To answer a question from memory, prefer reconstruct') and detailed when-to-use guidance for time_cue ('Pass it only when the request itself says when... omit it when the request names no time'). It does not, however, contrast against the other retrieval siblings such as recall_with_context, so usage coverage is strong but not exhaustive.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

recall_with_contextA
Read-only

Recall memories and merge with external conversation context. Automatically deduplicates, sorts chronologically, and returns a unified list. Replaces separate recall + manual merge in the caller. Content is preview-tiered by default — see recall's full_content / get_contents (full_content shares recall's 200k-char response budget, bug-211); a recalled row the preview cut carries excerpt / excerpt_basis as recall's do. Every external_context entry's content filters the recall (the caller already holds that text), but only role=user / role=assistant entries are merged into messages. When entries of other roles are present the response carries context_filter_only={roles:[...]} — those entries filtered the recall without appearing in the output, whether or not they dropped a memory this time. context_field_issues={entries:[{index, fields}]} (absent otherwise) names entries whose declared field was not a string: it was read as absent and the entry merged without it. CPERSONA_EXTERNAL_CONTEXT_MODE=reject refuses such a call instead. gate_fallback=true (absent otherwise) is forwarded from the underlying recall: every candidate fell below the quality gate and the below-gate lexical matches were returned instead of an empty result — treat them as low-confidence.

ParametersJSON Schema
NameRequiredDescriptionDefault
deepNoDeep recall — same semantics as in `recall`: halves the quality gate so weaker matches are admitted.
limitNoPer-retriever search depth for the underlying recall, not a pure response cap — same semantics as recall's limit: lowering it shrinks the candidate pool itself, not just the rows returned. (Agent-facing cap; the library layer accepts up to the scan window for direct callers.)
queryYesSearch query
channelNoMemory channel filter
agent_idYesAgent ID
source_idNov2.4.20 per-user source filter — passed through to recall. Same semantics as in `recall`.
project_idNov2.4.17 γ filter — passed through to recall. Same semantics as in `recall`. v2.5.1: pass '@auto' to resolve this agent's default from the server's operating context (the resolution is echoed as resolved_project_id; an unmapped agent yields operating_context_warning). bug-186: resolution requires a configured operating context. With none — the default, and equally the outcome of a sidecar that fails to parse — the sentinel is NOT resolved: it is stored and filtered as the literal project_id '@auto', resolved_project_id echoes '@auto', and no warning is raised. Read resolved_project_id before relying on the resolution.
session_keyNoOpaque session identity you declare — a partition hint, NOT authentication. It scopes this process's per-session state: the degraded-recall advisory's "already told you" memory, and which no-persist pause applies to this call. It does NOT filter stored data (use agent_id / project_id / channel for that), and it never reaches the database. Omit it to share one bucket with every other caller that omits it, which is the behaviour that predates this parameter.
full_contentNov2.5.0 preview tier opt-out — same semantics as in `recall`.
external_contextNoConversation history entries [{role, content, name?, user_id?, timestamp?}, ...]. Every declared field is a string; one that is not is read as absent and reported in context_field_issues (CPERSONA_EXTERNAL_CONTEXT_MODE).

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare readOnlyHint=true; the description adds substantial behavior beyond that: automatic dedup and chronological sort, the fact that every external_context entry filters the recall while only user/assistant roles merge, context_filter_only, context_field_issues, the CPERSONA_EXTERNAL_CONTEXT_MODE=reject refusal, and gate_fallback's low-confidence semantics. This is exactly the extra context annotations can't carry.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose is front-loaded in the first sentence, but the body is a dense wall of parenthetical version tags and bug references (v2.4.20, bug-211, v2.5.1, bug-186) that add noise rather than decision value for an agent. Length is partly justified by the tool's complexity, but the versioning asides do not earn their place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries return-value burden and does so well: unified list, context_filter_only, context_field_issues, gate_fallback, and preview-tiered rows with excerpt/excerpt_basis. It defers the detailed row shape to recall, which is a minor gap rather than a blocker.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds interaction semantics the schema doesn't: full_content shares recall's 200k-char response budget, and the role-based filtering vs. merging split. Some of it duplicates the nested item descriptions (context_field_issues, role handling), keeping it from a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ("Recall memories and merge with external conversation context") and immediately differentiates from the sibling: "Replaces separate recall + manual merge in the caller." An agent can distinguish this from recall without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Clear context for when to reach for it — you already hold external conversation text and want it merged with recall results — and it names the alternative it supersedes (separate recall + manual merge). It stops short of an explicit when-not-to-use or a direct routing rule against recall.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

reconstructA
Read-only

The recommended way to answer a question from memory. Returns up to count ITEMS (10 by default): units of memory, each quoting verbatim its most relevant record. content is the parts of that record that matched the query; pass head_ref, or an item's expand as it is, to get_contents to read more. No model is called and nothing is summarised; stored rows are never modified. COUNT IS A CEILING, not a fill target or a search depth: fewer items is a normal result and carries shortfall_reason, and nothing is padded. With the block arm on, up to reserved_count held items may follow the window. Breadth is set apart from count: raise top_k when items are missing evidence; max_hops and max_evidence bound the declared-relation walk and the rows kept per item. BUDGET bounds the characters of quoted text (content plus excerpts), where count bounds items: excerpts are omitted before items, and raising the budget never removes an item or an excerpt. Omit it for the server default. mode (lite / pro) caps the tokens returned (see it). READ FURTHER IN STEPS, smallest first: an item's expand, then the neighbouring nodes ({ref, node: [index - 1, index + 1]}), and the bare ref, the whole record, only when the parts did not answer. ITEM: claims lists the retained rows newest first (ref, as_of, why, hops, roles); excerpts quote the other claims. roles[].role names what the REFERENCED row is to this claim (supports / supersedes / corrects / qualifies / contradicts / temporal_predecessor); ignore a role you do not know. conflicts appears only when two rows cannot be ordered. A response adds fields only when the server did something other than asked (count_policy, budget_policy, bounds, gate_fallback); their absence does not say the items suffice or that the whole store was searched. trace=true returns the full audit. Declared associations widen the lexical search and add walked evidence inside items, never items. Full contract: docs/RELIABLE_RECALL_2_6.md section 7.

ParametersJSON Schema
NameRequiredDescriptionDefault
deepNoDeep recall for the candidate stage -- same semantics as in `recall`.
liteNoThe same as `mode: "lite"`, which is the name to use; kept so that older callers keep working. Not together with `mode`. Default false.
modeNoA named answer size whose returned JSON is at most `cap` cl100k_base tokens, counted as sent (`used_tokens` says how many). "lite" (cap 3,000) is for a question one or two records can answer: up to 2,800 characters unless `budget` is given, short records whole first, then the best-ranked passages of longer ones. "pro" (cap 5,000) reads 15 items by default and quotes as much as the cap holds. Both leave out `ranges`, `bounds` and the budget fields; an item whose only claim is its head carries that claim's `as_of` instead of `claims`. A larger cap never removes an item or an excerpt. Omit it for the default response, which has no cap. `trace=true` returns every field and is not held to the cap.
countNoCeiling on recall items returned -- not a fill target, not a search depth. Declare per call; omit to take the server default (10 unless configured). An operator-forced value overrides both. Requesting 5 with only 2 valid items returns 2; neither setting requires filling the window. Clamped to the server maximum, and the clamp is reported in count_policy rather than applied silently.
queryYesSearch query (empty returns recent memories)
top_kNoCandidate depth: how many rows the retrieval hands to bundling. This is the breadth knob; it is independent of `count` and is what to raise when items are missing evidence.
traceNoInclude candidate refs and cluster membership for local diagnosis, and the trace of the recall it made as trace.recall; no full text is added.
budgetNoPayload budget: characters of quoted text (item `content` plus `excerpts`) the response may carry. Bounds depth, where `count` bounds breadth, and breadth wins: excerpts are omitted before any item is. Omit for the server default, which is never less than one quote per item of the window; an operator-forced value overrides both; clamped to the server maximum and raised to one head quote, and budget_policy says which.
channelNoMemory channel filter
agent_idYesAgent identifier
max_hopsNoRelation hops the walk may follow from an item's candidates through declared entity -> entity relations. 0 adds no walked evidence. A relation left unfollowed at the bound is named in bounds.omitted. At most 5, as for traverse: a larger value is lowered to it, and bounds.max_hops then states the value applied.
time_cueNo2.6: when the answer was stored, as far as you remember — the same object recall takes (see recall's time_cue), applied to the candidate recall this reconstruction reads. The response carries time_cue when one was applied.
source_idNoPer-user source filter -- same semantics as in `recall`.
project_idNoγ filter -- same semantics as in `recall`, including the '@auto' sentinel, which resolves this agent's default from the server's operating context and echoes the resolution as resolved_project_id. With no configured operating context the sentinel is NOT resolved: it is filtered as the literal project_id '@auto'. Read resolved_project_id before relying on the resolution.
session_keyNoOpaque session identity you declare: a partition hint, not authentication and not a data filter. Forwarded to the candidate recall.
max_evidenceNoMaximum retained rows per item, bounding its claims and role targets. A cut is named in bounds.omitted and counted in the item's claims_omitted.

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint, the description discloses rich behavior: 'No model is called and nothing is summarised; stored rows are never modified,' that count is a ceiling carrying `shortfall_reason`, how budget degrades (excerpts dropped before items), what mode caps do, when extra fields appear (count_policy, bounds, gate_fallback), and that their absence is not proof of completeness. This is far more than the annotation provides.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is front-loaded with purpose and the key constraint (count is a ceiling), which is good. But it is very long and dense with capitalized imperatives and jargon that substantially restate what the 16 schema descriptions already say, so not every sentence earns its place given the total length.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the return-value burden and does so thoroughly: the ITEM structure (`claims`, `excerpts`, `roles`, `conflicts`), expand/read-more semantics, and conditional response fields are all explained. Nothing an agent needs to interpret a response correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so each of the 16 parameters is already documented in the schema, which sets the baseline at 3. The description reinforces the count-vs-budget breadth/depth framing, but this conceptual material is largely duplicated in the schema text and adds limited new parameter meaning.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence states a specific verb+resource and scope: 'The recommended way to answer a question from memory,' followed by what it returns (units of memory quoting verbatim records). It is easy to understand the core function. However, it never explicitly distinguishes itself from close siblings like `recall` and `recall_with_context`, several of whose semantics it merely references ('same semantics as in recall').

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives actionable guidance: raise `top_k` when items are missing evidence, and 'READ FURTHER IN STEPS, smallest first' using an item's `expand` then the bare ref via get_contents — naming the alternative tool for reading more. What is missing is any when/when-not routing against the sibling recall tools; usage is clear but not exhaustively comparative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

resume_persistenceA
Idempotent

Re-enable persistence immediately, clearing this caller's active no-persist TTL. Returns was_active=true if THIS bucket was paused before the call. It clears only the bucket session_key selects (response scope): with a session_key, your own pause and no other session's; without one, the shared keyless bucket, which on a streamable-HTTP deployment re-enables writes for every other keyless session too.

ParametersJSON Schema
NameRequiredDescriptionDefault
session_keyNoOpaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations cover idempotency (idempotentHint=true) and non-destructiveness, and the description goes well beyond them: it discloses the return value (was_active), the response `scope` field, and critically warns that omitting session_key on a streamable-HTTP deployment re-enables writes for every other keyless session. That shared-side-effect warning is exactly the kind of behavioral context annotations cannot carry.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The action is front-loaded in the first sentence, followed by return semantics and then scope caveats. It is dense but every sentence earns its place; the bolded scope clause is long but carries the highest-stakes information, so it is justified rather than padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description must carry return-value meaning, and it does (was_active, response `scope`). Combined with the side-effect disclosure, an agent has everything needed to invoke it correctly and understand the consequences of the session_key choice.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds real semantic value beyond the schema: it explains that session_key selects which pause bucket is cleared, that with a key only your own pause is affected, and that omitting it targets a shared keyless bucket. This meaningfully clarifies the parameter's blast radius.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Re-enable persistence immediately, clearing this caller's active no-persist TTL'), which precisely names the action and its mechanism. It is unambiguously the inverse of the sibling pause_persistence, so an agent can select it without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear usage context: re-enable persistence, and the scope of what gets re-enabled depending on session_key. However, it never explicitly names pause_persistence as the counterpart or states conditions for choosing between them, so routing relies on inference from the obvious inverse relationship.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_recall_precisionA
Idempotent

Set an agent's recall precision (knob 3) and recalibrate its quality gate. precision = strict | balanced | lenient maps to a specificity weight beta of 2.0 / 1.0 / 0.5 in the gate separation objective (sensitivity + beta*specificity): strict sits the gate higher (fewer contaminants, more misses), lenient lower (fewer misses, more contaminants). A raw beta > 0 overrides the named level; an empty precision with beta <= 0 clears the per-agent override and returns the agent to the global CPERSONA_RECALL_PRECISION default. The gate is recalibrated at the new beta immediately and persisted, so the change is live without a restart. Precision is a per-agent setting, not a per-recall argument: the gate threshold is precomputed on the separation curve at a fixed beta, so this tool recalibrates once instead.

ParametersJSON Schema
NameRequiredDescriptionDefault
betaNoRaw specificity weight; overrides the named precision when > 0.
agent_idYesAgent whose precision to set
precisionNostrict / balanced / lenient. Empty (with beta <= 0) clears the override.
session_keyNoOpaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare the safety profile (readOnlyHint=false, idempotentHint=true, destructiveHint=false), and the description adds genuinely new behavior: recalibration happens immediately and is persisted, the change is live without a restart, and clearing the override reverts to the global CPERSONA_RECALL_PRECISION default. It does not mention permissions, failure modes, or the returned payload, which keeps it at 4 rather than 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action and the recalibration consequence, and the level/beta mapping earns its space given the non-obvious semantics. The final sentence restates the recalibration that was already stated up front, and the level trade-offs are repeated in both the mapping and the parenthetical, so a little trimming is possible.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with no output schema, the description covers what changes, when it takes effect, and how the override is cleared or reset to the global default, which is what an agent needs to call it correctly. It omits authorization requirements and error/edge-case behavior (e.g. invalid beta or unknown agent_id), leaving a small gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3, but the description adds real meaning beyond the schema: the numeric beta values behind each named level (2.0/1.0/0.5), the precedence rule for beta over precision, and the effect of each level on gate placement. It still does not explain session_key beyond what the schema already says.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Set an agent's recall precision') plus the side effect ('recalibrate its quality gate'), which cleanly separates it from the read-side sibling get_recall_precision and from calibrate_threshold. The '(knob 3)' label and the beta mapping make the target unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear selection rules for the levels (strict/balanced/lenient) and for the override path (raw beta > 0 beats the named level; empty precision with beta <= 0 clears the override). It also explains the per-agent vs per-recall distinction, which steers correct use. It never names a sibling alternative or an explicit when-not-to-use, so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

storeA
Idempotent

Store a memory for future recall: put the text in content. agent_id may be omitted on a connection that can write to exactly one agent (the agent used is echoed as resolved_agent_id), and source defaults to that agent. lock:true also locks the memory, as lock_memory does, and the response says locked:true|false. Every response carries result, the one field to branch on: 'stored' (a new row: id, and embedded, whether a vector was kept; truncated:true when content was shortened to the length cap; nodes:{status:'queued'} when the text runs past the embedding window and its overflow-tree nodes were queued), 'skipped' (nothing written and nothing wrong: a duplicate id or content echoes the existing row's id, except reason='duplicate (unique index)', a concurrent-write race, which has none), or 'rejected' (ok:false, nothing written; reason is human-readable, not a stable token). Under pause_persistence the write is skipped and the response carries persisted:false (id:'no-persist'), which tells a paused write from a duplicate. The older message={content, id, source, timestamp, metadata} form is still accepted; send those fields there or at the top level, not both.

ParametersJSON Schema
NameRequiredDescriptionDefault
idNoOptional caller id: a later store with the same id in the same project is skipped as a duplicate.
lockNoAlso lock the memory against edits and deletion. Default false.
sourceNoWho produced the content, {type, id, name}. Default: {type:'Agent', id:<agent_id>}. Pass {} only when the producer is unknown.
channelNoMemory channel for context separation (e.g. 'chat'). Default: '' (shared).
contentNoThe text to store. Content that is empty — or that sanitizes to empty — is refused with ok:false, result:'rejected'.
messageNoThe older form of content, id, source, timestamp and metadata.
agent_idNoAgent identifier. May be omitted when this connection can write to exactly one agent.
metadataNoFree-form JSON, at most 8000 characters serialised (source has the same cap). Larger is rejected, not truncated.
timestampNoISO-8601 with an offset, e.g. '2026-07-22T12:00:00+00:00'. Default: now.
project_idNoIsolation bucket; omit or '' for the global pool (a recall in 'X' reads 'X' and the global pool). '@auto' resolves this agent's default from the operating context, echoed as resolved_project_id; with no operating context configured it is stored as the literal '@auto'.
session_keyNoOpaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.
associationsNoEntities and relations to declare against this memory, as declare_associations takes them: {entities: [{name, aliases}], relations: [{subject, predicate, object}]}, subject / object being entity names or 'mem:<id>' / 'ep:<id>' refs. Malformed items are reported in the response's associations.dropped and skipped; the memory is stored regardless.

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Far exceeds the annotations (which only cover readOnly/idempotent/destructive). It discloses truncation (truncated:true at the length cap), embedding-window overflow queueing (nodes:{status:'queued'}), the concurrency race behind reason='duplicate (unique index)', the pause_persistence no-persist case, and empty-content rejection.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose is front-loaded, but the body is a single dense wall of nested parentheses and run-on clauses that is hard to scan. Length is partly justified by complex result semantics with no output schema, but the structure could be far more digestible.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the full return-value burden and does so thoroughly (result, 'stored'/'skipped'/'rejected', persisted:false, ids, truncated). For a 12-parameter mutation tool it covers everything an agent needs to call and interpret it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is already 100%, so the baseline is 3. The description adds a bit beyond the schema (resolved_agent_id/resolved_project_id echoes, result branching per parameter state), but most parameter meaning is already carried by the schema itself.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening clause states a specific verb and resource: 'Store a memory for future recall: put the text in content.' It also distinguishes itself from siblings by noting that lock:true behaves 'as lock_memory does', so an agent can separate this from the dedicated lock tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear conditional usage guidance ('agent_id may be omitted on a connection that can write to exactly one agent', send legacy fields 'there or at the top level, not both'), but it never states when this tool should be chosen over recall/update_memory/import_memories or what situations make it inappropriate.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

traverseA
Read-only

The neighbourhood of a declared entity, as a graph: the entity named, its aliases, the entity -> entity relations declared on it and on what they reach, up to max_hops in either direction, and the refs of the records that mention each entity. Only what was declared (declare_associations, or associations on store); nothing is inferred. No record text: expand a ref with get_contents. entity is a name or an alias, compared after normalization; when it names more than one entity this call can read (a project's and the global pool's), all are starts. ORDER: entities by hops, then by the most recently declared relation that reached them, then by id; mentions by record id; relations most recently declared first. limit bounds both the entities returned and the refs listed per entity. Response: {entity, max_hops, limit, entities:[{id, name, hops, aliases?, mentions?, mentions_omitted?}], relations:[{id, subject, predicate, object, declared_by, declared_at, anchor_ref?}] (subject/object are entity ids from entities; a relation is listed when both ends are), entities_omitted?, bounds?:{omitted:[max_hops | limit]}, reason?:'no_such_entity'}. Relation ids are what declare_associations' retract takes. Records are listed only when this call could read them: the project, channel and source_id filters apply as in recall.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum entities returned, and maximum mentioning refs listed per entity.
entityYesA declared entity name or alias.
channelNoMemory channel filter -- same semantics as in `recall`.
agent_idYesAgent identifier
max_hopsNoRelations to follow from the entity, in either direction. 0 returns the entity alone.
source_idNoPer-user source filter on the mentioning records -- same semantics as in `recall`.
project_idNoγ filter -- same semantics as in `recall`. v2.5.1: pass '@auto' to resolve this agent's default from the server's operating context (the resolution is echoed as resolved_project_id; an unmapped agent yields operating_context_warning). bug-186: resolution requires a configured operating context. With none — the default, and equally the outcome of a sidecar that fails to parse — the sentinel is NOT resolved: it is stored and filtered as the literal project_id '@auto', resolved_project_id echoes '@auto', and no warning is raised. Read resolved_project_id before relying on the resolution.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only include readOnlyHint. The description adds extensive behavioral detail: only declared associations are returned, nothing is inferred, no record text, deterministic ordering rules, limit semantics, access-controlled record listing, and the no_such_entity error case. No contradiction exists with readOnlyHint.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long, but the first sentence front-loads the core purpose and every later sentence adds operational specifics (ordering, response shape, access rules, retract linkage). The only mild redundancy is restating `limit` semantics already present in the schema; overall the length is justified by the tool's complexity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description fully specifies the response shape, including optional fields, omitted flags, bounds, and the no_such_entity reason. It also covers ordering, limit behavior, access filtering, and cross-references to get_contents and recall, leaving nothing critical missing for a correct call.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema documents all parameters (100% coverage), so the baseline is 3. The description adds meaningful nuance beyond the schema, especially for `entity` (normalized comparison; multiple start entities when the name maps to more than one readable entity) and clarifies that filters behave as in recall. It does not fully detail every filter's edge cases, but the added value justifies a 4.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: it traverses the neighbourhood of a declared entity as a graph of entities, aliases, relations, and mentioning record refs. It distinguishes itself from siblings by pointing to get_contents for record text and by referencing recall for filter semantics.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Clear context is given about what the tool produces, and alternatives are referenced (get_contents for record text, recall for filter semantics). However, there is no explicit 'use this when ... and not when ...' statement, so exclusions and preference rules are left mostly implicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

unlock_memoryA
Idempotent

Unlock a memory to allow deletion and editing. Ownership enforced when agent_id provided.

ParametersJSON Schema
NameRequiredDescriptionDefault
agent_idNoAgent ID for ownership verification
memory_idYesMemory ID to unlock
session_keyNoOpaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations cover the safety profile (idempotent, non-destructive, not read-only), and the description adds genuinely new behavior: the unlock gate that enables subsequent edits/deletes, plus the conditional 'Ownership enforced when agent_id provided' authorization rule. It omits failure behavior for non-owners and whether the unlock state persists, so not a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences with zero filler; the purpose and its consequence are front-loaded before the authorization caveat.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 3-param state-changing gate tool with no output schema, the definition covers purpose, downstream effect, and the ownership rule. Minor gaps remain around non-owner error behavior and the scope/duration of the unlock, but the essential call-time information is present.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the schema already describes agent_id as 'Agent ID for ownership verification', memory_id as the target, and session_key at length. The description's 'Ownership enforced when agent_id provided' adds only a marginal conditional nuance (what happens when it is omitted), so baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Unlock a memory') and the concrete effect ('to allow deletion and editing'), which is enough to tell it apart from the inverse sibling lock_memory without opening a schema. It stops short of naming that sibling explicitly, but the intent is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: by saying unlocking enables deletion and editing, an agent can infer it precedes delete_memory/update_memory. There is no explicit when-to-use statement, no prerequisites, and no named alternative, so it lands at minimum-viable guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_memoryA
Idempotent

Update memory content by ID. Rejects if memory is locked. Ownership enforced when agent_id provided. The new content passes through the same sanitizer as store: it is capped at the content length limit (the response carries truncated:true when the cap bit) and [Memory from ...] annotations are stripped, so content consisting only of those is refused rather than written as an empty row. A new text that runs past the embedding window gets nodes:{status:'queued'}, as on store.

ParametersJSON Schema
NameRequiredDescriptionDefault
contentYesNew content for the memory
agent_idNoAgent ID for ownership verification
memory_idYesMemory ID to update
session_keyNoOpaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Adds substantial behavior beyond the annotations (readOnlyHint=false, idempotentHint=true, destructiveHint=false): the sanitizer passthrough, the content-length cap and the truncated:true response signal, stripping of [Memory from ...] annotations with refusal of annotation-only content, and nodes:{status:'queued'} when text exceeds the embedding window. These are non-obvious side effects an agent could not infer from structured fields.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core action ('Update memory content by ID') before listing caveats, and every sentence carries functional detail. The later sentences are dense and somewhat run-on, but no content is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description compensates by naming the response signals (truncated:true, nodes:{status:'queued'}) and the refusal case, giving an agent everything needed to interpret results. The mutation semantics, constraints, and failure modes are all covered.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: content is sanitized/capped rather than written verbatim, and agent_id activates ownership verification rather than being a passive identifier. memory_id's lock requirement is also surfaced, which the schema does not note.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource with an identifier ('Update memory content by ID') and anchors it against the sibling 'store' by describing shared sanitization behavior. It doesn't explicitly distinguish itself from update_profile, but the memory-vs-profile resource split is clear from the name and text.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete operating conditions: rejection when the memory is locked, and ownership enforcement when agent_id is supplied. This tells the agent when the call will fail and what agent_id buys, though it doesn't state an explicit when-to-use or a named alternative to use instead.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_profileA

Save a pre-computed agent profile to the database. The text passes through the same sanitizer as store, against the profile's own ceiling: it is capped at 2000 characters (CPERSONA_MAX_PROFILE_LENGTH) and the response carries truncated:true when the cap bit — branch on it, the discarded remainder is not stored anywhere else.

ParametersJSON Schema
NameRequiredDescriptionDefault
profileYesProfile text to save (pre-computed by caller). Capped at 2000 characters (CPERSONA_MAX_PROFILE_LENGTH); the response says truncated:true when the cap cut it.
agent_idYesAgent identifier
session_keyNoOpaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.

TDQS

A3.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=false and destructiveHint=false, and the description adds real behavioral value beyond them: it names the sanitizer, discloses the 2000-char ceiling, reveals the truncated:true response flag, and warns that the discarded remainder is not stored elsewhere. It omits whether an existing profile is overwritten on save, which is the one meaningful gap for a save operation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the core action, then a dense but relevant clause on cap behavior. Every clause carries information; the parenthetical constant name is the only mild filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, and the description compensates by explaining the response's truncated:true flag and its consequence. For a non-destructive write tool with full annotation and schema coverage, this is nearly complete; only overwrite/replace semantics are left unstated.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all three parameters, including the same 2000-char cap, making 3 the baseline. The description's only added nuance is that discarded text is not persisted anywhere, which is behavioral rather than parameter-meaning clarification.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("Save a pre-computed agent profile to the database") and the 'pre-computed' qualifier tells the agent the caller supplies the text. It references the sibling 'store' as the sanitizer source but never explicitly contrasts itself with get_profile or store, so sibling differentiation is only implicit.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is a weak hint that the profile is 'pre-computed by caller', implying this is a write-only sink rather than a generator. But there is no statement of when to use this versus get_profile, store, or update_memory, and no preconditions are named. The agent must infer routing from the name alone.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 2 tool updatesv2.6.10
    • Changedreconstruct2 fields changed
      • changedInput schema / properties / lite / description
        Previous value: -"A smaller, cheaper response, for a question one or two records can answer. Quotes at most 2,800 characters unless `budget` is given, short records whole first and then the best-ranked passages of longer ones. Leaves out `ranges`, `bounds` and the budget fields; an item whose only claim is its head carries that claim's `as_of` instead of `claims`. The response says `lite: true`. It can miss evidence the default finds: use the default when the question needs several records or a lite answer was incomplete. `trace=true` returns every field. Default false."New value: +"The same as `mode: \"lite\"`, which is the name to use; kept so that older callers keep working. Not together with `mode`. Default false."
      • addedInput schema / properties / mode
        Added value: +{
        +  "description": "A named answer size whose returned JSON is at most `cap` cl100k_base tokens, counted as sent (`used_tokens` says how many). \"lite\" (cap 3,000) is for a question one or two records can answer: up to 2,800 characters unless `budget` is given, short records whole first, then the best-ranked passages of longer ones. \"pro\" (cap 5,000) reads 15 items by default and quotes as much as the cap holds. Both leave out `ranges`, `bounds` and the budget fields; an item whose only claim is its head carries that claim's `as_of` instead of `claims`. A larger cap never removes an item or an excerpt. Omit it for the default response, which has no cap. `trace=true` returns every field and is not held to the cap.",
        +  "enum": [
        +    "lite",
        +    "pro"
        +  ],
        +  "type": "string"
        +}
    • Changedstore19 fields changed
      • changedInput schema / properties / agent_id / description
        Previous value: -"Agent identifier"New value: +"Agent identifier. May be omitted when this connection can write to exactly one agent."
      • changedInput schema / properties / associations / description
        Previous value: -"Associative memory to declare alongside this call: entities the text mentions, with their aliases, and subject–predicate–object relations. Stored verbatim; the server extracts nothing and infers nothing. On store, the stored memory is recorded as mentioning every entity named here and anchors every relation. Malformed items are reported in the response's associations.dropped and skipped; the memory is stored regardless. Optional."New value: +"Entities and relations to declare against this memory, as declare_associations takes them: {entities: [{name, aliases}], relations: [{subject, predicate, object}]}, subject / object being entity names or 'mem:<id>' / 'ep:<id>' refs. Malformed items are reported in the response's associations.dropped and skipped; the memory is stored regardless."
      • removedInput schema / properties / associations / properties
        Removed value: -{
        -  "entities": {
        -    "description": "Entities to register (if new) and mark as mentioned. Names and aliases are compared after normalization (NFKC, case-folded, whitespace collapsed), so two that normalize alike name one entity.",
        -    "items": {
        -      "properties": {
        -        "aliases": {
        -          "description": "Other names for the same entity. An alias resolves to at most one entity per scope; a second claim on it is dropped.",
        -          "items": {
        -            "type": "string"
        -          },
        -          "type": "array"
        -        },
        -        "name": {
        -          "description": "The canonical name, kept as written.",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "name"
        -      ],
        -      "type": "object"
        -    },
        -    "type": "array"
        -  },
        -  "relations": {
        -    "description": "Declared relations. subject / object are entity names (registered if new) or record refs 'mem:<id>' / 'ep:<id>' of this agent; predicate is free text, normalized. A predicate from the role vocabulary (supports, supersedes, corrects, qualifies, contradicts, temporal_predecessor) on a record → record relation is read by reconstruct as that role.",
        -    "items": {
        -      "properties": {
        -        "object": {
        -          "type": "string"
        -        },
        -        "predicate": {
        -          "type": "string"
        -        },
        -        "subject": {
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "subject",
        -        "predicate",
        -        "object"
        -      ],
        -      "type": "object"
        -    },
        -    "type": "array"
        -  }
        -}
      • changedInput schema / properties / channel / description
        Previous value: -"Memory channel for context separation (e.g. 'chat', 'discord'). Default: '' (shared)."New value: +"Memory channel for context separation (e.g. 'chat'). Default: '' (shared)."
      • addedInput schema / properties / content
        Added value: +{
        +  "description": "The text to store. Content that is empty — or that sanitizes to empty — is refused with ok:false, result:'rejected'.",
        +  "type": "string"
        +}
      • addedInput schema / properties / id
        Added value: +{
        +  "description": "Optional caller id: a later store with the same id in the same project is skipped as a duplicate.",
        +  "type": "string"
        +}
      • addedInput schema / properties / lock
        Added value: +{
        +  "default": false,
        +  "description": "Also lock the memory against edits and deletion. Default false.",
        +  "type": "boolean"
        +}
      • changedInput schema / properties / message / description
        Previous value: -"ClotoMessage to store. Legacy source shapes are normalized server-side where unambiguous (e.g. lowercase type words, Rust serde externally-tagged dicts, bare 'user'/'assistant' strings); unknown shapes are stored verbatim and surfaced by check_health(invalid_source_type)."New value: +"The older form of content, id, source, timestamp and metadata."
      • removedInput schema / properties / message / properties / content / description
        Removed value: -"The text to store. Content that is empty — or that sanitizes to empty — is refused with ok:false, result:'rejected'."
      • removedInput schema / properties / message / properties / id / description
        Removed value: -"Caller-supplied message id used for msg_id-based dedup (γ-project-scoped). Optional."
      • removedInput schema / properties / message / properties / metadata / description
        Removed value: -"Free-form JSON object for producer-specific context. Empty when unused. Serialised size is capped at 8000 characters (same cap for source); an oversized field is refused with result='rejected' rather than truncated, because a truncated JSON document is not a JSON document."
      • changedInput schema / properties / message / properties / source / description
        Previous value: -"Attribution of who produced the content. Canonical shape is {type, id, name}. Type is the discriminator; id / name identify the concrete producer. Store null / empty {} only when the producer is genuinely unknown. A null source is normalized to {} at the write seam, so both persist (and recall) as the anonymous {}."New value: +"Also a bare 'user' / 'assistant' word, or null, stored as the anonymous {}."
      • removedInput schema / properties / message / properties / source / properties
        Removed value: -{
        -  "id": {
        -    "description": "Stable producer id (e.g. discord user id, agent id). Empty when anonymous.",
        -    "type": "string"
        -  },
        -  "name": {
        -    "description": "Human-readable label for display. Empty when unknown.",
        -    "type": "string"
        -  },
        -  "type": {
        -    "description": "Producer role — send one of 'User', 'Agent', 'System'. Legacy producers that cannot are folded server-side at the write seam ('ai' / 'assistant' are normalized to 'Agent'; 'session' is normalized to 'System' (type words are matched case-insensitively)), and shapes outside that table are stored verbatim for check_health(invalid_source_type) to surface.",
        -    "type": "string"
        -  }
        -}
      • removedInput schema / properties / message / properties / timestamp / description
        Removed value: -"UTC ISO-8601 timestamp with offset (e.g. '2026-07-22T12:00:00+00:00'). Defaults to server-time UTC when omitted. Aware non-UTC offsets are accepted; naive strings are surfaced by check_health(timestamp_format_drift)."
      • addedInput schema / properties / metadata
        Added value: +{
        +  "description": "Free-form JSON, at most 8000 characters serialised (source has the same cap). Larger is rejected, not truncated.",
        +  "type": "object"
        +}
      • changedInput schema / properties / project_id / description
        Previous value: -"v2.4.17 isolation axis. Optional — omit or pass '' to store in the global pool. Reads via γ semantics: a recall with project_id='X' returns 'X' rows + global pool. v2.5.1: pass '@auto' to resolve this agent's default from the server's operating context (the resolution is echoed as resolved_project_id; an unmapped agent yields operating_context_warning). bug-186: resolution requires a configured operating context. With none — the default, and equally the outcome of a sidecar that fails to parse — the sentinel is NOT resolved: it is stored and filtered as the literal project_id '@auto', resolved_project_id echoes '@auto', and no warning is raised. Read resolved_project_id before relying on the resolution."New value: +"Isolation bucket; omit or '' for the global pool (a recall in 'X' reads 'X' and the global pool). '@auto' resolves this agent's default from the operating context, echoed as resolved_project_id; with no operating context configured it is stored as the literal '@auto'."
      • addedInput schema / properties / source
        Added value: +{
        +  "description": "Who produced the content, {type, id, name}. Default: {type:'Agent', id:<agent_id>}. Pass {} only when the producer is unknown.",
        +  "properties": {
        +    "id": {
        +      "type": "string"
        +    },
        +    "name": {
        +      "type": "string"
        +    },
        +    "type": {
        +      "description": "One of 'User', 'Agent', 'System'; legacy spellings are folded ('ai' / 'assistant' are normalized to 'Agent'; 'session' is normalized to 'System' (type words are matched case-insensitively)).",
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / timestamp
        Added value: +{
        +  "description": "ISO-8601 with an offset, e.g. '2026-07-22T12:00:00+00:00'. Default: now.",
        +  "type": "string"
        +}
      • removedInput schema / required
        Removed value: -[
        -  "agent_id",
        -  "message"
        -]
  2. 1 tool updatev2.6.5
    • Changedreconstruct1 field changed
      • addedInput schema / properties / lite
        Added value: +{
        +  "description": "A smaller, cheaper response, for a question one or two records can answer. Quotes at most 2,800 characters unless `budget` is given, short records whole first and then the best-ranked passages of longer ones. Leaves out `ranges`, `bounds` and the budget fields; an item whose only claim is its head carries that claim's `as_of` instead of `claims`. The response says `lite: true`. It can miss evidence the default finds: use the default when the question needs several records or a lite answer was incomplete. `trace=true` returns every field. Default false.",
        +  "type": "boolean"
        +}
  3. 1 tool updatev2.6.3
    • Changedrecall1 field changed
      • changedInput schema / properties / time_cue / description
        Previous value: -"2.6: when the answer was stored, as far as you remember. Give after and/or before (a date YYYY-MM-DD, which includes that whole day, or an ISO-8601 timestamp), or ago, plus confidence. The server also searches that period. Among the rows it returns anyway, one found there moves up by at most 3 / 2 / 1 places (sure / likely / vague), and as many extra seats (3 / 2 / 1) hold the best records that search found which the answer does not already hold: one no other search reached, or one the count cut. The returned rows are those of a recall without the cue, reordered, plus at most those seats: no row is removed or re-scored, and which rows pass the quality gate does not change. If the period holds nothing it is widened once, one confidence step. likely widens the period by half its length on each side, vague by its whole length. The response then carries time_cue: the period searched, whether it was widened, how many rows moved and how many seats were used. Pass it only when the request itself says when (a date, a month, \"last week\", \"in the spring\"); omit it when the request names no time, and never fill it with today's date or a guess. A cue whose own period starts within the last 24 hours (today, or later) is not used: the rows are those of a recall without a cue, and time_cue in the response says ignored. A cue that cannot be read returns an error and no messages."New value: +"2.6: when the answer was stored, as far as you remember. Give after and/or before (a date YYYY-MM-DD, which includes that whole day, or an ISO-8601 timestamp), or ago, plus confidence. The server also searches that period. Among the rows it returns anyway, one found there moves up by at most 3 / 2 / 1 places (sure / likely / vague), and as many extra seats (3 / 2 / 1) hold the best records that search found which the answer does not already hold: one no other search reached, or one the count cut. The returned rows are those of a recall without the cue, reordered, plus at most those seats: no row is removed or re-scored, and which rows pass the quality gate does not change. If the period holds nothing it is widened once, one confidence step. likely widens the period by half its length on each side, vague by its whole length. The response then carries time_cue: the period searched, whether it was widened, how many rows moved and how many seats were used, and remainder when the period held more records than the vector search reads and no coarse index could search the rest. Pass it only when the request itself says when (a date, a month, \"last week\", \"in the spring\"); omit it when the request names no time, and never fill it with today's date or a guess. A cue whose own period starts within the last 24 hours (today, or later) is not used: the rows are those of a recall without a cue, and time_cue in the response says ignored. A cue that cannot be read returns an error and no messages."
  4. 25 tool updatesv2.6.1
    • Changedarchive_episode1 field changed
      • addedInput schema / properties / session_key / maxLength
        Added value: +256
    • Changedcalibrate_threshold1 field changed
      • addedInput schema / properties / session_key / maxLength
        Added value: +256
    • Changedcheck_health1 field changed
      • addedInput schema / properties / session_key / maxLength
        Added value: +256
    • Changeddeclare_associations3 fields changed
      • changedInput schema / properties / associations / description
        Previous value: -"Associative memory to declare alongside this call: entities the text mentions, with their aliases, and subject–predicate–object relations. Stored verbatim; the server extracts nothing and infers nothing. On store, the stored memory is recorded as mentioning every entity named here and anchors every relation. Malformed items are reported in the response's associations.dropped and skipped; the memory is stored regardless. Optional."New value: +"The entities and relations to declare. Malformed items are reported in `dropped` and skipped."
      • changedInput schema / properties / associations / properties / entities / description
        Previous value: -"Entities to register (if new) and mark as mentioned. Names are compared after normalization (NFKC, case-folded, whitespace collapsed)."New value: +"Entities to register (if new) and mark as mentioned. Names and aliases are compared after normalization (NFKC, case-folded, whitespace collapsed), so two that normalize alike name one entity."
      • addedInput schema / properties / session_key / maxLength
        Added value: +256
    • Changeddeep_check1 field changed
      • addedInput schema / properties / session_key / maxLength
        Added value: +256
    • Changeddelete_agent_data1 field changed
      • addedInput schema / properties / session_key / maxLength
        Added value: +256
    • Changeddelete_episode1 field changed
      • addedInput schema / properties / session_key / maxLength
        Added value: +256
    • Changeddelete_memory1 field changed
      • addedInput schema / properties / session_key / maxLength
        Added value: +256
    • Changedget_contents2 fields changed
      • changedInput schema / properties / refs / description
        Previous value: -"Refs from recall messages ('mem:<id>' / 'ep:<id>'), or range objects such as {'ref': 'mem:<id>', 'node': [2, 3]} / {'ref': 'ep:<id>', 'span': [0, 800]} (max 20 per call)"New value: +"Refs from recall messages ('mem:<id>' / 'ep:<id>'), or range objects such as {'ref': 'mem:<id>', 'node': [2, 3]} / {'ref': 'ep:<id>', 'span': [0, 800]} / {'ref': 'mem:<id>', 'block': 4, 'revision': '<from an expand>'} (max 20 per call). At most one of node / span / block"
      • changedInput schema / properties / refs / items / anyOf
        Previous value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "properties": {
        -      "node": {
        -        "anyOf": [
        -          {
        -            "minimum": 0,
        -            "type": "integer"
        -          },
        -          {
        -            "items": {
        -              "minimum": 0,
        -              "type": "integer"
        -            },
        -            "maxItems": 2,
        -            "minItems": 2,
        -            "type": "array"
        -          }
        -        ]
        -      },
        -      "ref": {
        -        "type": "string"
        -      },
        -      "span": {
        -        "items": {
        -          "minimum": 0,
        -          "type": "integer"
        -        },
        -        "maxItems": 2,
        -        "minItems": 2,
        -        "type": "array"
        -      }
        -    },
        -    "required": [
        -      "ref"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "properties": {
        +      "block": {
        +        "anyOf": [
        +          {
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          {
        +            "items": {
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "maxItems": 2,
        +            "minItems": 2,
        +            "type": "array"
        +          }
        +        ]
        +      },
        +      "node": {
        +        "anyOf": [
        +          {
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          {
        +            "items": {
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "maxItems": 2,
        +            "minItems": 2,
        +            "type": "array"
        +          }
        +        ]
        +      },
        +      "ref": {
        +        "type": "string"
        +      },
        +      "revision": {
        +        "type": "string"
        +      },
        +      "span": {
        +        "items": {
        +          "minimum": 0,
        +          "type": "integer"
        +        },
        +        "maxItems": 2,
        +        "minItems": 2,
        +        "type": "array"
        +      }
        +    },
        +    "required": [
        +      "ref"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedget_session_findings1 field changed
      • addedInput schema / properties / session_key / maxLength
        Added value: +256
    • Changedimport_memories1 field changed
      • addedInput schema / properties / session_key / maxLength
        Added value: +256
    • Changedlock_memory1 field changed
      • addedInput schema / properties / session_key / maxLength
        Added value: +256
    • Changedmerge_memories1 field changed
      • addedInput schema / properties / session_key / maxLength
        Added value: +256
    • Changedmigrate_channel_axis1 field changed
      • addedInput schema / properties / session_key / maxLength
        Added value: +256
    • Changedpause_persistence1 field changed
      • addedInput schema / properties / session_key / maxLength
        Added value: +256
    • Changedpersistence_status1 field changed
      • addedInput schema / properties / session_key / maxLength
        Added value: +256
    • Changedrecall3 fields changed
      • addedInput schema / properties / session_key / maxLength
        Added value: +256
      • addedInput schema / properties / time_cue
        Added value: +{
        +  "additionalProperties": false,
        +  "description": "2.6: when the answer was stored, as far as you remember. Give after and/or before (a date YYYY-MM-DD, which includes that whole day, or an ISO-8601 timestamp), or ago, plus confidence. The server also searches that period. Among the rows it returns anyway, one found there moves up by at most 3 / 2 / 1 places (sure / likely / vague), and as many extra seats (3 / 2 / 1) hold the best records that search found which the answer does not already hold: one no other search reached, or one the count cut. The returned rows are those of a recall without the cue, reordered, plus at most those seats: no row is removed or re-scored, and which rows pass the quality gate does not change. If the period holds nothing it is widened once, one confidence step. likely widens the period by half its length on each side, vague by its whole length. The response then carries time_cue: the period searched, whether it was widened, how many rows moved and how many seats were used. Pass it only when the request itself says when (a date, a month, \"last week\", \"in the spring\"); omit it when the request names no time, and never fill it with today's date or a guess. A cue whose own period starts within the last 24 hours (today, or later) is not used: the rows are those of a recall without a cue, and time_cue in the response says ignored. A cue that cannot be read returns an error and no messages.",
        +  "properties": {
        +    "after": {
        +      "type": "string"
        +    },
        +    "ago": {
        +      "description": "Relative to now: {\"unit\": \"days\" | \"weeks\" | \"months\", \"value\": N} names the unit-long period centred N units ago (a month is 30 days); \"long_ago\" names the oldest third of what this scope holds.",
        +      "oneOf": [
        +        {
        +          "additionalProperties": false,
        +          "properties": {
        +            "unit": {
        +              "enum": [
        +                "days",
        +                "weeks",
        +                "months"
        +              ],
        +              "type": "string"
        +            },
        +            "value": {
        +              "minimum": 0,
        +              "type": "integer"
        +            }
        +          },
        +          "required": [
        +            "unit",
        +            "value"
        +          ],
        +          "type": "object"
        +        },
        +        {
        +          "enum": [
        +            "long_ago"
        +          ],
        +          "type": "string"
        +        }
        +      ]
        +    },
        +    "before": {
        +      "type": "string"
        +    },
        +    "confidence": {
        +      "enum": [
        +        "sure",
        +        "likely",
        +        "vague"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "confidence"
        +  ],
        +  "type": "object"
        +}
      • addedInput schema / properties / trace
        Added value: +{
        +  "default": false,
        +  "description": "2.6 recall trace: true adds `trace` to the response — which rows each stage (retrieval arms, fusion, quality gate, autocut, final order, count cut, reserved seats) kept, dropped or reordered, and why, with ranks and scores. It carries references only, never stored text, and is not stored on the server. trace_version identifies its shape. False (the default) returns the response unchanged.",
        +  "type": "boolean"
        +}
    • Changedrecall_with_context1 field changed
      • addedInput schema / properties / session_key / maxLength
        Added value: +256
    • Changedreconstruct7 fields changed
      • changedInput schema / properties / budget / description
        Previous value: -"Payload budget: characters of quoted text (item `content` plus `excerpts`) the response may carry. Bounds depth, where `count` bounds breadth, and breadth wins: excerpts are omitted before any item is. Omit for the server default, which is never less than one quote per item of the window; an operator-forced value overrides both; clamped to the server maximum and raised to one preview-tier excerpt, and budget_policy says which."New value: +"Payload budget: characters of quoted text (item `content` plus `excerpts`) the response may carry. Bounds depth, where `count` bounds breadth, and breadth wins: excerpts are omitted before any item is. Omit for the server default, which is never less than one quote per item of the window; an operator-forced value overrides both; clamped to the server maximum and raised to one head quote, and budget_policy says which."
      • changedInput schema / properties / count / description
        Previous value: -"Ceiling on recall items returned -- not a fill target, not a search depth. Declare per call; omit to take the server default (1 unless configured). An operator-forced value overrides both. Requesting 5 with only 2 valid items returns 2; neither setting requires filling the window. Clamped to the server maximum, and the clamp is reported in count_policy rather than applied silently."New value: +"Ceiling on recall items returned -- not a fill target, not a search depth. Declare per call; omit to take the server default (10 unless configured). An operator-forced value overrides both. Requesting 5 with only 2 valid items returns 2; neither setting requires filling the window. Clamped to the server maximum, and the clamp is reported in count_policy rather than applied silently."
      • changedInput schema / properties / max_hops / description
        Previous value: -"Relation hops the walk may follow from an item's candidates through declared entity -> entity relations. 0 adds no walked evidence. A relation left unfollowed at the bound is named in bounds.omitted."New value: +"Relation hops the walk may follow from an item's candidates through declared entity -> entity relations. 0 adds no walked evidence. A relation left unfollowed at the bound is named in bounds.omitted. At most 5, as for traverse: a larger value is lowered to it, and bounds.max_hops then states the value applied."
      • addedInput schema / properties / max_hops / maximum
        Added value: +5
      • addedInput schema / properties / session_key / maxLength
        Added value: +256
      • addedInput schema / properties / time_cue
        Added value: +{
        +  "description": "2.6: when the answer was stored, as far as you remember — the same object recall takes (see recall's time_cue), applied to the candidate recall this reconstruction reads. The response carries time_cue when one was applied.",
        +  "type": "object"
        +}
      • changedInput schema / properties / trace / description
        Previous value: -"Include candidate refs and cluster membership for local diagnosis; no full text is added."New value: +"Include candidate refs and cluster membership for local diagnosis, and the trace of the recall it made as trace.recall; no full text is added."
    • Changedresume_persistence1 field changed
      • addedInput schema / properties / session_key / maxLength
        Added value: +256
    • Changedset_recall_precision1 field changed
      • addedInput schema / properties / session_key / maxLength
        Added value: +256
    • Changedstore2 fields changed
      • changedInput schema / properties / associations / properties / entities / description
        Previous value: -"Entities to register (if new) and mark as mentioned. Names are compared after normalization (NFKC, case-folded, whitespace collapsed)."New value: +"Entities to register (if new) and mark as mentioned. Names and aliases are compared after normalization (NFKC, case-folded, whitespace collapsed), so two that normalize alike name one entity."
      • addedInput schema / properties / session_key / maxLength
        Added value: +256
    • Changedunlock_memory1 field changed
      • addedInput schema / properties / session_key / maxLength
        Added value: +256
    • Changedupdate_memory1 field changed
      • addedInput schema / properties / session_key / maxLength
        Added value: +256
    • Changedupdate_profile1 field changed
      • addedInput schema / properties / session_key / maxLength
        Added value: +256
  5. 8 tool updatesv2.5.12
    • Addeddeclare_associations
    • Changeddeep_check1 field changed
      • changedInput schema / properties / checks / description
        Previous value: -"Checks to run (empty = all). Options: anonymous_source, short_content, stale_profile, orphaned_episodes, calibration_staleness, near_duplicate"New value: +"Checks to run (empty = all). Options: anonymous_source, short_content, stale_profile, orphaned_episodes, calibration_staleness, near_duplicate, unnormalized_content, embedding_norm"
    • Changedget_contents3 fields changed
      • changedInput schema / properties / refs / description
        Previous value: -"Refs from recall messages, e.g. ['mem:123', 'ep:45'] (max 20 per call)"New value: +"Refs from recall messages ('mem:<id>' / 'ep:<id>'), or range objects such as {'ref': 'mem:<id>', 'node': [2, 3]} / {'ref': 'ep:<id>', 'span': [0, 800]} (max 20 per call)"
      • addedInput schema / properties / refs / items / anyOf
        Added value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "properties": {
        +      "node": {
        +        "anyOf": [
        +          {
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          {
        +            "items": {
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "maxItems": 2,
        +            "minItems": 2,
        +            "type": "array"
        +          }
        +        ]
        +      },
        +      "ref": {
        +        "type": "string"
        +      },
        +      "span": {
        +        "items": {
        +          "minimum": 0,
        +          "type": "integer"
        +        },
        +        "maxItems": 2,
        +        "minItems": 2,
        +        "type": "array"
        +      }
        +    },
        +    "required": [
        +      "ref"
        +    ],
        +    "type": "object"
        +  }
        +]
      • removedInput schema / properties / refs / items / type
        Removed value: -"string"
    • Changedrecall1 field changed
      • changedInput schema / properties / exclude_contents / description
        Previous value: -"Normalized content strings to exclude from results (starts-with match). Used to prevent duplication with conversation context already known to the caller."New value: +"Normalized content strings to exclude from results (starts-with match). Used to prevent duplication with conversation context already known to the caller. bug-399: the starts-with rule holds only at or above 32 characters. A shorter entry has to EQUAL the stored content (after the normalization this parameter already asks for: stripped and lower-cased) — a short prefix would otherwise suppress every memory beginning with it, inside the retrievers and with nothing in the response reporting the exclusion. Size entries at or above that length when you mean a prefix."
    • Changedrecall_with_context8 fields changed
      • changedInput schema / properties / external_context / description
        Previous value: -"Conversation history entries [{role, name?, user_id?, content, timestamp?}, ...]"New value: +"Conversation history entries [{role, content, name?, user_id?, timestamp?}, ...]. Every declared field is a string; one that is not is read as absent and reported in context_field_issues (CPERSONA_EXTERNAL_CONTEXT_MODE)."
      • addedInput schema / properties / external_context / items / properties / content / description
        Added value: +"The entry's text. A string — a value that is not one is read as absent and reported in context_field_issues."
      • removedInput schema / properties / external_context / items / properties / content / type
        Removed value: -"string"
      • addedInput schema / properties / external_context / items / properties / name
        Added value: +{
        +  "description": "Display label for a role=user entry; becomes source.name, and source.id when user_id is absent. Default 'User'. A string — a value that is not one is read as absent and reported in context_field_issues."
        +}
      • addedInput schema / properties / external_context / items / properties / role / description
        Added value: +"'user' or 'assistant'; other roles filter the recall without being merged. A string — a value that is not one is read as absent and reported in context_field_issues."
      • removedInput schema / properties / external_context / items / properties / role / type
        Removed value: -"string"
      • addedInput schema / properties / external_context / items / properties / timestamp
        Added value: +{
        +  "description": "ISO-8601 stamp deciding where this entry lands in the merged chronology. An entry without one — or with one that names no instant — sorts ahead of every dated message. A string — a value that is not one is read as absent and reported in context_field_issues."
        +}
      • addedInput schema / properties / external_context / items / properties / user_id
        Added value: +{
        +  "description": "Stable id for a role=user entry; becomes source.id as 'discord:<user_id>'. A string — a value that is not one is read as absent and reported in context_field_issues."
        +}
    • Addedreconstruct
    • Changedstore2 fields changed
      • addedInput schema / properties / associations
        Added value: +{
        +  "description": "Associative memory to declare alongside this call: entities the text mentions, with their aliases, and subject–predicate–object relations. Stored verbatim; the server extracts nothing and infers nothing. On store, the stored memory is recorded as mentioning every entity named here and anchors every relation. Malformed items are reported in the response's associations.dropped and skipped; the memory is stored regardless. Optional.",
        +  "properties": {
        +    "entities": {
        +      "description": "Entities to register (if new) and mark as mentioned. Names are compared after normalization (NFKC, case-folded, whitespace collapsed).",
        +      "items": {
        +        "properties": {
        +          "aliases": {
        +            "description": "Other names for the same entity. An alias resolves to at most one entity per scope; a second claim on it is dropped.",
        +            "items": {
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          "name": {
        +            "description": "The canonical name, kept as written.",
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "name"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "relations": {
        +      "description": "Declared relations. subject / object are entity names (registered if new) or record refs 'mem:<id>' / 'ep:<id>' of this agent; predicate is free text, normalized. A predicate from the role vocabulary (supports, supersedes, corrects, qualifies, contradicts, temporal_predecessor) on a record → record relation is read by reconstruct as that role.",
        +      "items": {
        +        "properties": {
        +          "object": {
        +            "type": "string"
        +          },
        +          "predicate": {
        +            "type": "string"
        +          },
        +          "subject": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "subject",
        +          "predicate",
        +          "object"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • changedInput schema / properties / message / properties / source / type
        Previous value: -"object"New value: +[
        +  "object",
        +  "string",
        +  "null"
        +]
    • Addedtraverse
  6. 23 tool updatesv2.5.10
    • Changedarchive_episode1 field changed
      • addedInput schema / properties / session_key
        Added value: +{
        +  "default": "",
        +  "description": "Opaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.",
        +  "type": "string"
        +}
    • Changedcalibrate_threshold1 field changed
      • addedInput schema / properties / session_key
        Added value: +{
        +  "default": "",
        +  "description": "Opaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.",
        +  "type": "string"
        +}
    • Changedcheck_health1 field changed
      • addedInput schema / properties / session_key
        Added value: +{
        +  "default": "",
        +  "description": "Opaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.",
        +  "type": "string"
        +}
    • Addedcheck_update
    • Changeddeep_check1 field changed
      • addedInput schema / properties / session_key
        Added value: +{
        +  "default": "",
        +  "description": "Opaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.",
        +  "type": "string"
        +}
    • Changeddelete_agent_data1 field changed
      • addedInput schema / properties / session_key
        Added value: +{
        +  "default": "",
        +  "description": "Opaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.",
        +  "type": "string"
        +}
    • Changeddelete_episode1 field changed
      • addedInput schema / properties / session_key
        Added value: +{
        +  "default": "",
        +  "description": "Opaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.",
        +  "type": "string"
        +}
    • Changeddelete_memory1 field changed
      • addedInput schema / properties / session_key
        Added value: +{
        +  "default": "",
        +  "description": "Opaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.",
        +  "type": "string"
        +}
    • Addedget_session_findings
    • Changedimport_memories1 field changed
      • addedInput schema / properties / session_key
        Added value: +{
        +  "default": "",
        +  "description": "Opaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.",
        +  "type": "string"
        +}
    • Changedlock_memory1 field changed
      • addedInput schema / properties / session_key
        Added value: +{
        +  "default": "",
        +  "description": "Opaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.",
        +  "type": "string"
        +}
    • Changedmerge_memories1 field changed
      • addedInput schema / properties / session_key
        Added value: +{
        +  "default": "",
        +  "description": "Opaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.",
        +  "type": "string"
        +}
    • Changedmigrate_channel_axis1 field changed
      • addedInput schema / properties / session_key
        Added value: +{
        +  "default": "",
        +  "description": "Opaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.",
        +  "type": "string"
        +}
    • Changedpause_persistence1 field changed
      • addedInput schema / properties / session_key
        Added value: +{
        +  "default": "",
        +  "description": "Opaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.",
        +  "type": "string"
        +}
    • Changedpersistence_status1 field changed
      • addedInput schema / properties / session_key
        Added value: +{
        +  "default": "",
        +  "description": "Opaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.",
        +  "type": "string"
        +}
    • Changedrecall2 fields changed
      • changedInput schema / properties / limit / description
        Previous value: -"Per-retriever search depth, not a pure response cap (CSC #716): the value is handed to each retrieval channel (vector / episode FTS / keyword) as its top-K, so lowering it shrinks the candidate pool itself — rows beyond the depth are unreachable at any gate value, and score normalization / autocut operate on the smaller pool, which can also reorder what remains. Fewer rows than this may be returned. (Agent-facing cap; the library layer accepts up to the scan window for direct callers.)"New value: +"Per-retriever search depth, not a pure response cap: the value is handed to each retrieval channel (vector / episode FTS / keyword) as its top-K, so lowering it shrinks the candidate pool itself — rows beyond the depth are unreachable at any gate value, and score normalization / autocut operate on the smaller pool, which can also reorder what remains. Fewer rows than this may be returned. (Agent-facing cap; the library layer accepts up to the scan window for direct callers.)"
      • addedInput schema / properties / session_key
        Added value: +{
        +  "default": "",
        +  "description": "Opaque session identity you declare — a partition hint, NOT authentication. It scopes this process's per-session state: the degraded-recall advisory's \"already told you\" memory, and which no-persist pause applies to this call. It does NOT filter stored data (use agent_id / project_id / channel for that), and it never reaches the database. Omit it to share one bucket with every other caller that omits it, which is the behaviour that predates this parameter.",
        +  "type": "string"
        +}
    • Changedrecall_with_context2 fields changed
      • changedInput schema / properties / limit / description
        Previous value: -"Per-retriever search depth for the underlying recall, not a pure response cap — same semantics as recall's limit (CSC #716): lowering it shrinks the candidate pool itself, not just the rows returned. (Agent-facing cap; the library layer accepts up to the scan window for direct callers.)"New value: +"Per-retriever search depth for the underlying recall, not a pure response cap — same semantics as recall's limit: lowering it shrinks the candidate pool itself, not just the rows returned. (Agent-facing cap; the library layer accepts up to the scan window for direct callers.)"
      • addedInput schema / properties / session_key
        Added value: +{
        +  "default": "",
        +  "description": "Opaque session identity you declare — a partition hint, NOT authentication. It scopes this process's per-session state: the degraded-recall advisory's \"already told you\" memory, and which no-persist pause applies to this call. It does NOT filter stored data (use agent_id / project_id / channel for that), and it never reaches the database. Omit it to share one bucket with every other caller that omits it, which is the behaviour that predates this parameter.",
        +  "type": "string"
        +}
    • Changedresume_persistence1 field changed
      • addedInput schema / properties / session_key
        Added value: +{
        +  "default": "",
        +  "description": "Opaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.",
        +  "type": "string"
        +}
    • Changedset_recall_precision1 field changed
      • addedInput schema / properties / session_key
        Added value: +{
        +  "default": "",
        +  "description": "Opaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.",
        +  "type": "string"
        +}
    • Changedstore1 field changed
      • addedInput schema / properties / session_key
        Added value: +{
        +  "default": "",
        +  "description": "Opaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.",
        +  "type": "string"
        +}
    • Changedunlock_memory1 field changed
      • addedInput schema / properties / session_key
        Added value: +{
        +  "default": "",
        +  "description": "Opaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.",
        +  "type": "string"
        +}
    • Changedupdate_memory1 field changed
      • addedInput schema / properties / session_key
        Added value: +{
        +  "default": "",
        +  "description": "Opaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.",
        +  "type": "string"
        +}
    • Changedupdate_profile1 field changed
      • addedInput schema / properties / session_key
        Added value: +{
        +  "default": "",
        +  "description": "Opaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.",
        +  "type": "string"
        +}
  7. 2 tool updatesv2.5.6
    • Changedrecall1 field changed
      • changedInput schema / properties / deep / description
        Previous value: -"Deep recall — disable time and completion decay for exhaustive search"New value: +"Deep recall — halves the quality gate (and the calibrated fused gate), so weaker matches are admitted. It also disables time and completion decay, which are inert unless CPERSONA_CONFIDENCE_ENABLED=true, and it does NOT widen the scan window (CPERSONA_MAX_MEMORIES) — deep is about how weak a match may be, not how far back the search reaches."
    • Changedrecall_with_context1 field changed
      • changedInput schema / properties / deep / description
        Previous value: -"Disable time decay"New value: +"Deep recall — same semantics as in `recall`: halves the quality gate so weaker matches are admitted."
  8. 5 tool updatesv2.5.4
    • Changedcalibrate_threshold1 field changed
      • addedInput schema / properties / method / enum
        Added value: +[
        +  "separation",
        +  "percentile",
        +  "zscore"
        +]
    • Changedrecall1 field changed
      • changedInput schema / properties / limit / description
        Previous value: -"Max memories to return (agent-facing cap; the library layer accepts up to the scan window for direct callers)"New value: +"Per-retriever search depth, not a pure response cap (CSC #716): the value is handed to each retrieval channel (vector / episode FTS / keyword) as its top-K, so lowering it shrinks the candidate pool itself — rows beyond the depth are unreachable at any gate value, and score normalization / autocut operate on the smaller pool, which can also reorder what remains. Fewer rows than this may be returned. (Agent-facing cap; the library layer accepts up to the scan window for direct callers.)"
    • Changedrecall_with_context1 field changed
      • changedInput schema / properties / limit / description
        Previous value: -"Max recalled memories (agent-facing cap; the library layer accepts up to the scan window for direct callers)"New value: +"Per-retriever search depth for the underlying recall, not a pure response cap — same semantics as recall's limit (CSC #716): lowering it shrinks the candidate pool itself, not just the rows returned. (Agent-facing cap; the library layer accepts up to the scan window for direct callers.)"
    • Changedstore2 fields changed
      • changedInput schema / properties / message / properties / source / properties / type / description
        Previous value: -"Producer role — this enum IS the contract; send one of these. Legacy producers that cannot are folded server-side at the write seam ('ai' / 'assistant' are normalized to 'Agent'; 'session' is normalized to 'System' (type words are matched case-insensitively)), and shapes outside that table are stored verbatim for check_health(invalid_source_type) to surface."New value: +"Producer role — send one of 'User', 'Agent', 'System'. Legacy producers that cannot are folded server-side at the write seam ('ai' / 'assistant' are normalized to 'Agent'; 'session' is normalized to 'System' (type words are matched case-insensitively)), and shapes outside that table are stored verbatim for check_health(invalid_source_type) to surface."
      • removedInput schema / properties / message / properties / source / properties / type / enum
        Removed value: -[
        -  "User",
        -  "Agent",
        -  "System"
        -]
    • Changedupdate_profile1 field changed
      • changedInput schema / properties / profile / description
        Previous value: -"Profile text to save (pre-computed by caller)"New value: +"Profile text to save (pre-computed by caller). Capped at 2000 characters (CPERSONA_MAX_PROFILE_LENGTH); the response says truncated:true when the cap cut it."
  9. 17 tool updatesv2.5.2
    • Changedarchive_episode1 field changed
      • changedInput schema / properties / project_id / description
        Previous value: -"v2.4.17 isolation axis. Omit or pass '' for the global pool."New value: +"v2.4.17 isolation axis. Omit or pass '' for the global pool. v2.5.1: pass '@auto' to resolve this agent's default from the server's operating context (the resolution is echoed as resolved_project_id; an unmapped agent yields operating_context_warning). bug-186: resolution requires a configured operating context. With none — the default, and equally the outcome of a sidecar that fails to parse — the sentinel is NOT resolved: it is stored and filtered as the literal project_id '@auto', resolved_project_id echoes '@auto', and no warning is raised. Read resolved_project_id before relying on the resolution."
    • Addedcalibrate_threshold
    • Addedcheck_health
    • Addeddelete_episode
    • Addeddelete_memory
    • Addedexport_memories
    • Addedget_operating_context
    • Addedget_recall_precision
    • Changedlist_episodes1 field changed
      • changedInput schema / properties / project_id / description
        Previous value: -"v2.4.17 γ filter. Same semantics as list_memories."New value: +"v2.4.17 γ filter. Same semantics as list_memories. v2.5.1: pass '@auto' to resolve this agent's default from the server's operating context (the resolution is echoed as resolved_project_id; an unmapped agent yields operating_context_warning). bug-186: resolution requires a configured operating context. With none — the default, and equally the outcome of a sidecar that fails to parse — the sentinel is NOT resolved: it is stored and filtered as the literal project_id '@auto', resolved_project_id echoes '@auto', and no warning is raised. Read resolved_project_id before relying on the resolution."
    • Changedlist_memories1 field changed
      • changedInput schema / properties / project_id / description
        Previous value: -"v2.4.17 γ filter. Omit → no filter; '' → global pool only; 'X' → 'X' ∪ global pool."New value: +"v2.4.17 γ filter. Omit → no filter; '' → global pool only; 'X' → 'X' ∪ global pool. v2.5.1: pass '@auto' to resolve this agent's default from the server's operating context (the resolution is echoed as resolved_project_id; an unmapped agent yields operating_context_warning). bug-186: resolution requires a configured operating context. With none — the default, and equally the outcome of a sidecar that fails to parse — the sentinel is NOT resolved: it is stored and filtered as the literal project_id '@auto', resolved_project_id echoes '@auto', and no warning is raised. Read resolved_project_id before relying on the resolution."
    • Addedpause_persistence
    • Addedrecall
    • Addedrecall_with_context
    • Addedresume_persistence
    • Changedstore4 fields changed
      • changedInput schema / properties / message / properties / content / description
        Previous value: -"The text to store. Empty content is skipped."New value: +"The text to store. Content that is empty — or that sanitizes to empty — is refused with ok:false, result:'rejected'."
      • changedInput schema / properties / message / properties / metadata / description
        Previous value: -"Free-form JSON object for producer-specific context. Empty when unused."New value: +"Free-form JSON object for producer-specific context. Empty when unused. Serialised size is capped at 8000 characters (same cap for source); an oversized field is refused with result='rejected' rather than truncated, because a truncated JSON document is not a JSON document."
      • changedInput schema / properties / message / properties / source / properties / type / description
        Previous value: -"Producer role. 'Assistant' / 'ai' are normalized to 'Agent'; 'session' is normalized to 'System'."New value: +"Producer role — this enum IS the contract; send one of these. Legacy producers that cannot are folded server-side at the write seam ('ai' / 'assistant' are normalized to 'Agent'; 'session' is normalized to 'System' (type words are matched case-insensitively)), and shapes outside that table are stored verbatim for check_health(invalid_source_type) to surface."
      • changedInput schema / properties / project_id / description
        Previous value: -"v2.4.17 isolation axis. Optional — omit or pass '' to store in the global pool. Reads via γ semantics: a recall with project_id='X' returns 'X' rows + global pool. v2.5.1: pass '@auto' to resolve this agent's default from the server's operating context (echoed as resolved_project_id)."New value: +"v2.4.17 isolation axis. Optional — omit or pass '' to store in the global pool. Reads via γ semantics: a recall with project_id='X' returns 'X' rows + global pool. v2.5.1: pass '@auto' to resolve this agent's default from the server's operating context (the resolution is echoed as resolved_project_id; an unmapped agent yields operating_context_warning). bug-186: resolution requires a configured operating context. With none — the default, and equally the outcome of a sidecar that fails to parse — the sentinel is NOT resolved: it is stored and filtered as the literal project_id '@auto', resolved_project_id echoes '@auto', and no warning is raised. Read resolved_project_id before relying on the resolution."
    • Addedunlock_memory
    • Addedupdate_profile
  10. 15 tool updatesv2.5.1
    • Changedarchive_episode1 field changed
      • changedInput schema / properties / history / description
        Previous value: -"Original conversation messages (used for timestamp extraction and embedding)"New value: +"Original conversation messages (used for start/end timestamp extraction; the episode embedding is computed from summary)"
    • Removedcalibrate_threshold
    • Removedcheck_health
    • Removeddelete_episode
    • Removeddelete_memory
    • Removedexport_memories
    • Addedget_contents
    • Removedget_recall_precision
    • Removedpause_persistence
    • Removedrecall
    • Removedrecall_with_context
    • Removedresume_persistence
    • Changedstore3 fields changed
      • changedInput schema / properties / message / description
        Previous value: -"ClotoMessage to store (id, content, source, timestamp, metadata)"New value: +"ClotoMessage to store. Legacy source shapes are normalized server-side where unambiguous (e.g. lowercase type words, Rust serde externally-tagged dicts, bare 'user'/'assistant' strings); unknown shapes are stored verbatim and surfaced by check_health(invalid_source_type)."
      • addedInput schema / properties / message / properties
        Added value: +{
        +  "content": {
        +    "description": "The text to store. Empty content is skipped.",
        +    "type": "string"
        +  },
        +  "id": {
        +    "description": "Caller-supplied message id used for msg_id-based dedup (γ-project-scoped). Optional.",
        +    "type": "string"
        +  },
        +  "metadata": {
        +    "description": "Free-form JSON object for producer-specific context. Empty when unused.",
        +    "type": "object"
        +  },
        +  "source": {
        +    "description": "Attribution of who produced the content. Canonical shape is {type, id, name}. Type is the discriminator; id / name identify the concrete producer. Store null / empty {} only when the producer is genuinely unknown. A null source is normalized to {} at the write seam, so both persist (and recall) as the anonymous {}.",
        +    "properties": {
        +      "id": {
        +        "description": "Stable producer id (e.g. discord user id, agent id). Empty when anonymous.",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Human-readable label for display. Empty when unknown.",
        +        "type": "string"
        +      },
        +      "type": {
        +        "description": "Producer role. 'Assistant' / 'ai' are normalized to 'Agent'; 'session' is normalized to 'System'.",
        +        "enum": [
        +          "User",
        +          "Agent",
        +          "System"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "timestamp": {
        +    "description": "UTC ISO-8601 timestamp with offset (e.g. '2026-07-22T12:00:00+00:00'). Defaults to server-time UTC when omitted. Aware non-UTC offsets are accepted; naive strings are surfaced by check_health(timestamp_format_drift).",
        +    "type": "string"
        +  }
        +}
      • changedInput schema / properties / project_id / description
        Previous value: -"v2.4.17 isolation axis. Optional — omit or pass '' to store in the global pool. Reads via γ semantics: a recall with project_id='X' returns 'X' rows + global pool."New value: +"v2.4.17 isolation axis. Optional — omit or pass '' to store in the global pool. Reads via γ semantics: a recall with project_id='X' returns 'X' rows + global pool. v2.5.1: pass '@auto' to resolve this agent's default from the server's operating context (echoed as resolved_project_id)."
    • Removedunlock_memory
    • Removedupdate_profile
  11. 2 tool updatesv2.4.37
    • Changedcheck_health1 field changed
      • addedInput schema / properties / checks
        Added value: +{
        +  "description": "Registry check names to run (empty = all). See cpersona.checks.HEALTH_CHECK_NAMES.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
    • Changeddeep_check1 field changed
      • changedInput schema / properties / checks / description
        Previous value: -"Checks to run (empty = all). Options: anonymous_source, short_content, stale_profile, orphaned_episodes"New value: +"Checks to run (empty = all). Options: anonymous_source, short_content, stale_profile, orphaned_episodes, calibration_staleness, near_duplicate"
  12. 13 tool updatesv2.4.34
    • Changedarchive_episode2 fields changed
      • addedInput schema / properties / channel
        Added value: +{
        +  "description": "v2.4.22 conversation-channel tag (e.g. a Discord channel id). Default '' (= unscoped). Channel-scoped recall returns episodes whose channel matches; this powers the per-channel episodic loop.",
        +  "type": "string"
        +}
      • addedInput schema / properties / project_id
        Added value: +{
        +  "description": "v2.4.17 isolation axis. Omit or pass '' for the global pool.",
        +  "type": "string"
        +}
    • Changedcalibrate_threshold3 fields changed
      • addedInput schema / properties / method
        Added value: +{
        +  "description": "'percentile' (default), 'zscore', or 'separation' (two-population, learns the operating point from null vs nearest-neighbour positives)",
        +  "type": "string"
        +}
      • addedInput schema / properties / percentile
        Added value: +{
        +  "description": "Null-distribution quantile for method='percentile' (default: 0.95, higher = stricter)",
        +  "type": "number"
        +}
      • changedInput schema / properties / z_factor / description
        Previous value: -"Z-score multiplier (default: 1.0, higher = stricter)"New value: +"Z-score multiplier for method='zscore' (default: 1.0, higher = stricter)"
    • Addedget_recall_precision
    • Changedlist_episodes1 field changed
      • addedInput schema / properties / project_id
        Added value: +{
        +  "description": "v2.4.17 γ filter. Same semantics as list_memories.",
        +  "type": "string"
        +}
    • Changedlist_memories1 field changed
      • addedInput schema / properties / project_id
        Added value: +{
        +  "description": "v2.4.17 γ filter. Omit → no filter; '' → global pool only; 'X' → 'X' ∪ global pool.",
        +  "type": "string"
        +}
    • Addedmigrate_channel_axis
    • Addedpause_persistence
    • Addedpersistence_status
    • Changedrecall2 fields changed
      • addedInput schema / properties / project_id
        Added value: +{
        +  "description": "v2.4.17 γ filter. Omit → no filter (all projects). '' → global pool only. 'X' → 'X' bucket ∪ global pool. Threaded through cascade / RRF / vector / FTS / keyword paths.",
        +  "type": "string"
        +}
      • addedInput schema / properties / source_id
        Added value: +{
        +  "default": "",
        +  "description": "v2.4.20 per-user source filter. Empty (default) = no filter. Non-empty = prefix match against json_extract(source, '$.id'), e.g. 'discord:12345' to restrict to one Discord user, or 'discord:' to scope to all Discord-sourced memories. Episodes are skipped when set (no per-user source tagging).",
        +  "type": "string"
        +}
    • Changedrecall_with_context2 fields changed
      • addedInput schema / properties / project_id
        Added value: +{
        +  "description": "v2.4.17 γ filter — passed through to recall. Same semantics as in `recall`.",
        +  "type": "string"
        +}
      • addedInput schema / properties / source_id
        Added value: +{
        +  "default": "",
        +  "description": "v2.4.20 per-user source filter — passed through to recall. Same semantics as in `recall`.",
        +  "type": "string"
        +}
    • Addedresume_persistence
    • Addedset_recall_precision
    • Changedstore1 field changed
      • addedInput schema / properties / project_id
        Added value: +{
        +  "description": "v2.4.17 isolation axis. Optional — omit or pass '' to store in the global pool. Reads via γ semantics: a recall with project_id='X' returns 'X' rows + global pool.",
        +  "type": "string"
        +}
  13. 6 tool updatesv2.4.10
    • Addeddeep_check
    • Addedlock_memory
    • Changedrecall1 field changed
      • addedInput schema / properties / exclude_contents
        Added value: +{
        +  "description": "Normalized content strings to exclude from results (starts-with match). Used to prevent duplication with conversation context already known to the caller.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
    • Addedrecall_with_context
    • Addedunlock_memory
    • Addedupdate_memory

TDQS

A3.8/5.0

Scored across 34 tools

Disambiguation4/5

Most tools have clearly distinct purposes (storage, recall, graph, integrity, persistence, admin), and descriptions go out of their way to explain when to prefer one over another (e.g. reconstruct over recall). However there are three recall entry points (recall, reconstruct, recall_with_context) and three overlapping diagnostics (check_health, deep_check, get_session_findings) whose boundaries — especially fix vs report-only vs pull — require careful reading to keep straight.

Naming Consistency4/5

Names are uniformly snake_case, so no casing chaos, but the verb convention varies across the set: some are get_/list_/delete_/update_ prefixed (get_contents, list_memories, delete_memory) while others are bare verbs or nouns (store, reconstruct, recall, traverse, pause_persistence, migrate_channel_axis). Readable and mostly predictable, with minor deviations.

Tool Count3/5

34 tools is on the heavy side for a single server, and a few clusters (three recall paths, three health/diagnostic tools, several admin/ops tools) inflate the surface. The domain is genuinely broad — memory/episode/profile CRUD, associative graph, integrity, persistence control, and release management — so most tools earn a place, but the count is borderline unwieldy.

Completeness5/5

The surface is remarkably complete: full CRUD for memories, episodes, and profiles; locking; multi-strategy recall plus ref expansion; association declaration, traversal, and retraction; health/deep/integrity diagnostics; calibration and precision controls; backup/import/export/merge; persistence pause/resume; and update checks. No obvious operational dead ends for the stated memory-server purpose.

Maintenance

ActivityActive
ResponsivenessUnresponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    Persistent AI memory server with 3-layer hybrid search (vector + FTS5 + keyword), confidence scoring via Reciprocal Rank Fusion, episodic/profile memory, and 16 tools. Zero LLM dependency. Works standalone with Claude Desktop and Claude Code. MIT licensed.
    3
    Business Source 1.1
  • A
    license
    B
    quality
    B
    maintenance
    Cross-agent memory server: hybrid (vector + full-text + knowledge-graph) recall, per-user private/shared visibility, write-side secret/PII redaction, and as-of-date bi-temporal fact queries. Auto-injection hooks for Claude Code / Cursor / Codex; self-hostable on PostgreSQL or SQLite.
    46
    9
    MIT