PseudoLife-MCP
OfficialPersistent long-term memory MCP server for coding agents — store, retrieve, consolidate, and coordinate knowledge across sessions and clients.
Store durable facts, decisions, and observations with source tags, episodes, authority, and distortion tolerance.
Search memories via hybrid dense + lexical retrieval, with filters, reranking, BM25, recency boost, and ranking traces.
Maintain a canonical cortex of current facts per
entity.attributeslot, including contested slots, set-valued slots, freshness decay, and full version history.Supersede, reinforce, forget, reinstate, consolidate, or bulk-clean memories with audit trails and historical preservation.
Build and query a typed knowledge graph: relate/unrelate entities, bind aliases, define relations, traverse neighborhoods, and run multi-hop recall.
Store and search cited world facts with age-decayed trust and source URLs.
Record procedural outcomes and search learned lessons for do/avoid guidance on future tasks.
Manage session episodes: start/end nested sub-episodes, title sessions, and summarize episode activity.
Run dream consolidation passes that extract canonical facts and graph structure from recent memory streams.
Ingest and search background documents (txt/md/pdf/html) in a separate RAG reference bank.
Coordinate multiple agents via peer roster/status/leases, park records, addressed mail, wake decisions, and board views.
Adjust your visible toolset tier, inspect memory stats, and use the Cortex Console web UI for observation and steering.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@PseudoLife-MCPremember that my staging box is haze-02"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Pseudolife-MCP
简体中文 · 日本語 · 한국어 · Português (BR) · Español
Persistent long-term memory for Claude Code, Codex, and other MCP clients.
An MCP server that gives coding agents a long-term memory that persists across sessions — surviving context compactions and fresh tasks. Your coding agent is the intelligence; this server is its memory on disk.

What you get:
Associative memory with honest forgetting — a flat similarity store ranked by hybrid dense-plus-lexical retrieval, with conflict detection that admits potential updates while preserving earlier source notes; whole-note replacement is explicit. (The measured verdict: a preregistered ablation campaign found the previous 8-band continuum tied a flat store on every gate, so the simpler structure ships; the continuum remains one config line away.)
Canonical facts, not vibes — one current value per
entity.attributeslot (or a member set, for slots that hold many concurrent values); corrections supersede rather than silently overwrite, and the full version history survives.Dreams — a bundled local extractor, or any OpenAI-compatible endpoint (a Claude model on your Max plan, a GPT-5.6 model on a ChatGPT plan, LM Studio, Ollama, vLLM), consolidates the memory stream into facts and a knowledge graph while you're not looking.
Lessons from its own work — successes, dead-ends, and your corrections become do/avoid guidance surfaced at the start of every session.
A web console to watch it think — the Cortex Console above, plus cited world facts, session episodes, and document RAG.
Measured, with receipts — the full 500-question LongMemEval sweep, all six question types, and every number ships with its committed run artifact:
LongMemEval oracle, 500 questions | naive RAG | commit-gated cascade |
accuracy, all six question types | 0.688 | 0.690 |
context tokens per question | ~1210 | ~883 |
knowledge-update slice (78 of the 500) | 0.859 |
|
Equal accuracy to naive RAG across the whole benchmark on ~73% of the
context, and better calibrated about what it does not know: on BEAM-100K's
abstention questions the fact spine scores 0.950 against naive RAG's
0.775, unchanged under two independent judges. Read that as calibration,
not recall — in the budget-matched five-arm run of 2026-09-02 (rag 0.725 there;
one replicate, local judge) an arm served no memory at all scores 1.000 on
the same questions, because refusing is the right answer there and an
empty context always refuses. The fact spine loses where an answer has to
be aggregated across sessions. The second claim to survive a judge swap is
a win rather than a wash: re-run on 2026-09-04 with the hybrid arm
budget-matched to the control at 6 turns, the same 500 questions give
hybrid 0.730 against naive RAG's 0.690 under the local judge and
0.736 against 0.694 under claude-opus-5 — paired +0.040 / +0.042,
p 0.015 / 0.013 — bought with more context, ~1229 tokens against the
control's ~1124, not less, and carried mostly by temporal-reasoning
questions. Graded by a local, byte-reproducible judge (the cross-judge check
names its second judge) — compare within rows, never against GPT-judged
leaderboards.
Retired 2026-08-25 (#188): the 0.936 knowledge-update headline. It was measured on the 2026-07-30 bench stack (Qwen3.6-27B answerer and judge). Re-running the same 78 questions after the 2026-08-17 migration to Qwen3.8-27B puts the cascade at 0.846, below the naive-RAG control — which lands on 0.859 on both stacks. The cascade serves the fact-spine answer unless that channel says "I don't know", so it measures the answerer's abstention behaviour as much as the memory: 32/78 abstentions at 46/46 commit precision on the old stack, 22/78 at 0.839 on the new one. The 500-question table above is on the older judge and has not been re-judged, so read its cascade row as an upper bound.
Full tables, the per-type breakdown, both stacks side by side, and every artifact: Benchmarks.
Quickstart
Install and register the lite tier. No Docker, no database to set up, no container runtime:
pip install "pseudolife-mcp[lite]"
claude mcp add --scope user pseudolife-memory -- pseudolife-mcpCodex instead of Claude Code — same shape:
pip install "pseudolife-mcp[lite]"
codex mcp add pseudolife-memory --env PSEUDOLIFE_WRITER_ID=codex -- pseudolife-mcpFor Codex, finish setup before starting a fresh task. In the existing
[mcp_servers.pseudolife-memory] table in ~/.codex/config.toml, add
startup_timeout_sec = 240, tool_timeout_sec = 240, and required = true.
The shim can wait up to 180 seconds for a cold daemon; Codex's default
startup budget is 10 seconds. required makes missing memory visible at
startup and waits for its initial catalog. These are starting budgets,
not a promise that a first model download fits. The tool budget leaves time for
the shim's 180-second deadline to report a failure before the host cancels it; prewarm with
pseudolife-mcp serve in a terminal if needed.
Approve memory_message in that table's tool configuration
([mcp_servers.pseudolife-memory.tools.memory_message] approval_mode = "approve", or allow it once and keep the approval); Codex hook setup
(python ops/setup-codex-hooks.py) sets it when you approve the hooks, and
keeps any value you chose. Board mail can wake an
idle Codex task by default, and the woken task reads its mail with that tool:
without the approval it stalls on a prompt until someone answers it. Set
PSEUDOLIFE_CODEX_DOORBELL = "0" in the same env table to keep the task
from being woken (see Codex doorbell).
The agent board (peer awareness and addressed mail between sessions) is on by
default, behind bearer authentication. Without coordination.allowed_principals
in the daemon's config.yaml, only the singular PSEUDOLIFE_MCP_TOKEN
principal is admitted. A Codex bearer from a PSEUDOLIFE_MCP_TOKENS map stays
off the board until an operator lists it (allowed_principals: [default, codex]).
Until then a shim on the default setting leaves coordination off without an
error; one pinned with --enable shows an attach-unavailable hint instead.
python ops/setup-codex-coordination.py --check reports ready (default-on)
or names the cause. See
Codex CLI and desktop.
The MCP handshake delivers compact recall/capture/reflection instructions.
For the complete standing guidance, copy the
bundled memory block into your project
AGENTS.md or ~/.codex/AGENTS.md. For session briefings and per-turn
reminders, follow Codex hooks and verification.
Use one MCP registration and one hook source; an installed plugin may
already provide either. After the daemon is running, execute
pseudolife-mcp doctor from the same environment as the registered command.
It checks the handshake and annotations without calling bank tools. When
the shell has no PSEUDOLIFE_MCP_TOKEN or PSEUDOLIFE_MCP_TOKEN_FILE,
doctor takes the token from the Claude Code registration (~/.claude.json,
or under CLAUDE_CONFIG_DIR), else from the Codex one, and names where it
came from in credential_source; with none and a daemon that requires a
token, it reports BearerMissing.
Then in either coding agent: "remember that my staging box is haze-02" →
the agent calls memory_store; next session, "which box is staging?" →
memory_search finds it. Browse everything at the Cortex Console:
http://127.0.0.1:8765/ui/.
The first session auto-starts the daemon, which provisions an embedded
PostgreSQL 18 (pgvector included, via pg0-embedded) under a stable
per-user data dir and downloads the embedding model (~1.2 GB, one-time).
It is a real Postgres bank, not a cut-down one: pseudolife-mcp backup
writes a standard owner-free pg_dump archive (plus a state archive, 7-day
rotation) that restores into any PostgreSQL 18 target regardless of role —
the Docker tier included — so outgrowing lite is a dump/restore, not a
migration project (backups). For a
tier- and Postgres-version-independent copy, pseudolife-mcp export /
import move the whole bank as portable JSONL
(logical export / import).
Windows needs an ASCII-only data path
(PSEUDOLIFE_MCP_DATA_DIR).
What lite gives you, and the one thing it doesn't
lite (pip) | durable (Docker) | |
Associative store, hybrid search, supersession, version history | yes | yes |
Cortex facts, knowledge graph, lessons, world facts, episodes | yes | yes |
Cortex Console, document RAG, | yes | yes |
Dream consolidation filling the cortex on its own | no extractor ships | yes — bundled local CPU sidecar |
External volumes, health-checked services, deploy/rollback tooling | no | yes |
The gap, stated plainly. Lite ships no extractor, so the dream
pass still runs, prunes, and acknowledges its input batch, but writes no
canonical facts: on this path memory_fact_set is the only cortex
writer. Everything else above works. Nothing about this is silent —
curl http://127.0.0.1:8765/health reports "extractor": "none", and the
stdio shim says the same on stderr at session start.
Any OpenAI-compatible endpoint closes it. The daemon inherits the environment it starts from, so two variables are the whole fix — with a local Ollama:
export PSEUDOLIFE_DREAM_BASE_URL=http://localhost:11434/v1
export PSEUDOLIFE_DREAM_MODEL=qwen2.5:7b
pseudolife-mcp serve$env:PSEUDOLIFE_DREAM_BASE_URL = "http://localhost:11434/v1"
$env:PSEUDOLIFE_DREAM_MODEL = "qwen2.5:7b"
pseudolife-mcp serve/health then reports "extractor": "configured". One gotcha: a daemon
that is already running keeps the environment it started with, and the shim
reattaches to it rather than spawning a new one — stop the old daemon
first. A hosted endpoint works too, and costs you the zero-egress
property: memory text leaves the machine. Extractor tiers, quality, and the
trade-offs: Dreaming.
Related MCP server: agent-mem0
Durable tier — Docker (recommended for a long-lived bank)
Everything above plus the bundled extractor, external volumes, health-checked services, and backup/rollback tooling. Requires Docker and at least one MCP-capable coding agent — Claude Code, Codex, and Gemini CLI are wired end-to-end; anything else gets paste-ready config (provider matrix). One command from clone to first memory:
git clone https://github.com/Pseudogiant-xr/Pseudolife-MCP.git
cd Pseudolife-MCP
ops/install.sh # Linux / macOS
ops\install.ps1 # Windows (pwsh 7+)
# Codex: add --client codex / -Client codex
# Codex defaults to automatic hook-source detection and asks once for approval.
# Unattended hook approval: --codex-hook-trust yes / -CodexHookTrust yes
# Instructions only: --codex-hooks skip --instructions append
# PowerShell equivalent: -CodexHooks skip -Instructions append
# Both: add --client both / -Client both
# Gemini: add --client gemini — or several: --client claude,codex,gemini
# Other MCP agents (Cursor, Windsurf, Zed, ...): --client genericThe installer first asks where the memory bank lives: on this machine (the default, and everything below), on another machine that already runs it (a client-only install that asks for the daemon's URL and token), or on this machine with other machines connecting to it (see Sharing one bank across machines). It then asks which agents to wire (multi-select, with a capability matrix showing exactly what each one gets — session briefing, per-turn discipline, standing file), runs the preflight (one exact fix line per missing prerequisite), then asks which dream extractor should consolidate memories —
sidecar — the bundled local CPU model; no Claude plan needed, works for everyone, and keeps every memory on the box (~11.8 GB image);
claude-only — the lightest install: a Claude model via a CLI shim (
claude-opus-5-5by default since 2026-09-29, when it cleared the extraction-ladder gate againstclaude-opus-5; needs a logged-in Max-planclaudeCLI); the sidecar image is never built or pulled (~11.8 GB lighter; dreams pause while the shim is down);claude-fallback — the Claude shim primary, the bundled sidecar as automatic fallback (Max-plan CLI plus the ~11.8 GB image);
openai-only / openai-fallback — the same two shapes on an OpenAI subscription: a GPT-5.6 or GPT-6 model (Terra by default) via the Codex CLI shim on a signed-in ChatGPT plan (extraction quality unmeasured — see the dreaming guide);
endpoint / endpoint-fallback — any OpenAI-compatible server you name (
--extractor-url,--model: LM Studio, Ollama, vLLM, a hosted API), alone or with the sidecar as fallback. The earlier namessonnet-*andcodex-*still work as deprecated spellings —
then brings the stack up, installs the selected clients' session hooks
(where the client has a hook system), registers the MCP transport (the
stdio shim by default, with a per-provider writer id; direct HTTP via
--transport http), and health-checks the daemon — finishing with a
per-agent ladder of what got wired and what that agent's platform cannot
support. Codex setup offers one choice to enable automatic memory briefings,
reminders, and session cleanup (plus, where the agent board is on, a board
check-in at session start and a new-mail hint per prompt), use standing
instructions only, or skip.
Automatic setup reuses an enabled PseudoLife plugin or installs the three
lifecycle hooks, backs up configuration, approves only their exact current
definitions, and verifies execution. If verification fails, the same approval
allows the standing memory block as a fallback; setup reports the remaining
repair step. Hook-less providers (Gemini CLI and generic agents) are offered
the standing block. --instructions append always writes the block from examples/CLAUDE.memory.md into
~/.claude/CLAUDE.md / ~/.codex/AGENTS.md / ~/.gemini/GEMINI.md
(useful for subagent visibility even with hooks).
Idempotent — re-run any time; --extractor <mode> switches extractor
setups. Non-interactive example:
ops/install.sh --extractor sidecar --client codex --codex-hook-trust yes.
Without explicit hook approval, unattended setup does not grant trust; use
--codex-hooks skip --instructions append for instructions only. Explicit
--instructions skip prevents fallback edits.
The installer also turns the agent board on: it mints a bearer token in
ops/.env (owner-only, never printed) and gives each shim client it wires an
owner-only token file. Re-running it on an existing install adds that file to
the Claude Code registration in place. The ladder's last line, and
pseudolife-mcp doctor, say whether the board is on or why it is off.
Use doctor --host codex or --host claude-code for a compact coordination
snapshot: reachability, bearer admission, registration evidence, tool inventory
and configured wake are separate. Default doctor is read-only; health and a
configured wake path do not prove delivery. The coordination diagnostic
quickstart
covers saved-instance checks and an explicitly disposable mail proof.
--no-token / -NoToken keeps an open-loopback install with the board
dormant (Turning the board on).
Linux (Docker Engine): your user must be in the docker group —
sudo usermod -aG docker $USER, then log out/in (the preflight checks this).
Image sizes, the Windows WSL2 memory cap, and what the installer automates: the containerized install below.
ops/preflight.sh --client codex # or ops\preflight.ps1 -Client codex
docker volume create pseudolife-mcp-bank
docker volume create pseudolife-mcp-state
docker compose -f ops/docker-compose.yml up -d --build # first build, once
# ...or pull the prebuilt images instead of building (releases >= 0.14.0):
docker compose -f ops/docker-compose.yml -f ops/docker-compose.ghcr.yml pull pseudolife-pg pseudolife-daemon
docker compose -f ops/docker-compose.yml -f ops/docker-compose.ghcr.yml up -d
# Verify, then wire the transport into one or both clients.
curl http://127.0.0.1:8765/health
# Stdio shim (the installer's default — per-session episode identity).
# PSEUDOLIFE_MCP_NO_SPAWN=1 makes the shim wait for the container instead
# of spawning a host fallback that can shadow the Docker bank after a
# reboot; set it on Docker-tier registrations like these.
pip install pseudolife-mcp
claude mcp add --scope user pseudolife-memory --env PSEUDOLIFE_MCP_NO_SPAWN=1 -- pseudolife-mcp
codex mcp add pseudolife-memory --env PSEUDOLIFE_MCP_NO_SPAWN=1 -- pseudolife-mcp
# ...or direct HTTP (no pip package needed; fine for single-session setups):
claude mcp add --transport http --scope user pseudolife-memory http://127.0.0.1:8765/mcp
codex mcp add pseudolife-memory --url http://127.0.0.1:8765/mcp
# Reinforce the protocol-level memory loop with a global standing instruction:
cat examples/CLAUDE.memory.md >> ~/.claude/CLAUDE.md
cat examples/CLAUDE.memory.md >> ~/.codex/AGENTS.md
# (PowerShell: Add-Content "$env:USERPROFILE\.claude\CLAUDE.md" (Get-Content examples\CLAUDE.memory.md -Raw))Optional knobs live in ops/.env (cp ops/.env.example ops/.env — the
install/update scripts scaffold it too; every value is commented, a missing
file runs entirely on defaults).
What this is
A memory engine exposed over MCP. There's no chat UI and no LLM doing the thinking — your coding agent is the intelligence; these are tools it calls to store and recall what matters. (Models are bundled as plumbing: baked embedding weights for retrieval, and the optional CPU extractor sidecar that consolidates memories into facts while you sleep.)
Where it sits among the common approaches to agent memory — each column is a fair tool for what it's for; this table is about what question each one answers, not who's wrong:
notes file ( | auto-journaling plugin | plain vector store | Pseudolife-MCP | |
Survives sessions and compactions | yes | yes | yes | yes |
"What is X now?" has one current answer | if you curate it | no — replays what happened | no — every stored version competes at recall | yes — slot-keyed cortex |
A canonical-fact correction replaces the old value | you edit the file | appended beside it | old and new both retrievable, unranked by recency of truth | cortex supersedes, with full version history kept |
Facts know their age and go stale | no | no | no | dated, freshness-decayed, quarantined when stale |
Distils do/avoid lessons from its own outcomes | no | no | no | yes |
Benchmark numbers ship with their raw run artifacts | — | typically no | typically no | every published number, test-enforced |
Auto-journaling records what the agent did; Pseudolife curates what it learned. Both are useful — they answer different questions. Named alternatives — Mem0, Zep/Graphiti, Letta, Cognee, memU, Memori — and the cases where one of them is the better pick: Comparison.
It layers several complementary stores: the associative store (a flat
embedding store ranked by cosine similarity fused with a BM25 lexical pool
(on by default), with conflict-aware admission and explicit source-note
replacement; an 8-tier
banded layout is available as an opt-in preset); the cortex (slot-keyed canonical facts — one current
value per entity.attribute, or a member set for set-valued slots — with
provenance tiers and contender parking instead of silent overwrites); a typed knowledge graph over those facts
with a closed relation vocabulary and on-read inference; the world
cortex (durable cited facts about external reality, age-decayed trust);
procedural lessons learned from the agent's own work; and a ChromaDB
reference bank for document RAG. The canonical layers in depth:
the memory model; the graph and multi-hop
recall: retrieval.
State lives in Postgres (the durable source of truth) behind a single long-lived daemon; every session attaches through a thin stdio shim (installer default — per-session identity) or directly over HTTP (single-session setups). The result: Claude can pick up where it left off, correct itself when facts change, and reason over relationships — without you re-explaining context each session.
Documentation
This README is the front door — install, wiring, and the basic loop. The deep material lives in the user guide:
Page | What's in it |
Env vars, tuned defaults, toolset tiers, stdio shim, LAN sharing, data layout, backups, schema history | |
Capability matrix per coding agent, memory instruction layers, AGENTS.md standard, Codex hook setup and verification, writer ids | |
Reranker, BM25 hybrid, abstention floors, ranking-trace debugging, | |
Extractor tiers, the bundled sidecar, upgrading the extractor, Sonnet-fallback, cadence, deep dream, consolidation | |
Daemon-owned session episodes, the briefing hook, nested sub-episodes, tags | |
Cortex slots, provenance contenders, world cortex, lessons, temporal/HLC stamps | |
LongMemEval results; why extraction quality dominates | |
Mem0, Zep/Graphiti, Letta, Cognee, memU, Memori — the axes, and when to use something else | |
Memory poisoning (ASI06): every shipped mitigation, and what is not defended | |
Exposing the daemon over Tailscale, a LAN or a proxy; per-machine principals; client-only installs | |
Guided ChatGPT developer-app setup, private keys, cloud verification and optional autostart | |
The test suite's own Postgres login, and running agent sessions under a separate account that cannot reach the bank's keys | |
Agent mailboxes, maintainer passkeys and the board's audit log after a database restore |
Plus evals/README.md (full benchmark methodology) and
CONTRIBUTING.
Tools exposed
The surface was consolidated 2026-07-02 (55 → 32 tools; now 38 with
memory_toolset, the set-slot pair and coordination): lifecycle families became verb-dispatched tools
(memory_dream, memory_forget, memory_graph_review), and
dump/introspection views moved to the Cortex Console (REST) — the manifest
is agent context every session, so it stays lean.
Tool | Purpose |
| Remember one durable fact / decision / observation (canonical facts reach the cortex via the dream pass or |
| Associative retrieval; canonical |
| Newest stores, timestamp-ordered (debug + session catch-up) |
| Correct the selected entry by ID, or one unique exact-text match; ambiguous/missing targets fail closed. Keep the old entry as history; |
| Reinstate one independently reviewed retired entry under its durable ID; Postgres-only, named-principal, exact-preimage, append-only and idempotent. Refuses any trace invalidation and never confirms derived cortex facts |
| Forget from one store: |
| Store occupancy, hit rates, totals |
| Experimental peer awareness or update of the caller's registered context, on by default for authenticated installs (coordination); lists peers active within the hour (three hours while holding a lease), each status with its age and a stale flag past two hours, and each row by its session's |
| Experimental addressed mail: |
| Dereference a memory id to its full episode (+ |
| The one CURRENT canonical value at a slot (+ parked contenders); on an empty slot returns ranked |
| Assert a canonical fact deliberately (insert / confirm / supersede / contest); |
| Settle a contested slot — adopt ( |
| Add/confirm or retract one member of a set-valued slot (many concurrent values, e.g. tags — not one NOW value); a scalar there converts to a set one-way on first |
| With |
| Assert a cited WORLD fact (external knowledge; age-decayed trust by freshness class) |
| Search world facts — each carries |
| Record a procedural outcome signal ( |
| Recall learned lessons for the task at hand — heed |
| Drive the dream: |
| Work the review queue: |
| Name THIS session's auto-opened episode (default titles are generic); |
| Open/close a nested sub-episode for a substantial task; entries stored while open carry its id; |
| Stats + tag/source distribution + recent entries within an episode |
| Cluster near-duplicate memories ripe for consolidation |
| Replace selected entries with one canonical note; validate every ID (or unique exact text) before any changes |
| Assert a typed edge (closed relation vocabulary; re-assertion bumps confidence) |
| Retract an edge (superseded, kept for audit) |
| Bind an alternative name — lookups resolve aliases first |
| Entity neighborhood (≤3 hops) with derived transitive/inverse edges and per-edge |
| Multi-hop retrieval for relational questions; |
| Grow the closed relation vocabulary (deliberate, rare act) |
| Index a file (txt/md/pdf/html) verbatim in the reference bank — the lossless complement to agent-side distillation (division of labor) |
| RAG search over the reference bank only |
| Check or change this principal's visibility tier: |
Each tool returns plain JSON. See pseudolife_memory/mcp_server.py for
docstrings — those are what Claude reads to decide when to call which tool.
The five recall-path tools return compact entries by default (result
payloads are agent context on every retrieval; search and recent entries
keep their write date), and memory_fact_get likewise drops bookkeeping
keys from its record; pass verbose=true for full metadata. Full-table dumps and topology views live in the Cortex Console
(/api/*) and the pseudolife-mcp briefing CLI.
Toolset tiers. Three visibility tiers — minimal (10 tools), core
(24), full (38) — filtered per principal at
tools/list; a principal (the named bearer-token identity, or the writer
id for single-token installs) steps its own tier up or down with
memory_toolset before calling a hidden tool. Defaults, per-client mapping, and weak-model
deployments:
Configuration — toolset tiers.
Architecture
One memory daemon owns the bank and serves MCP over streamable HTTP
at /mcp; every Claude Code session (and any LAN agent) attaches to it.
Postgres 18 + pgvector (in Docker on the durable tier; the lite tier
runs the same Postgres embedded, no container) is the durable source of
truth —
the in-memory store is a write-through cache hydrated at startup
(a small weights.pt persists only counters — there are no MLP weights).
The daemon runs either containerized (recommended — portable, no host Python) or as a host process. Claude Code attaches through a thin torch-free stdio shim (the installer default — per-session identity, needed for concurrent sessions) or directly over HTTP (simpler for a single session):
Claude session A ─┐ stdio shim (installer default) or HTTP
Claude session B ─┼───────────────────► pseudolife-mcp daemon ─► Postgres (Docker)
LAN agent ────────┘ or stdio shim (single writer) pgvector
(per session) host proc OR DockerThis kills two v0.1 hazards by construction: a single writer means
concurrent sessions can't clobber each other, and entries are transactional
so a crash can't wipe the bank. The single writer is enforced: the daemon
holds a Postgres advisory-lock writer lease on its bank. A second daemon,
or a script or eval that opens the live bank through the service, refuses
to start and names the process that holds it. Stop the daemon before
offline maintenance such as ops/dedup_cortex.py. If the bank fails to
load at startup, the daemon serves nothing rather than a partly loaded
bank, and /health reports degraded with the reason until a retry
succeeds. On top of the associative store sit the
canonical layers — cortex, world facts, lessons, temporal/HLC stamps
(the memory model) — joined to a typed
knowledge graph walkable via memory_graph and multi-hop memory_recall
(retrieval & the graph).
Install — containerized (any OS)
What the durable tier
installer above does, by hand. The whole stack — Postgres and the memory daemon — runs in Docker.
No host Python, no torch install, no version skew; the daemon image bakes
in CPU-only torch and the embedding weights — Qwen/Qwen3-Embedding-0.6B
(the default retrieval backbone since schema v25) plus all-MiniLM-L6-v2
(kept baked for the ONNX-parity test path) — so it runs identically on
Windows / macOS / Linux. Requires only Docker; built once: ~5.0 GB daemon
image (measured 2026-07-29 on the deployed build) + ~0.6 GB Postgres +
~11.8 GB extractor sidecar (measured 2026-08-20 with the v3 multi-task
bake; skip the sidecar entirely with the installer's claude-only mode).
The ~12.6 GB and ~10.4 GB figures published before
2026-07-29 are retired: both were inflated by a CUDA torch build that a
dependency-resolution bug pulled into the image (see the CHANGELOG); the
daemon has always been CPU-only.
git clone https://github.com/Pseudogiant-xr/Pseudolife-MCP.git
cd Pseudolife-MCP
# 1. One-time: create the two persistent volumes (bank + daemon state).
docker volume create pseudolife-mcp-bank
docker volume create pseudolife-mcp-state
# 2. Build + start all three services (Postgres, extractor, then the daemon).
docker compose -f ops/docker-compose.yml up -d --buildOr skip the ~5 GB daemon build entirely and pull the prebuilt images (releases ≥ 0.14.0):
docker compose -f ops/docker-compose.yml -f ops/docker-compose.ghcr.yml pull pseudolife-pg pseudolife-daemon
docker compose -f ops/docker-compose.yml -f ops/docker-compose.ghcr.yml up -dThe extractor sidecar is not published and still builds locally; update the
pull path with pseudolife-mcp update (backup, pinned image, rollback tag;
see Updating), not a bare pull + up -d.
Upgrading from a pre-rename install (volumes
ops_pseudolife_pgdata/ops_pseudolife_data)? Don't rename those volumes — keep pointing at them by creatingops/.envwithPSEUDOLIFE_BANK_VOLUME=ops_pseudolife_pgdataandPSEUDOLIFE_STATE_VOLUME=ops_pseudolife_databeforeup. See the compose header.
Windows: cap Docker Desktop's WSL2 VM, which otherwise claims up to ~50% of host RAM — how much the stack actually needs, the
ops/wslconfig.exampletemplate, and the daemon container's own memory cap: Configuration — Windows / WSL2 memory.
The daemon serves MCP at http://127.0.0.1:8765/mcp and restarts with
Docker — no logon task needed. First build downloads the model into the
image (once); every container start after that is offline and fast. Wire
Claude Code in via the stdio shim (installer default) or directly over
HTTP (both below). Where the data actually lives, and
how to back it up:
Configuration — data layout.
Other machines, one bank: sessions on a laptop, a server or a container can use this daemon too, through a client-only install that runs just the shim. Exposing the daemon (Tailscale Serve, a LAN publish or a reverse proxy), per-machine tokens and board admission: Sharing one bank across machines.
Host-process install (Windows, for GPU / dev): run Postgres in Docker
but the daemon on host Python — for hacking on the daemon or running the
embedder on a local GPU. Steps, the pseudolife-mcp CLI modes, and the
logon autostart task:
Configuration — host-process install.
Updating
Upgrading from before the agent board (no bearer token yet): this
migration step applies to installer-managed Docker installations. Rerun
ops/install.ps1 (Windows) or ops/install.sh (Linux / macOS) with the
same client selection (sessions can stay open: the shim installs as a new
runtime beside the running one).
The installer creates a bearer token for the default shim install and
migrates the environment of the installer-managed pseudolife-memory
stdio registration for Claude Code in place. Custom registrations are
preserved; follow the installer's printed credential warnings for Gemini
or custom registrations. -All / --all and ops/update_clients.py do not
create the token or migrate the registration environment. Then refresh clients
with the Everything at once recipe below and restart them.
A plugin marketplace added as Pseudogiant-xr/Pseudolife-MCP (installers up
to 0.16.1) is refreshed over SSH, which fails on a machine with no GitHub SSH
key. pseudolife-mcp update and the installers move it to the HTTPS URL
themselves, with backups. If that step reports a failure, the manual fallback
is: in settings.json ($CLAUDE_CONFIG_DIR, else ~/.claude), set the
pseudolife-mcp entry's source under extraKnownMarketplaces to
{"source": "git", "url": "https://github.com/Pseudogiant-xr/Pseudolife-MCP.git"},
then run claude plugin marketplace add https://github.com/Pseudogiant-xr/Pseudolife-MCP.git
(never marketplace remove it: that uninstalls the plugin).
One command, no checkout: the installed shim updates the whole install from a release:
pseudolife-mcp update # the newest release on PyPI
pseudolife-mcp update --tag 0.15.1
pseudolife-mcp update --check # exit 0 when a newer release exists, 3 when currentThe first update from 0.15.0 or earlier has no such command (that shim
answers "unknown mode", and that daemon never announces a release): from a
checkout, git pull, then ops/update.sh --all or ops/update.ps1 -All;
for a pipx or pip install, pipx install --force "pseudolife-mcp[lite]==<version>"
or pip install --upgrade "pseudolife-mcp[lite]==<version>" (the [lite]
extra only for a lite install). After that, pseudolife-mcp update exists.
On a client-only machine (the daemon on another host), update and
--clients-only move this machine's clients to the daemon's release.
On a Docker-tier install it pulls the pinned GHCR daemon image, backs the
bank up (the checkout's backup script when the compose project still has
one, else its own pg_dump + state-volume tar into ~/.pseudolife-mcp/ backups), tags the running image for rollback, recreates only the
daemon container from the compose files it was created with (or the
package's bundled copies when the checkout is gone), waits for /health
at the new version, then installs the release as a new shim runtime beside
the running one, refreshes the plugin cache and prints the Codex hook
step. The backup stays visible and deliberate: nothing here automates it
away. --clients-only / --daemon-only take one half; the shim itself
runs from wherever it was registered, so use its full path when
pseudolife-mcp is not on PATH. On a pip / lite install it upgrades
the package in the interpreter that holds it (pip, or pipx) and restarts
nothing: it says what to restart.
You are told when it is time: the daemon checks PyPI for the newest
release in the background (updates.check_releases, on by default) and
every session's briefing then opens with release X is available — run pseudolife-mcp update. With updates.unattended_clients: true in
config.yaml (off by default) a Docker-tier shim on the daemon's host
installs the daemon's release as its own new runtime and refreshes the
plugin cache by itself whenever the daemon is newer than it; the daemon
recreate stays a deliberate command.
On a headless host, pseudolife-mcp update --schedule 03:30 installs a
daily task or timer that applies a new release only while
updates.unattended_daemon: true is set and no session is active on the
agent board, with the same backup and rollback tag, and posts a board
notice either way. Codex keeps its hook approvals across updates (it
approves the hook definitions, not the scripts), and an update from a
checkout refreshes manual Codex hook copies itself. Where Codex runs the
plugin's hooks, the client step refreshes Codex's installed plugin copy
through codex plugin marketplace upgrade while the approved hook
definitions are unchanged (Codex specifics);
only a changed hooks.json makes every update path print the approval steps.
See Updating.
Lite tier by hand: one command, bank untouched:
pip install -U "pseudolife-mcp[lite]"On Windows, first close every Claude Code, Codex and Claude Desktop session using the shim (quit Desktop from the tray): upgrading a package that is running can leave it half-removed.
Docker tier from a checkout: after a git pull (or local code
change), redeploy the daemon only — safely, without touching Postgres
or the extractor:
.\ops\update.ps1 # Windows./ops/update.sh # Linux / macOSBoth are thin wrappers over the same Python deploy pseudolife-mcp update
runs (ops/update.py → pseudolife_memory/update_cli.py), so there is
one implementation. It backs up the bank (pg_dump + a state-volume tar), tags a rollback
image (when a previous one exists — it says so loudly when there isn't),
rebuilds + recreates only the daemon, and waits for /health.
It never runs down -v. (Host-process install: just restart the daemon —
pip install -e . is editable.) Build cache is pruned automatically after
every healthy deploy; see
Docker disk retention for the
weekly Scheduled Task and the manual .vhdx compact. Never run
docker system prune --volumes, which deletes volumes.
The image records the commit it was built from, and /health reports it
as build (git_sha, dirty, built_at, and source: checkout or
release). So the script refuses a tree
with uncommitted or untracked files, and lists them. It also refuses a
tree git cannot describe (no git, not a clone, or git's safe.directory
refusal, which it quotes). Commit or clean up first, or pass
-AllowDirty / --allow-dirty to deploy the tree as it is: stamped
dirty: true, or unknown when git cannot describe it. Each deploy
builds a new image, so the daemon container is recreated even when the
commit has not changed.
Everything at once: the daemon is one of three installs. The shim
your clients launch and the Claude Code plugin are separate and do not
move with it. -All / --all moves them in the same run, after the
daemon is healthy:
.\ops\update.ps1 -All # Windows./ops/update.sh --all # Linux / macOSNo session has to be closed for the shim step. Each shim version installs
into its own runtime (%LOCALAPPDATA%\pseudolife-mcp\runtimes\NNNNNN
on Windows, ~/.local/share/pseudolife-mcp/runtimes/NNNNNN elsewhere) and
every client registers one launcher path
(%LOCALAPPDATA%\pseudolife-mcp\bin\pseudolife-mcp.exe /
~/.local/share/pseudolife-mcp/bin/pseudolife-mcp) that starts the newest
complete runtime. The installer and the update step also make
pseudolife-mcp typed in a terminal reach the launcher. On Linux and macOS
~/.local/bin/pseudolife-mcp becomes a link to it; an older pipx or
pip --user entry there is moved aside as pseudolife-mcp.<kind>-<stamp>
(never deleted), and anything else there is left alone and named. When
~/.local/bin is not on PATH, the step prints the line to add to your
shell profile: export PATH="$HOME/.local/bin:$PATH". On Windows the
launcher directory goes first on your user PATH, ahead of pipx's and
pip's copies; open a new terminal for the name to reach the launcher,
because a terminal that was already open keeps its old PATH.
pseudolife-mcp doctor reports what the name resolves to
(path_resolution) and warns when that is not the launcher; the
launcher's full path always works.
The step installs the checkout as a new runtime beside the old one, moves
any registration that still names a runtime, pipx or virtualenv path to
the launcher in place (Claude Code, Codex, Claude Desktop and Gemini CLI;
each file is backed up first as <file>.bak-<stamp>), and removes older
runtimes once no process runs from them and no registration names them.
Sessions already running keep the runtime they started with; the next
session start uses the new one. A shim running straight from this
checkout's .venv is already live and is named instead. It then
refreshes the plugin cache when its bytes differ from the marketplace
clone (claude plugin update installs the new copy beside the one
running sessions use; nothing is uninstalled), and reports whether
Codex's hook copy matches the checkout (that refresh is a consent step:
python ops/setup-codex-hooks.py). It ends with a ladder of what moved
and which clients need a restart; a client-side step that fails is
reported, never a failed deploy. The same helper runs on its own:
python ops/update_clients.py, and python ops/shim_runtime.py manages
the runtimes by hand (install, list, prune, migrate). Custom
registrations are preserved and named; upgrade those in their own
interpreter. A daemon-side credential change with an old shim leaves the
two out of step: the Claude Desktop registrar refuses a shim that cannot
read the selected token file (exit 4), and names the upgrade.
Upgrading past 2026-09-28: board mail starts waking idle sessions. Once the plugin cache and the shim move (
-All, then a client restart), a Claude Code session and a Codex task with acodexCLI are woken when mail arrives that clears the need they parked on; before this both wake paths were opt-in. Nothing rings for chatter, and rings are capped. To keep the old behaviour, setPSEUDOLIFE_AGENT_WAKE_HOOK=0in theenvblock of~/.claude/settings.jsonandPSEUDOLIFE_CODEX_DOORBELL = "0"in the Codex server'senvtable (PSEUDOLIFE_AGENT_COORDINATION=0in either place turns off the board for that client).pseudolife-mcp doctorshows each client's wake path underwake.
The three tell on each other: /health reports the daemon's version
and a digest of the hook scripts it shipped with; the session briefing
opens with a one-line notice when the plugin's version differs from the
daemon's (naming /plugin marketplace update pseudolife-mcp then
/plugin update pseudolife-memory@pseudolife-mcp, or the daemon redeploy,
whichever side is behind), or when the version matches but the hooks do
not (naming the --all command above); the shim says so on stderr and
ahead of its instructions; and pseudolife-mcp doctor reports
version_mismatch.
Two upgrades are not automatic, because neither can be done safely in place. Both have a step-by-step runbook — backup, dry run, apply, verify, roll back — and a fresh install needs neither:
A bank older than 0.11.0 (schema v25): every embedding column moved from
vector(384)tovector(1024), so the daemon refuses to start rather than half-migrate. Re-embed offline withops/migrate_embeddings.py— the v25 migration runbook.A Docker-tier bank created before 2026-08-14 (PostgreSQL 16 → 18): a Postgres major bump cannot reuse the old data volume. Run
pwsh ops/migrate-pg18.ps1— the PostgreSQL 18 migration runbook.
Wire into your coding agent
Plugin (hooks + commands). The installer adds it whenever Claude Code
is a selected client (--claude-plugin skip / -ClaudePlugin skip opts
out; an installed plugin is left alone). It wires the session hooks
(briefing + episode identity), the memory-loop instructions, and the
/dream + /memory-status commands. By hand, the same two commands inside
Claude Code do it:
/plugin marketplace add https://github.com/Pseudogiant-xr/Pseudolife-MCP.git
/plugin install pseudolife-memory@pseudolife-mcpThe plugin replaces the settings.json hook, and the daemon serves a compact
memory core and a live briefing as session context. By default
(memory_policy.variant: compact) the full CLAUDE.md block below is not
served; append it if you want the complete guidance.
It deliberately does not bundle the MCP server: Claude Code loads a
plugin server alongside any user-registered one with no deduplication, which
doubled every session's tool namespace next to the installer's registration
— so the transport is registered exactly once, by ops/install.* (stdio
shim by default — per-session episode identity) or the one-liner below.
Hooks an earlier install wrote to ~/.claude/settings.json would duplicate
the plugin's; the installer offers to remove them once the plugin runs
(--claude-legacy-hooks remove / -ClaudeLegacyHooks remove unattended).
Details, non-default ports/tokens, and migration:
plugin/README.md.
Manual transport registration. The installer's default (shim mode) registers a thin stdio shim — one shim process per session, so every session carries its own tier-1 identity. The same wiring by hand:
pip install pseudolife-mcp # daemon in Docker; add [lite] for the pip tier
claude mcp add --scope user pseudolife-memory --env PSEUDOLIFE_MCP_NO_SPAWN=1 -- pseudolife-mcpPSEUDOLIFE_MCP_NO_SPAWN=1 belongs on Docker-tier registrations: the shim
then waits for the container instead of spawning a host-side fallback whose
port bind can race a still-booting Docker and shadow the real bank. On the
[lite] pip tier drop the --env — there the spawn fallback is the
zero-config path.
Direct HTTP works too — the daemon serves MCP over HTTP natively (no shim, no host command, nothing OS-specific; concurrent sessions then share one episode identity, so it fits single-session setups best):
claude mcp add --transport http --scope user pseudolife-memory http://127.0.0.1:8765/mcp(--scope user registers it for every project; drop it to register for the
current project only.) Or write the equivalent JSON yourself — into
~/.claude.json under the top-level mcpServers key for user scope, or into
a .mcp.json at a project root for project scope:
{
"mcpServers": {
"pseudolife-memory": {
"type": "http",
"url": "http://127.0.0.1:8765/mcp"
}
}
}For a token-protected daemon, add a headers key to that Claude JSON entry:
"headers": { "Authorization": "Bearer <your-token>" }.
Claude Desktop (the app, including its Cowork and Code sessions) — the installer writes the entry for you:
ops/install.sh --client claude-desktop # Windows: ops\install.ps1 -Client claude-desktopDesktop has no mcp add; its servers live in claude_desktop_config.json
(macOS ~/Library/Application Support/Claude/, Linux ~/.config/Claude/,
Windows %APPDATA%\Claude\ — except the Store/MSIX build, whose real file
is under %LOCALAPPDATA%\Packages\Claude_*\LocalCache\Roaming\Claude\; the
installer prefers that path when it exists). The equivalent entry by hand:
{
"mcpServers": {
"pseudolife-desktop": {
"command": "/absolute/path/to/pseudolife-mcp",
"env": {
"PSEUDOLIFE_WRITER_ID": "claude-desktop",
"PSEUDOLIFE_MCP_NO_SPAWN": "1",
"PSEUDOLIFE_MCP_DAEMON_URL": "http://127.0.0.1:8765"
}
}
}
}The entry is named pseudolife-desktop on purpose. Desktop's Code tab runs
Claude Code, which starts its own per-session pseudolife-memory server; when
an app-level entry has the same name, Desktop sends the session's
mcp__pseudolife-memory__* calls to the app-level entry and the session's own
server gets none. Re-running the installer renames an entry it wrote under the
old name (its env sets PSEUDOLIFE_WRITER_ID to claude-desktop), keeping
any env keys you added and backing the config up first. It leaves any other
pseudolife-memory entry alone and warns about it. Chat and Cowork then list
the tools as mcp__pseudolife-desktop__*.
Two things differ from the CLI clients. Desktop launches MCP servers with a
sanitized environment — PATH plus a few system variables, none of your
shell's exports — so command must be the shim's absolute path (which pseudolife-mcp / Get-Command pseudolife-mcp), and a token-protected
daemon needs "PSEUDOLIFE_MCP_TOKEN_FILE": "/absolute/path/to/a/private/file"
in that env block: a bearer exported in your OS environment never reaches
the shim. The symptom of forgetting it is every session failing with
"Couldn't start for Cowork and Code sessions. Error: unhandled errors in a
TaskGroup (1 sub-exception)" — a 401 under the SDK's wrapper, which the
shim now names plainly on stderr at startup. When the daemon is
token-gated the installer writes that file (owner-only) from
PSEUDOLIFE_MCP_TOKEN in its environment or ops/.env, or migrates a
literal token already in the entry into it; with no token to write it
says so and exits 3. The shim must also be able to read that file:
releases through 0.15.0 only read the literal PSEUDOLIFE_MCP_TOKEN, so
the registrar probes <command> --help for the file form first and
refuses an older shim (exit 4, nothing written) rather than register an
entry that would fail with the same TaskGroup error — upgrade the shim
(re-run the installer, or python ops/update_clients.py --only shim from
the checkout: it installs a new runtime beside the running one, so no
session has to close) and re-run. After any edit, fully quit Desktop from the tray or
menu-bar icon and relaunch — closing the window does not reload the
config.
Codex — the installer's default (shim mode) wires the same stdio shim, so a Codex session gets its own tier-1 identity instead of inheriting a concurrent Claude session's episode:
pip install pseudolife-mcp
codex mcp add pseudolife-memory --env PSEUDOLIFE_MCP_NO_SPAWN=1 -- pseudolife-mcp(Same Docker-tier note as the Claude wiring above: keep
PSEUDOLIFE_MCP_NO_SPAWN=1 when the daemon runs in Docker; drop it on the
[lite] pip tier.)
The HTTP one-liner works too (no pip package needed):
codex mcp add pseudolife-memory --url http://127.0.0.1:8765/mcpOr add the equivalent user-level entry to ~/.codex/config.toml:
[mcp_servers.pseudolife-memory]
url = "http://127.0.0.1:8765/mcp"
bearer_token_env_var = "PSEUDOLIFE_MCP_TOKEN"For that Codex HTTP configuration, export PSEUDOLIFE_MCP_TOKEN in the
environment that launches Codex. The token stays out of config.toml, and
Codex reads it when connecting. This is unnecessary for the default stdio shim.
Gemini CLI — same shape (-s user matters: Gemini defaults to project
scope; the -e env gives Gemini sessions their own write attribution, and
the same Docker-tier PSEUDOLIFE_MCP_NO_SPAWN=1 note as above applies):
pip install pseudolife-mcp
gemini mcp add -s user -e PSEUDOLIFE_WRITER_ID=gemini -e PSEUDOLIFE_MCP_NO_SPAWN=1 pseudolife-memory pseudolife-mcpOr HTTP, no pip package needed:
gemini mcp add -s user -t http pseudolife-memory http://127.0.0.1:8765/mcpNote: since 2026-06-18 Google no longer serves individual-tier accounts
(free, AI Pro, AI Ultra) through Gemini CLI — OAuth sign-in fails and
points at Antigravity. The wiring above stays correct, but individual
accounts need API-key auth (GEMINI_API_KEY) to actually run sessions —
or use Google Antigravity itself, which connects to the same bank via
~/.gemini/config/mcp_config.json; both are covered in
the providers guide.
Any other MCP-capable agent (Cursor, Windsurf, Zed, Copilot CLI, …) —
add the generic mcpServers entry to that tool's MCP config (ops/install.sh --client generic prints both shapes ready to paste):
{
"mcpServers": {
"pseudolife-memory": {
"command": "pseudolife-mcp",
"env": {
"PSEUDOLIFE_WRITER_ID": "mcp-client",
"PSEUDOLIFE_MCP_NO_SPAWN": "1"
}
}
}
}What each agent gets — and what its platform can't support (hooks, per-turn discipline): the provider matrix.
Verify: run claude mcp list, codex mcp list, or gemini mcp list
(the server should report connected), then ask the agent to "store a memory
that this install works" and check it
appears in the Console's Stream view at http://127.0.0.1:8765/ui/.
Preferring stdio (this is what the installer wires by default, for per-session identity)? A thin torch-free shim proxies stdio to the daemon: stdio shim · sharing one bank across machines · backups & restore rehearsal · agent mailbox recovery.
Recommended agent setup (CLAUDE.md / AGENTS.md)
The server's value depends on the agent using it. The MCP server advertises
the core loop through protocol-level instructions; the shim adds the
messageboard check-in when its coordination adapter is up.
The plugin's memory SessionStart hook (also used by verified Codex hooks)
delivers a short operating guide and a bounded briefing; without the plugin,
the installer's Claude Code settings.json hook
(pseudolife-mcp briefing --hook-json) delivers the same two.
A separate coordination hook asks the agent to set its project,
task and status, discover peers, and read pending messages, but only where
the board is on for that credential (it is on by default behind bearer
authentication, so an open install or a disabled board adds no check-in).
Detailed memory
guidance remains in the bundled standing block. Hooks add per-prompt reminders
and session bookkeeping; neither delivery method
guarantees that the model performs every requested memory operation.
By default (memory_policy.variant: compact) hooks serve at most that
short guide, and the detailed block reaches an agent only as a standing copy
(the full_separate_hook variant serves it in a separate hook; see
Startup memory policy).
For the complete guidance, for subagent visibility (subagents read CLAUDE.md but not hook output), or in place of
hooks, append it to Claude's global ~/.claude/CLAUDE.md, Codex's
global ~/.codex/AGENTS.md, Gemini's global ~/.gemini/GEMINI.md, or a
per-project CLAUDE.md / AGENTS.md:
cat examples/CLAUDE.memory.md >> ~/.claude/CLAUDE.md
cat examples/CLAUDE.memory.md >> ~/.codex/AGENTS.md
cat examples/CLAUDE.memory.md >> ~/.gemini/GEMINI.mdAdd-Content "$env:USERPROFILE\.claude\CLAUDE.md" (Get-Content examples\CLAUDE.memory.md -Raw)
Add-Content "$env:USERPROFILE\.codex\AGENTS.md" (Get-Content examples\CLAUDE.memory.md -Raw)For hook-less providers this standing block supplies the full memory policy,
but it cannot provide a live briefing or run session cleanup. AGENTS.md is the cross-vendor standard for standing
agent instructions (Linux Foundation-governed; read by Codex, Copilot,
Cursor, Gemini CLI, Zed, and 30+ others), so a per-project AGENTS.md
carrying the block reaches almost every agent at once. Claude Code is the
holdout — it reads CLAUDE.md — but a CLAUDE.md whose first line is
@AGENTS.md imports the shared file, so one copy serves every tool.
The block (examples/CLAUDE.memory.md) teaches
the loop: RECALL at the start (memory_search / memory_lesson_search /
memory_fact_get / memory_world_search), CAPTURE as you go
(memory_store with an honest origin, memory_fact_set for canonical
facts, memory_world_set for cited external facts, source="status" for
verbose logs so they stay out of the dream), REFLECT at the end
(memory_outcome, with used_ids naming the hits you actually used — the
dream distils these signals into the lessons surfaced at your next session
start).
For an existing Codex installation, run python ops/setup-codex-hooks.py.
The helper asks once, detects the hook source, backs up changed configuration,
persists scoped trust through Codex, and verifies startup briefing, prompt
reminder, and session cleanup, plus the agent-board check-in where the board
is on. The Docker installer runs this step for you.
See Codex setup options and fallback.
For Claude Code, use the plugin, or the legacy
ops/install-hook.ps1 -Client claude / ops/install-hook.sh --client claude
for briefing and reminder hooks. The legacy --client codex path remains
available but only writes hook definitions; it does not complete trust and
verification. Session episodes also work without hooks through the daemon:
Episodes & sessions.
Current Codex runtimes enable hooks by default, including Windows.
Availability depends on the application/runtime and policy, not the model.
If [features] hooks = false is intentional, keep it and use the standing
AGENTS.md block. Codex runs the plugin's Windows hooks as native
PowerShell 7 commands; Claude Code runs their Bash commands through Git
Bash, so it needs Git for Windows installed (see
plugin/README.md).
See the official hook protocol.
Codex hook trust: setup approval is limited to PseudoLife's current hook
definitions: the memory and coordination SessionStart and UserPromptSubmit
handlers and SessionEnd, plus, with the plugin, its Stop entry (Claude
Code's wake hook, on by default; in Codex it runs only the park gate), its
SubagentStart and two SubagentStop handlers (Claude Code's subagent
board hooks, a no-op in Codex, plus the park gate) and its PreToolUse
guard. It does not approve other plugins or bypass
future trust checks. The same consent sets approval_mode = "approve" for
the memory_message tool on the pseudolife-memory server, unless you set
another value yourself, so a Codex thread can then read and send board
mail without asking. Codex approves the definitions, not the scripts they
run, so the approval also covers the scripts later PseudoLife updates
install (for manual copies the update installs them itself, verified by
content). Changed definitions need approval again, and so does a
handler a plugin update adds; Codex skips an unapproved one silently in the
desktop app, which pseudolife-mcp update (from a checkout, ops/update.ps1 -All or ops/update_clients.py) reports as needs-approval. If automatic setup cannot
use the installed runtime's trust interface, it reports the problem and
asks you to open /hooks to review and trust the definitions. Approved standing
instructions remain available as fallback. Installed files alone do not
establish that hooks are working.
Usage patterns
At session start — loads what you've worked on before, persistent across compactions:
memory_search("project context for X")During work — store real decisions; skip fleeting chatter (the shipped store gate is permissive, so deliberate, durable claims only):
memory_store("Decided to use stdio transport for the MCP because no port conflicts", source="pseudolife")When corrected — marks the old fact superseded and stores the
correction; both surface in future retrieval, the new one ranked higher.
Select the entry by the id carried on the search or recent hit:
memory_supersede(
entry_id=417,
new_text="Provider interface uses async calls — sync version was the v0.7 prototype only"
)old_text= still selects by the full stored text when that text is exactly
unique among live entries; it is the legacy selector and the only one file
mode has. Ambiguous or missing targets change nothing.
Hygiene — memory and fact scopes hard-delete (at least one filter
is required for scope memory, preventing accidental wholesale deletion;
several filters narrow the match, so text="probe", source="status" is
the probe entry in that source, not the whole source; a match over
memory.delete_confirm_threshold entries — default 20, 0 disables — is
refused with would_delete until the call repeats with
confirm_bulk=true; on Postgres, forgetting an entry also retires the
current facts, dream edges and lessons it was the last surviving source of,
keeping them as history, and queues affected session digests for
regeneration); lesson and world scopes retire the slot with an
audit row and are reversible with memory_graph_review(action="restore_slot", store=..., src="entity|attribute"); for "keep the history but mark it
wrong" use memory_supersede instead:
memory_forget(scope="memory", source="test-noise") # refused past 20 matches
memory_forget(scope="memory", source="test-noise", confirm_bulk=True)
memory_forget(scope="fact", entity="test-entity")Discovering what's in the bank: open the Cortex Console — sources, tags, episodes, and full-table views all live there. Going deeper: reranking, BM25, abstention, and trace debugging · episodes + tags · canonical facts, contenders, world facts, lessons · the consolidation workflow.
Dreaming — consolidating memories into facts
A dream distils the recent associative stream into canonical cortex
facts while you're not looking: pull unconsolidated memories → extract
(entity, attribute, value) → acknowledge those exact entries durably.
New entries remain pending regardless of their timestamps; failed acknowledgement
can replay claim application. Manual commits use the token returned by pull.
Extraction is pluggable:
Tier | How it runs | Needs | Quality |
0 — none | no extractor configured — the dream still runs, prunes, and acknowledges input batches, but writes no canonical facts | nothing | none ( |
1 — agent-driven | the agent itself is the gateway: the | the agent you already run | highest |
2 — shipped default | daemon auto-sweep → the bundled CPU sidecar, or any OpenAI-compatible endpoint | nothing (sidecar) | high; free if local |
The stack ships tier 2 preconfigured (the bespoke Gemma 4 E4B extractor fine-tune in a llama.cpp sidecar, internal-only). The sweep cadence, pointing dreams at a bigger local model or at Claude Sonnet with automatic sidecar fallback, the full-corpus deep dream graph pass, and the privacy/cost trade-offs: Dreaming.
Benchmarks
The headline is the whole benchmark, not a slice: all six LongMemEval question types, 500 questions, oracle variant, run end to end through the memory (qwen-27b extraction under the v25 embedding backbone, BM25-on turn retrieval). Single pass, graded by the local Qwen3.6-27B bench judge (2026-08-03):
arm | accuracy | context tokens/question |
naive RAG (top-6 turns) | 0.688 | ~1210 |
cortex facts only | 0.416 | ~158 |
hybrid (facts + top-3 turns) | 0.664 | ~842 |
commit-gated cascade | 0.690 | ~883 |
The cascade is a serving policy, not a fourth pipeline: answer from the consolidated facts when that channel commits, fall back to raw-turn RAG when it abstains. Overall this is a wash on accuracy at ~73% of the context — 0.690 vs 0.688 is one question in 500 on a single pass, and nobody should read it as a win. The fact spine alone answers at ~13% of RAG's token budget, at a large accuracy cost outside the types it is built for. The structure is per type:
question type | n | naive RAG | commit-gated cascade |
knowledge-update (facts change) | 78 | 0.859 |
|
single-session-user | 70 | 0.929 | 0.943 |
single-session-assistant | 56 | 0.911 | 0.929 |
single-session-preference | 30 | 0.800 | 0.700 |
temporal-reasoning | 133 | 0.526 | 0.526 |
multi-session | 133 | 0.504 | 0.474 |
The consolidated spine helps where a fact changes and where the answer
sits inside one session; it loses where the answer must be aggregated
across sessions or ordered in time, because per-fact consolidation is
exactly what discards that structure. BEAM-100K reproduces the same shape
independently. Its abstention questions are where the spine looks best —
the fact-spine arm scores 0.950 against naive RAG's 0.775, identical under
the local judge and under an independent Opus-class judge — but the
2026-09-02 five-arm run bounds that reading: a no-memory arm scores 1.000
there, so the edge is calibration (a small fact context refuses where raw
turns confabulate), not evidence that the memory recalled anything. Setup, caveats,
both bench stacks side by side, and the evidence that extraction quality is
the dominant factor: Benchmarks; full
methodology: evals/README.md.
Retrieval itself was re-measured on the same corpus before the v25 backbone
swap (150 questions, 74,183 haystack turns, 299 gold turns; pure recall — no
reader, no judge): Qwen/Qwen3-Embedding-0.6B reaches R@10 0.809 against
bge-base-en-v1.5's 0.742 and the previously-shipped all-MiniLM-L6-v2's
0.572, and beats bge-base head-to-head +32/−12 at k=10 (p=0.004).
Artifacts: embedder-recall-shootout-20260727.json,
embedder-recall-qwen-vs-bge-20260728.json.
Cortex Console (web UI)
An operator dashboard served by the daemon itself — point a browser at
http://127.0.0.1:8765/ui/ (the /health and /mcp endpoints are
unchanged; the console is additive). It's a read-mostly instrument panel for
seeing and steering the memory a human otherwise can't observe:
Observatory (health, per-layer counts, the memory store's capacity meter, dream
gauges, consolidation review), Cortex (canonical facts by entity with
provenance, version-history ladders, Adopt/Discard for contested slots),
World / Lessons / Episodes, Stream (live search with rerank/BM25
toggles and a ranking-trace panel), Recall (multi-hop walks and paths
between two entities), Graph (a 3D galaxy of entities with an entity page
per star, and a table view), Review (the graph review queue: Accept/Reject
merges or — for a source file and its own bare concept, band.py ↔ band —
record an implements edge instead of forcing merge-or-dismiss; proposals a
background dream has already judged carry a verdict chip — accept/reject/leave
with confidence, the model's reason in the tooltip — as a lead, never a
decision), Insight (hubs, communities and open questions from the graph
digest), and Settings (every safe config.yaml scalar with
live-vs-restart badges, diff-preview, and atomic save). Bookmarks into the
pre-v3 console (#/console, #/atlas, #/coordination) land on the
matching view.
The Board is a read-only coordination view: active roster/status age, reported
children, park needs/resume, resource holders and FIFO queues. Pending mail
counts are visible only for the caller's principal; the latest 100 retained
send/read/ack/wake/expiry events omit all message bodies. This view requires
a configured bearer on coordination.allowed_principals, even on an otherwise
open loopback installation. Refresh neither receives/acknowledges mail nor
settles expired leases. Snapshots are marked stale after a minute; use Refresh
for current state. The API is GET /api/agents?view=coordination&limit=50
(roster limit 1–50); the default /api/agents awareness response is unchanged.
Incoming audit visibility uses current recipient ownership, so incoming events
may no longer appear after the recipient address is pruned; audit retention
also bounds the timeline. A cold durable tier reports unavailable rather than
initializing the bank through this read.
Auth mirrors /mcp: /ui (static shell) and /health are open; /api/*
requires the same PSEUDOLIFE_MCP_TOKEN bearer when one is set (the console
prompts for it and stores it locally). REST POST bodies are capped in
wire bytes: 4 MiB for the text-bearing writes (/api/facts/set,
/api/consolidate, /api/supersede), 32 KiB for /api/coordination/*,
16 KiB for the session-end hook, 1 KiB for /api/pair, and 256 KiB for
everything else; a larger body gets HTTP 413 {"error": "request_too_large"}. No CDN, fully offline: a Svelte
build committed under pseudolife_memory/web/static/ with vendored OFL fonts
and a vendored 3D engine, served straight from the daemon, so neither the
daemon image nor a pip install needs Node. The source is in
frontend/; CI rebuilds it and fails if the committed
build differs. Developing the UI? A fixture-backed dev server (no Postgres,
no torch) serves the console against canned data:
python -m pseudolife_memory.web.devserver → http://127.0.0.1:8770/ui/.
Its payloads self-announce ("fixtures": true on /health), and the
topbar shows a "Demo data, not a real bank" chip, so a fixture run is never
mistaken for a real bank.
Capabilities at a glance
Capability | Status |
Transport | Streamable-HTTP MCP daemon ( |
Storage | Postgres 18 + pgvector (source of truth); ChromaDB for the reference bank |
Associative store | Flat similarity store (default since the 2026-08-15 measured verdict; the 8-tier banded preset remains opt-in); hybrid dense + BM25 ranking (BM25 on by default); contradiction detection admits potential updates, including a deterministic slot-identity path regardless of embedding similarity, while retaining earlier source notes; whole-note supersession requires an explicit replacement operation |
Canonical-fact cortex | Single-writer: LLM dream pass + |
Set-valued slots |
|
Provenance contenders | Tier-rank guard |
Fact currency | Every cortex fact is dated ( |
Write-time labels |
|
Knowledge graph | Typed entities/edges, closed relation vocab, on-read closure (Postgres + NetworkX, no AGE/Cypher) |
World cortex |
|
Procedural memory |
|
Sense of time + multi-writer | Per-write stamp (tx/valid time, HLC ordering, writer/session); |
Episodes + tags | Session episodes daemon-owned, keyed by a resolved five-tier session identity; hook eager-open or lazy-open on first store + idle reaper + prune-empty + resume-after-reap; nested sub-episodes with subtree-expanded recall; multi-valued |
Session briefing | SessionStart hook injects lessons + verified world facts + last-session recap once per conversation (resume/compact get the episode handle only); the plugin's per-turn note speaks only when lessons or other sessions' status notes changed ( |
Consolidation |
|
Optional components | Cross-encoder reranker ( |
Web console | Cortex Console at |
Schema version | v55 (Postgres meta version) — additive |
Troubleshooting
Start with curl http://127.0.0.1:8765/health — it reports the daemon's
package version, the schema version, storage backend, auth state, and
persist_errors (non-zero means
writes are failing to reach Postgres; check docker logs pseudolife-mcp-daemon).
The cortex stays empty (canonical facts never appear on their own).
/healthreporting"extractor": "none"means no extractor is configured, so the dream writes no facts andmemory_fact_setis the only cortex writer — expected on the lite tier. Point the daemon at an OpenAI-compatible endpoint (Quickstart) or use the Docker tier's bundled sidecar."extractor": "disabled"instead means dreaming itself is switched off in config."extractor": "stalled"means an extractor is configured but live dreams have stopped reaching it; thestallsub-object gives the reason and times. Forstall.reasonlogin_expired, the extractor CLI's login lapsed (or a hosted endpoint rejected its key): re-runclaude auth login(orcodex login) on the daemon host. See When dreaming stalls.Lite daemon refuses to start on Windows with a message about the data path: the embedded Postgres runtime needs an ASCII-only data directory. Set
PSEUDOLIFE_MCP_DATA_DIRto one (e.g.C:\pseudolife-data) — Configuration.First build is slow / big. The daemon image (~5.0 GB, several minutes to build) bakes in CPU torch and the embedding weights (Qwen3-Embedding-0.6B plus MiniLM); the extractor sidecar adds a ~5.3 GB model download on its first build. Every start after that is offline and fast — if a rebuild is re-downloading models, the Docker layer cache was pruned.
Daemon unreachable after
wsl --shutdown(Windows): the host port forward is gone —docker restart pseudolife-mcp-daemonre-establishes it.Docker eating RAM (Windows): the WSL2 VM (
Vmmem) claims up to ~50% of host memory by default. Copyops/wslconfig.exampleto%USERPROFILE%\.wslconfig, tunememory=, thenwsl --shutdown.Port already in use: the stack binds
127.0.0.1:8765(daemon) and127.0.0.1:5433(Postgres). Change the host side inops/docker-compose.ymlif either collides.Console shows "offline" / Unauthorized: "offline" means the daemon isn't reachable (see above); a 401 prompt means it runs with
PSEUDOLIFE_MCP_TOKEN— paste that token into the Console's Token dialog.The coding agent doesn't see the tools:
claude mcp listorcodex mcp listshould showpseudolife-memory✓ connected. If not, re-check the URL (http://127.0.0.1:8765/mcp— the/mcppath matters) and the bearer header when a token is set. The daemon preloads the embedder on a warmup thread at start (~5–10 s); a very early first call can race it and take a few seconds.Tools vanish after an upgrade / the client log says "Connection closed": the shim's registered command can live outside the repo venv, and the MCP SDK v2 migration set an
mcp>=2.1floor — an older SDK in that environment crashes the shim on start. The shim detects this and prints the interpreter path and the exact fix on stderr:pip install -U "mcp>=2.1,<2.2"in that interpreter, or re-run the installer (which registers the project venv's shim).Claude Desktop says "Couldn't start for Cowork and Code sessions. Error: unhandled errors in a TaskGroup (1 sub-exception)": the real exception is at the bottom of
mcp-server-pseudolife-desktop.log(mcp-server-pseudolife-memory.logfor an entry not yet renamed) in the app's log folder (%LOCALAPPDATA%\Claude\Logson Windows,~/Library/Logs/Claudeon macOS). If it is a 401, the daemon is token-gated and the Desktop-launched shim holds no credential: Desktop sanitizes the environment, so putPSEUDOLIFE_MCP_TOKEN_FILEin the entry'senv(see Claude Desktop under Wire into your coding agent) or re-runops/install.* --client claude-desktop, then fully quit and relaunch. On the Windows Store build the file lives under%LOCALAPPDATA%\Packages\Claude_*\LocalCache\Roaming\Claude\. If the entry already carriesPSEUDOLIFE_MCP_TOKEN_FILEand still 401s, the shim predates token-file support (PyPI releases through 0.15.0 read only the literal token):pseudolife-mcp --helpfrom a capable shim listsPSEUDOLIFE_MCP_TOKEN_FILE; upgrade the shim (python ops/update_clients.py --only shimfrom the checkout installs a new runtime beside the running one, so no session has to close) and re-run the installer, which now refuses to register an older one against a token file.A harness "removed tools" notice is not an outage. A resumed session can carry a larger tool roster in its transcript than the current toolset tier serves — that's a visibility filter, not a disconnect. Make one
memory_searchcall before concluding the MCP is down.
Uninstall
Lite tier: remove the MCP registration (claude mcp remove pseudolife-memory / codex mcp remove pseudolife-memory), then
pip uninstall pseudolife-mcp. If you also want the bank gone, delete
the per-user data directory (%LOCALAPPDATA%\pseudolife-mcp on Windows,
~/.local/share/pseudolife-mcp on Linux, ~/Library/Application Support/pseudolife-mcp on macOS — or wherever PSEUDOLIFE_MCP_DATA_DIR
points). Back it up first: pseudolife-mcp backup works on lite too.
Docker tier — deletion is deliberate at every step:
# 1. Optional: take a final backup first (ops/backup.ps1 or ops/backup.sh).
# 2. Stop and remove the containers (volumes survive this).
docker compose -f ops/docker-compose.yml down
# 3. Remove the MCP registration.
claude mcp remove pseudolife-memory
codex mcp remove pseudolife-memory
gemini mcp remove pseudolife-memory -s user
# 4. Only when you're sure: delete the data volumes (THIS is the memory).
docker volume rm pseudolife-mcp-bank pseudolife-mcp-stateHost-process installs: also unregister the logon task
(Unregister-ScheduledTask -TaskName "Pseudolife-MCP Daemon") and remove
the SessionStart briefing hook — plus the UserPromptSubmit memory-change
hook (pseudolife-mcp prompt-hook; older installs: the discipline echo) — from ~/.claude/settings.json and/or
~/.codex/hooks.json (a timestamped .bak-* sits next to each edited file).
Testing
pip install -e .[dev], then pytest tests/. The suite covers every
layer, from the MemoryService surface to the Cortex Console REST API;
model-heavy pieces are stubbed so it stays fast and offline. The PG-backed
suites each target a throwaway per-run pseudolife_memory_test_<pid>
database on the bundled dev container (never your real bank; concurrent
runs can't collide), dropped on exit, and skip cleanly without Postgres.
The suite logs in with its own test login, which cannot open the bank
(pseudolife-mcp test-login create writes ~/.pseudolife-mcp/test-pg.env;
see agent isolation), else the password in
ops/.env (override with PSEUDOLIFE_TEST_DATABASE_URL or
PSEUDOLIFE_TEST_PG_PASSWORD); a server that is reachable but rejects the
credentials errors the PG-backed tests rather than skipping them, so a
rotated password can never produce a green run by accident. Full dev setup: CONTRIBUTING.
What's not built yet
Reflection via MCP sampling — would let the dream borrow Claude itself as the extractor; Claude Code doesn't yet support it.
Replication / offline copies — one daemon owns one bank; other machines use it over the network (remote bank), but there is no replica or offline mode.
Automated world-knowledge ingestion — populating the world cortex from the live web needs a web-fetch tool the standalone server doesn't ship; an agent with web access can automate the fetch+cite step today via
memory_world_set.
Support
Solo-maintained, best-effort. One person builds, tests, and runs this; there is no support contract and no response-time commitment. That said, issues are read and most get an answer.
Something is broken → open a bug report. The form asks for your
/healthoutput, schema version, install tier, and client, because those four answer most questions before any back-and-forth.Something is missing → open a feature request. Say what you were trying to do, not only what to add.
A security problem → do not open a public issue. Use GitHub's private vulnerability reporting — SECURITY.md. Memory integrity specifically: security posture.
Sending a patch → CONTRIBUTING and CODE_OF_CONDUCT. The bar is "surgical, tested, and explained", not "big".
If you need someone to call, Comparison — use something else if names vendors who sell support.
License
Available Tools
38 toolsdocument_ingestADestructive
Index a file into the reference bank — a separate store for background documents (papers, manuals, codebases) retrieved by pure cosine similarity, kept apart from conversational memory.
Returns: {source, chunks_stored, chunks_total}.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Path to a .txt / .md / .pdf file, resolved on the SERVER's filesystem — with the Docker daemon, a path visible inside the container (e.g. a mounted volume), not a host path. | |
| source | No | Source tag for the chunks; defaults to the filename. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the write/destructive/non-idempotent profile, so the description only needs to add context. It adds meaningful architectural detail (separate reference store, pure cosine-similarity retrieval) but says nothing about what ingestion overwrites or how repeated ingests behave, which matters for a destructiveHint=true tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Short and front-loaded: the core action and store definition come first, then the return shape. The return-value sentence is slightly redundant given an output schema exists, but the description remains efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter ingest tool with full schema coverage and an output schema, the description covers purpose, storage model, and return shape. The only real gap is behavioral detail on the destructive/non-idempotent nature already hinted at in annotations.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both parameters (path, source) are already documented in the schema, including the server-filesystem caveat. The description adds no parameter-level meaning beyond that, making the baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Index a file into the reference bank') and scopes it to background documents, which separates it from the memory_* cluster. It doesn't explicitly name document_search as the retrieval counterpart, so it's clear but not fully sibling-differentiated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: the examples (papers, manuals, codebases) and 'kept apart from conversational memory' suggest when this store applies, but there is no explicit when-to-use statement and no named alternative such as document_search or memory_store.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
document_searchARead-only
Search the reference bank only — ingested documents, no
conversational memories mixed in. For docs AND memories together, use
memory_search.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Natural-language description of the passage wanted. | |
| top_k | No | Max chunks returned. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, destructiveHint=false and openWorldHint=false, so the safety profile is covered. The description adds the corpus-scope constraint, but says nothing about result ordering, relevance behavior, or chunk granularity beyond what the schema/output schema implies.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences with zero waste; the corpus-scope constraint is front-loaded ahead of the cross-reference to the alternative tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With annotations carrying the safety profile, an output schema present, and both parameters fully documented, the description only needs to establish scope and routing — which it does completely.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% (query and top_k both documented in the schema), so the baseline is 3. The description adds no syntax, formatting, or query-construction guidance beyond the schema's 'Natural-language description of the passage wanted.'
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Search) and a precisely scoped resource (the reference bank / ingested documents only), and explicitly names the sibling it is not (memory_search). An agent can distinguish it from the ~30 memory_* siblings without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use (reference bank only, no conversational memories) and the alternative plus its selecting condition (docs AND memories together → memory_search). Nothing about tool selection is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_agentsC
Bearer required; list before shared work/resume.
project/task: relevance only. No adapter: unknown scope; idle_omitted counts idle. Adapter auth updates; omissions stay. expect: overdue seconds; children <=8 ([] clears); activity != lock. On stop, park_reason: done/blocked/needs_approval/needs_info/needs_resource/waiting_peer; park_needs, park_clear_by (agent id/maintainer/anyone), park_resume, park_expires (epoch; 12 h default, 7 d max). Ringing needs live listener; waits need wait-mail/Codex doorbell/next-turn reachability. ""/plain status clears. Claim coordinator:/claim:; reclaim renews, release frees, busy queues; status/expect optional. Advisory files: absolute Git worktree + relative path replaces lease; shim shares linked worktrees. HTTP: prepared SHA-256 repository_id/path. No globs/directories/edit enforcement. Park/status grants no approval.
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | ||
| task | No | ||
| lease | No | ||
| action | No | list | |
| expect | No | ||
| status | No | ||
| project | No | ||
| children | No | ||
| worktree | No | ||
| park_needs | No | ||
| park_reason | No | ||
| park_resume | No | ||
| park_expires | No | ||
| park_clear_by | No | ||
| repository_id | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=false, idempotentHint=false, destructiveHint=false, openWorldHint=false, but the description offers little beyond constraints: park expiry defaults (12 h/7 d max), 'children <=8', 'advisory files', 'No globs/directories/edit enforcement', 'Park/status grants no approval'. It never explains idempotency, retry behavior, or the effect of each action, which matters for a non-idempotent, non-read-only tool. The bearer-auth note is useful but leans on annotations for the rest.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The prose is a dense, telegraphic wall of semicolon-separated fragments ('Ringing needs live listener; waits need wait-mail/Codex doorbell/next-turn reachability') that is difficult to parse and not front-loaded with the tool's core purpose. Many sentences do not earn their place in their current form because their referents are unclear, so this fails conciseness and structure despite being short.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be described, but for a 15-parameter, non-read-only, non-idempotent coordination tool the description leaves key behaviors (what 'list' returns, how claims/parks interact, failure/retry semantics, which actions accept which params) unexplained. The scattered hints help but fall well short of what an agent needs to call this correctly across its four actions.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must supply meaning, and it partially does: park_reason enum values, park_clear_by options (agent id/maintainer/anyone), children <=8 with '[] clears', expect semantics ('overdue seconds'), and the claim scheme (coordinator:<project>/claim:<path>). But 15 parameters exist and several (path, task, lease, worktree, repository_id, park_needs, park_resume, park_expires) are only mentioned in passing or have their semantics left implicit.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names concrete resources (claims, parks, leases, projects/tasks) and a bearer-auth requirement, and the first line hints at a list-before-shared-work workflow. However, it never opens with a clear statement of what the tool does as a whole (e.g., 'Coordinate multi-agent state: register activity, claim work, park/resume tasks'), so an agent must infer the purpose from scattered fragments. The 'project/task: relevance only' fragment is opaque without context.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It offers implied guidance: 'list before shared work/resume' and 'project/task: relevance only', plus action-ish hints ('reclaim renews, release frees, busy queues'). But there is no explicit statement of when to use this vs. siblings like memory_message or memory_session_title, and no when-not-to-use. The advice is present but fragmentary and requires the agent to piece it together.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_aliasADestructive
Bind an alternative name to an entity (e.g. pg → postgres)
so facts and graph lookups under either name land on the same node.
Returns the entity's full alias list.
| Name | Required | Description | Default |
|---|---|---|---|
| alias | Yes | The alternative name. | |
| entity | Yes | The canonical entity to bind onto. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true, non-idempotent, non-read-only, so the safety profile is covered by structured data. The description usefully adds the downstream effect (lookups resolve to the same node) and the return value, but it never discloses what the 'destructive' behavior actually is — e.g. whether re-binding an alias already owned by another entity overwrites that binding.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences, the operation is front-loaded, and the effect and return value follow immediately. No sentence is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description needn't explain the returned alias list, and annotations cover the mutation safety profile, so the core is complete. The one meaningful omission for a destructive bind is conflict/overwrite behavior, which leaves it slightly short of full.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and both parameters are documented as 'canonical entity' and 'alternative name', so the schema carries the load. The description's example directionally reinforces the alias→entity mapping but adds no format, collision, or validation semantics. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
It uses a specific verb and resource ('Bind an alternative name to an entity') and the `pg` → `postgres` example makes the direction of the binding unambiguous. It is distinguishable from siblings like memory_set_add or memory_graph_relate, though it never names an alternative to contrast against.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The clause 'so facts and graph lookups under either name land on the same node' conveys the rationale and implies when aliasing is useful, but there is no explicit when-to-use, when-not-to-use, or pointer to a sibling such as memory_graph_relate. Usage 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.
memory_consolidateADestructive
Replace a cluster of near-duplicate memories with one canonical note. Use exactly one selector mode; there is no similarity fallback. All targets must resolve before any changes. Missing, retired or ambiguous targets cause no mutation; search again and resubmit IDs. Selected entries remain as history after replacement.
Returns: {superseded_count, superseded_texts, superseded_ids, new_memory_stored}.
| Name | Required | Description | Default |
|---|---|---|---|
| tags | No | Labels for the new note. | |
| source | No | Source tag for the new note. | |
| new_text | Yes | The canonical note that replaces them. | |
| replaces | No | Unique exact stored texts; omit with entry_ids. | |
| entry_ids | No | Positive IDs in this bank; prefer over replaces. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds real behavior beyond the annotations: all-or-nothing atomicity ('All targets must resolve before any changes'), the exact failure modes that suppress mutation ('Missing, retired or ambiguous'), and the post-condition that 'selected entries remain as history after replacement.' These are the facts an agent needs before a destructive call and none are in the hints.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the action, then constraint, then failure behavior, then return shape. No sentence is filler; the return-key line is dense and useful.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, atomic, multi-target mutation, the description covers what is replaced, how targets are selected, what happens on failure, and what history remains. The output schema exists and the description's return summary is a harmless convenience rather than a gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 selector-mode semantics on top: exactly one of 'replaces'/'entry_ids' must be used and there is no similarity fallback, which is stronger than the schema's 'omit with entry_ids.'
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('replace') and resource ('a cluster of near-duplicate memories') with the outcome ('one canonical note'), so the agent knows exactly what it does. It does not differentiate from the sibling memory_supersede, which arguably overlaps, leaving the agent to infer the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete operating rules: 'Use exactly one selector mode; there is no similarity fallback,' plus the failure path ('search again and resubmit IDs'). It stops short of naming the sibling tool an agent should use instead when it does not already have a resolved cluster.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_consolidation_candidatesARead-only
Find clusters of near-duplicate memories ripe for consolidation —
the same thing phrased five ways across five sessions. Anchor with a
query or an episode; read the clusters, synthesise one
canonical note, then commit it via memory_consolidate.
Each member carries its id; commit with
memory_consolidate(entry_ids=[...]) rather than the members' texts —
IDs survive rewording and duplicate phrasing, exact text does not.
Returns: {count, clusters: [{cohesion, size, members}]}.
| Name | Required | Description | Default |
|---|---|---|---|
| tags | No | Consider only entries carrying one of these tags. | |
| query | No | Topic-driven anchor: cluster memories near this description. | |
| top_k | No | How many candidate entries to cluster over. | |
| episode | No | Session-driven anchor: cluster within this episode id. | |
| sources | No | Consider only entries with one of these source tags. | |
| max_clusters | No | Max clusters returned. | |
| min_cohesion | No | Minimum intra-cluster cosine — raise it to flag only near-duplicates. | |
| min_cluster_size | No | Drop clusters with fewer members than this. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds genuine context beyond that: the commit path must use member IDs rather than texts, with the rationale that 'IDs survive rewording and duplicate phrasing, exact text does not.' It also surfaces the anchor requirement, which the annotations do not.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The definition is front-loaded with the core purpose and follows with the workflow, ID guidance, and return shape. Every sentence is substantive. The 'Returns:' line is mildly redundant given an output schema exists, which keeps it from a 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With annotations covering read-only safety and an output schema documenting the return shape, the description only needs to convey purpose, workflow, and the commit handoff. It does all three. A richer treatment of how clusters are ranked or how many to expect might push it higher, but nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 adds meaning beyond the schema by requiring the caller to 'anchor with a query or an episode' — the schema shows both as optional and defaulting to null, so this either/or constraint is real added guidance. The rest of the parameter description is redundant with the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource — 'Find clusters of near-duplicate memories ripe for consolidation' — with a concrete example ('the same thing phrased five ways across five sessions'). It distinguishes this step from the commit step by naming memory_consolidate as the follow-up, though it doesn't contrast directly with general search siblings like memory_search or memory_recall.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit workflow: anchor with a query or an episode, read the clusters, synthesise one canonical note, then commit via memory_consolidate. That names the next tool and the condition for using this one. It stops short of saying when NOT to use this tool versus a plain search, so it falls just 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.
memory_dreamADestructive
Drive the dream — consolidation of recent memories into canonical facts and graph structure.
Actions:
status: backlog + whether a sweep would fire. Read-only.
pull: unconsolidated memories, oldest first; write facts via
memory_fact_set, then commit.
run: a server-side dream with the configured extractor
(loop to drain).
deep: full-corpus graph consolidation; dry run unless
apply. Settle candidates via
memory_graph_review; duplicate lesson/world slots are
listed for hand curation. Lists are capped; truncated
holds their full counts.
runs: recent dream passes (tallies, status).
rollback: revert a committed pass from its journal (facts +
events; traces/cursor kept).
Returns: per-action dict; {error} on bad input.
| Name | Required | Description | Default |
|---|---|---|---|
| apply | No | deep: True writes the consolidation (graph tables are snapshotted first); the default is a dry run. | |
| limit | No | pull/run: how many memories to process (pull defaults to 40). runs: how many passes to list (defaults to 10). | |
| action | Yes | ||
| cursor | No | Deprecated; use commit_token. | |
| run_id | No | rollback: which pass to revert; defaults to the newest committed pass. | |
| snippets | No | deep: False omits the evidence snippets. | |
| commit_token | No | commit: token returned by pull. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With annotations already declaring destructiveHint=true and readOnlyHint=false, the description adds real context beyond them: rollback reverts facts + events while traces/cursor are kept, deep snapshots graph tables before writing and defaults to a dry run, duplicate lesson/world slots require hand curation, and lists are capped with 'truncated' holding full counts. It does not discuss auth requirements or cost/rate limits, so it is rich but not exhaustive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded in one sentence and the action list is organized and scannable. Given six actions and seven parameters the length is defensible, though a few lines (e.g. rollback details) could be tighter without losing meaning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a multi-action tool with 7 params and an output schema, the description covers nearly everything an agent needs. The one gap is the 'commit' action, which appears in the enum and is referenced inside the pull line but never given its own described entry, leaving its behavior implicit.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 86%, so most parameters are already documented. The description adds meaning beyond the schema for the 'action' enum values, whose schema entries carry only a title, by explaining what each action does and its read/write semantics; it also flags 'commit' as the write step after pull. The remaining param notes largely restate schema descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening states a specific verb+resource: 'Drive the dream — consolidation of recent memories into canonical facts and graph structure,' and each action (status/pull/run/deep/runs/rollback) is named and described. However, it never explicitly differentiates itself from consolidation-related siblings like memory_consolidate or memory_consolidation_candidates, so the agent must infer the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Per-action guidance is strong: status is labeled read-only, pull is for unconsolidated memories (oldest first) with an explicit follow-up path via memory_fact_set then commit, deep is full-corpus with dry-run default, rollback reverts a committed pass. It stops short of stating when NOT to use this tool versus siblings, so it lacks full alternative routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_episode_endB
Close the current open sub-episode and pop back to its parent.
| Name | Required | Description | Default |
|---|---|---|---|
| episode | No | Your session handle — pops only within your own session's subtree; the session root is never closed. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=false, idempotentHint=false and destructiveHint=false, so the safety profile is already covered. The description adds the stack-pop semantics (closes and returns to parent), but omits what happens when there is no open sub-episode and does not mention that repeated calls are non-idempotent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with no filler; the action and its effect come first. It is efficient, though it could carry one clause of precondition without bloat.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained, and the tool is simple with one optional parameter. However, for a non-idempotent state-mutating stack operation the description says nothing about error or no-op behavior when there is no open sub-episode.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single 'episode' parameter is already documented in the schema, including the session-scope constraint and the guarantee that the session root is never closed. The description adds nothing beyond the schema, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Close') and resource ('the current open sub-episode') plus the stack effect ('pop back to its parent'), which clearly distinguishes it from memory_episode_start. It does not explicitly name its sibling counterpart, 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: an agent infers it should call this when a sub-episode is open, and it should use memory_episode_start to open one. There is no explicit when-to-use, no statement about what happens if no sub-episode is open, and no named alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_episode_startA
Open a named sub-episode; it nests under the session episode, and
memories stored while it is open carry its id + title for episode-scoped
search. memory_episode_end closes it and pops back.
| Name | Required | Description | Default |
|---|---|---|---|
| hint | No | Optional note on what the task is about. | |
| title | Yes | Short name for the task, used in later recaps. | |
| episode | No | Your session handle (from the session-start briefing) — anchors the sub-episode to YOUR session when several run concurrently. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare the write/idempotency profile (readOnlyHint=false, idempotentHint=false); the description goes beyond them by disclosing the nesting/stacking semantics and the side effect that memories written while open carry the episode id + title. It omits auth or concurrency caveats beyond the reference to several sessions running concurrently.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences with zero filler. The core action and the nesting relationship are front-loaded, and the closing counterpart is mentioned last as a natural follow-on.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained. The description adequately covers the state transition and scoping effect for a stateful episode tool, leaving only minor gaps such as what happens on nested or repeated opens.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 title, hint, and episode (session handle). The description adds no format or syntax detail beyond what the schema provides, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Open a named sub-episode') and immediately clarifies the containment model (nests under the session episode). It also names the sibling that undoes it ('memory_episode_end closes it and pops back'), so an agent can distinguish the pair without reading either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains the condition for use: memories stored while the episode is open get tagged with its id and title for episode-scoped search, which implies you open one before storing related memories. It names the closing complement, but does not explicitly contrast against other ways of scoping memories (e.g. memory_store alone).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_episode_summaryARead-only
Stats, tag/source distribution and recent entries for one episode
("summarise what we worked on"); {found: false} if unknown.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | An episode id, as it appears on search/recent results. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so safety is covered. Beyond that, the description adds a genuinely useful behavioral fact: the tool returns {found: false} when the episode id is unknown, which tells the agent how to detect a miss instead of assuming an exception.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single compact sentence with no filler. The return-value content is front-loaded rather than the action verb, which is a minor ordering quirk, but nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be enumerated, and the description nonetheless flags the unknown-id case. For a one-parameter, read-only summary tool this is close to complete; only the absence of routing guidance against similar read tools leaves a small gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is a single parameter with 100% schema description coverage ("An episode id, as it appears on search/recent results"), so the schema already carries the semantics and the description adds nothing further about the id. Baseline 3 applies when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names the resource (one episode) and enumerates what is returned: stats, tag/source distribution, and recent entries. It is clearly a read/summary operation, distinct from siblings like memory_episode_start/end, though the verb itself is implied rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The quoted phrase "summarise what we worked on" gives an implied use case, but there is no explicit when-to-use guidance, no exclusions, and no named alternative (e.g. memory_recent or memory_history which could also surface recent activity). Usage must be inferred.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_fact_getARead-only
Look up the one CURRENT value at an (entity, attribute) slot.
One value per slot. A null record means EMPTY, not unknown —
memory_search still finds context. A set-valued slot returns
{kind: "set", members, removed} instead — members: [] means
EMPTY too.
Returns: {record | null, contenders} (+ entity_ref when the
entity has a graph node). Non-empty contenders = unsettled
conflict (see memory_fact_resolve); on an empty slot,
candidates lists nearby slots — ranked leads, not answers.
re_verify = a memory this fact was derived from has since been
corrected; the value still stands but check it before acting. Set slots
carry it too, at the slot. PostgreSQL keeps this warning after the
corrected source memory is evicted or deleted; file mode has no durable
retraction warning. verbose=True adds the record's provenance,
support and temporal stamp; memory_history shows the slot's version
chain.
| Name | Required | Description | Default |
|---|---|---|---|
| entity | Yes | The slot's subject; the (entity, attribute) match is case- and separator-insensitive. | |
| verbose | No | Full record; the default drops bookkeeping keys. | |
| attribute | Yes | The slot's attribute. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only safety, so the description is free to add deeper semantics: null means EMPTY (not unknown), set slots return {kind: "set", members, removed}, non-empty contenders signal conflict, and re_verify flags a corrected source memory. It even distinguishes PostgreSQL durable warnings from file-mode behavior — context far beyond 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.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense but front-loaded: the core lookup and the null-is-empty rule come first, followed by return shape and edge-case flags. Nearly every sentence earns its place, though the return-format detail is heavier than strictly necessary given an output schema exists.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 3-parameter read tool with a rich output schema and full annotation coverage, the description covers the edge cases an agent would otherwise misread: empty vs unknown, set-slot shape, conflict signaling, and staleness warnings. Nothing needed to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 adds meaning beyond the schema's terse "Full record; the default drops bookkeeping keys" by specifying that verbose adds provenance, support, and temporal stamp. That is genuine added value over the structured field.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a precise verb+resource+scope: "Look up the one CURRENT value at an (entity, attribute) slot." This clearly distinguishes it from memory_fact_set (writes a slot), memory_fact_resolve (settles conflicts), and memory_search (broad retrieval). An agent can identify the exact operation 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Routes the agent to alternatives with conditions: memory_search for context on empty slots, memory_fact_resolve for unsettled conflicts, memory_history for version chains. It lacks an explicit "use this instead of X when..." framing for the primary lookup case, but the sibling routing is concrete and actionable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_fact_resolveADestructive
Settle a CONTESTED fact slot after checking with the human.
Returns: {resolved, accepted, action, current, record} or
{resolved: false, reason: "no_contender"}.
| Name | Required | Description | Default |
|---|---|---|---|
| accept | Yes | True adopts the parked contender as the new current value (the old value is kept as history); False discards the contender and keeps the current value. | |
| entity | Yes | The contested slot's subject. | |
| attribute | Yes | The contested slot's attribute. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true, non-idempotent, non-read-only, so the safety profile is partly covered. The description adds genuinely new context: the human-confirmation precondition and the failure shape ({resolved:false, reason:'no_contender'}). It does not, however, elaborate on the destructive consequences beyond what the schema's 'accept' description already says.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, front-loaded with the action and its precondition. The Returns block is somewhat redundant given an output schema exists, but naming the 'no_contender' failure shape is still worth the space, so it stays efficient overall.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 3-required-param mutation with an output schema and full annotation coverage, the description supplies the purpose, the human-confirmation precondition, and the failure mode. Return-value detail is rightly left to the output schema. A bit more on alternatives and destructive consequence would complete it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already carries the parameter meaning, including the accept True/False semantics. The description adds only the notion of a 'parked contender' and the human-check context. Baseline 3 is appropriate when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource: settling a 'CONTESTED fact slot'. This is clearly distinguishable from siblings like memory_fact_set and memory_fact_get, which imply setting/getting rather than resolving a contested state. It stops short of explicitly naming those siblings, so it earns a 4 rather than a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives one implied precondition: this is only for a slot that is already contested, and only 'after checking with the human'. That narrows usage meaningfully. However, it never names the alternative tools (memory_fact_set, memory_supersede) or states when NOT to use this, so the routing guidance remains inferential.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_fact_setADestructive
Assert a canonical fact — insert, confirm, or correct a slot.
A new value at an existing slot supersedes the old (history kept).
A conflicting write parks as a contender (action="contested",
winner under current) — check with the human, settle via
memory_fact_resolve.
authority / distortion_tolerance inherit the slot's labels
unless restated.
Returns: {action: inserted|confirmed|superseded|contested, ...record}.
| Name | Required | Description | Default |
|---|---|---|---|
| value | Yes | The value that is canonical NOW. | |
| entity | Yes | The slot's subject; the (entity, attribute) match is case- and separator-insensitive. | |
| origin | No | Who asserted it: "user" = the human told you; otherwise "action"/"agent". Omitted records "agent". | |
| episode | No | Episode handle for attribution. | |
| attribute | Yes | The slot's attribute. | |
| authority | No | Speech act of the source: "directive" / "quoted" (doc or third party) / "observation"; "auto" infers. | auto |
| confidence | No | How sure you are, 0..1. | |
| freshness_class | No | How fast the value rots. "auto" infers the decay rate from the entity kind. | auto |
| distortion_tolerance | No | "constraint" = verbatim, pinned in recall; "auto" infers only that. | auto |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds substantial context beyond the annotations: the old value is superseded but history is kept (softening the destructiveHint), conflicting writes park as contenders rather than overwriting, and authority/distortion_tolerance inherit slot labels unless restated. This is exactly the mutation-safety detail the destructive/non-idempotent annotations flag as risky.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Densely front-loaded — the core action leads, then conflict semantics, then inheritance, then the return shape. No filler sentences, though a few clauses are terse enough to require a second read.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 9-parameter mutation tool with a contested-state model, the description covers action semantics, conflict handling, inheritance behavior, and even the return shape (despite an output schema existing). 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.
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 earns an extra point by documenting cross-parameter behavior the schema cannot express: authority and distortion_tolerance inherit the slot's labels unless restated, which changes how an agent should reason about defaults on a write.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a precise verb and resource: 'Assert a canonical fact — insert, confirm, or correct a slot.' The three modes map cleanly onto the slot model, and it explicitly routes the conflict case to the sibling memory_fact_resolve, so an agent can distinguish it from memory_fact_get and memory_store.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear conditional guidance for the contested case ('check with the human, settle via memory_fact_resolve') and explains supersede vs. confirm behavior. It lacks an explicit statement of when NOT to use this versus memory_store or memory_supersede, so it stops short of the top tier.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_forgetADestructive
Forget from one memory store. memory hard-deletes entries
(junk/test cleanup), retiring their digests and facts/edges left
unsupported; fact hard-deletes (no audit trail); world and lesson
RETIRE the slot with an audit row, undone by memory_graph_review( action="restore_slot"). For "now wrong, keep history" use
memory_fact_set (facts) or memory_supersede (memories) instead.
scope="memory" needs at least one of text/substring/
source/episode/tag; several NARROW the match (AND, like
memory_search): text + source is one entry, not the whole source.
Over memory.delete_confirm_threshold (20) matches it refuses with
would_delete until confirm_bulk=True. The other scopes need
entity.
Returns: {deleted_count | removed, ...}; {error} on bad input.
| Name | Required | Description | Default |
|---|---|---|---|
| tag | No | memory scope: entries carrying this tag. | |
| text | No | memory scope: entries with exactly this text. | |
| scope | Yes | Which store to delete from. | |
| entity | No | fact/world scope: the slot's subject. lesson scope: the task. | |
| source | No | memory scope: entries with this source tag. | |
| episode | No | memory scope: entries stamped with this episode id. | |
| attribute | No | fact/world scope: one slot's attribute; omit to purge the whole entity. lesson scope: the aspect. | |
| substring | No | memory scope: entries whose text contains this. | |
| confirm_bulk | No | memory scope: allow over memory.delete_confirm_threshold (20) matches; else refused, reporting would_delete. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true, but the description adds material context beyond them: memory/fact are hard-deletes with no audit trail (retiring digests and orphaning facts/edges), while world/lesson retire with an audit row undoable via memory_graph_review(restore_slot), and the bulk-confirm refusal path at 20 matches. This is exactly the behavioral depth the annotations 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.
Is the description appropriately sized, front-loaded, and free of redundancy?
The text is front-loaded with the per-scope behavior, then parameter constraints, then the return shape. It is information-dense but a single sentence spans hard-delete vs retire plus the restore path, which slightly crowds the structure. Nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 9-parameter destructive tool with an output schema, the description covers the per-scope effects, required-parameter alternatives, destroy-vs-retire semantics, the bulk-confirm guard, and the escape hatches (memory_fact_set, memory_supersede, restore_slot). An agent has everything needed to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 adds real value on top by stating that scope=memory needs at least one of text/substring/source/episode/tag, that several narrow via AND rather than widening, and that the other scopes require entity – conditions the per-property schema descriptions don't capture.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb ('Forget' / hard-delete / retire) and resource (entries across four named scopes), and names the sibling tools (memory_fact_set, memory_supersede, memory_graph_review) with which it could be confused. It distinctly differentiates itself by scope behavior, which no other sibling does.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly states which alternative to use for the 'now wrong, keep history' case – memory_fact_set for facts and memory_supersede for memories – and carves out when hard-delete is appropriate (junk/test cleanup) versus when retiring is appropriate. When-not guidance is explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_getA
Dereference a memory id to the full stored episode plus
consolidated_into — the canonical facts it produced. Reading it
gently reinforces it. Superseded: adds replaced_by, as in search.
{found: false, faded: true} once forgotten.
| Name | Required | Description | Default |
|---|---|---|---|
| entry_id | Yes | A memory id, as returned by search results or by a fact's ``source_entries``. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds meaningful behavior beyond the annotations: reading gently reinforces the memory (explaining why readOnlyHint=false), superseded entries include replaced_by, and forgotten entries return {found: false, faded: true}. It omits permission/auth context, but the reinforcement side effect is the key non-obvious trait and it is disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and kept short. Some fragments ('Superseded: adds replaced_by, as in search.') are terse to the point of being cryptic, but there is little wasted text.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return shape need not be spelled out, and the description still adds the special-case response for forgotten entries. For a single-parameter read tool it is nearly complete, missing only explicit routing among sibling memory reads.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single entry_id parameter is already documented in the schema, including where the id comes from. The description adds only marginal meaning beyond that, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (dereference) and resource (a memory id to its full stored episode plus consolidated_into), and clarifies what the payload contains. It differentiates the episode payload from the canonical facts it produced, but does not explicitly contrast with near-siblings like memory_fact_get or memory_episode_summary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied: you call it when you hold a memory id from search results or a fact's source_entries and want the full episode. The 'as in search' clause hints at behavioral parity with search, but there is no explicit when-to-use versus alternatives such as memory_fact_get.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_graphARead-only
Read an entity's graph neighborhood: nodes, typed edges, and each
node's canonical facts. Transitive/inverse edges arrive pre-derived
(marked derived: true with rule provenance).
Returns: {found, entity, nodes, edges, paths}.
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | Also return the shortest path from ``entity`` to this entity under ``paths``; its nodes are folded into the neighborhood. | |
| depth | No | Hops from the root. Max 3. | |
| entity | Yes | The root entity to read out from. | |
| include_facts | No | False omits each node's canonical facts. | |
| relation_filter | No | Keep only edges whose relation contains this substring. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so safety is covered. The description adds real behavioral value beyond them: transitive/inverse edges arrive pre-derived and are flagged derived:true with rule provenance. It does not explain the non-idempotent hint or cost/limits, but the derived-edge semantics are genuinely useful.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three compact sentences, front-loaded with the core action and followed by the derived-edge caveat. The explicit 'Returns:' line is somewhat redundant given an output schema exists, but it is brief rather than padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only traversal tool with an output schema and safety annotations, the description is largely sufficient: it states scope, the pre-derived edge semantics, and the return keys. Nothing an agent needs to invoke it correctly is missing, though a note on traversal cost or depth limits would round it out.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 entity, depth, to, include_facts, and relation_filter. The description adds no extra parameter semantics (e.g., depth interaction with relation_filter or path folding behavior beyond what the schema states), so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb+resource: 'Read an entity's graph neighborhood: nodes, typed edges, and each node's canonical facts.' This is clearly distinct from the graph mutators (memory_graph_relate/unrelate) and review tools, but the description never names a sibling to route against, so it stops short of explicit differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by 'read an entity's graph neighborhood', so an agent can infer it is the traversal/expansion tool. However, with ~40 siblings including memory_search, memory_recall, and memory_fact_get, there is no explicit when-to-use-this-vs-that guidance or exclusion criteria.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_graph_relateADestructive
Assert a typed relation between two entities, e.g. ("web-app", "runs-on", "host-1"). Entities auto-create and resolve through
aliases; re-asserting an edge bumps its confidence. On a rejected
relation, pick a suggestion, fall back to related-to, or grow the
vocabulary deliberately via memory_relation_define.
Returns: {src, relation, dst, confidence, warnings} or
{error: "unknown_relation", suggestions}.
| Name | Required | Description | Default |
|---|---|---|---|
| dst | Yes | The object entity. | |
| src | Yes | The subject entity. | |
| origin | No | Who asserted the edge. | |
| dst_type | No | Entity kind for ``dst``: set when the node is created, or filled in on an existing node that has none. | |
| relation | Yes | From the closed registry: ``depends-on``, ``part-of``, ``runs-on``, ``hosts``, ``uses``, ``configures``, ``stores-data-in``, ``related-to``. Separator variants normalise; an unknown name is rejected WITH the closest matches. | |
| src_type | No | Entity kind for ``src``: set when the node is created, or filled in on an existing node that has none. | |
| confidence | No | How sure you are, 0..1. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the mutation/safety profile (readOnly=false, destructive=true, idempotent=false), and the description adds meaningful behavior on top: entities auto-create and resolve through aliases, re-asserting an edge bumps confidence (which explains the non-idempotent hint), and unknown relations are rejected with suggestions. No contradiction with 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.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the action and an example, then behavior, then the return shape, in a compact paragraph with no filler. Dense but each sentence carries information; the only minor redundancy is restating the return shape despite an output schema existing.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-parameter mutation tool, the description covers the critical unknowns an agent needs: auto-creation side effects, alias resolution, confidence bumping on re-assert, the rejection/suggestion path, and the fallback tool. With full schema coverage and an output schema present, nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 src/dst/relation/confidence/origin/types, including the closed relation registry and its normalisation/rejection behavior. The description reinforces the triplet shape with an example but adds no syntax or constraint detail beyond what the schema provides, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Assert a typed relation between two entities') and grounds it with a concrete triplet example ("web-app", "runs-on", "host-1"). It also distinguishes itself from the vocabulary-management sibling memory_relation_define, so an agent can identify the tool's role 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit branch guidance for the failure case: on a rejected relation, pick a suggestion, fall back to related-to, or call memory_relation_define to grow the vocabulary. This names an alternative tool and the condition that selects it, though it does not state when to prefer this over other writes like memory_store or memory_set_add.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_graph_reviewADestructive
Work the graph review queue — deep-dream proposals that need a verdict before they touch the graph.
Actions:
list: pending findings/proposals.
propose: file link proposals for review.
relate: related-not-duplicate verdict — writes the
relation edge and dismisses the pair.
dismiss_pair: mark src/dst genuinely distinct.
dismiss_slot_pair: same for lesson/world duplicate listings.
restore_slot: undo a lesson/world forget (forgets retire, never
delete) — store + src (the retired key).
accept_link/reject_link: settle an edge proposal by id.
accept_merge: fold a near-duplicate into its twin.
accept_junk: delete an over-extraction artifact.
reject_entity: keep the entity, dismiss the proposal.
Returns: per-action dict; {error} on bad input.
| Name | Required | Description | Default |
|---|---|---|---|
| dst | No | relate/dismiss_pair/dismiss_slot_pair: the second entity or key. | |
| src | No | relate/dismiss_pair: the first entity. dismiss_slot_pair: an "entity|attribute" key from the deep response; restore_slot: retired key or entity. | |
| scope | No | list: keep only analyzer findings whose entities carry this memory source (Atlas project); queued proposals always list; omit or "all" for everything. Not a finding kind. | |
| store | No | dismiss_slot_pair/restore_slot: "lesson" or "world". | |
| action | No | list | |
| relation | No | relate: edge relation to write (graph vocabulary). | |
| proposals | No | propose: ``[{src, relation, dst, similarity?, rationale?}]``. | |
| proposal_id | No | Id actions: the proposal to settle. | |
| proposal_ids | No | Id actions: many proposals at once. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true, readOnlyHint=false and idempotentHint=false, and the description is consistent with them. It adds meaningful context beyond the annotations: 'forgets retire, never delete', that relate writes the relation edge and dismisses the pair, and what accept_merge/accept_junk actually do to data. It stops short of disclosing auth/permission needs or irreversibility per action.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in one sentence, followed by a scannable action list and a one-line return note. The awkward indentation and the split of some entries across lines cost a little, but there is no filler and each line carries information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so the brief 'per-action dict; {error} on bad input' note is sufficient. All 11 enum values are described, and with 0 required params the default of `list` is implied by the description. Missing only per-action required-parameter hints, which would help an agent call non-default actions correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 89%, so the schema already documents nearly every parameter and even maps params to actions (e.g. 'relate/dismiss_pair: the first entity'). The description's param mentions ('store + src (the retired key)', 'settle an edge proposal by id') largely restate the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific resource (the graph review queue) and frames it as 'deep-dream proposals that need a verdict before they touch the graph', then enumerates all 11 actions with one-line semantics. It distinguishes itself from siblings like memory_consolidate and memory_dream by tying the queue to dream proposals, but it never disambiguates the `relate` action from the sibling tool memory_graph_relate, which appears to write the same kind of edge.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The per-action lines imply when each action applies ('relate' for related-not-duplicate, 'accept_junk' for over-extraction artifacts), which is real guidance. However, there is no explicit when-to-use-this-tool-vs-alternatives statement, no prerequisites or ordering, and no indication of which actions require which params before calling.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_graph_unrelateADestructive
Retract a relation — the edge is marked superseded (kept for audit)
and leaves memory_graph results. Re-asserting the same triple later
revives it.
| Name | Required | Description | Default |
|---|---|---|---|
| dst | Yes | The edge's object entity. | |
| src | Yes | The edge's subject entity. | |
| relation | Yes | The edge's relation. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and idempotentHint=false, so the safety profile is covered. The description adds valuable non-obvious behavior: the edge is marked superseded but kept for audit, and re-asserting revives it. This goes beyond annotations by explaining the audit/revival semantics. Minor gap: doesn't explicitly note non-idempotency, but annotations cover that.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the core action (retract a relation) followed by the behavioral detail (audit-kept, revival). No filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given annotations cover safety (destructive, not idempotent) and an output schema exists (so return details are not needed), the description provides sufficient context for correct invocation. A slight gap remains: no explicit guidance on when to prefer this over nearby alternatives, but the core behavior is well-specified.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents src, relation, and dst. The description adds no additional semantics for these parameters. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (retract) and resource (a relation/edge in the memory graph), and distinguishes itself from the sibling memory_graph_relate by describing the opposite operation. An agent can distinguish this from graph_relate without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Clear implied context: use when a relation should be retracted / removed from graph results. The mention of revival on re-assertion gives the agent a hint about reversibility. However, no explicit 'when to use this vs alternatives' (e.g., vs memory_forget, memory_supersede, memory_set_remove) is given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_historyARead-only
Read an entity's past. SLOT mode (attribute given): every
version of that canonical fact slot, oldest→newest, each with
writer/session, tx/valid time, and age ("what did this used to be?
who set it?") — compaction thins chains past ~30d. CHAIN mode
(attribute omitted): the entity's dated fact/entry/edge/lesson
events merged oldest→newest ("what led to X?").
Returns: {entity, attribute, count, versions} (slot mode) or
{found, entity, count, events} (chain mode).
| Name | Required | Description | Default |
|---|---|---|---|
| as_of | No | Slot mode only: ISO-8601 or epoch seconds; returns only versions written by then. | |
| entity | Yes | The subject whose past to read. | |
| attribute | No | The fact slot to read; omit for chain mode. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, and the description adds real context beyond them: oldest-to-newest ordering, the fields returned per version (writer/session, tx/valid time, age), and the ~30d compaction caveat. The compaction note is a genuinely useful behavioral trait not visible in any structured field.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense but front-loaded: purpose first, then mode breakdown, then return shapes. Each clause carries information (mode, ordering, fields, caveat) rather than filler, though the inline return-shape enumeration is somewhat verbose given an output schema exists.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-mode read tool with a documented output schema and full parameter coverage, the description covers mode selection, ordering, returned fields, and a data-retention caveat. 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.
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 attribute ('omit for chain mode') and as_of ('slot mode only'). The description reinforces the mode-switch meaning of attribute but adds little syntactic detail beyond what the schema states, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (read) and resource (an entity's past) and cleanly splits the tool into two named modes with distinct semantics. An agent can tell exactly what it does without opening the schema, and the two-mode framing distinguishes it from simple retrieval siblings like memory_get.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit mode-selection logic (attribute given = slot mode, omitted = chain mode) and parenthetical example questions that map intent to mode. It stops short of naming alternative sibling tools or exclusion conditions, so it is clear context without full routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_lesson_searchARead-only
Search learned lessons (procedural memory) by similarity to the task
at hand. Call at the START of a task: what worked, what to avoid, what
the user corrected before. Heed polarity - entries — known
dead-ends. A lesson describes the run it came from, not this one:
apply it where today's specifics match, or it anchors you on a
stale framing — re_verify: true marks one whose subject facts
have changed since, so re-derive that one.
Returns: {count, entries: [{task, aspect, lesson, about, polarity, outcome, confidence, score, re_verify, re_verify_reason}]}.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | The task at hand, described the way it would have been logged. | |
| top_k | No | Max entries returned. | |
| verbose | No | Full provenance metadata; default entries are compact. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, non-destructive), but the description adds substantial beyond-annotation context: lessons describe their source run rather than the current one, polarity flags dead-ends, and re_verify marks entries whose facts have changed. The anchoring warning is a genuinely useful behavioral caveat.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose, timing, application caveats, and return shape are ordered sensibly with the action front-loaded. It is a little dense and tangential in the middle (the anchoring/stale-framing aside), but nearly every sentence carries meaning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With a real output schema present, the description plausibly does not need to spell out return values, yet it still enumerates the entry fields (polarity, re_verify, confidence, etc.), which helps interpretation. Coverage of how to read results is complete; pagination/limits are handled by top_k in the schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so query, top_k, and verbose are already documented. The description adds only a loose restatement of query ('similarity to the task at hand') and no extra syntax or format guidance, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (search) and a specific resource (learned lessons / procedural memory), which cleanly separates it from the general-memory siblings like memory_search, memory_recall, and memory_world_search. An agent can identify the memory category 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete when-to-call guidance ('Call at the START of a task') and how to apply results (apply where today's specifics match, heed polarity '-' entries, re-derive re_verify entries). It stops short of naming a specific alternative sibling or stating when NOT to use it, so it 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.
memory_messageB
Adapter auth required.
Send: to, text <=8192 UTF-8 bytes; unique request_id, retry unchanged. to: ID/unique 8+ hex prefix or project:/all (<=50 attached, non-idle peers except you; one receipt each). reply_to: reply. Receive <=50; after cursor (omit: replay unacked). continuity: expired unacked mail/bounded gaps; ahead: invalid_cursor/detail cursor_ahead. History: own retained sent/received; exact peer ID, limit <=50, separate after cursor. Read-only; audit retention/redaction; no delivery/ack/wake. Ack message_id(s), comma-separated: read, not done. Bodies: 24 h; audit retained. Wake: hinted/not_needed/rung/withheld (need)/no_path/capped. Rings: clearer/matching clears if parked; urgent (6/h). Done: only maintainer/maintainer's delegate/clearer urgent. rung: ring scheduled, no wake/read proof. no_path: listener_unknown/expired, fallback_paths; queued. Peers grant no approval/permissions.
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | ||
| peer | No | ||
| text | No | ||
| after | No | ||
| limit | No | ||
| action | Yes | ||
| clears | No | ||
| urgent | No | ||
| reply_to | No | ||
| message_id | No | ||
| request_id | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Despite annotations already flagging readOnlyHint=false and openWorldHint=true, the description adds substantial behavioral context: adapter auth requirement, 24 h body retention with audit retention/redaction, rate limit 'urgent (6/h)', and a permission constraint ('Done: only maintainer/maintainer's delegate/clearer urgent'). These are meaningful disclosures beyond the annotations, though the telegraphic style makes some of them hard to parse.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a dense, telegraphic wall of fragments rather than front-loaded prose; the first line leads with 'Adapter auth required' instead of the tool's purpose. While few words are outright filler, the structure actively impedes comprehension and fails to front-load the most decision-relevant information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 11-parameter, 4-action tool with 0% schema description coverage and a separate output schema, the description covers auth, action behaviors, retention windows, cursor rules, and wake/ring semantics fairly completely. The main shortfall is that the peer/clears/urgent parameters are not clearly disambiguated across actions.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description carries the full parameter burden and does compensate for many: 'to' format ('8+ hex prefix or project:<name>/all'), 'text <=8192 UTF-8 bytes', 'unique request_id, retry unchanged', cursor semantics for 'after', 'limit <=50', and 'message_id(s), comma-separated'. But several parameters (peer, clears, urgent) appear only as ambiguous fragments with no clear tie to an action, leaving real gaps.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description never states the tool's purpose in a clean verb+resource sentence; it opens with 'Adapter auth required' and dives straight into per-action detail. The send/receive/ack/history actions do convey that this is a peer-messaging tool, but an agent must infer the overall purpose rather than read it, and there is no differentiation from siblings like memory_agents or memory_search.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Action-specific usage is implied through fragments ('omit: replay unacked', 'Read-only', 'Ack message_id(s): read, not done'), which give some sense of when each action applies. However there is no explicit when-to-use vs when-not guidance, and no routing against alternative sibling tools, so usage remains inferred rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_outcomeA
Record a procedural outcome — what worked, failed, or was corrected. The dream distils signals into next session's lessons.
Returns {recorded, signal_id, task, outcome}; needs Postgres.
used_ids adds used_ids_recorded (credited),
used_ids_unmatched (nothing served it),
used_ids_served_elsewhere (another session did),
used_ids_ignored (not ids), used_ids_truncated (over 50),
used_ids_errors (write failed), used_ids_reason (why none
landed).
| Name | Required | Description | Default |
|---|---|---|---|
| task | Yes | Kind of task, in stable wording ("deploy engine to host") so signals for the same work group. | |
| about | No | The tool or approach concerned; aids traversal. | |
| detail | No | What worked, or what the dead-end was. | |
| episode | No | Episode handle for attribution. | |
| outcome | Yes | What happened. | |
| polarity | No | "+" do-this or "-" avoid; usually omit — it is inferred from the outcome. | |
| used_ids | No | Ids of the search hits you actually used, e.g. [1421, 903] — the relevance label only you can write. At most 50. Credits this session's searches from the last hour; log before that lapses. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the write/non-idempotent/non-destructive profile, so the description's added value is the Postgres dependency ('needs Postgres'), the credit mechanism for used_ids, and the one-hour expiry window. It also explains the used_ids_* result buckets, which clarifies what a partial or failed attribution looks like. It stops short of stating permissions or failure behavior beyond the used_ids_errors bucket.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded in the first sentence, followed by dependency and return information. The long used_ids_* enumeration is informative but dense and partly duplicates the output schema, slightly bloating the definition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-parameter write tool with annotations and an output schema, the description covers purpose, environment dependency, the credit/timing constraint, and partial-failure semantics. Nothing critical is missing, though the relationship to sibling memory tools is unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so every parameter is already documented, including used_ids, about, detail, and polarity. The description mostly restates the used_ids semantics ('the relevance label only you can write', 'at most 50', last-hour crediting) rather than adding new meaning. Baseline 3 applies when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb+resource ('Record a procedural outcome') and enumerates the recorded outcome kinds (worked, failed, corrected). It is clearly distinguishable from storage siblings like memory_store or memory_message in substance, though it never names an alternative to route against.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by 'what worked, failed, or was corrected' and by the instruction to log used_ids 'before that lapses' (a one-hour window), which is genuinely actionable timing guidance. However, there is no explicit when-to-use/when-not statement and no named alternative among the many memory_* siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_recallARead-only
Multi-hop retrieval over the knowledge graph, for RELATIONAL
questions whose answer is reached by following links — "what does X
ultimately run on?", "how does A reach C?" — which single-shot
memory_search can't chain. Read-only. low_confidence: true
means no seed entity matched — fall back to memory_search.
Returns: {seeds, entities, edges, paths, texts, iterations}.
entities/edges/texts are capped (currently 10/15/6) with a
per-hop reservation, so a hub seed's own 1-hop ring can't crowd out
the deeper hops the walk exists to reach; edges prefers links
between surviving entities; each entity's facts is capped
(currently 5). A fact carrying re_verify stands on a memory that
has since been corrected — the value still stands, but check it before
acting. A seed entity's constraint facts come first, marked
pinned. truncated: true (with searches_issued) means a
search ceiling or time budget stopped the walk early: some re-queries,
and possibly deeper hops, were skipped, so supporting texts and deeper
entities may be missing — narrow the question or lower hops.
Details: docs/guide/retrieval.md.
| Name | Required | Description | Default |
|---|---|---|---|
| hops | No | Max graph hops. Clamped to 1..5. | |
| query | Yes | Natural-language relational question; its top hits seed the graph walk. | |
| top_k | No | Bounds only the SEED search (the initial hits that name the walk's start entities), not the result, which is capped separately; up to 3 ``texts`` slots go to seed hits. | |
| verbose | No | Full fact/edge provenance and untruncated texts. Default facts are ``{attribute, value}``, edges ``{src, relation, dst}``, texts truncated to a preview. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover only the safety profile (readOnlyHint true, destructiveHint false); the description goes well beyond by disclosing capping behavior (10/15/6 with per-hop reservation), fact cap of 5, the meaning of re_verify on corrected memories, pinned constraint facts, and what truncated/searches_issued implies about missing data. This is unusually rich behavioral context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in the first sentence and every later sentence carries operational detail (caps, re_verify, truncated). It is dense rather than bloated, though 'Read-only' duplicates the readOnlyHint annotation and the return-field listing slightly overlaps the output schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite having an output schema, the description supplies the interpretive layer the schema cannot: what capping, re_verify, pinned facts, and truncated mean for the agent's next action. Combined with the doc pointer, nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 hops, top_k, and verbose. The description still adds meaning by tying hops to the truncated failure mode ('lower hops') and explaining why results are capped independently of top_k, which the schema does not spell out.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (multi-hop retrieval) and resource (knowledge graph) plus the exact class of question it serves (relational, link-following). It explicitly distinguishes itself from memory_search, which 'can't chain', so an agent can route 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names the alternative (memory_search) and the condition that selects it, gives a fallback rule when low_confidence is true, and tells the agent to narrow the question or lower hops when truncated. When-to-use, when-not, and recovery paths are all explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_recentARead-only
List the N most recently stored memories, newest first — timestamp
order, not relevance. Useful for "what did I just store?" and for
catching up at the start of a session. The sources/episodes/
tags filters AND-combine.
| Name | Required | Description | Default |
|---|---|---|---|
| n | No | How many entries to return. | |
| tags | No | Keep only entries carrying one of these tags. | |
| sources | No | Keep only entries with one of these source tags. | |
| verbose | No | Full per-entry metadata; default entries are compact. | |
| episodes | No | Keep only entries stamped with one of these episode ids. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so safety is covered. The description adds non-obvious behavior: the ordering guarantee and that sources/episodes/tags filters AND-combine, which an agent could otherwise assume was OR. It does not need to explain return values since an output schema exists.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, zero waste, with the core identity (most recent N, newest first) front-loaded before the usage hints and the filter-combination note.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 5-param, zero-required read tool with full schema coverage, annotations, and an output schema, nothing an agent needs is missing: ordering, scope, filter interaction, and use contexts are all stated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 goes beyond the per-parameter schema text by specifying that the three filter parameters AND-combine, a cross-parameter semantic not derivable from individual field descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (List), resource (memories), quantity (N), and ordering semantics ('newest first — timestamp order, not relevance'). The 'not relevance' clause implicitly contrasts with memory_search, letting an agent distinguish the two 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names two concrete use cases ('what did I just store?' and 'catching up at the start of a session'), which is clear positive guidance. It stops short of explicitly naming memory_search as the alternative for relevance-based retrieval or stating when-not to use it, so it falls just below the top tier.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_reinforceA
Strengthen one memory after reading it via memory_get and finding
it genuinely useful — a deliberate "this mattered" signal that helps it
resist forgetting. Read first, then reinforce.
| Name | Required | Description | Default |
|---|---|---|---|
| entry_id | Yes | The id of the memory to strengthen. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already disclose that this is a non-read-only, non-idempotent, non-destructive operation, so the safety profile is covered. The description adds the useful effect ('resist forgetting') but does not address whether repeated calls compound strength (relevant given idempotentHint=false) or how invalid ids are handled.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One front-loaded sentence that leads with the action and its rationale. 'Read first, then reinforce' mildly restates the earlier 'after reading it via memory_get' clause, a small redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter mutation with an output schema, the description supplies the intent, the trigger, and the ordering. The remaining gap is idempotency/compounding behavior, which is a minor omission given the output schema carries the response.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single parameter is fully described in the schema, so the baseline is 3. The description adds only a light link between the id and the memory_get workflow, without new format or constraint details.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Strengthen') and resource ('one memory'), and clarifies the effect ('helps it resist forgetting'). It is clearly distinguishable from siblings like memory_forget, memory_supersede, and memory_reinstate, which imply opposite or different semantics.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit trigger — only after reading via memory_get and finding it 'genuinely useful' — and states the ordering constraint ('Read first, then reinforce'). It does not, however, name specific alternative siblings or state when reinforcement should be skipped in favor of them.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_reinstateADestructiveIdempotent
Reinstate one reviewed retired entry by durable ID. PostgreSQL only; requires a named principal and exact retirement preimage. Refuses trace-invalidated entries and never changes derived cortex. Retry an uncertain call with the same UUID and inputs.
| Name | Required | Description | Default |
|---|---|---|---|
| reason | Yes | Non-empty reason recorded in the audit. | |
| entry_id | Yes | Positive durable entry ID from this bank. | |
| operation_id | Yes | New canonical UUID; reuse it unchanged after an uncertain response. | |
| reviewer_ids | Yes | Non-empty reviewer identifiers recorded in the audit. | |
| expected_text_sha256 | Yes | Lowercase SHA-256 of the reviewed entry text. | |
| evidence_packet_sha256 | Yes | Lowercase SHA-256 binding the private review packet. | |
| expected_source_sha256 | Yes | Lowercase SHA-256 of the reviewed source tag. | |
| expected_superseded_at | Yes | Exact reviewed superseded_at database value. | |
| expected_superseded_by_text_sha256 | Yes | Lowercase SHA-256 of the reviewed replacement text. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds substantial context beyond the annotations: backend constraint ('PostgreSQL only'), an auth requirement ('requires a named principal'), a precondition ('exact retirement preimage'), and explicit refusal/scope behavior ('Refuses trace-invalidated entries and never changes derived cortex'). These go well beyond the destructive/idempotent hints the annotations already carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four dense sentences with the core verb+resource front-loaded and each clause carrying distinct information (backend, auth, precondition, refusal behavior, retry). No filler, though it is slightly more compact-packing than a maximal 5 might demand.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 9-parameter mutation tool with an output schema, the description covers auth needs, preconditions, refusal cases, mutation scope, and retry semantics; return values are appropriately left to the output schema. A minor gap is that the resulting state transition after reinstatement is only implied.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 9 parameters in detail. The description adds only indirect context ('by durable ID', 'same UUID', 'exact retirement preimage'), which reinforces but does not extend what the schema provides. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource — 'Reinstate one reviewed retired entry by durable ID' — which distinguishes it from the opposite operation (memory_supersede) and from memory_reinforce/memory_forget. It does not explicitly name the sibling it differs from, 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the domain (reinstating a reviewed retired entry) and by the retry clause 'Retry an uncertain call with the same UUID and inputs.' However, there is no explicit when-not or named alternative, so guidance is only at the implied level.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_relation_defineADestructive
Add a relation to the closed graph vocabulary — a deliberate, rare act. Prefer the builtins; define one only when a recurring connection genuinely fits none of them.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | The new relation name, hyphenated like the builtins. | |
| dst_type | No | Soft entity-kind expectation for the object; a mismatch warns, never rejects. | |
| src_type | No | Soft entity-kind expectation for the subject; a mismatch warns, never rejects. | |
| inverse_of | No | Pair with an existing relation, as ``runs-on`` is the inverse of ``hosts``. | |
| transitive | No | True closes the relation transitively, so chained edges arrive pre-derived. | |
| description | Yes | What the relation means, for later readers. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true, idempotentHint=false, and readOnlyHint=false, so the safety profile is covered. The description adds that this is a 'deliberate, rare act' on a 'closed' vocabulary, implying weight and permanence, but it doesn't state reversibility, auth requirements, or the effect on existing edges. Adequate context beyond annotations, but not rich.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences that front-load the action and scope, then the caveat. No filler; every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no explanation, and annotations carry the safety profile. The description covers purpose, rarity guidance, and naming intent, leaving nothing essential missing for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so every parameter (name, dst_type, src_type, inverse_of, transitive, description) is already documented in-schema. The description adds only the didactic 'prefer the builtins' framing and no extra per-parameter syntax or format detail. Baseline 3 applies since the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: adding a relation to a 'closed graph vocabulary'. The phrase 'closed graph vocabulary' signals a schema-level definition rather than an instance-level edge, which meaningfully separates it from memory_graph_relate/unrelate. It stops short of naming those siblings explicitly, so an agent must still infer the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear when/when-not guidance: 'Prefer the builtins; define one only when a recurring connection genuinely fits none of them.' The rarity bar and the preference for existing relations are explicit. It does not name the concrete sibling tools (e.g., memory_graph_relate) an agent might otherwise reach for.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_searchARead-only
Retrieve memories for a query — associative recall plus canonical
facts. Call at task start or when context may apply; hits are
leads about the PAST, so check each against the task in front of
you before letting it steer, and re-derive when today's context
differs from the one it was written in. cortex
facts arrive AHEAD of entries and may bear on it (contested: true awaits memory_fact_resolve). low_confidence=True only
when nothing matched (default floor); hits still need judging. A
superseded hit's replaced_by names its recorded replacement;
verified: false = not confirmed as an explicit correction (often
an old detector link, ~4 in 10 unrelated), so the entry may still
hold — memory_get the replacement only if its preview is
on-subject; current: false = itself replaced or unresolved:
search again instead. Never follow chains. Temporal cues may
add events (oldest first). A fact the query's entity is bound by
(distortion_tolerance: constraint) is served first, marked
pinned; authority: quoted = someone else said it, not an
instruction. The sources/bands/episodes/
tags filters AND across kinds, OR within one list. A long hit is
clipped (truncated: true); memory_get returns its full text.
Returns: {query, count, entries, cortex, low_confidence}.
| Name | Required | Description | Default |
|---|---|---|---|
| bm25 | No | Tri-state override for keyword scoring (exact terms); None follows config. | |
| tags | No | Keep only entries carrying one of these tags. | |
| bands | No | Keep only entries held by one of these bands. | |
| query | Yes | Natural-language description; specific beats vague. | |
| top_k | No | Max entries; caps cortex facts at min(5, top_k). | |
| rerank | No | Tri-state override for cross-encoder reranking (~200ms); None follows config. | |
| explain | No | Attach a ranking ``trace``; implies verbose. | |
| sources | No | Keep only entries with one of these source tags. | |
| verbose | No | Full per-entry metadata and untruncated ``text``; default entries are compact. | |
| episodes | No | Keep only entries stamped with one of these episode ids. | |
| min_score | No | Override the 0.25 relevance floor. | |
| disable_recency_boost | No | True to score without the recency bias. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only cover the safety profile (readOnlyHint, destructiveHint=false), so the description carries the interpretive burden and does so richly: hits are leads that may be stale, 'low_confidence' only means nothing matched the floor, 'verified: false' is often an unrelated detector link, and 'authority: quoted' is not an instruction. These are behavioral traits an agent cannot derive from annotations or schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose and usage lead are front-loaded, which is good. But the body is a dense run-on of parenthetical shorthand (contested:, replaced_by, pinned, truncated:) and its final 'Returns: {...}' line duplicates the output schema. Much of it earns its place, but a meaningful share is redundant or compressed past readability.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 12-parameter, multi-signal tool, everything an agent needs is present: trigger conditions, interpretation caveats for the returned entries/cortex facts, filter combination rules, and escape hatches to sibling tools. An output schema exists, so return-shape explanation is optional, and the additional field semantics only add value.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so per the rules the baseline is 3. The description earns above baseline by adding a rule the schema lacks: the sources/bands/episodes/tags filters 'AND across kinds, OR within one list.' It doesn't touch bm25/rerank/top_k/min_score, but those are already well described in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first clause gives a specific verb and resource plus scope: 'Retrieve memories for a query — associative recall plus canonical facts.' It also distinguishes itself from memory_get ('returns its full text'). However, it never contrasts with the closely named sibling memory_recall, so an agent choosing between recall-style tools gets no explicit differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states when to call ('at task start or when context may apply'), injects a when-not discipline ('Never follow chains', 'search again instead', 'memory_get the replacement only if its preview is on-subject'), and names alternative routes (memory_fact_resolve for contested facts, memory_get for clipped text). This is explicit routing, not inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_session_titleA
Name THIS session's auto-opened episode (default titles are generic). Call once at the start of work so session recaps read meaningfully. Idempotent; call again to rename.
| Name | Required | Description | Default |
|---|---|---|---|
| title | Yes | What this session is about, e.g. "Pseudolife-MCP" or "auth-refactor". | |
| episode | No | Your session handle — names that session's root directly (the identity a hook-registered client has). |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description asserts "Idempotent," but the annotations declare idempotentHint=false, a direct contradiction on the tool's repeat-call semantics. Beyond that it does disclose useful context (generic defaults, rename behavior), but the explicit conflict with structured metadata is disqualifying.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the action and the reason to call it, with zero filler. The trailing "Idempotent; call again to rename" is compact but is also the clause that introduces the annotation conflict.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need not be described, and the description covers when to call and what gets named. It is complete enough for an agent to invoke correctly, aside from the idempotency inconsistency.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and both parameters (title, episode) are fully documented in the schema with examples and defaults. The description adds no parameter-level detail beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb ("Name") and a precise target ("THIS session's auto-opened episode"), and explicitly frames the value proposition ("default titles are generic"). An agent can distinguish it from siblings like memory_episode_start or memory_episode_summary without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear timing guidance ("Call once at the start of work so session recaps read meaningfully") and the rename case ("call again to rename"). It does not name an explicit alternative tool or exclusion, 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.
memory_set_addA
Add/confirm a member of a set-valued slot (many concurrent values, not one NOW value). A scalar there converts to a set on first call — one-way — except number-led scalars ("32", "$1,500"), which are protected: the add parks as a contender (action="contested", settle via memory_fact_resolve). Read with memory_fact_get.
Returns: {action, entity, attribute, member, members_count}.
| Name | Required | Description | Default |
|---|---|---|---|
| entity | Yes | The slot's subject. | |
| member | Yes | The member to add or re-confirm. | |
| attribute | Yes | The slot's attribute. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the safety profile (readOnly=false, destructive=false, idempotent=false, openWorld=false). The description goes well beyond them by disclosing the one-way scalar-to-set conversion, the special protection for number-led scalars, and the contested/contender outcome — non-obvious side effects an agent cannot infer from the schema. It stops short of describing rate limits or failure modes.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core purpose, then the scalar-conversion edge case, then the routing hints and return shape. It is dense and jargon-heavy ("parks as a contender"), but every clause carries behavioral information that is not available elsewhere, so little is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so the trailing returns line is largely redundant, but the description covers the operation's key nuance (set semantics, one-way conversion, contested outcome) for a genuinely non-trivial memory tool. It could be more complete about the relationship to memory_set_remove or when to prefer the scalar slot tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 the slot is set-valued (contextualizing entity/attribute) and that a member can be re-confirmed rather than only inserted. The schema itself only offers terse labels ("The slot's subject"), so this framing is genuinely additive.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (add/confirm a member of a set-valued slot) and immediately disambiguates it from scalar single-value semantics ("many concurrent values, not one NOW value"). It also names the sibling read tool (memory_fact_get) and the resolution tool (memory_fact_resolve), so an agent can place it in the family without opening other schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Clearly signals when this tool applies: set-valued slots with many concurrent members. It routes contested adds to memory_fact_resolve and reads to memory_fact_get. It does not explicitly say when NOT to use it (e.g., the scalar alternative memory_fact_set), which keeps it short of a full 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_set_removeADestructive
Retract one current set member (audit row kept). Read with memory_fact_get.
Returns: {action, entity, attribute, member, members_count}.
| Name | Required | Description | Default |
|---|---|---|---|
| entity | Yes | The slot's subject. | |
| member | Yes | The current member to retract. | |
| attribute | Yes | The slot's attribute. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and readOnlyHint=false, so safety is covered. The description adds real context beyond them: '(audit row kept)' discloses soft-delete/retention semantics, telling the agent the retraction is recoverable and auditable. It does not address idempotency (idempotentHint=false) or what happens on a repeated call.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Very short and front-loaded: the operation and its audit behavior come first. The 'Returns: {...}' line is largely redundant since an output schema exists, which is the only wasted space.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 3-required-param mutation with annotations and an output schema, the definition covers purpose, retention semantics, and the read path. Gaps are minor: no idempotency note and no statement of what happens when the member is not currently present.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so entity/attribute/member are already documented. The phrase 'current set member' adds a mild constraint that the member must be currently present, but no format or error semantics beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource: 'Retract one current set member'. The word 'Retract' contrasts implicitly with the sibling memory_set_add, and 'one' bounds the operation. It stops short of naming the add/supersede alternatives outright, so the sibling contrast must be inferred.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The only routing guidance is 'Read with memory_fact_get', which points at the read path but does not say when to retract vs. using memory_supersede, memory_forget, or memory_fact_resolve. Usage is implied by the verb rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_statsARead-only
Memory-bank vital signs: store occupancy vs capacity, hit rates, true-drop count, and totals. Use to gauge how much has been remembered or to diagnose why retrieval feels off.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, covering the safety profile for this read-only tool. The description adds only a list of reported metrics, which the output schema already provides, and gives no additional behavioral context such as auth needs, rate limits, or side effects.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences: the first front-loads the resource and its metrics, the second gives the use case. No wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter read-only stats tool with an output schema and comprehensive annotations, the description covers purpose and usage adequately. It could be slightly richer about what the metrics mean or when to prefer other introspection tools, but nothing critical is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Zero parameters, so the baseline is 4. The description adds no parameter information, but none is needed because the schema is empty.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific resource ('Memory-bank vital signs') and enumerates the exact metrics returned (store occupancy vs capacity, hit rates, true-drop count, totals), so an agent knows what the tool does. However, it does not name a sibling or use a clear verb like 'get', so it is clear but not maximally differentiated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit when-to-use guidance: 'Use to gauge how much has been remembered or to diagnose why retrieval feels off.' It does not mention when not to use it or name alternative introspection tools (e.g., memory_agents, memory_toolset), so it gives clear context without exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_storeADestructive
Store one durable fact, decision, or observation. Use proactively
for anything worth keeping — one claim per call, and decide which
kind it is: PERSIST what stays true and will be wanted back; leave
task-scoped detail in CONTEXT ONLY; RE-VERIFY a fast-changing value
at its source, parking it with memory_fact_set(..., freshness_class="volatile") rather than persisting a stale one;
ASK when the claim is ambiguous instead of
persisting the guess. Near-duplicates are
dropped, not erred (stored=False,
reason="below_surprise_threshold"). For canonical NOW use
memory_fact_set.
Returns: {stored, surprise, reason, cortex_promoted}.
| Name | Required | Description | Default |
|---|---|---|---|
| tags | No | Optional labels, e.g. ["decision", "blocker"]. | |
| text | Yes | The claim to remember. | |
| origin | No | Who asserted the claim. | |
| source | No | Stable per-project/topic tag for later filtering. | agent |
| episode | No | Episode handle for attribution. | |
| authority | No | Speech act: "directive" (an instruction to you) / "quoted" (a doc or third party said it) / "observation"; "auto" infers. | auto |
| distortion_tolerance | No | "constraint" = must survive verbatim, pinned in recall; "auto" infers only that. | auto |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare destructiveHint=true and idempotentHint=false, and the description reinforces this by disclosing that near-duplicates are dropped rather than erred, with stored=False and reason='below_surprise_threshold'. It adds real behavioral context beyond the annotations, though it doesn't spell out what a store overwrites or any permission/rate constraints.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core purpose in the first sentence and then gives a compact decision procedure. It is dense but every clause carries guidance; the parenthetical return-key detail is slightly redundant given the output schema, which keeps it just short of a 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description need not explain return values, and it still summarizes them. For a seven-parameter mutation tool, it covers purpose, routing, dedup behavior, and the volatile-value caveat adequately, though it omits any note on overwrite/permission semantics.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema documents all seven parameters, and the description does not map its PERSIST/RE-VERIFY guidance onto the authority or distortion_tolerance enums. It even references a freshness_class parameter that lives on memory_fact_set, not this schema, so it adds little beyond the structured fields. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Store) and resource (one durable fact, decision, or observation) and immediately distinguishes itself from memory_fact_set, which is named as the destination for canonical NOW. An agent can tell what this tool is for and how it differs from the closest sibling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use guidance (proactively, one claim per call) and a decision procedure: persist durable claims, leave task-scoped detail in context only, re-verify volatile values, ask when ambiguous. It also names the alternative (memory_fact_set) and the condition that selects it, leaving little to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_supersedeADestructive
Mark a stored memory obsolete and record its replacement. The old entry is kept but flagged superseded, so retrieval ranks the correction higher and shows both together.
Use exactly one selector. Missing, retired, or ambiguous targets cause no mutation; search again and resubmit an ID. No similarity fallback.
Returns: {superseded_count, superseded_texts, superseded_ids, new_memory_stored, derived_flagged} — the last being the canonical facts the dream built
on the memories just corrected. They are FLAGGED, never rewritten;
check each and re-assert the ones that moved. Each row carries
has_current_value: false means the slot holds no current fact any
more — blast radius worth seeing, but nothing to go re-check. The list
is capped, live slots first; derived_flagged_truncated /
derived_flagged_total say when a correction reached further than
the cap.
| Name | Required | Description | Default |
|---|---|---|---|
| entry_id | No | Positive search/recent ID in this bank; preferred selector. | |
| new_text | Yes | The replacement claim; stored fresh. | |
| old_text | No | Unique exact stored text; omit with entry_id. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations (destructiveHint/readOnlyHint/idempotentHint). It discloses that the old entry is retained-but-flagged, that failed selectors produce no mutation, that there is no similarity fallback, and how derived facts are FLAGGED (never rewritten) with truncation-cap semantics — all material behavior an agent needs before mutating.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads purpose and selector rules before the returns detail; every section is dense with operative content. The Returns block is long and partly overlaps the output schema, but its semantic interpretation (has_current_value, truncation flags) is not pure repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive mutation with an output schema and full annotation coverage, this is essentially complete: purpose, selector rules, failure behavior, and return semantics are all covered. Minor redundancy with the output schema keeps it from a 5.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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: 'Use exactly one selector,' telling the agent entry_id and old_text are mutually exclusive alternatives and that entry_id is preferred. That constraint is not obvious from the schema alone.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Mark a stored memory obsolete and record its replacement') and immediately clarifies the distinguishing semantic: the old entry is kept but flagged, so retrieval ranks the correction higher. This separates it from deletion-style siblings like memory_forget without needing to name them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear operating guidance: 'Use exactly one selector,' failure modes (missing/retired/ambiguous targets cause no mutation), and the remediation ('search again and resubmit an ID'). It does not explicitly name which sibling to use instead of this tool (e.g. forget vs supersede vs reinstate), so it stops short of full alternative routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_toolsetA
Adjust YOUR visible toolset, one tier at a time (minimal → core →
full; scoped to your credential/writer identity, free, instant). Core
adds graph/recall, world facts, lessons, documents; full adds
supersede/forget/history, dream and graph-review admin. status
reports the ladder. Expand first: clients reject hidden-tool calls.
| Name | Required | Description | Default |
|---|---|---|---|
| action | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds behavioral context beyond the annotations: it specifies the tool is free and instant, scoped to credential/writer identity, and that expanding is required because 'clients reject hidden-tool calls.' It does not explicitly state what happens to visible tools when collapsing (e.g., whether they become hidden or inaccessible), which would be useful for a mutation tool. Annotations indicate non-read-only and non-destructive, which is consistent, but the description adds value without fully covering the consequences of collapse.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loaded: it starts with the core purpose, then lists tier contents, then adds critical usage guidance. Every sentence earns its place without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (managing visible toolset tiers) and the presence of an output schema (which likely reports status or tier changes), the description is largely complete for an agent to invoke correctly. It covers actions, tier contents, and the necessity to expand first. It could be improved by noting the exact effect of 'collapse' (e.g., whether tools are removed or just hidden) to fully inform the agent, but it is sufficient for most use cases.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has a single enum parameter 'action' with values expand/collapse/status, but the schema description coverage is 0%. The description explains the expand and collapse actions through the tier ladder and mentions that 'status' reports the ladder. However, it doesn't add syntax or format details beyond what's implied by the enum. With only one parameter and baseline 4 for zero params, but here there is 1 parameter with an enum and the description provides some meaning for each action, a 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action ('Adjust YOUR visible toolset, one tier at a time'), names the spectrum (minimal → core → full), and clearly delineates what each tier adds (core adds graph/recall, world facts, lessons, documents; full adds supersede/forget/history, dream and graph-review admin). This is a precise verb+resource statement that differentiates it from siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states when to use it ('Expand first: clients reject hidden-tool calls'), what the tiers are, and that it is 'scoped to your credential/writer identity, free, instant.' It provides clear operational guidance and a prerequisite (expand before calling hidden tools).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_world_searchARead-only
Search current WORLD facts (sourced external knowledge) by
similarity. Use when a task turns on an external fact your training
data may have stale. Entries carry effective_confidence
(age-decayed), a stale flag (re-verify before relying on it), and
their source_url / source_quote for citation.
Returns: {count, entries}.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Natural-language description of the external fact needed. | |
| top_k | No | Max entries returned. | |
| verbose | No | Full provenance metadata; default entries are compact. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/destructive/idempotent hints, so the bar is lower, and the description adds genuinely useful semantics: age-decayed effective_confidence, a stale flag with an explicit re-verify instruction, and source_url/source_quote for citation. It stops short of describing ranking or latency behavior, but the field-level disclosure is substantive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads purpose, then the trigger condition, then entry semantics, then the return shape. Every sentence carries distinct information with no restatement of the name or schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present and 100% parameter coverage, the description need not explain return format, so its job is mostly done. It covers trust signals (confidence, stale, citation) well; the only real omission is how it relates to memory_world_set for writes and other retrieval siblings.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 query, top_k, and verbose; baseline 3 applies. The description adds no parameter-level guidance (no hints on query phrasing, sensible top_k, or when verbose pays off), so it neither helps nor compensates here.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Search) and a scoped resource (current WORLD facts / sourced external knowledge) and explicitly distinguishes itself from generic memory recall by naming the domain. An agent can tell this apart from memory_search, memory_fact_get, or document_search without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a concrete activation condition: 'Use when a task turns on an external fact your training data may be stale.' That is a real when-to-use rule, but it names no alternative tools (e.g. document_search or memory_search) and gives no when-not boundary.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_world_setADestructive
Assert a canonical WORLD fact — sourced EXTERNAL knowledge (versions, prices, who-holds-a-role, research findings), kept separate from user/project facts. Route verified web/docs findings here, with the citation. A newer source supersedes an older value at the same slot.
Returns: {action: inserted|confirmed|superseded|rejected, ...record}.
| Name | Required | Description | Default |
|---|---|---|---|
| value | Yes | The externally-sourced value. | |
| entity | Yes | The slot's subject. | |
| attribute | Yes | The slot's attribute. | |
| confidence | No | Source confidence, 0..1. | |
| source_url | No | http(s) citation URL; any other scheme is rejected. | |
| content_hash | No | Hash of the fetched source, for change detection. | |
| retrieved_at | No | Epoch seconds the source was fetched. | |
| source_quote | No | The 1-2 sentences the claim was extracted from. | |
| freshness_class | No | Trust decay applied at read time: ``evergreen`` never decays, ``slow`` is months, ``volatile`` is weeks. | volatile |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true, readOnlyHint=false, idempotentHint=false and openWorldHint=false, so the safety profile is covered. The description adds genuine behavioral context beyond that: the supersession model ('A newer source supersedes an older value at the same slot'), telling the agent what happens to a prior value on a conflicting write.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core purpose and keeps the description compact. The 'Returns:' sentence is redundant because an output schema already exists, but the waste is minor and the overall structure is efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Output schema exists, so return values need not be explained, and all parameters are fully documented in the schema. The description still covers the domain distinction, the routing condition, and the supersession behavior, making it adequate for a 9-parameter mutation tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 9 parameters (including confidence semantics, URL scheme rejection, and freshness_class decay). The description adds only the vague phrase 'with the citation', which does not enrich parameter meaning beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Assert a canonical WORLD fact') and enumerates the domain (versions, prices, who-holds-a-role, research findings). It scopes itself apart from user/project facts, but does not name the sibling (e.g. memory_fact_set) that handles those, so differentiation is implicit rather than explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear positive trigger ('Route verified web/docs findings here, with the citation') and implies the complement by keeping world facts separate from user/project facts. However, it never names an alternative tool or states a when-not condition, leaving the routing rule partly to inference.
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.
11 tool updates
v0.16.0- Added
memory_agents - Changed
memory_consolidate7 fields changed- added
Input schema / properties / entry_idsAdded value: +{ + "anyOf": [ + { + "items": { + "type": "integer" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Positive IDs in this bank; prefer over replaces.", + "title": "Entry Ids" +} - added
Input schema / properties / replaces / anyOfAdded value: +[ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } +] - added
Input schema / properties / replaces / defaultAdded value: +null - changed
Input schema / properties / replaces / descriptionPrevious value: -"The memories being folded in; each is matched by exact text or close paraphrase."New value: +"Unique exact stored texts; omit with entry_ids." - removed
Input schema / properties / replaces / itemsRemoved value: -{ - "type": "string" -} - removed
Input schema / properties / replaces / typeRemoved value: -"array" - changed
Input schema / requiredPrevious value: -[ - "replaces", - "new_text" -]New value: +[ + "new_text" +]
- Changed
memory_dream2 fields changed- added
Input schema / properties / commit_tokenAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "commit: token returned by pull.", + "title": "Commit Token" +} - changed
Input schema / properties / cursor / descriptionPrevious value: -"commit: the newest pulled timestamp. Required for that action."New value: +"Deprecated; use commit_token."
- Changed
memory_fact_get1 field changed- added
Input schema / properties / verboseAdded value: +{ + "default": false, + "description": "Full record; the default drops bookkeeping keys.", + "title": "Verbose", + "type": "boolean" +}
- Changed
memory_forget6 fields changed- added
Input schema / properties / confirm_bulkAdded value: +{ + "default": false, + "description": "memory scope: allow over memory.delete_confirm_threshold (20) matches; else refused, reporting would_delete.", + "title": "Confirm Bulk", + "type": "boolean" +} - changed
Input schema / properties / episode / descriptionPrevious value: -"memory scope: delete entries stamped with this episode id."New value: +"memory scope: entries stamped with this episode id." - changed
Input schema / properties / source / descriptionPrevious value: -"memory scope: delete entries with this source tag."New value: +"memory scope: entries with this source tag." - changed
Input schema / properties / substring / descriptionPrevious value: -"memory scope: delete entries whose text contains this."New value: +"memory scope: entries whose text contains this." - changed
Input schema / properties / tag / descriptionPrevious value: -"memory scope: delete entries carrying this tag."New value: +"memory scope: entries carrying this tag." - changed
Input schema / properties / text / descriptionPrevious value: -"memory scope: delete entries whose text matches this exactly."New value: +"memory scope: entries with exactly this text."
- Changed
memory_graph_review6 fields changed- changed
Input schema / properties / dst / descriptionPrevious value: -"relate/dismiss_pair: the second entity. dismiss_slot_pair: an \"entity|attribute\" key from the deep response."New value: +"relate/dismiss_pair/dismiss_slot_pair: the second entity or key." - changed
Input schema / properties / proposal_id / descriptionPrevious value: -"Id actions: the one proposal to settle."New value: +"Id actions: the proposal to settle." - changed
Input schema / properties / proposal_ids / descriptionPrevious value: -"Id actions: settle many proposals in one call, instead of ``proposal_id``."New value: +"Id actions: many proposals at once." - changed
Input schema / properties / relation / descriptionPrevious value: -"relate: the edge relation to write, from the graph vocabulary."New value: +"relate: edge relation to write (graph vocabulary)." - changed
Input schema / properties / scope / descriptionPrevious value: -"list: keep only findings of this kind."New value: +"list: keep only analyzer findings whose entities carry this memory source (Atlas project); queued proposals always list; omit or \"all\" for everything. Not a finding kind." - changed
Input schema / properties / store / descriptionPrevious value: -"dismiss_slot_pair / restore_slot: which store the key belongs to — \"lesson\" or \"world\"."New value: +"dismiss_slot_pair/restore_slot: \"lesson\" or \"world\"."
- Added
memory_message - Changed
memory_outcome1 field changed- added
Input schema / properties / used_idsAdded value: +{ + "anyOf": [ + { + "items": { + "type": "integer" + }, + "type": "array" + }, + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Ids of the search hits you actually used, e.g. [1421, 903] — the relevance label only you can write. At most 50. Credits this session's searches from the last hour; log before that lapses.", + "title": "Used Ids" +}
- Added
memory_reinstate - Changed
memory_search3 fields changed- changed
Input schema / properties / bm25 / descriptionPrevious value: -"Tri-state override for keyword scoring, which aids exact-term queries; None follows config."New value: +"Tri-state override for keyword scoring (exact terms); None follows config." - changed
Input schema / properties / top_k / descriptionPrevious value: -"Max entries returned."New value: +"Max entries; caps cortex facts at min(5, top_k)." - changed
Input schema / properties / verbose / descriptionPrevious value: -"Full per-entry metadata; the default is compact ``{id, text, source, tags, score}`` plus supersession when set."New value: +"Full per-entry metadata and untruncated ``text``; default entries are compact."
- Changed
memory_supersede6 fields changed- added
Input schema / properties / entry_idAdded value: +{ + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Positive search/recent ID in this bank; preferred selector.", + "title": "Entry Id" +} - added
Input schema / properties / old_text / anyOfAdded value: +[ + { + "type": "string" + }, + { + "type": "null" + } +] - added
Input schema / properties / old_text / defaultAdded value: +null - changed
Input schema / properties / old_text / descriptionPrevious value: -"The memory now obsolete. Matched exact-text first, then by nearest embedding — a close paraphrase works."New value: +"Unique exact stored text; omit with entry_id." - removed
Input schema / properties / old_text / typeRemoved value: -"string" - changed
Input schema / requiredPrevious value: -[ - "old_text", - "new_text" -]New value: +[ + "new_text" +]
33 tool updates
v0.15.0- Changed
document_ingest2 fields changed- added
Input schema / properties / path / descriptionAdded value: +"Path to a .txt / .md / .pdf file, resolved on the SERVER's filesystem — with the Docker daemon, a path visible inside the container (e.g. a mounted volume), not a host path." - added
Input schema / properties / source / descriptionAdded value: +"Source tag for the chunks; defaults to the filename."
- Changed
document_search2 fields changed- added
Input schema / properties / query / descriptionAdded value: +"Natural-language description of the passage wanted." - added
Input schema / properties / top_k / descriptionAdded value: +"Max chunks returned."
- Changed
memory_alias2 fields changed- added
Input schema / properties / alias / descriptionAdded value: +"The alternative name." - added
Input schema / properties / entity / descriptionAdded value: +"The canonical entity to bind onto."
- Changed
memory_consolidate4 fields changed- added
Input schema / properties / new_text / descriptionAdded value: +"The canonical note that replaces them." - added
Input schema / properties / replaces / descriptionAdded value: +"The memories being folded in; each is matched by exact text or close paraphrase." - added
Input schema / properties / source / descriptionAdded value: +"Source tag for the new note." - added
Input schema / properties / tags / descriptionAdded value: +"Labels for the new note."
- Changed
memory_consolidation_candidates8 fields changed- added
Input schema / properties / episode / descriptionAdded value: +"Session-driven anchor: cluster within this episode id." - added
Input schema / properties / max_clusters / descriptionAdded value: +"Max clusters returned." - added
Input schema / properties / min_cluster_size / descriptionAdded value: +"Drop clusters with fewer members than this." - added
Input schema / properties / min_cohesion / descriptionAdded value: +"Minimum intra-cluster cosine — raise it to flag only near-duplicates." - added
Input schema / properties / query / descriptionAdded value: +"Topic-driven anchor: cluster memories near this description." - added
Input schema / properties / sources / descriptionAdded value: +"Consider only entries with one of these source tags." - added
Input schema / properties / tags / descriptionAdded value: +"Consider only entries carrying one of these tags." - added
Input schema / properties / top_k / descriptionAdded value: +"How many candidate entries to cluster over."
- Changed
memory_dream5 fields changed- added
Input schema / properties / apply / descriptionAdded value: +"deep: True writes the consolidation (graph tables are snapshotted first); the default is a dry run." - added
Input schema / properties / cursor / descriptionAdded value: +"commit: the newest pulled timestamp. Required for that action." - added
Input schema / properties / limit / descriptionAdded value: +"pull/run: how many memories to process (pull defaults to 40). runs: how many passes to list (defaults to 10)." - added
Input schema / properties / run_id / descriptionAdded value: +"rollback: which pass to revert; defaults to the newest committed pass." - added
Input schema / properties / snippets / descriptionAdded value: +"deep: False omits the evidence snippets."
- Changed
memory_episode_end1 field changed- added
Input schema / properties / episodeAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Your session handle — pops only within your own session's subtree; the session root is never closed.", + "title": "Episode" +}
- Changed
memory_episode_start3 fields changed- added
Input schema / properties / episodeAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Your session handle (from the session-start briefing) — anchors the sub-episode to YOUR session when several run concurrently.", + "title": "Episode" +} - added
Input schema / properties / hint / descriptionAdded value: +"Optional note on what the task is about." - added
Input schema / properties / title / descriptionAdded value: +"Short name for the task, used in later recaps."
- Changed
memory_episode_summary1 field changed- added
Input schema / properties / id / descriptionAdded value: +"An episode id, as it appears on search/recent results."
- Changed
memory_fact_get2 fields changed- added
Input schema / properties / attribute / descriptionAdded value: +"The slot's attribute." - added
Input schema / properties / entity / descriptionAdded value: +"The slot's subject; the (entity, attribute) match is case- and separator-insensitive."
- Changed
memory_fact_resolve3 fields changed- added
Input schema / properties / accept / descriptionAdded value: +"True adopts the parked contender as the new current value (the old value is kept as history); False discards the contender and keeps the current value." - added
Input schema / properties / attribute / descriptionAdded value: +"The contested slot's attribute." - added
Input schema / properties / entity / descriptionAdded value: +"The contested slot's subject."
- Changed
memory_fact_set9 fields changed- added
Input schema / properties / attribute / descriptionAdded value: +"The slot's attribute." - added
Input schema / properties / authorityAdded value: +{ + "default": "auto", + "description": "Speech act of the source: \"directive\" / \"quoted\" (doc or third party) / \"observation\"; \"auto\" infers.", + "enum": [ + "auto", + "directive", + "observation", + "quoted" + ], + "title": "Authority", + "type": "string" +} - added
Input schema / properties / confidence / descriptionAdded value: +"How sure you are, 0..1." - added
Input schema / properties / distortion_toleranceAdded value: +{ + "default": "auto", + "description": "\"constraint\" = verbatim, pinned in recall; \"auto\" infers only that.", + "enum": [ + "auto", + "constraint", + "procedural", + "belief", + "preference", + "episodic" + ], + "title": "Distortion Tolerance", + "type": "string" +} - added
Input schema / properties / entity / descriptionAdded value: +"The slot's subject; the (entity, attribute) match is case- and separator-insensitive." - added
Input schema / properties / episode / descriptionAdded value: +"Episode handle for attribution." - added
Input schema / properties / freshness_class / descriptionAdded value: +"How fast the value rots. \"auto\" infers the decay rate from the entity kind." - added
Input schema / properties / origin / descriptionAdded value: +"Who asserted it: \"user\" = the human told you; otherwise \"action\"/\"agent\". Omitted records \"agent\"." - added
Input schema / properties / value / descriptionAdded value: +"The value that is canonical NOW."
- Changed
memory_forget8 fields changed- added
Input schema / properties / attribute / descriptionAdded value: +"fact/world scope: one slot's attribute; omit to purge the whole entity. lesson scope: the aspect." - added
Input schema / properties / entity / descriptionAdded value: +"fact/world scope: the slot's subject. lesson scope: the task." - added
Input schema / properties / episode / descriptionAdded value: +"memory scope: delete entries stamped with this episode id." - added
Input schema / properties / scope / descriptionAdded value: +"Which store to delete from." - added
Input schema / properties / source / descriptionAdded value: +"memory scope: delete entries with this source tag." - added
Input schema / properties / substring / descriptionAdded value: +"memory scope: delete entries whose text contains this." - added
Input schema / properties / tag / descriptionAdded value: +"memory scope: delete entries carrying this tag." - added
Input schema / properties / text / descriptionAdded value: +"memory scope: delete entries whose text matches this exactly."
- Changed
memory_get1 field changed- added
Input schema / properties / entry_id / descriptionAdded value: +"A memory id, as returned by search results or by a fact's ``source_entries``."
- Changed
memory_graph5 fields changed- added
Input schema / properties / depth / descriptionAdded value: +"Hops from the root. Max 3." - added
Input schema / properties / entity / descriptionAdded value: +"The root entity to read out from." - added
Input schema / properties / include_facts / descriptionAdded value: +"False omits each node's canonical facts." - added
Input schema / properties / relation_filter / descriptionAdded value: +"Keep only edges whose relation contains this substring." - added
Input schema / properties / to / descriptionAdded value: +"Also return the shortest path from ``entity`` to this entity under ``paths``; its nodes are folded into the neighborhood."
- Changed
memory_graph_relate7 fields changed- added
Input schema / properties / confidence / descriptionAdded value: +"How sure you are, 0..1." - added
Input schema / properties / dst / descriptionAdded value: +"The object entity." - added
Input schema / properties / dst_type / descriptionAdded value: +"Entity kind for ``dst``: set when the node is created, or filled in on an existing node that has none." - added
Input schema / properties / origin / descriptionAdded value: +"Who asserted the edge." - added
Input schema / properties / relation / descriptionAdded value: +"From the closed registry: ``depends-on``, ``part-of``, ``runs-on``, ``hosts``, ``uses``, ``configures``, ``stores-data-in``, ``related-to``. Separator variants normalise; an unknown name is rejected WITH the closest matches." - added
Input schema / properties / src / descriptionAdded value: +"The subject entity." - added
Input schema / properties / src_type / descriptionAdded value: +"Entity kind for ``src``: set when the node is created, or filled in on an existing node that has none."
- Changed
memory_graph_review9 fields changed- changed
Input schema / properties / action / enumPrevious value: -[ - "list", - "propose", - "relate", - "dismiss_pair", - "dismiss_slot_pair", - "accept_link", - "reject_link", - "accept_merge", - "accept_junk", - "reject_entity" -]New value: +[ + "list", + "propose", + "relate", + "dismiss_pair", + "dismiss_slot_pair", + "restore_slot", + "accept_link", + "reject_link", + "accept_merge", + "accept_junk", + "reject_entity" +] - added
Input schema / properties / dst / descriptionAdded value: +"relate/dismiss_pair: the second entity. dismiss_slot_pair: an \"entity|attribute\" key from the deep response." - added
Input schema / properties / proposal_id / descriptionAdded value: +"Id actions: the one proposal to settle." - added
Input schema / properties / proposal_ids / descriptionAdded value: +"Id actions: settle many proposals in one call, instead of ``proposal_id``." - added
Input schema / properties / proposals / descriptionAdded value: +"propose: ``[{src, relation, dst, similarity?, rationale?}]``." - added
Input schema / properties / relation / descriptionAdded value: +"relate: the edge relation to write, from the graph vocabulary." - added
Input schema / properties / scope / descriptionAdded value: +"list: keep only findings of this kind." - added
Input schema / properties / src / descriptionAdded value: +"relate/dismiss_pair: the first entity. dismiss_slot_pair: an \"entity|attribute\" key from the deep response; restore_slot: retired key or entity." - added
Input schema / properties / store / descriptionAdded value: +"dismiss_slot_pair / restore_slot: which store the key belongs to — \"lesson\" or \"world\"."
- Changed
memory_graph_unrelate3 fields changed- added
Input schema / properties / dst / descriptionAdded value: +"The edge's object entity." - added
Input schema / properties / relation / descriptionAdded value: +"The edge's relation." - added
Input schema / properties / src / descriptionAdded value: +"The edge's subject entity."
- Changed
memory_history3 fields changed- added
Input schema / properties / as_of / descriptionAdded value: +"Slot mode only: ISO-8601 or epoch seconds; returns only versions written by then." - added
Input schema / properties / attribute / descriptionAdded value: +"The fact slot to read; omit for chain mode." - added
Input schema / properties / entity / descriptionAdded value: +"The subject whose past to read."
- Changed
memory_lesson_search3 fields changed- added
Input schema / properties / query / descriptionAdded value: +"The task at hand, described the way it would have been logged." - added
Input schema / properties / top_k / descriptionAdded value: +"Max entries returned." - added
Input schema / properties / verbose / descriptionAdded value: +"Full provenance metadata; default entries are compact."
- Changed
memory_outcome6 fields changed- added
Input schema / properties / about / descriptionAdded value: +"The tool or approach concerned; aids traversal." - added
Input schema / properties / detail / descriptionAdded value: +"What worked, or what the dead-end was." - added
Input schema / properties / episode / descriptionAdded value: +"Episode handle for attribution." - added
Input schema / properties / outcome / descriptionAdded value: +"What happened." - added
Input schema / properties / polarity / descriptionAdded value: +"\"+\" do-this or \"-\" avoid; usually omit — it is inferred from the outcome." - added
Input schema / properties / task / descriptionAdded value: +"Kind of task, in stable wording (\"deploy engine to host\") so signals for the same work group."
- Changed
memory_recall4 fields changed- added
Input schema / properties / hops / descriptionAdded value: +"Max graph hops. Clamped to 1..5." - added
Input schema / properties / query / descriptionAdded value: +"Natural-language relational question; its top hits seed the graph walk." - added
Input schema / properties / top_k / descriptionAdded value: +"Bounds only the SEED search (the initial hits that name the walk's start entities), not the result, which is capped separately; up to 3 ``texts`` slots go to seed hits." - added
Input schema / properties / verbose / descriptionAdded value: +"Full fact/edge provenance and untruncated texts. Default facts are ``{attribute, value}``, edges ``{src, relation, dst}``, texts truncated to a preview."
- Changed
memory_recent5 fields changed- added
Input schema / properties / episodes / descriptionAdded value: +"Keep only entries stamped with one of these episode ids." - added
Input schema / properties / n / descriptionAdded value: +"How many entries to return." - added
Input schema / properties / sources / descriptionAdded value: +"Keep only entries with one of these source tags." - added
Input schema / properties / tags / descriptionAdded value: +"Keep only entries carrying one of these tags." - added
Input schema / properties / verbose / descriptionAdded value: +"Full per-entry metadata; default entries are compact."
- Changed
memory_reinforce1 field changed- added
Input schema / properties / entry_id / descriptionAdded value: +"The id of the memory to strengthen."
- Changed
memory_relation_define6 fields changed- added
Input schema / properties / description / descriptionAdded value: +"What the relation means, for later readers." - added
Input schema / properties / dst_type / descriptionAdded value: +"Soft entity-kind expectation for the object; a mismatch warns, never rejects." - added
Input schema / properties / inverse_of / descriptionAdded value: +"Pair with an existing relation, as ``runs-on`` is the inverse of ``hosts``." - added
Input schema / properties / name / descriptionAdded value: +"The new relation name, hyphenated like the builtins." - added
Input schema / properties / src_type / descriptionAdded value: +"Soft entity-kind expectation for the subject; a mismatch warns, never rejects." - added
Input schema / properties / transitive / descriptionAdded value: +"True closes the relation transitively, so chained edges arrive pre-derived."
- Changed
memory_search12 fields changed- added
Input schema / properties / bands / descriptionAdded value: +"Keep only entries held by one of these bands." - added
Input schema / properties / bm25 / descriptionAdded value: +"Tri-state override for keyword scoring, which aids exact-term queries; None follows config." - added
Input schema / properties / disable_recency_boost / descriptionAdded value: +"True to score without the recency bias." - added
Input schema / properties / episodes / descriptionAdded value: +"Keep only entries stamped with one of these episode ids." - added
Input schema / properties / explain / descriptionAdded value: +"Attach a ranking ``trace``; implies verbose." - added
Input schema / properties / min_score / descriptionAdded value: +"Override the 0.25 relevance floor." - added
Input schema / properties / query / descriptionAdded value: +"Natural-language description; specific beats vague." - added
Input schema / properties / rerank / descriptionAdded value: +"Tri-state override for cross-encoder reranking (~200ms); None follows config." - added
Input schema / properties / sources / descriptionAdded value: +"Keep only entries with one of these source tags." - added
Input schema / properties / tags / descriptionAdded value: +"Keep only entries carrying one of these tags." - added
Input schema / properties / top_k / descriptionAdded value: +"Max entries returned." - added
Input schema / properties / verbose / descriptionAdded value: +"Full per-entry metadata; the default is compact ``{id, text, source, tags, score}`` plus supersession when set."
- Changed
memory_session_title2 fields changed- added
Input schema / properties / episodeAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Your session handle — names that session's root directly (the identity a hook-registered client has).", + "title": "Episode" +} - added
Input schema / properties / title / descriptionAdded value: +"What this session is about, e.g. \"Pseudolife-MCP\" or \"auth-refactor\"."
- Changed
memory_set_add3 fields changed- added
Input schema / properties / attribute / descriptionAdded value: +"The slot's attribute." - added
Input schema / properties / entity / descriptionAdded value: +"The slot's subject." - added
Input schema / properties / member / descriptionAdded value: +"The member to add or re-confirm."
- Changed
memory_set_remove3 fields changed- added
Input schema / properties / attribute / descriptionAdded value: +"The slot's attribute." - added
Input schema / properties / entity / descriptionAdded value: +"The slot's subject." - added
Input schema / properties / member / descriptionAdded value: +"The current member to retract."
- Changed
memory_store7 fields changed- added
Input schema / properties / authorityAdded value: +{ + "default": "auto", + "description": "Speech act: \"directive\" (an instruction to you) / \"quoted\" (a doc or third party said it) / \"observation\"; \"auto\" infers.", + "enum": [ + "auto", + "directive", + "observation", + "quoted" + ], + "title": "Authority", + "type": "string" +} - added
Input schema / properties / distortion_toleranceAdded value: +{ + "default": "auto", + "description": "\"constraint\" = must survive verbatim, pinned in recall; \"auto\" infers only that.", + "enum": [ + "auto", + "constraint", + "procedural", + "belief", + "preference", + "episodic" + ], + "title": "Distortion Tolerance", + "type": "string" +} - added
Input schema / properties / episode / descriptionAdded value: +"Episode handle for attribution." - added
Input schema / properties / origin / descriptionAdded value: +"Who asserted the claim." - added
Input schema / properties / source / descriptionAdded value: +"Stable per-project/topic tag for later filtering." - added
Input schema / properties / tags / descriptionAdded value: +"Optional labels, e.g. [\"decision\", \"blocker\"]." - added
Input schema / properties / text / descriptionAdded value: +"The claim to remember."
- Changed
memory_supersede2 fields changed- added
Input schema / properties / new_text / descriptionAdded value: +"The replacement claim; stored fresh." - added
Input schema / properties / old_text / descriptionAdded value: +"The memory now obsolete. Matched exact-text first, then by nearest embedding — a close paraphrase works."
- Changed
memory_world_search3 fields changed- added
Input schema / properties / query / descriptionAdded value: +"Natural-language description of the external fact needed." - added
Input schema / properties / top_k / descriptionAdded value: +"Max entries returned." - added
Input schema / properties / verbose / descriptionAdded value: +"Full provenance metadata; default entries are compact."
- Changed
memory_world_set9 fields changed- added
Input schema / properties / attribute / descriptionAdded value: +"The slot's attribute." - added
Input schema / properties / confidence / descriptionAdded value: +"Source confidence, 0..1." - added
Input schema / properties / content_hash / descriptionAdded value: +"Hash of the fetched source, for change detection." - added
Input schema / properties / entity / descriptionAdded value: +"The slot's subject." - added
Input schema / properties / freshness_class / descriptionAdded value: +"Trust decay applied at read time: ``evergreen`` never decays, ``slow`` is months, ``volatile`` is weeks." - added
Input schema / properties / retrieved_at / descriptionAdded value: +"Epoch seconds the source was fetched." - added
Input schema / properties / source_quote / descriptionAdded value: +"The 1-2 sentences the claim was extracted from." - added
Input schema / properties / source_url / descriptionAdded value: +"http(s) citation URL; any other scheme is rejected." - added
Input schema / properties / value / descriptionAdded value: +"The externally-sourced value."
3 tool updates
v0.14.0- Changed
memory_dream2 fields changed- changed
Input schema / properties / action / enumPrevious value: -[ - "status", - "pull", - "commit", - "run", - "deep" -]New value: +[ + "status", + "pull", + "commit", + "run", + "deep", + "runs", + "rollback" +] - added
Input schema / properties / run_idAdded value: +{ + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Run Id" +}
- Changed
memory_graph_review3 fields changed- changed
Input schema / properties / action / enumPrevious value: -[ - "list", - "propose", - "dismiss_pair", - "dismiss_slot_pair", - "accept_link", - "reject_link", - "accept_merge", - "accept_junk", - "reject_entity" -]New value: +[ + "list", + "propose", + "relate", + "dismiss_pair", + "dismiss_slot_pair", + "accept_link", + "reject_link", + "accept_merge", + "accept_junk", + "reject_entity" +] - added
Input schema / properties / proposal_idsAdded value: +{ + "anyOf": [ + { + "items": { + "type": "integer" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Proposal Ids" +} - added
Input schema / properties / relationAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Relation" +}
- Changed
memory_history1 field changed- added
Input schema / properties / as_ofAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "As Of" +}
35 tool updates
v0.11.0- First observed
document_ingest - First observed
document_search - First observed
memory_alias - First observed
memory_consolidate - First observed
memory_consolidation_candidates - First observed
memory_dream - First observed
memory_episode_end - First observed
memory_episode_start - First observed
memory_episode_summary - First observed
memory_fact_get - First observed
memory_fact_resolve - First observed
memory_fact_set - First observed
memory_forget - First observed
memory_get - First observed
memory_graph - First observed
memory_graph_relate - First observed
memory_graph_review - First observed
memory_graph_unrelate - First observed
memory_history - First observed
memory_lesson_search - First observed
memory_outcome - First observed
memory_recall - First observed
memory_recent - First observed
memory_reinforce - First observed
memory_relation_define - First observed
memory_search - First observed
memory_session_title - First observed
memory_set_add - First observed
memory_set_remove - First observed
memory_stats - First observed
memory_store - First observed
memory_supersede - First observed
memory_toolset - First observed
memory_world_search - First observed
memory_world_set
TDQS
Scored across 38 tools
There is a dense cluster of overlapping retrieval tools (memory_search, memory_recall, memory_lesson_search, memory_world_search, memory_recent, document_search) and several write paths (memory_store, memory_fact_set, memory_set_add, memory_world_set, memory_supersede, memory_consolidate). The extremely detailed descriptions do a lot to separate them, but the boundaries are subtle enough that an agent could easily misselect.
Names are uniformly snake_case and grouped under coherent prefixes (memory_fact_*, memory_set_*, memory_graph_*, memory_episode_*, memory_world_*), which makes the surface navigable. Minor deviations exist: some are verb-led (memory_search) while others are bare nouns (memory_dream, memory_alias, memory_graph), and document_* breaks the memory_ prefix.
38 tools is heavy and well above the comfortable band, though the domain (memory, facts, sets, graph, world, lessons, documents, episodes, messaging, dreaming) is genuinely broad. The built-in memory_toolset tiering (minimal/core/full) mitigates this by letting agents hide unused tools, keeping it borderline rather than clearly excessive.
Coverage is close to exhaustive: store/search/get/supersede/forget/reinstate/reinforce for memories, full fact-slot and set lifecycle, world facts, lessons, graph relate/unrelate/alias, consolidation and dream/review workflows, episodes, and document ingestion. Lifecycle operations and administrative escape hatches are all present with no obvious dead ends.
Maintenance
Related MCP Connectors
Persistent cross-session memory shared by Codex, Claude Code, ChatGPT, and other AI agents.
Persistent memory for Claude Code and Cursor. Stop re-explaining your project every session.
Persistent memory for Claude Code, Cursor and Codex. Facts retire when they change.
Persistent AI memory shared across Claude, ChatGPT, coding agents, and compatible MCP clients.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceProvides long-term memory capabilities for Claude through persistent storage and full-text search of context across conversations. Enables storing, searching, and managing memories organized by categories like facts, preferences, projects, and goals.11 npm1MIT
- AlicenseNot gradedqualityDmaintenanceProvides persistent cross-session memory for Claude Code, enabling it to remember user preferences, decisions, and project context across new sessions.Apache 2.0
- AlicenseNot gradedqualityCmaintenancePersistent memory management for Claude Code, allowing agents to store and retrieve user preferences, environment notes, and skills across sessions.2 npm5MIT
- AlicenseAqualityDmaintenanceEnables persistent memory for Claude Code sessions by recording observations and building knowledge graphs for cross-session learning and domain knowledge management.11MIT