PseudoLife-MCP
OfficialThis MCP server provides persistent long-term memory, canonical facts, knowledge graph retrieval, consolidation, and agent coordination for coding agents.
Store, search, retrieve, reinforce, supersede, consolidate, forget, and reinstate memories, with stats and recent-entry views.
Maintain canonical facts per
(entity, attribute)slot: get/set/resolve contested facts, manage set-valued slots, and read version history or causal chains.Store and search cited world facts, record procedural outcomes, and recall learned lessons.
Build and query a typed knowledge graph with aliases, relations, neighborhood walks, multi-hop recall, and a review queue.
Manage session episodes: name sessions, start/end sub-episodes, and summarize episode contents.
Run, inspect, and roll back dream consolidation passes; perform deep graph consolidation.
Ingest documents and search a separate reference bank for document RAG.
Coordinate agent sessions: list/update peers, park sessions, claim/release leases or files, and send/receive/ack board mail.
Change the visible tool tier (
minimal,core,full) viamemory_toolset.
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: Claude Memory MCP Server
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 (with the compose v2 and buildx plugins) 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 a pairing code
from pseudolife-mcp invite, or a 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, Docker's compose v2 and buildx plugins included),
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).
Docker Engine also needs the buildx plugin, which Docker Desktop bundles:
the Dockerfiles' RUN --mount caches need BuildKit, and without buildx the
build dies with "the --mount option requires BuildKit". The preflight
fails without it and prints the install line for each distro (Arch: sudo pacman -S docker-buildx; Debian/Ubuntu with Docker's repository or Fedora:
docker-buildx-plugin).
In the Claude and Codex CLI shim extractor modes on Linux, ops/install.sh
also checks that the daemon's container reaches the shim on the host. A
host firewall such as ufw can drop that traffic, and dreams then pause
(or fall back to the sidecar) while the shim itself looks healthy; the
summary marks [!] Extractor shim, and a warning above it names the cause.
When ufw is enabled with a dropping input policy, it names the narrowest rule (sudo ufw allow from <the daemon's network> to <docker0 address> port <shim port> proto tcp), and --firewall-rule ask|yes|no (default ask) decides whether to add it: ask offers it once
at a terminal, defaulting to no, and probes again once the rule is added; an unattended run
changes no firewall unless given --firewall-rule yes, and prints the
command instead. ops/install.ps1 has no equivalent: the check and the
flag are Linux-only.
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
reference bank for document RAG, stored in the bank since schema v57. 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
(the CMS counters live in the bank too, in cms_counters since schema
v57; 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 (with the compose v2 and
buildx plugins, which Docker Desktop bundles); 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; on a client-only machine the same command installs a
daily job that moves its shim and plugin cache to the daemon's release. 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, ingested documents included since v57) |
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 | v58 (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 is signed out (or a hosted endpoint rejected its key): sign it in again on the machine running the CLI shim (stall.shim_remoteis true when that is not the daemon's machine) by runningclaude, then/login(orcodex login). 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 shim needs the MCP SDK v2 — an SDK older than v2 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.2,<2.3"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 destructiveHint=true, idempotentHint=false and readOnlyHint=false, so the safety profile is covered. The description adds the conceptual context of a separate cosine-similarity store, but it does not explain the notable implications of the annotations: what is 'destructive' about ingesting, and whether re-ingesting the same file duplicates chunks given idempotentHint=false. Useful but incomplete beyond the structured 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?
Two sentences, front-loaded with purpose and a compact clarifying phrase, then a short returns line. Efficient overall, though the Returns enumeration is largely redundant given that 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?
Purpose, storage context and return shape are covered, and an output schema exists so return values need not be spelled out. The one real gap is behavioral: for a non-idempotent, destructive-flagged ingestion tool the description never says whether repeated ingest of the same file duplicates or replaces chunks.
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 with its server-side filesystem caveat, and the source tag defaulting to filename) are already fully documented in the schema. The description adds no parameter-level detail, which is the expected baseline when the schema does the work.
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 (Index) and resource (a file into the reference bank) and immediately characterizes the destination as a distinct store for background documents, differentiating it from conversational memory and from the sibling document_search (which retrieves rather than ingests). An agent can tell what this does 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?
The contrast with 'conversational memory' clearly implies when to route here (background corpora like papers, manuals, codebases) versus the many memory_* siblings, and names example document types. It stops short of an explicit when-not or a named alternative tool, so it is strong context rather than full routing guidance.
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; positive integer. |
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 usefully adds the corpus boundary (only ingested documents, no memories), but adds nothing about ranking, empty results, or pagination behavior beyond 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 tight sentences, zero waste, with the scope constraint front-loaded ahead of the sibling redirect. 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?
With an output schema present, return values need not be explained, and the description covers scope and routing adequately. Minor omission of edge-case behavior (e.g. no-match handling) keeps it just short of a full 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% with a documented natural-language query and top_k default, so the schema carries the parameter meaning. The description adds no syntax or format detail beyond what the schema already provides, making the baseline 3 correct.
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 resource (the reference bank / ingested documents), and immediately scopes it against the sibling by clarifying it returns documents only, with no conversational memories. An agent can differentiate this from memory_search 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?
Gives an explicit when-to-use plus a named alternative and its triggering condition: docs alone -> this tool, docs AND memories together -> memory_search. Nothing 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_agentsA
Coordinate agent sessions on the shared board: list peers and leases, update your own status or park, claim/release shared resources. List before shared work and on resume. idle_omitted counts idle peers. Status and parks grant no approval; board writes need an authenticated adapter.
update: omitted fields stay. A status update with no park fields clears any park, and its result's warning says so. Park when you stop (park_reason, park_needs, park_clear_by, park_resume); done means no follow-up expected. Automatic wake needs a live listener; otherwise mail waits for your next turn.
claim/release: one selector - lease (coordinator: or claim:), or worktree+path (local shim), or repository_id+path (HTTP). Reclaim renews; a busy lease queues you. File claims are advisory, not edit locks; no globs or directories.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | update: the name the board shows for you, up to 120 chars; it overrides your harness's title. "" clears yours. | |
| path | No | claim/release: one file relative to worktree/repository_id, up to 4096 chars; no globs or directories. | |
| task | No | list/update: current task, up to 120 chars. | |
| lease | No | claim/release: coordinator:<project> or claim:<path>, up to 120 chars. Omit with file selectors. | |
| action | No | list (default), update, claim or release; pass only that action's fields. | list |
| expect | No | update/claim: expected duration in seconds, integer 1..604800; marks overdue, not a timer or lease TTL. | |
| status | No | update: progress; claim: lease purpose. Up to 240 chars. On update, clears any park unless park fields are given. | |
| project | No | list/update: project name, up to 120 chars; relevance only. | |
| children | No | update: at most 8 distinct nonempty labels, each up to 40 chars. [] clears manual labels; automatic children remain. | |
| worktree | No | claim/release, local shim only: absolute Git worktree path, up to 4096 chars; requires path, excludes lease/repository_id. | |
| park_needs | No | update: what would unblock you, up to 120 chars; senders use clears only when their message satisfies this need. | |
| park_reason | No | update: done, blocked, needs_approval, needs_info, needs_resource or waiting_peer. Empty string clears; null/omitted sends no reason. | |
| park_resume | No | update: what to do once cleared, up to 240 chars. | |
| park_expires | No | update: positive finite Unix epoch seconds, at most now + 7 days; new parks default to now + 12 hours, refinements keep expiry. | |
| park_clear_by | No | update: who may wake this park: exact agent ID, maintainer, anyone, or a supported lease name; up to 120 chars. | |
| repository_id | No | claim/release, HTTP: prepared 64-char lowercase SHA-256 repository ID; requires path, excludes lease/worktree. |
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: discloses that board writes require an authenticated adapter, that status/parks grant no approval, that file claims are advisory rather than edit locks, that automatic wake needs a live listener or mail waits a turn, and that reclaim renews while a busy lease queues you. It also spells out the non-obvious side effect that a status update without park fields clears any park and surfaces a warning.
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 groups guidance by action (list, update, claim/release), which matches how an agent will scan it. The telegraphic, fragment-heavy style compresses 16 parameters into little space, but a few clauses ("idle_omitted counts idle peers") are too terse to parse on first 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?
An output schema exists so return values need not be documented, and the description covers the high-risk gaps for a 4-action, 16-param tool: auth requirement, advisory nature of claims, wake/listener caveat, park defaults and expiry behavior. Only the list/update scoping of project/task relevance is left 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 coverage is 100%, so baseline is 3; the description still adds cross-parameter semantics the schema cannot express per-field — mutually exclusive selector forms (lease vs worktree+path vs repository_id+path), 'omitted fields stay' on update, and park-clearing behavior. cryptic fragment like "idle_omitted counts idle peers" is unexplained and adds little.
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 sentence names the resource (agent sessions on the shared board) and enumerates the four verbs (list, update, claim, release), so an agent can tell what it does without opening the schema. It never names a sibling, but no sibling in the list covers leases/board coordination, so ambiguity is low.
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?
"List before shared work and on resume" and "Park when you stop ... done means no follow-up expected" give concrete triggering conditions for two of the four actions. Claim/release selection is also guided by the one-selector rule. It lacks explicit when-not/alternative-tool routing, keeping it below a 5.
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 readOnlyHint=false, destructiveHint=true and idempotentHint=false, so the safety profile is covered. The description adds the useful consequence that lookups under either name resolve to the same node, but it never explains the destructive aspect the annotation flags (e.g. whether an alias already bound elsewhere is silently overwritten) or persistence behavior.
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, zero filler, with the core action and its rationale front-loaded and the return value disclosed last. 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 the return-value note is a bonus rather than a necessity, and the two parameters are fully documented in the schema. The only gap is conflict/overwrite semantics, which the destructiveHint annotation raises but the description does not address.
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's ``pg`` → ``postgres`` example adds real meaning by clarifying the direction of the alias/canonical relationship that the terse schema descriptions ("The alternative name", "The canonical entity to bind onto") leave slightly ambiguous.
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 concrete verb ("Bind") and resource ("an alternative name to an entity") and reinforces it with a concrete example (``pg`` → ``postgres``). It is clearly distinguishable from most siblings, though it never names the adjacent tools (memory_set_add, memory_graph_relate) that also create bindings.
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 through the example and the phrase "so facts and graph lookups under either name land on the same node." There is no explicit statement of when to prefer aliasing over other binding tools, nor any prerequisite or exclusion guidance.
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?
Annotations already declare destructiveHint=true and idempotentHint=false, but the description adds real value beyond them: pre-flight atomicity (all targets resolve or nothing mutates) and the fact that superseded entries are retained as history rather than deleted. It doesn't cover auth/permission needs, but the mutation semantics are well 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 purpose sentence, then compact operational rules, then the return shape. Every sentence carries distinct information and nothing is 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 destructive consolidation tool with full schema coverage, an output schema, and safety annotations, the description covers the remaining gaps: atomicity, selector exclusivity, history retention, and the return keys. 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 coverage is 100%, so the baseline is 3. The description adds meaning beyond the schema by stating that exactly one selector mode must be used and that there is no similarity fallback, which clarifies the replaces vs entry_ids relationship that the schema only hints at with 'prefer over replaces'.
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) plus the resulting artifact (one canonical note). It implicitly separates itself from single-entry tools like memory_supersede, but never names a sibling to draw the line explicitly.
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 guidance: use exactly one selector mode, no similarity fallback, all targets must resolve before mutation, and re-search/resubmit on missing/retired/ambiguous targets. Strong when/how context, but it does not name alternative tools (e.g., memory_supersede or memory_consolidation_candidates) or state when not to consolidate.
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; positive integer. | |
| 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; positive integer. | |
| 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; positive integer. |
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 genuine context beyond that — this is read-only discovery feeding a separate mutation, and the ID-not-text commit contract matters because IDs survive rewording. It also discloses the return shape. It stops short of noting limits on how many clusters or entries are scanned beyond the schema's defaults.
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 paragraphs, purpose front-loaded, then the workflow, then the commit contract and return shape. The prose is dense but every clause carries actionable information; nothing 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?
Covers purpose, anchor choice, the follow-up commit call, the ID-vs-text caveat, and the return shape, which is more than sufficient given an output schema already exists and annotations carry the safety profile.
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 eight parameters including the topic-driven vs session-driven anchor distinction. The description restates the query/episode anchoring but adds no syntax, format, or interaction detail beyond it, 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+resource ('find clusters of near-duplicate memories ripe for consolidation') and frames the scope precisely as a discovery step, clearly distinct from the sibling memory_consolidate which performs the write. An agent can separate the two tools 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?
Gives an explicit three-step workflow (anchor with query/episode, read clusters, synthesise, commit via memory_consolidate) and names the alternative tool for the write step. It also resolves the no-required-params ambiguity by telling the agent to supply an anchor.
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). Positive integer. | |
| 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 destructiveHint=true and non-idempotent already declared, the description still adds real substance: which action is read-only (status), that deep snapshots graph tables before writing, that rollback reverts facts and events while keeping traces/cursor, and that list results are capped with full counts in 'truncated'. It does not cover auth requirements or concurrency/rate behavior, so it stops short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Strong front-loading: the one-line purpose precedes a tidy action-indexed list, and each bullet earns its place by pairing an action with its workflow consequence. Minor deduction for the dense wrapping and for the action list omitting 'commit', which forces the reader to reconstruct it from the pull bullet and the commit_token parameter.
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 terse 'Returns: per-action dict; {error} on bad input' is sufficient. For a 7-parameter, destructive, multi-mode tool, the per-action map covers most what an agent needs, but the enumerated 'commit' action is never given its own entry, leaving one mode described only indirectly.
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 the schema already documents apply, limit, run_id, snippets, cursor and commit_token with per-action context. The description largely mirrors that (dry-run apply, pull default of 40), adding only marginal framing such as the pull-then-commit token flow. Baseline 3 is appropriate when the schema carries the load.
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 sentence gives a specific verb and resource ('consolidation of recent memories into canonical facts and graph structure'), and the per-action breakdown makes each mode legible. It falls short of a 5 only because it never distinguishes itself from close siblings such as memory_consolidate and memory_consolidation_candidates, which an agent must disambiguate on its own.
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?
Each action carries contextual guidance: 'status' is read-only backlog inspection, 'pull' is for unconsolidated memories with an explicit follow-up chain (memory_fact_set then commit), 'deep' is a dry run unless apply and routes candidates to memory_graph_review. What's missing is any when-not guidance or explicit comparison against the sibling consolidation tools.
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?
The annotations already declare readOnly=false, destructive=false, idempotent=false, and openWorld=false. The description adds stack-pop semantics and scope ('current open sub-episode', 'parent'), but it does not explain error behavior when no sub-episode is open or what happens to the closed episode's content.
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 that states the core action with no filler. Every word 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?
With an output schema, full parameter documentation, and annotations covering safety, the description only needs to convey the core operation, which it does. It would be stronger if it stated the prerequisite of an open sub-episode or the behavior when none exists.
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%: the single optional episode parameter is fully documented in the schema as the session handle. The main description adds no parameter 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-resource pair: closing the current open sub-episode and returning to its parent. It does not explicitly contrast with the sibling memory_episode_start, so it stops short of full sibling 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?
The description gives no explicit when-to-use or when-not-to-use guidance, nor does it name alternatives such as memory_episode_start. Usage is only implied by the phrase 'current open sub-episode.'
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 declare non-readonly, non-idempotent, non-destructive, but the description adds genuine behavioral context beyond them: the sub-episode nests under the session episode, memories written while open are tagged with its id and title, and end pops back to the parent. What it does not clarify is what repeated starts do or whether state persists across calls.
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 action and then the consequence and pair-tool. The only blemish is the awkward mid-sentence line wrapping in the source text; content-wise there is 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?
An output schema exists, so return values need not be described, and the description covers the lifecycle (start/end), the nesting model, and the memory-tagging effect. It is nearly complete for a state-mutating episode tool, missing only edge-case behavior on repeated starts or when a session handle is absent.
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 title, hint, and episode are already documented in the schema; the description only reinforces 'named' and the title's role in recaps/episode-scoped search. It adds no syntax or format detail beyond the schema, 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 ('Open') and resource ('named sub-episode') and immediately explains the nesting relationship and its effect on subsequently stored memories. It also names the paired sibling memory_episode_end, so an agent can distinguish it from the closing tool 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?
Usage is implied by the effect statement ('memories stored while it is open carry its id + title for episode-scoped search') and by naming memory_episode_end as the closer, but there is no explicit 'use this when / not when' guidance or discussion of alternatives for scoping memories.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_episode_summaryBRead-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, destructiveHint=false, and closed-world, so the safety profile is covered. The description adds one genuinely useful behavioral detail: it returns {found: false} for an unknown id. Beyond that edge case it adds nothing (no pagination or permission notes), so a 3 is fair.
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?
Extremely tight and front-loaded: the returned contents lead, followed by the intent paraphrase and the not-found case. Slightly awkward inline-code formatting, but no wasted sentences.
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 single-param read tool with a rich output schema, full schema coverage, and annotations, the definition is nearly self-sufficient; the {found: false} disclosure covers the main behavioral unknown. Nothing further is strictly required, though alternative routing remains undocumented.
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?
With one parameter and 100% schema description coverage (the id is described as 'as it appears on search/recent results'), the schema carries full weight. The description adds no syntax or format detail 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?
The description names the resource (one episode) and enumerates the outputs (stats, tag/source distribution, recent entries), so an agent can tell what it returns. However it lacks an explicit verb and doesn't distinguish itself from siblings like memory_stats or memory_get beyond the episode scoping. Clear but not sibling-differentiating.
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?
There is a natural-language trigger ("summarise what we worked on"), which hints at intent, but no explicit when-to-use, when-not-to-use, or named alternatives among the many siblings (memory_stats, memory_episode_end, memory_get). The agent must infer the routing.
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;
open questions go to memory_search. A null record means EMPTY, not
unknown. 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 (core)); 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 (full) 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 declare readOnlyHint=true and destructiveHint=false, and the description goes well beyond them: null means EMPTY not unknown, contenders signals an unsettled conflict, re_verify warns the value may be stale, and it discloses a backend difference (PostgreSQL keeps the warning after eviction, file mode has no durable retraction). This is unusually rich behavioral disclosure for a read 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?
The core purpose is front-loaded in the first clause and every sentence carries information. It is dense with backtick notation and multiple nested concepts, which costs some readability, but there is little 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?
Despite an output schema existing, the description supplies interpretation the schema cannot: what null, contenders, candidates and re_verify mean. An agent has everything needed to call and correctly interpret this 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 baseline is 3. The description adds meaning beyond the schema by explaining that verbose=True brings in provenance, support and temporal stamp, complementing the schema's terser 'default drops bookkeeping keys'.
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: 'look up the one CURRENT value at an (entity, attribute) slot'. It explicitly distinguishes itself from the sibling memory_search ('open questions go to memory_search'), so an agent can route correctly 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?
Gives clear routing guidance to memory_search for open questions and points to memory_fact_resolve for unsettled conflicts and memory_history for the version chain. It does not, however, state exclusions like when this tool is the wrong choice for a set-valued slot versus memory_set_add/remove.
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, readOnlyHint=false, and idempotentHint=false, so the safety profile is covered. The description adds the human-check precondition and the two outcome branches (resolved/no_contender), but since an output schema exists, the return-value text is largely redundant and it adds little about what is actually destroyed beyond what the schema's accept parameter explains.
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 action and precondition come first, followed by the return shape. The return block is arguably redundant given the output schema, but the whole thing is tight and waste-free.
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 full annotation coverage and an output schema, the description supplies the key context an agent needs: that this resolves a contested slot and requires prior human confirmation. Nothing essential is missing, though it could state the consequence of accepting vs discarding more explicitly.
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 all three parameters (entity, attribute, accept) are documented in the schema, including the history-keeping behavior of accept. The description adds no parameter-level meaning, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (settle) and resource (a CONTESTED fact slot), which signals it handles only the contested-resolution path rather than general fact writes handled by siblings like memory_fact_set or memory_supersede. It stops short of explicitly naming those alternatives, so sibling differentiation 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?
"after checking with the human" supplies a clear precondition/context for when this tool is appropriate, and "CONTESTED fact slot" narrows the trigger condition. No explicit when-not cases or named alternatives are given, but the usage context is unambiguous.
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's one NOW value. Narrative, decisions, observations: memory_store; many concurrent values: memory_set_add (a set-valued slot errors here).
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 (core).
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?
Annotations already flag a destructive, non-idempotent write, and the description adds substantial context beyond that: a new value supersedes the old with history retained, a conflicting write parks as a contender and returns action="contested" with the winner under current, and authority/distortion_tolerance inherit from the slot's labels unless restated. That is real behavioral disclosure about destructive effects and conflict semantics.
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 core action is front-loaded in the first sentence, followed by sibling routing, supersede/contest semantics, inheritance defaults, and the return shape — every sentence carries information. It is dense and fragment-heavy, which slightly taxes readability, but there is 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?
Despite nine parameters and a write path, the description covers the decisive details an agent needs: sibling routing, error case (set-valued slot), conflict outcome and its resolution path, inheritance defaults, and even the return shape (redundant with the output schema but harmless). Nothing material 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, but the description adds meaning the schema does not: authority and distortion_tolerance inherit the slot's labels unless restated, which explains the interaction of two otherwise opaque enum parameters. The remaining parameters (origin, episode, confidence, freshness_class) are left to the schema, which is adequate but no more.
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 canonical fact — insert, confirm, or correct a slot's one NOW value') and explicitly separates itself from siblings memory_store (narrative) and memory_set_add (many concurrent values). An agent can distinguish it from memory_fact_resolve and memory_supersede 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 routing rules: narrative/decisions/observations go to memory_store, many concurrent values go to memory_set_add, and a set-valued slot errors here. It also says how to handle the contested case ('check with the human, settle via memory_fact_resolve'), which is precisely the when/when-not/alternative guidance the dimension asks for.
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?
Goes well beyond the destructiveHint annotation by disclosing which scopes hard-delete with no audit trail (fact) versus retire with an audit row (world/lesson), the confirm_bulk threshold of 20, and the would_delete refusal shape. These are exactly the behavioral facts an agent needs before a destructive 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?
Dense but front-loaded: scope behaviors first, then alternatives, then filter rules, then the bulk-refusal guard. Every clause carries information, though the backtick-heavy formatting and run-on density cost it a point.
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 9 parameters, an output schema, and destructive annotations, the description covers the required scope-dependent rules, the bulk-confirmation guard, and the undo path. Nothing material to correct invocation 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, but the description adds cross-parameter semantics the schema cannot express: scope="memory" needs at least one filter, several filters NARROW the match (AND), and non-memory scopes require entity. This mapping of filters to scopes 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 (forget/delete/retire) and resource (memory store) and enumerates the four scopes with their distinct behaviors. An agent can distinguish this from siblings like memory_supersede or memory_fact_set 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?
Explicitly routes the agent: 'For now wrong, keep history use memory_fact_set (facts) or memory_supersede (memories) instead,' and names memory_graph_review(action="restore_slot") as the undo path. When-to-use and when-to-use-something-else are both stated.
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?
Discloses behavior annotations cannot express: that reading gently reinforces the memory (which explains readOnlyHint=false and idempotentHint=false), that superseded entries additionally return replaced_by, and the exact forgotten-state payload {found: false, faded: true}. This is a read with a documented side effect, and the description is the only place that fact lives.
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 purpose and tightly written, with no filler sentences. The phrasing is telegraphic ('Superseded: adds replaced_by, as in search'), which is efficient but slightly fragmentary rather than cleanly structured.
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 enumerated, yet the description still flags the important edge-state shapes (superseded, forgotten) and the reinforcement side effect. Only minor gaps remain, such as behavior for an invalid or unknown id versus a forgotten one.
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 documented in the schema, including where the id originates. The description adds no syntax, format, or constraint information about entry_id beyond what the schema already 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 and resource: dereference a memory id to the full stored episode plus the canonical facts it produced (consolidated_into). It implicitly contrasts with the search/fact siblings by naming what it returns, but never names an alternative tool outright, so it stops short of full sibling 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 through the entry_id parameter ('as returned by search results or by a fact's source_entries'), which tells the agent where ids come from. There is no explicit when-to-use/when-not, no named alternative (e.g. memory_fact_get or memory_search), and no guidance on when dereferencing is preferable to those.
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 establish the safety profile (readOnly, non-destructive, closed-world), so the description only needs to add read-specific context — and it does: transitive/inverse edges arrive pre-derived, are flagged `derived: true`, and carry rule provenance. That is real behavioral detail an agent cannot get from annotations, though pagination/size limits are unmentioned.
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?
Tight and front-loaded: purpose first, then the derived-edge behavior, then the return keys. The trailing return-shape sentence partially duplicates the output schema, but it is short enough not to be wasteful.
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 5-parameter schema at full coverage, an output schema, and annotations covering the safety profile, the description supplies the one thing structured data cannot — how edges are derived and flagged. It is nearly complete; a note on result size or the shortest-path behavior would close the remaining 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 description coverage is 100%, so depth, to, include_facts, and relation_filter are fully documented in the schema itself. The description adds no parameter-level meaning beyond that, which matches the baseline 3.
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 ('Read an entity's graph neighborhood') and enumerates what it returns (nodes, typed edges, canonical facts). It clearly reads as the graph-traversal counterpart to memory_get/memory_search, but it never names or distinguishes itself from those siblings explicitly.
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 scope ('an entity's graph neighborhood') implies when you'd reach for it, and the mention of a `to`-style shortest path is only in the schema. There is no explicit when-to-use/when-not guidance versus memory_get, memory_recall, or memory_graph_review.
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 (full).
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 flag destructive=true, idempotent=false and openWorld=false, and the description adds real substance on top: entities auto-create, names resolve through aliases, re-asserting bumps confidence, and unknown relation names are rejected WITH closest matches plus a suggestions payload. It does not explain why the call is flagged destructive or whether conflicting existing edges are overwritten.
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 verb and a worked example, and each following clause carries new information (auto-create, alias resolution, confidence bump, error recovery). Minor waste: the trailing return-shape sentence duplicates the output schema, and the dangling ``(full)`` qualifier on memory_relation_define is unclear.
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 mutating graph tool with full annotations and an output schema, the description covers the behaviours an agent actually needs: creation side effects, alias resolution, idempotency-ish confidence bumping, and the rejected-relation recovery path. Gaps remain around overwrite/conflict behaviour and the exact meaning of the destructive flag.
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 earns extra by explaining the runtime semantics of src/dst (auto-creation and alias resolution) and of relation (closed registry, normalisation, rejection behaviour) rather than just restating field names. It adds no detail on origin, src_type/dst_type, or how confidence interacts with re-assertion.
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 (assert) on a specific resource (typed relation between two entities) and pins the semantics down with a concrete triple example using a real registry relation. It also names the sibling memory_relation_define as the escape hatch, and the 'assert' vs sibling memory_graph_unrelate contrast is implicit but 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?
Gives explicit conditional guidance for the failure path: on a rejected relation, take a suggestion, fall back to ``related-to``, or extend the registry via ``memory_relation_define``. It does not, however, say when to reach for this tool versus memory_graph, memory_store, or memory_graph_review.
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 and readOnlyHint=false, but the description adds real behavioral context beyond them: restore_slot notes 'forgets retire, never delete', relate 'writes the relation edge and dismisses the pair', accept_junk deletes over-extraction artifacts, and accept_merge folds entities. It also documents the return shape and {error} on bad input. It doesn't state auth/rate-limit constraints, so 4.
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 purpose sentence followed by a scannable action list; every line carries a distinct verdict or effect. Efficient for an 11-action multiplexer, with only minimal redundancy from the trailing return 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?
An output schema exists and annotations cover the safety profile, so the description needn't explain return values. It covers all 11 actions and the retire-never-delete semantics, but omits sequencing prerequisites (e.g. whether a list/propose must precede an id-based settle).
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 src, dst, store, scope, relation, proposals, proposal_id and proposal_ids in detail. The description reinforces parameter roles in context ('store + src (the retired key)', 'settle an edge proposal by id') but adds little beyond the structured fields. 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 opening sentence gives a specific verb and resource: work the graph review queue for deep-dream proposals awaiting a verdict before touching the graph. That clearly separates this from direct-write tools like memory_graph_relate or generation tools like memory_dream. It stops short of naming a sibling or explicitly contrasting, so 4 rather than 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?
Each of the 11 actions is annotated with what it decides (e.g. 'relate: related-not-duplicate verdict', 'dismiss_pair: mark src/dst genuinely distinct', 'reject_entity: keep the entity, dismiss the proposal'), which functions as per-action usage guidance. No explicit when-not or alternative-tool routing is given, so it lands at 4.
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 flag destructiveHint=true, but the description adds crucial nuance beyond them: the retraction is a soft delete ('marked superseded (kept for audit)') rather than a hard erase, it removes the edge from memory_graph results, and re-asserting the same triple revives it. This materially changes how an agent should treat the 'destructive' operation.
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 core effect (superseded, kept for audit, removed from results) is front-loaded and the revival behavior follows. 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?
With annotations covering the safety profile and an output schema covering return values, the description's remaining job is the soft-delete/revival semantics, which it delivers well. It could still be strengthened by contrasting with the relate/supersede siblings, but 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 description coverage is 100% (src/relation/dst each documented), so the schema carries parameter meaning. The description alludes to the triple structure ('the same triple') but adds no format, syntax, or edge-resolution detail beyond the schema. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
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') and describes the effect (edge marked superseded, leaves memory_graph results). It does not explicitly distinguish itself from the nearby sibling memory_graph_relate or memory_supersede, so an agent must infer the pairing, but the operation itself 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 implied by the operation (retracting an existing triple), and the revival note hints at reversibility, but there is no explicit when-to-use/when-not guidance or named alternative despite siblings like memory_graph_relate and memory_supersede. Minimum viable.
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 date or epoch seconds, not relative words like 'yesterday'; 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 cover the safety profile (readOnly, non-destructive, closed-world), so the description rightly spends its budget elsewhere: it discloses result ordering (oldest→newest), included metadata (writer/session, tx/valid time, age), and a genuine degradation trait — compaction thins chains past ~30 days. That retention caveat is information an agent cannot get from annotations or schema, though it could say more about pagination or why idempotentHint is false on a read.
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 purpose, then the mode branch, with uppercase mode labels making the split scannable. The trailing 'Returns:' block is largely redundant given an output schema exists, which is the only real waste.
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 three-parameter read tool with a full schema and an output schema, the description covers mode semantics, ordering, metadata, and retention limits adequately; return-shape detail is duplicated rather than needed. An agent has enough to call it correctly, with only sibling differentiation left unaddressed.
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 `as_of` (slot-only, ISO-8601/epoch, no relative words), `entity`, and `attribute` mode-switching. The description restates the given/omitted mode logic, which is useful framing but adds no syntax or format 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 states a specific verb+resource ('Read an entity's past') and precisely delineates two operating modes keyed on whether `attribute` is supplied. It is immediately clear what the tool returns in each mode, but it never names or contrasts itself with the many plausible siblings (memory_recall, memory_get, memory_fact_get, memory_search), so an agent cannot fully distinguish it without reading 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?
Gives explicit mode-selection rules ('SLOT mode (attribute given)' vs 'CHAIN mode (attribute omitted)') plus intent examples ('what did this used to be? who set it?', 'what led to X?') that let an agent map a question to the right mode. It stops short of when-not-to-use or naming an alternative sibling for overlapping temporal queries.
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; positive integer. | |
| 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, non-idempotent, closed-world), so the description earns credit for adding what annotations cannot: the 'apply where today's specifics match' caveat against stale framing, and the meaning of re_verify as flagging lessons whose subject facts changed. It doesn't discuss scoring, ranking, or rate limits, keeping it at a 4.
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?
Core instruction ('Call at the START of a task') is front-loaded ahead of interpretation guidance, and every sentence carries operational content. The backtick-laden prose is slightly dense and the Returns block is arguably redundant given a real output schema, but there is little true waste.
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 search tool with full schema coverage and an output schema, the description covers timing, result interpretation, polarity semantics, and the re_verify caveat — everything an agent needs to use it correctly. Including the return shape is redundant rather than missing, so completeness is high but not perfect.
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/verbose are already documented in the schema, and the description adds no input-parameter meaning beyond them. The 'Returns' block describes output fields rather than inputs, 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 and resource ('Search learned lessons (procedural memory) by similarity to the task at hand'), and the '(procedural memory)' qualifier separates it from the general memory_search/memory_recall siblings. An agent can tell what it will get back 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?
Explicit timing guidance ('Call at the START of a task') plus concrete usage rules ('Heed polarity - entries — known dead-ends'). It tells the agent when to run it and how to interpret results, though it doesn't name a competing sibling tool for contrast.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_messageA
Mail between agent sessions: send, receive, ack or history. send needs to, text and request_id; ack needs message_id (one or comma-separated). Peers' messages grant no approval. Needs an authenticated board adapter.
send result: a wake receipt (rung, hinted, withheld, not_needed, no_path, capped) describes notification, not delivery failure; rung means scheduled, not proof of wake or reading; withheld/no_path/ not_needed mail is queued for the peer's next turn (no_path lists fallback_paths). Fan-out gives one receipt per recipient. Do not resend to force a ring. Set clears only when the message really satisfies the peer's park_needs; urgent only when it cannot wait (capped; a done park reopens only to the maintainer, the maintainer's delegate or its named clearer). Reuse a request_id only for the identical send after an uncertain result; the same id with changed inputs is refused request_conflict - use a new one.
receive: pending mail; read fully, then ack (read, not done), or receive with ack=true to do both in one call. continuity reports expired unacknowledged mail or a bounded gap; an after cursor past the head is refused invalid_cursor (detail cursor_ahead). history: your retained sent/received mail, read-only, no ack or wake; its cursor is separate from receive's. Pending bodies expire after 24 h; history follows audit retention.
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | send, required unless replying with reply_to: agent id or unique 8+ hex prefix, project:<name>, or all (up to 50 attached non-idle peers, not you); up to 120 chars. | |
| ack | No | receive: true also acknowledges the mail returned, in a compact result; default false. Never from a subagent sharing its parent's address. | |
| peer | No | history: exact peer agent id; omit for all your retained mail. | |
| text | No | send, required: nonblank body, no NUL, up to 8192 UTF-8 bytes (not characters). | |
| after | No | receive/history: cursor from the same action; omit for unacknowledged receive mail or earliest retained history. Reset when peer changes. | |
| limit | No | receive/history: integer 1..50, default 50. | |
| action | Yes | send, receive, ack or history; pass only that action's fields. | |
| clears | No | send: the recipient's park_needs this message satisfies, up to 120 chars; may permit a ring, never guarantees one. | |
| urgent | No | send: justified interruption, default false; regular urgency capped at 6/hour. Does not bypass done-park authority or ring caps. | |
| reply_to | No | send: ID/unique 8+ hex prefix of retained mail from this recipient to you, up to 120 chars; no fanout. Omit to: the reply goes to that mail's sender (how to answer origin maintainer). | |
| message_id | No | ack, required: one id or 8+ hex prefix, or up to 50 comma-separated; ack only mail you read. | |
| request_id | No | send, required: nonempty unique string, up to 120 chars (e.g. UUID). Reuse only with identical inputs after uncertainty. |
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 non-read-only, open-world, non-idempotent, non-destructive; the description goes far beyond, disclosing the auth prerequisite ('Needs an authenticated board adapter'), wake-receipt code meanings (rung/hinted/withheld/not_needed/no_path/capped), that rung is scheduling not proof of reading, 24h pending-body expiry, request_conflict on changed inputs with a reused request_id, and invalid_cursor (cursor_ahead). This is exactly the behavioral context annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The action list and send requirements are front-loaded, and it uses line breaks to separate receive/history/continuity sections. It is dense and long, and a few clauses (e.g. the receipt-code list) read as a wall of text, but nearly every sentence carries actionable constraint rather than 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?
Despite an output schema existing (so return shapes need not be explained), the description still supplies the semantics of result codes, plus auth, expiry, retention, cursor isolation between receive and history, and the main error codes. For a 12-parameter, four-action tool this is complete enough to invoke correctly without further digging.
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 adds cross-parameter semantics the schema lacks, such as 'Reuse a request_id only for the identical send', the cursor being reset when the peer changes, and reply_to implying the recipient when 'to' is omitted. It is largely complementary rather than duplicative, so it lands above baseline.
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 line 'Mail between agent sessions: send, receive, ack or history' states a specific resource (inter-agent mail) and enumerates all four verbs the single tool dispatches, so an agent can immediately tell it apart from the memory_* recall/store siblings. The per-action sections then pin down what each verb 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 gives explicit conditions for the ambiguous choices: ack means 'read, not done', use ack=true to combine read+ack, clears 'only when the message really satisfies the peer's park_needs', urgent 'only when it cannot wait', and 'Do not resend to force a ring'. There is no sibling routing (this tool is self-contained), so it stops short of a full when/when-not/alternatives matrix, but the internal guidance is strong.
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.
used_ids credits this session's searches from the last hour;
log before that lapses.
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. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations establish this is a non-read-only, non-idempotent, non-destructive write, and the description adds substantial context beyond that: it requires Postgres, it feeds a downstream dream/consolidation cycle, and it documents failure/partial modes (used_ids_unmatched, used_ids_served_elsewhere, used_ids_ignored, used_ids_truncated, used_ids_errors). It does not address idempotency — repeated logging of the same outcome presumably creates duplicate signals given idempotentHint=false — which is the one notable gap.
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 correctly front-loaded, but the final sentence enumerates seven used_ids_* return fields — redundant given that an output schema exists and the description is not required to explain return values. That enumeration bloats the description and dilutes the actionable content.
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 a full output schema, the description covers purpose, the DB dependency, the crediting window, and the downstream lesson cycle. The main omission is whether repeated calls are safe/duplicative, which matters given idempotentHint=false.
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 every parameter; baseline would be 3. The description goes beyond the schema by explaining the semantics of used_ids (it credits this session's searches, and only those from the last hour) and the downstream meaning of unmatched/served_elsewhere outcomes, adding genuine value over the field text.
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 ("Record") and resource ("procedural outcome") and enumerates the outcome space ("what worked, failed, or was corrected"). The phrase "signals into next session's lessons" and the used_ids crediting make clear this is the outcome/lesson-logging tool rather than the general-purpose memory_store or memory_lesson_search 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?
Provides one concrete usage constraint — used_ids only credits searches from the last hour, so "log before that lapses" — which implies a timing window for calling it. But there is no explicit when-to-use-this-vs-alternatives guidance: nothing tells the agent when to pick memory_outcome over memory_store, memory_message, or memory_reinforce.
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 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 too. 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 | Positive integer. 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 only cover the safety profile (readOnly, non-destructive); the description goes well beyond by disclosing the capping/reservation behavior, the meaning of re_verify (memory corrected, value still stands but check it), pinned constraint facts, and the truncated/searches_issued early-stop semantics with remediation advice.
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 and the memory_search distinction are front-loaded, and each subsequent sentence describes a distinct return-field behavior (caps, re_verify, pinned, truncated). It is dense and long, but almost every sentence earns its place by adding behavioral semantics rather than restating structured fields.
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, yet the description supplies the interpretation layer the schema can't (what truncation and re_verify mean for the caller). For a multi-hop, non-idempotent retrieval tool, an agent has everything needed to call it correctly and interpret results.
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 hops, query, top_k, and verbose are already fully documented in the schema, establishing a baseline of 3. The description adds only marginal param meaning, e.g. tying hops to truncation ('lower hops') and hinting at question narrowing, but adds no syntax 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 ('Multi-hop retrieval over the knowledge graph') and scopes it to RELATIONAL questions with concrete examples. It explicitly distinguishes itself from the sibling memory_search by noting single-shot retrieval 'can't chain' the links this tool follows.
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 ('what does X ultimately run on?'), when-not (single-shot questions belong to memory_search), and a concrete fallback condition (low_confidence: true means no seed matched, fall back to memory_search). Nothing 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_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; positive integer. | |
| 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, destructiveHint=false, explaining the safety profile, so the description adds the ordering semantics (timestamp vs relevance) and the filter combination rule ('AND-combine'). It does not discuss result bounding/pagination beyond the n limit, so it is solid 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?
Two sentences, zero filler, with the ordering constraint front-loaded before the use cases. 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 shape needn't be explained; the description covers purpose, ordering, and filter interaction. It could be marginally more complete by naming the relevance-based sibling it contrasts with, but 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, but the description adds real semantics beyond the schema: the sources/episodes/tags filters AND-combine (the schema does not state the combination operator). That is genuine added value over the per-parameter 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) and resource (most recently stored memories) plus the ordering contract ('newest first — timestamp order, not relevance'), which implicitly separates it from the relevance-ranked memory_search sibling. An agent can select it without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete when-to-use contexts: 'what did I just store?' and catching up at session start. It stops short of naming the alternative tool (memory_search/memory_recall) for contrast, so the routing is contextual rather than explicit.
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 establish that this is a non-readOnly, non-destructive, closed-world operation, so the description only needed to add context. It does add meaningful behavior: the required read-before-write ordering and the intended effect of reducing forgetting. It stops short of explaining whether repeated calls stack or are capped, which matters given idempotentHint=false.
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 in the opening clause and follows with the condition and the ordering rule. Two sentences with no redundant padding, though the em-dash aside is slightly more ornate than necessary.
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 cover the safety profile. For a single-parameter mutation-with-effect tool, the description supplies the trigger, the ordering constraint, and the purpose, leaving nothing an agent needs in order 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?
Only one parameter, and schema description coverage is 100% ('The id of the memory to strengthen'), so the schema already carries the semantics. The description implies the target must be a single memory previously fetched via memory_get, which is mild added context but does not exceed the schema. 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 and resource: 'Strengthen one memory' and explicitly frames the effect as helping a memory 'resist forgetting'. It clearly differentiates itself from memory_get by naming it as the prerequisite read step. It does not, however, contrast itself with adjacent siblings like memory_reinstate or memory_supersede.
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 situational trigger ('after reading it via memory_get and finding it genuinely useful') and an explicit procedural rule ('Read first, then reinforce'). It lacks any when-not guidance or a pointer to an alternative tool for cases where the memory was not useful.
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?
Annotations already declare destructive=true and idempotent=true, so the safety bar is pre-cleared; the description adds real value beyond them with refusal rules ('Refuses trace-invalidated entries'), a blast-radius limit ('never changes derived cortex'), and retry semantics. It omits what exactly is mutated on reinstate, keeping it out of 5 territory.
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 short front-loaded sentences covering action, constraints, refusal behavior and retry, with no filler. Dense but every clause carries an operational fact, though the ';' run-on packs several ideas into one sentence.
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 and rich annotations present, the description covers the remaining essentials: engine constraint, preimage requirement, refusal behavior, and retry guidance. The only loose end is the un-parameterized 'named principal' reference against the actual reviewer_ids field.
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?
At 100% schema coverage the baseline is 3, but the description earns more by linking concepts to parameters: 'durable ID' anchors entry_id and 'exact retirement preimage' plus 'same UUID and inputs' anchors the hash/operation_id fields. It doesn't resolve the fact that 'named principal' has no matching parameter.
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 precise verb and resource ('Reinstate one reviewed retired entry by durable ID'), and the single-entry scope makes it distinguishable from broad write tools. It does not explicitly name a sibling such as memory_supersede or memory_forget, 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?
It states prerequisites ('PostgreSQL only', 'requires a named principal and exact retirement preimage') and a retry protocol, which is clear context for correct invocation. It never says when to choose this over alternatives like memory_supersede, so no exclusion guidance.
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?
The annotations already declare destructiveHint=true and readOnlyHint=false, so the mutation risk is covered structurally. The description adds the useful framing that this is a 'deliberate, rare act' against a 'closed graph vocabulary,' but says nothing about permanence, name-collision behavior, or whether a defined relation can ever be removed.
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 purpose and followed immediately by the caution. No filler, and the most decision-relevant constraint (prefer builtins) lands before the agent scans the 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?
An output schema exists, so return values need no explanation, and the schema carries all parameter detail. What remains thin is the consequence model: this mutates a global vocabulary but the description does not state whether the addition is permanent or how conflicts are handled.
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 six parameters, including hyphenation, soft type expectations, inverse pairing and transitivity. The description adds no parameter 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?
The description names a specific verb and resource: 'Add a relation to the closed graph vocabulary.' The word 'vocabulary' implicitly separates it from sibling edge-manipulation tools like memory_graph_relate, but it never names that contrast explicitly, so an agent must infer the distinction.
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 when-not condition ('define one only when a recurring connection genuinely fits none of them') and routes the agent toward alternatives ('Prefer the builtins'). This is exactly the routing guidance needed for a rare, high-consequence tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_searchARead-only
Search shared memory in natural language: past work, decisions, preferences, canonical facts and ingested documents. Call at task start and whenever prior context may matter. Exact value of a known (entity, attribute): memory_fact_get; lessons: memory_lesson_search. Core tier (expand if absent, then rediscover): memory_recall for multi-hop questions, memory_world_search for cited external facts, document_search for documents only.
Hits are leads about the PAST: check each against today's task and re-derive when its context differs. cortex facts come first and may bear on the query; contested: true needs a human-checked memory_fact_resolve (core); pinned marks a constraint on the query's entity; authority: quoted is someone else's claim. low_confidence: true only when nothing matched at the default floor; hits still need judging.
A superseded hit's replaced_by names its replacement. verified: false = not confirmed as an explicit correction, so the hit may still hold; memory_get (core) the replacement only if its preview is on-subject. current: false = search again. Never follow chains. truncated: true hits have full text via memory_get. Filters narrow direct entry hits, not cortex, documents or added neighbors; AND across kinds, OR within a list.
Returns {query, count, entries, cortex, low_confidence}; temporal queries may add events, oldest first.
| Name | Required | Description | Default |
|---|---|---|---|
| bm25 | No | Keyword-scoring override for exact terms; true/false overrides config, null follows it. | |
| tags | No | Tags of direct entry hits; null or [] means no tag filter. | |
| bands | No | Bands of direct entry hits; null or [] means no band filter. | |
| query | Yes | Natural-language description; specific beats vague. | |
| top_k | No | Direct entry hits to retrieve, a positive integer (default 8); documents and neighbors may add a few. Compact payloads cap cortex facts at min(5, top_k). Use top_k, not limit. | |
| rerank | No | Cross-encoder reranking override (~200ms); true/false overrides config, null follows it. | |
| explain | No | Attach a ranking trace and imply verbose; default false. | |
| sources | No | Source tags of direct entry hits; null or [] means no source filter. | |
| verbose | No | Full metadata and untruncated entry text; default false returns compact entries. | |
| episodes | No | Episode IDs of direct entry hits; null or [] means no episode filter. | |
| min_score | No | Override relevance threshold (shipped 0.25); null follows config. | |
| disable_recency_boost | No | True scores without recency bias; default false. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnly, non-destructive), so the bar is met, yet the description goes well beyond: hits are 'leads about the PAST' requiring re-derivation, cortex facts come first, contested/pinned/authority/low_confidence flag meanings, superseded replaced_by handling, verified:false semantics, 'never follow chains', and current:false meaning re-search. This is unusually rich operating context that the schema and annotations do not provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads purpose, then usage, then hit-interpretation, then filters, then return shape – a sensible ordering. It is dense and telegraphic in places (semicolon-chained clauses), but almost every sentence carries operational meaning; a small amount of the flag glossary could be tightened.
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, output-schema-bearing tool this covers what an agent needs: when to call, when to call siblings, how to interpret each hit flag, filter semantics, and the return shape ({query, count, entries, cortex, low_confidence} plus events for temporal queries) even though the output schema exists.
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 not in the schema: filters 'narrow direct entry hits, not cortex, documents or added neighbors' and combine 'AND across kinds, OR within a list'. The bm25/rerank/min_score overrides are left to the schema, so it is not a full 5.
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?
Opens with a specific verb+resource ('Search shared memory in natural language') and enumerates the content types covered (past work, decisions, preferences, canonical facts, documents). It explicitly demarcates itself from siblings by naming memory_fact_get, memory_lesson_search, memory_recall, memory_world_search and document_search for the cases it does not handle.
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 invocation timing ('Call at task start and whenever prior context may matter') and routes the agent to alternatives by condition: exact (entity, attribute) to memory_fact_get, lessons to memory_lesson_search, multi-hop to memory_recall, cited external facts to memory_world_search. Nothing 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_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 explicitly claims "Idempotent," but the annotations declare idempotentHint=false. This is a direct textual conflict on a declared behavioral trait, and an agent could be misled into blind retries. The useful context it does add (state mutation, rename semantics, timing) is outweighed by contradicting the structured safety 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?
Two short sentences, purpose front-loaded, with the rationale for calling it early rather than burying it. Every clause carries information; nothing is redundant padding.
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, and the annotations cover the safety profile for this narrowly scoped mutation. The description covers when to call and what it affects, but the idempotency statement leaves the mutation/retry semantics muddled rather than fully resolved.
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, but the description adds meaning the schema omits: it clarifies that omitting `episode` targets this session's own auto-opened episode, whereas the schema leaves the null default's behavior unexplained. That is genuine added value for the optional parameter.
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 and scope: "Name THIS session's auto-opened episode," and explains the default it replaces ("default titles are generic"). It is clearly separable from siblings like memory_store, memory_message, or memory_episode_start, which do different things.
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 timing ("Call once at the start of work") and a follow-up case ("call again to rename"), which is real when-to-use guidance. It does not name an alternative sibling or state when not to use it, so it stops short of 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 (core)). 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 declare the safe-write profile (readOnlyHint=false, destructiveHint=false, idempotentHint=false), and the description adds substantial beyond-that context: the one-way scalar-to-set conversion on first call, the protected number-led scalars, and the action='contested' parking behavior. This is exactly the kind of side-effect disclosure the annotations cannot express.
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 scope, and the returns block is short. The parentheticals ('32', '$1,500') and em-dash clauses make it dense but every sentence carries information, so it stays 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?
An output schema exists so return values need not be spelled out, and the description still summarizes them. Conversion semantics, the contested path, and read alternatives are all covered; only explicit permission/auth prerequisites are absent for a non-destructive mutation.
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, and the description adds little per-parameter meaning. It clarifies that a 'member' is added or re-confirmed into a set, but the 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?
States a specific verb ('Add/confirm a member') and resource ('set-valued slot'), and immediately scopes it against the scalar case ('many concurrent values, not one NOW value'). An agent can tell it apart from memory_fact_set and memory_set_remove 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 clear when-to-use context (sets rather than scalar NOW values) and routes the contested case to memory_fact_resolve and reads to memory_fact_get. It does not spell out when NOT to use the tool versus other mutators, but the set/scalar distinction effectively covers the decision.
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 idempotentHint=false, so the safety profile is partly covered. The description nonetheless adds a genuinely non-obvious behavioral fact — '(audit row kept)' — telling the agent this is a soft retraction with a preserved audit trail rather than an erasure, which the annotations do not convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded and very tight; the destructive behavior and the read-path pointer come first. The trailing 'Returns: {...}' line is redundant given that an output schema exists, which costs it a perfect score but not much else.
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 tool with full schema coverage, annotations, and an output schema, the description covers the essentials: what it mutates, that the audit trail survives, and how to verify. It is silent on failure behavior when the member is absent, but that gap is minor given the structured data available.
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 all three parameters are documented in the schema, so the description need not restate them. It adds no syntax, format, or edge-case meaning beyond 'the current member to retract,' which is already implied by the schema text; 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: 'Retract one current set member.' The parenthetical clarifies the scope (single member) and the audit semantics, so an agent can distinguish this from memory_set_add or memory_forget without opening the schema. It does not, however, explicitly name those 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?
'Read with memory_fact_get' gives one concrete follow-up action, which is useful routing guidance. But there is no statement of when to use this versus memory_set_add, memory_supersede, or memory_forget, so the selection guidance remains implicit.
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, so the safety profile is covered and the bar is lower. The description adds that this is a diagnostic/inspection surface rather than a mutation, but with an output schema present it needn't restate return structure, and it offers no extra behavioral context (refresh cadence, cost, scoping) beyond the metric names.
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 the metric list front-loaded and a single actionable usage clause following. No filler sentences; 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?
For a zero-parameter tool with a published output schema and rich annotations, the description supplies enough context to call it correctly and know why. It could be slightly more complete by hinting at what to do with a bad reading (which sibling to turn to), but nothing required for invocation 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?
The tool takes zero parameters, so there are no parameter semantics to explain; per the rubric this is the baseline 4. Nothing in the description misleads about inputs.
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 memory bank's "vital signs") and enumerates the concrete metrics returned: store occupancy vs capacity, hit rates, true-drop count, and totals. This clearly sets it apart from the read/write memory siblings, though it never names a sibling directly to sharpen the contrast.
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?
"Use to gauge how much has been remembered or to diagnose why retrieval feels off" gives two explicit usage contexts, which is strong when-to-use guidance. It stops short of stating when-not to use it or naming an alternative (e.g. memory_search for retrieval debugging), so it isn't 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_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; "status" for in-flight progress notes (peers see those; the dream skips them). | 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?
Adds real behavior beyond annotations: near-duplicates are silently dropped rather than errored, with stored=False and reason="below_surprise_threshold", and it sketches the return keys. Annotations (destructive=true, idempotent=false, openWorld=false) cover the write/safety profile, so this supplementary dedup semantics is the valuable addition.
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 action and the persist/context/verify routing before edge-case details. It is dense but mostly earns its length; the trailing 'Returns:' block partially duplicates 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?
Given seven parameters, rich enums, and an existing output schema, the description supplies enough routing and dedup context for correct invocation. The explicit return-value listing is redundant against the output schema but not harmful.
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 enums are self-documenting, so the schema already carries parameter meaning. The description adds only the general constraint of one claim per call and indirect framing of authority/freshness, without explaining tags, origin, source, or episode beyond what the schema already states.
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 (store one durable fact, decision, or observation) and explicitly distinguishes itself from the sibling memory_fact_set for canonical NOW values. An agent can identify the tool's role 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 explicit decision rules: PERSIST what stays true, leave task-scoped detail to CONTEXT ONLY, RE-VERIFY volatile values at source via memory_fact_set, and ASK when ambiguous. It also names the alternative tool for canonical now-values, so when/when-not is fully covered.
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. Test junk or a never-true entry:
memory_forget; a canonical slot: memory_fact_set.
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?
Annotations declare destructiveHint=true and idempotentHint=false, but the description goes well beyond them: the old entry is kept and flagged rather than deleted, retrieval ranks the correction higher, derived canonical facts are FLAGGED never rewritten, and no-mutation-on-bad-target behavior is spelled out. This is exactly the blast-radius context an agent needs before calling a destructive 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?
Dense and front-loaded — purpose first, then alternatives, then selector rule, then return semantics. It is on the long side and spends several lines interpreting return fields even though an output schema exists, which is mild redundancy, but nearly every sentence carries operational weight.
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, non-idempotent mutation with three parameters, the description covers selectors, failure modes, the non-destructive flagging model, derived-fact blast radius, and truncation fields. Nothing an agent needs to invoke it correctly is missing, even accounting for the output 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 coverage is 100%, so the baseline is 3, but the description adds the mutual-exclusivity rule ('Use exactly one selector') that the schema's anyOf-nullable fields do not enforce, plus recovery guidance for a failed selector. That is real value beyond the schema, though it doesn't explain selector precedence when both are supplied.
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 ('Mark a stored memory obsolete and record its replacement') and immediately differentiates from siblings by naming memory_forget for junk/never-true entries and memory_fact_set for canonical slots. An agent can distinguish this from the ~35 sibling memory tools 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?
Explicitly routes to alternatives ('Test junk or a never-true entry: memory_forget; a canonical slot: memory_fact_set') and gives the operational precondition ('Use exactly one selector'). It also specifies the failure path — missing, retired, or ambiguous targets cause no mutation, so search again — and rules out similarity fallback.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_toolsetA
Change your server-visible tool tier: minimal -> core -> full, one step per expand; collapse steps down; status shows the current tier and what each tier adds. Core adds the board (memory_agents, memory_message), graph/recall, world facts, documents; full adds supersede/forget/history, dream and graph-review admin. After expand, rediscover tools in the client: list_changed_sent means the notification was sent, not client refresh. If a named tool is still absent at its required tier, report the visibility mismatch; do not keep expanding.
| 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?
Annotations already disclose the mutation profile (readOnlyHint=false, idempotentHint=false, destructiveHint=false), so the bar is lower. The description adds genuinely useful behavior beyond that: the one-step-per-expand constraint and the important caveat that 'list_changed_sent' means the notification was sent, not that the client refreshed. It does not address persistence/session scope of the tier change, which is a minor gap.
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 clause, and the tier contents follow before the workflow caveats. It is dense and multi-clause (slightly heavier than needed), but every sentence carries operational value and nothing is pure 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?
An output schema exists, so return-value explanation is rightly omitted. The description covers tier transitions, what each tier adds, notification semantics, and the mismatch-handling rule, which is thorough for a one-param state-change tool. It could note whether tier state is session- or server-scoped, but nothing essential for correct invocation 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 0% and the single 'action' param has only an enum, so the description must carry the meaning. It does: expand, collapse (steps down), and status ('shows the current tier and what each tier adds') are each explained, compensating well for the bare 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 (change) and resource (server-visible tool tier) and enumerates the three actions (expand, collapse, status) plus what each tier adds. This is a meta-tool whose purpose is unmistakable against the memory_* and document_* siblings, which it explicitly manages visibility of rather than being one of 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?
It gives operational when-to-use guidance (one step per expand, collapse steps down) and an explicit when-not/exclusion: 'do not keep expanding' when a named tool is still absent. It also routes the agent through the post-expand rediscovery workflow and the visibility-mismatch reporting condition, 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_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; positive integer. | |
| 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, non-idempotent), yet the description adds real behavioral context beyond them: entries carry an age-decayed effective_confidence, a stale flag that means 're-verify before relying on it', and source_url/source_quote for citation. Those reliability semantics are the kind of thing an agent cannot infer from structured fields alone; only the return-shape line is somewhat redundant.
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 purpose and the usage trigger, then a compact disclosure of entry metadata. The trailing 'Returns: {count, entries}' line is largely wasted given a machine-readable output schema exists, but overall the text is tight with no padding.
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 similarity search with full schema coverage, annotations, and an output schema, the description supplies everything else the agent needs: when to reach for it, what makes results trustworthy (confidence decay, stale flag), and how to cite them. No material gaps remain.
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, top_k and verbose are each documented in the schema. The description adds no parameter-level detail (no guidance on top_k sizing or when verbose is worth it), so the schema does all the work; baseline 3 is correct.
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 ('Search current WORLD facts ... by similarity') and disambiguates the data pool with the parenthetical '(sourced external knowledge)'. That qualifier separates it from generic memory_search / memory_recall / document_search without the agent needing to open sibling 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?
Gives a clear triggering condition: 'Use when a task turns on an external fact your training data may be stale.' It does not name alternatives (e.g. memory_search for personal memory, document_search for uploaded documents) or state when not to use it, so it stops short of explicit routing.
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, idempotentHint=false and openWorldHint=false; the description adds the key non-obvious behavior that a newer source supersedes an older value at the same slot, which explains the non-idempotent, overwriting nature. It does not discuss auth requirements or what happens to the superseded record beyond the return action label.
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 plus a short return line, with the core scope statement front-loaded before the routing guidance. No filler or repetition of the tool name.
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 the description covers purpose, routing, slot/supersede semantics and return actions; the 'Returns' line is technically redundant given the output schema but harmless. It leaves the destructive overwrite implication slightly implicit rather than stating plainly that an existing value is replaced.
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 entity, attribute, value, confidence, source_url and freshness_class are all already documented in the schema. The description only reinforces the citation requirement and slot semantics, adding little beyond what the structured fields provide; 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+resource ('Assert a canonical WORLD fact') and immediately scopes it to externally sourced knowledge, listing concrete examples (versions, prices, role holders, research findings). It explicitly contrasts with user/project facts, so an agent can distinguish it from memory_fact_set 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?
'Route verified web/docs findings here, with the citation' gives a clear inclusion criterion, and the separation from user/project facts implicitly routes other assertions to the fact tools. It stops short of naming an alternative sibling or stating when NOT to use it (e.g. unverified or purely user-stated claims).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
1 tool update
v0.18.3- Changed
memory_agents2 fields changed- changed
Input schema / properties / park_reason / anyOfPrevious value: -[ - { - "maxLength": 20, - "type": "string" - }, - { - "type": "null" - } -]New value: +[ + { + "enum": [ + "done", + "blocked", + "needs_approval", + "needs_info", + "needs_resource", + "waiting_peer", + "" + ], + "type": "string" + }, + { + "type": "null" + } +] - changed
Input schema / properties / park_reason / descriptionPrevious value: -"update: done, blocked, needs_approval, needs_info, needs_resource or waiting_peer (max 20 chars). Empty string clears; null/omitted sends no reason."New value: +"update: done, blocked, needs_approval, needs_info, needs_resource or waiting_peer. Empty string clears; null/omitted sends no reason."
1 tool update
v0.18.2- Changed
memory_message1 field changed- added
Input schema / properties / ackAdded value: +{ + "default": false, + "description": "receive: true also acknowledges the mail returned, in a compact result; default false. Never from a subagent sharing its parent's address.", + "title": "Ack", + "type": "boolean" +}
38 tool updates
v0.18.1- Changed
document_ingest1 field changed- added
Input schema / additionalPropertiesAdded value: +false
- Changed
document_search3 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / top_k / descriptionPrevious value: -"Max chunks returned."New value: +"Max chunks returned; positive integer." - added
Input schema / properties / top_k / minimumAdded value: +1
- Changed
memory_agents17 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / action / descriptionAdded value: +"list (default), update, claim or release; pass only that action's fields." - added
Input schema / properties / children / descriptionAdded value: +"update: at most 8 distinct nonempty labels, each up to 40 chars. [] clears manual labels; automatic children remain." - added
Input schema / properties / expect / descriptionAdded value: +"update/claim: expected duration in seconds, integer 1..604800; marks overdue, not a timer or lease TTL." - added
Input schema / properties / lease / descriptionAdded value: +"claim/release: coordinator:<project> or claim:<path>, up to 120 chars. Omit with file selectors." - added
Input schema / properties / nameAdded value: +{ + "anyOf": [ + { + "maxLength": 120, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "update: the name the board shows for you, up to 120 chars; it overrides your harness's title. \"\" clears yours.", + "title": "Name" +} - added
Input schema / properties / park_clear_by / descriptionAdded value: +"update: who may wake this park: exact agent ID, maintainer, anyone, or a supported lease name; up to 120 chars." - added
Input schema / properties / park_expires / descriptionAdded value: +"update: positive finite Unix epoch seconds, at most now + 7 days; new parks default to now + 12 hours, refinements keep expiry." - added
Input schema / properties / park_needs / descriptionAdded value: +"update: what would unblock you, up to 120 chars; senders use clears only when their message satisfies this need." - added
Input schema / properties / park_reason / descriptionAdded value: +"update: done, blocked, needs_approval, needs_info, needs_resource or waiting_peer (max 20 chars). Empty string clears; null/omitted sends no reason." - added
Input schema / properties / park_resume / descriptionAdded value: +"update: what to do once cleared, up to 240 chars." - added
Input schema / properties / path / descriptionAdded value: +"claim/release: one file relative to worktree/repository_id, up to 4096 chars; no globs or directories." - added
Input schema / properties / project / descriptionAdded value: +"list/update: project name, up to 120 chars; relevance only." - added
Input schema / properties / repository_id / descriptionAdded value: +"claim/release, HTTP: prepared 64-char lowercase SHA-256 repository ID; requires path, excludes lease/worktree." - added
Input schema / properties / status / descriptionAdded value: +"update: progress; claim: lease purpose. Up to 240 chars. On update, clears any park unless park fields are given." - added
Input schema / properties / task / descriptionAdded value: +"list/update: current task, up to 120 chars." - added
Input schema / properties / worktree / descriptionAdded value: +"claim/release, local shim only: absolute Git worktree path, up to 4096 chars; requires path, excludes lease/repository_id."
- Changed
memory_alias1 field changed- added
Input schema / additionalPropertiesAdded value: +false
- Changed
memory_consolidate1 field changed- added
Input schema / additionalPropertiesAdded value: +false
- Changed
memory_consolidation_candidates7 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / max_clusters / descriptionPrevious value: -"Max clusters returned."New value: +"Max clusters returned; positive integer." - added
Input schema / properties / max_clusters / minimumAdded value: +1 - changed
Input schema / properties / min_cluster_size / descriptionPrevious value: -"Drop clusters with fewer members than this."New value: +"Drop clusters with fewer members than this; positive integer." - added
Input schema / properties / min_cluster_size / minimumAdded value: +1 - changed
Input schema / properties / top_k / descriptionPrevious value: -"How many candidate entries to cluster over."New value: +"How many candidate entries to cluster over; positive integer." - added
Input schema / properties / top_k / minimumAdded value: +1
- Changed
memory_dream3 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / limit / anyOfPrevious value: -[ - { - "type": "integer" - }, - { - "type": "null" - } -]New value: +[ + { + "minimum": 1, + "type": "integer" + }, + { + "type": "null" + } +] - changed
Input schema / properties / limit / descriptionPrevious value: -"pull/run: how many memories to process (pull defaults to 40). runs: how many passes to list (defaults to 10)."New value: +"pull/run: how many memories to process (pull defaults to 40). runs: how many passes to list (defaults to 10). Positive integer."
- Changed
memory_episode_end1 field changed- added
Input schema / additionalPropertiesAdded value: +false
- Changed
memory_episode_start1 field changed- added
Input schema / additionalPropertiesAdded value: +false
- Changed
memory_episode_summary1 field changed- added
Input schema / additionalPropertiesAdded value: +false
- Changed
memory_fact_get1 field changed- added
Input schema / additionalPropertiesAdded value: +false
- Changed
memory_fact_resolve1 field changed- added
Input schema / additionalPropertiesAdded value: +false
- Changed
memory_fact_set6 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / attribute / minLengthAdded value: +1 - added
Input schema / properties / confidence / maximumAdded value: +1 - added
Input schema / properties / confidence / minimumAdded value: +0 - added
Input schema / properties / entity / minLengthAdded value: +1 - added
Input schema / properties / value / minLengthAdded value: +1
- Changed
memory_forget1 field changed- added
Input schema / additionalPropertiesAdded value: +false
- Changed
memory_get1 field changed- added
Input schema / additionalPropertiesAdded value: +false
- Changed
memory_graph1 field changed- added
Input schema / additionalPropertiesAdded value: +false
- Changed
memory_graph_relate3 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / confidence / maximumAdded value: +1 - added
Input schema / properties / confidence / minimumAdded value: +0
- Changed
memory_graph_review1 field changed- added
Input schema / additionalPropertiesAdded value: +false
- Changed
memory_graph_unrelate1 field changed- added
Input schema / additionalPropertiesAdded value: +false
- Changed
memory_history2 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / as_of / descriptionPrevious value: -"Slot mode only: ISO-8601 or epoch seconds; returns only versions written by then."New value: +"Slot mode only: ISO-8601 date or epoch seconds, not relative words like 'yesterday'; returns only versions written by then."
- Changed
memory_lesson_search3 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / top_k / descriptionPrevious value: -"Max entries returned."New value: +"Max entries returned; positive integer." - added
Input schema / properties / top_k / minimumAdded value: +1
- Changed
memory_message12 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / action / descriptionAdded value: +"send, receive, ack or history; pass only that action's fields." - added
Input schema / properties / after / descriptionAdded value: +"receive/history: cursor from the same action; omit for unacknowledged receive mail or earliest retained history. Reset when peer changes." - added
Input schema / properties / clears / descriptionAdded value: +"send: the recipient's park_needs this message satisfies, up to 120 chars; may permit a ring, never guarantees one." - added
Input schema / properties / limit / descriptionAdded value: +"receive/history: integer 1..50, default 50." - added
Input schema / properties / message_id / descriptionAdded value: +"ack, required: one id or 8+ hex prefix, or up to 50 comma-separated; ack only mail you read." - added
Input schema / properties / peer / descriptionAdded value: +"history: exact peer agent id; omit for all your retained mail." - added
Input schema / properties / reply_to / descriptionAdded value: +"send: ID/unique 8+ hex prefix of retained mail from this recipient to you, up to 120 chars; no fanout. Omit to: the reply goes to that mail's sender (how to answer origin maintainer)." - added
Input schema / properties / request_id / descriptionAdded value: +"send, required: nonempty unique string, up to 120 chars (e.g. UUID). Reuse only with identical inputs after uncertainty." - added
Input schema / properties / text / descriptionAdded value: +"send, required: nonblank body, no NUL, up to 8192 UTF-8 bytes (not characters)." - added
Input schema / properties / to / descriptionAdded value: +"send, required unless replying with reply_to: agent id or unique 8+ hex prefix, project:<name>, or all (up to 50 attached non-idle peers, not you); up to 120 chars." - added
Input schema / properties / urgent / descriptionAdded value: +"send: justified interruption, default false; regular urgency capped at 6/hour. Does not bypass done-park authority or ring caps."
- Changed
memory_outcome3 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / polarity / anyOfPrevious value: -[ - { - "type": "string" - }, - { - "type": "null" - } -]New value: +[ + { + "enum": [ + "+", + "-" + ], + "type": "string" + }, + { + "type": "null" + } +] - changed
Input schema / properties / used_ids / descriptionPrevious value: -"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."New value: +"Ids of the search hits you actually used, e.g. [1421, 903] — the relevance label only you can write. At most 50."
- Changed
memory_recall3 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / top_k / descriptionPrevious 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."New value: +"Positive integer. 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 / top_k / minimumAdded value: +1
- Changed
memory_recent3 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / n / descriptionPrevious value: -"How many entries to return."New value: +"How many entries to return; positive integer." - added
Input schema / properties / n / minimumAdded value: +1
- Changed
memory_reinforce1 field changed- added
Input schema / additionalPropertiesAdded value: +false
- Changed
memory_reinstate1 field changed- added
Input schema / additionalPropertiesAdded value: +false
- Changed
memory_relation_define1 field changed- added
Input schema / additionalPropertiesAdded value: +false
- Changed
memory_search13 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / bands / descriptionPrevious value: -"Keep only entries held by one of these bands."New value: +"Bands of direct entry hits; null or [] means no band filter." - changed
Input schema / properties / bm25 / descriptionPrevious value: -"Tri-state override for keyword scoring (exact terms); None follows config."New value: +"Keyword-scoring override for exact terms; true/false overrides config, null follows it." - changed
Input schema / properties / disable_recency_boost / descriptionPrevious value: -"True to score without the recency bias."New value: +"True scores without recency bias; default false." - changed
Input schema / properties / episodes / descriptionPrevious value: -"Keep only entries stamped with one of these episode ids."New value: +"Episode IDs of direct entry hits; null or [] means no episode filter." - changed
Input schema / properties / explain / descriptionPrevious value: -"Attach a ranking ``trace``; implies verbose."New value: +"Attach a ranking trace and imply verbose; default false." - changed
Input schema / properties / min_score / descriptionPrevious value: -"Override the 0.25 relevance floor."New value: +"Override relevance threshold (shipped 0.25); null follows config." - changed
Input schema / properties / rerank / descriptionPrevious value: -"Tri-state override for cross-encoder reranking (~200ms); None follows config."New value: +"Cross-encoder reranking override (~200ms); true/false overrides config, null follows it." - changed
Input schema / properties / sources / descriptionPrevious value: -"Keep only entries with one of these source tags."New value: +"Source tags of direct entry hits; null or [] means no source filter." - changed
Input schema / properties / tags / descriptionPrevious value: -"Keep only entries carrying one of these tags."New value: +"Tags of direct entry hits; null or [] means no tag filter." - changed
Input schema / properties / top_k / descriptionPrevious value: -"Max entries; caps cortex facts at min(5, top_k)."New value: +"Direct entry hits to retrieve, a positive integer (default 8); documents and neighbors may add a few. Compact payloads cap cortex facts at min(5, top_k). Use top_k, not limit." - added
Input schema / properties / top_k / minimumAdded value: +1 - changed
Input schema / properties / verbose / descriptionPrevious value: -"Full per-entry metadata and untruncated ``text``; default entries are compact."New value: +"Full metadata and untruncated entry text; default false returns compact entries."
- Changed
memory_session_title1 field changed- added
Input schema / additionalPropertiesAdded value: +false
- Changed
memory_set_add1 field changed- added
Input schema / additionalPropertiesAdded value: +false
- Changed
memory_set_remove1 field changed- added
Input schema / additionalPropertiesAdded value: +false
- Changed
memory_stats1 field changed- added
Input schema / additionalPropertiesAdded value: +false
- Changed
memory_store2 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / source / descriptionPrevious value: -"Stable per-project/topic tag for later filtering."New value: +"Stable per-project/topic tag for later filtering; \"status\" for in-flight progress notes (peers see those; the dream skips them)."
- Changed
memory_supersede1 field changed- added
Input schema / additionalPropertiesAdded value: +false
- Changed
memory_toolset1 field changed- added
Input schema / additionalPropertiesAdded value: +false
- Changed
memory_world_search3 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / top_k / descriptionPrevious value: -"Max entries returned."New value: +"Max entries returned; positive integer." - added
Input schema / properties / top_k / minimumAdded value: +1
- Changed
memory_world_set3 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / confidence / maximumAdded value: +1 - added
Input schema / properties / confidence / minimumAdded value: +0
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
The retrieval family (memory_search, memory_recall, memory_world_search, memory_lesson_search, document_search, memory_recent) and the write family (memory_store, memory_fact_set, memory_world_set, memory_set_add, memory_consolidate, memory_supersede) genuinely overlap in purpose, but the descriptions explicitly route between them ("exact value of a known (entity, attribute): memory_fact_get; lessons: memory_lesson_search") so an agent can differentiate with careful reading. Each tool ultimately targets a distinct store or operation, though the semantic distance between e.g. memory_store and memory_fact_set requires a steep learning curve. No two tools appear to do the same thing.
Almost everything uses a memory_<verb>_<noun> snake_case pattern with strong subsystem prefixes (memory_fact_*, memory_set_*, memory_world_*, memory_graph_*, memory_episode_*). Deviations are minor: document_ingest/document_search use a different prefix for the separate reference bank, and a few are noun-only or asymmetric (memory_stats, memory_toolset, memory_agents, memory_message, and memory_consolidate vs memory_consolidation_candidates).
38 tools is heavy, but the domain is genuinely broad (episodic memory, canonical facts, world facts, lessons, graph, documents, agent mail/board, dream admin), so most tools earn a place. The minimal/core/full tier system via memory_toolset is a real mitigation that keeps the visible surface small per session. Still, the full tier is a large, admin-heavy surface that sits at the borderline of over-scoped.
Coverage is unusually thorough: memory lifecycle (store/get/search/forget/supersede/reinstate/reinforce/history), canonical facts with sets and conflict resolution, world facts with sourcing, lessons, document ingest/search, graph relate/unrelate/read/multi-hop recall, review queue, consolidation, and agent coordination. Gaps are modest: no way to delete or retract an ingested document, no direct lesson authoring (only via outcome/dream), and no entry text-editing path other than supersede. These are workaround-able rather than 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.
Private memory for AI agents: save and recall facts across Claude Code, Codex, Cursor and ChatGPT.
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.8 npm1MIT
- AlicenseAqualityDmaintenanceEnables persistent memory for Claude Code sessions by recording observations and building knowledge graphs for cross-session learning and domain knowledge management.11MIT
- AlicenseNot gradedqualityBmaintenanceProvides persistent long-term memory for Claude Code by enabling semantic save, search, and context retrieval across sessions.1MIT
- AlicenseNot gradedqualityAmaintenanceGives Claude Code a persistent identity and cross-session memory with semantic search over saved facts, decisions, and journals. It also detects and classifies user corrections into behavioral patterns with lifecycle trends, reflecting periodically to promote or retire working frameworks.6 npmMIT