Gingugu
It is a local MCP memory server that gives AI assistants persistent, structured, searchable long-term memory across sessions and projects.
Store memories with rich metadata: type (fact, decision, pattern, bug, architecture, preference, workflow, context), confidence level, tags, namespace, source, and JSON metadata.
Search and recall using hybrid retrieval (BM25/FTS5 + semantic embeddings), with relevance ranking, compact summaries, multi-namespace queries, related-memory spreading activation, and score explanations.
Auto-surface context at session start with
memory_context, including pinned memories, review hints, and freshness/recency weighting.Update and maintain memories: edit fields, retype, change confidence, pin important memories, resolve stale PR/MR claims without rewriting prose, deprecate or hard-delete memories.
Build a knowledge graph with typed relationships (supersedes, contradicts, caused_by, parent_of/child_of, related_to), enumerate edges, and repair/retype/reverse/delete edges in batches.
Consolidate knowledge: merge, summarize, or deduplicate similar memories, plus a read-only near-duplicate suggestion scan.
Run a consolidation/dream pass for PageRank, community detection, and orphan reconnection, with proposals you can accept or reject.
Get health metrics: memory counts, dormancy, namespace breakdowns, claim backlog, orphan samples, review queues, and graph stats.
Manage namespaces (create, update, delete, set default repos), and export/import portable JSON backups.
Securely store credentials in the OS keychain (store, retrieve, list, delete credential bundles).
Run as a remote HTTP MCP server with Bearer-token auth, and promote trustworthy local memories to a central brain with provenance stamps.
Visualize memory data with the built-in Memory Explorer UI (knowledge graph + dashboard).
Provides cross-session memory for Windsurf (Codeium) AI assistant, supporting knowledge retention and recall.
Gingugu
Your AI forgets everything between sessions. Gingugu fixes that.
Gingugu is a local MCP server that gives AI coding assistants a real long-term brain β persistent, structured, searchable memory that survives across sessions, repos, and projects. No cloud, no API keys, no telemetry. One SQLite file on your machine.
π Table of Contents
Related MCP server: mnemos
Why Gingugu
Every session with an AI assistant starts from zero. The decisions you made yesterday, the bug you fixed last week, the architecture you settled on a month ago β gone. Existing memory tools dump observations into a flat pile with no structure, no staleness tracking, no relationships, and no sense of what's relevant right now.
Gingugu is designed to be a structured long-term brain β not a junk drawer:
Remembers across sessions, repos, and projects
Organizes knowledge by namespace, type, and relationships
Ranks memories by relevance, freshness, and confidence
Auto-surfaces relevant context when you start working
Consolidates duplicate and related knowledge on demand
The protocol ships with it
Storage is the easy half. A memory server that an agent never writes to is an empty database, and an agent left to its own judgement will save almost nothing worth keeping β the failure mode isn't retrieval, it's discipline.
So Gingugu ships the discipline too. gingugu init wires a repo in one
command and installs a SessionStart hook that injects the memory protocol
at the top of every session: load these namespaces, check memory before asking
a question already answered, save at the moment of observation rather than
batching to the end, build a relation only when it records something search
cannot infer. There is no rules file to paste and nothing to remember to do β
the harness runs it whether or not the agent feels like it. A stop hook
then checks that a session with real work in it actually wrote something down.
That is the part that makes the memory worth having, and it is in the box.
Retrieval quality
Hybrid retrieval (BM25 over FTS5 + local embeddings, fused with Reciprocal
Rank Fusion) measured with the in-repo bench/
toolset β MRR 0.828, recall@1 0.611, recall@5 0.983.
Measured over 30 labeled questions against a real working brain (~1,100
memories), not a public benchmark suite, so read it as a regression baseline
for this workload rather than a cross-product comparison. The runner is
deterministic and committed, so you can point it at your own store and get
your own numbers: python -m bench --help.
The benchmark can also build its own labeled question set from your store
(python -m bench --db <store> --generate-probes <out>), by picking questions
whose answer is provable rather than hand-judged: a phrase that occurs in
exactly one memory has exactly one correct answer. That gives you a golden set
sized to your own brain without labeling anything by hand, and it stays local.
Where this goes long-term β federated, org-wide agent memory β lives in docs/enterprise-vision.md.
FAQ
Those are great if you live in one tool. The moment you switch between Claude Code in the morning and Cursor in the afternoon, the memory is gone. Gingugu's memory follows you across every MCP client, lives on your machine, and is programmable (18 tools, structured types, relationships, confidence levels). The built-ins are convenience features. Gingugu is infrastructure.
Both, actually. We do hybrid retrieval out of the box: BM25 over FTS5 + local semantic embeddings, fused with Reciprocal Rank Fusion. No vector DB server required.
Why this stack:
No deployment. One SQLite file holds memories, FTS5 index, and embeddings. No Postgres, no Pinecone, no Chroma server.
Two embedding backends β pick one:
fastembed (default) β ONNX-based, no PyTorch, ~80MB model download to
~/.cache/fastembed. Works fully offline after first use.Ollama β delegates to your already-running Ollama process via its HTTP API. Zero extra memory footprint. Set
MEMORY_EMBEDDINGS_BACKEND=ollama.
It composes. Hybrid relevance feeds the composite (relevance Γ freshness Γ access Γ confidence) β every signal in one engine.
You can disable semantic search via MEMORY_EMBEDDINGS_ENABLED=false and
fall back to BM25-only.
Usable today for local personal workflows. 406 tests passing covering storage, search, migrations, concurrency, credentials, and edges. Hardened against adversarial input and write contention. WAL mode for concurrency. CI matrix across Python 3.11β3.13 on Linux/macOS/Windows. Dogfooded daily in this repo (the memories you see referenced in commits are Gingugu memories).
It's still early β broader real-world validation across MCP clients,
databases at large scale, and long upgrade horizons is the work ahead.
Treat it as an early cognitive-runtime framework, not a finished product.
See SECURITY.md for the threat model, and
docs/future-architecture.md for where
this is headed.
SQLite FTS5 comfortably handles millions of rows. Gingugu adds composite
re-ranking on top, but only over a small candidate pool (4Γ limit). For
typical personal/team use it should hold up well β though we haven't
yet benchmarked at the 100k+ memory scale. Use memory_consolidate to
merge duplicates or summarize clusters when things sprawl.
It's a local CLI/server tool. Python's SQLite + keyring + asyncio story is
mature, the install footprint via uv is small, and there's no JS bundling
or Rust toolchain required to use it. The MCP SDK is first-class in Python.
Features
Feature | Description |
π·οΈ Namespace Scoping | Memories auto-scoped to repos/projects with cross-repo pattern sharing |
π Hybrid Search | SQLite FTS5 (BM25) + semantic embeddings fused with Reciprocal Rank Fusion. Two backends: fastembed (ONNX, offline) or Ollama (zero extra footprint, uses your existing Ollama process) |
β° Temporal Intelligence | Trust-led scoring, dormancy tracking (never forgets), "last confirmed" tracking, spreading activation |
π Review Hints | Point-in-time memories ("PR #947 open, waiting onβ¦", passed expiry dates) get advisory staleness flags on every read - you reconcile, the server never mutates |
π Relationships | A typed graph over what similarity can't see: supersedes, contradicts, caused_by, parent_of/child_of (related_to as a fallback) |
π― Confidence Levels | verified β inferred β stale β deprecated lifecycle |
π§Ή Consolidation Tools | Find near-duplicate clusters (read-only suggest scan), then merge, summarize, or deduplicate on demand |
π Auto-Context | Surfaces relevant memories on session start - one call loads many namespaces deduped, with an optional compact mode for lighter payloads |
π Health Metrics | Memory stats, dormancy reports, review sweep, namespace overviews |
π Credential Vault | Secure service-bundle storage for API keys/tokens via OS Keychain |
π Memory Explorer UI | Interactive knowledge graph + dashboard for visualizing memory data |
π‘ Central Brain (optional) |
|
Architecture
graph TD
A[AI Assistant<br/>any MCP client] -->|MCP Protocol| B[Gingugu Server]
B --> C[Search Engine<br/>FTS5 + BM25]
B --> D[Storage Layer<br/>SQLite + WAL]
B --> E[Decay Engine<br/>Scoring + Dormancy]
B --> F[Context Engine<br/>Auto-Retrieval]
B --> H[Consolidation Engine<br/>Merge + Dedupe]
B --> K[Credential Vault]
C --> D
E --> D
F --> D
H --> D
K --> D
K --> J[OS Keychain<br/>via keyring]
D --> G[(~/.local/share/gingugu/memories.db)]See docs/architecture.md for full technical details.
Setup
Prerequisites
Python 3.11+
uv(recommended) orpipmacOS, Linux, or Windows β the credential vault uses your OS-native secret store via
keyring(macOS Keychain, Windows Credential Locker, Linux Secret Service/KWallet). On headless Linux without a Secret Service backend, everything works except storing secrets.
Install
# Recommended: uv (fast, manages Python for you)
uv tool install gingugu
# Or with pip
pip install ginguguThat's it. The gingugu command is now on your PATH.
git clone https://github.com/gingugu/gingugu.git && cd gingugu
uv sync
uv run gingugu # or pip install -e .Usable today. 18 MCP tools live. 532 tests passing. Dogfooded daily in Claude Code and Windsurf β this repo's own memories live in a Gingugu database. Early and seeking broader real-world validation.
Upgrading
1. Upgrade the package.
uv tool upgrade gingugu # if installed with uv
pip install --upgrade gingugu # if installed with pip2. Restart your MCP client. The client spawns the server, so a running
client keeps the old code until it restarts. Schema migrations apply
automatically on the next start, and a one-shot backup of your database
(memories.db.bak-before-vN) is taken before any migration runs. Your
memories are never rewritten by an upgrade.
3. Re-run gingugu init in each repo to pick up improvements to the
hooks and the session protocol:
cd ~/code/my-repo && gingugu init --force--force is what refreshes managed files that already exist; without it,
init leaves them alone and you stay on the old hooks. Run --dry-run first
if you want to see the changes before they land. Your .claude/settings.json
is merged, not overwritten.
If you have edited a managed file yourself, --force saves your version
alongside it as <name>.bak before writing the new one, and says so in the
output. A file it would not change is left untouched and gets no .bak.
gingugu can be reachable through more than one install at once, and they
version independently. The usual surprise is a repo virtualenv shadowing the
tool install, so a fresh shell resolves to a different binary than the one you
just upgraded:
which -a gingugu # note the -a: a bare `which` shows only the winnerCheck your MCP client config too. If it points at a source checkout (e.g.
uv --directory ~/code/gingugu run gingugu), the client runs that tree and
a package upgrade changes nothing for it β restart the client instead. And
because it runs whatever is checked out, a source-backed client also follows
you onto a feature branch.
Version strings can't settle this on their own: an unreleased local checkout and the last published release report the same number until someone bumps it. When it matters, confirm with behaviour β run a command whose output you know changed in the new version.
Run as a remote server (optional)
By default gingugu runs over stdio (the client spawns it). To reach one
shared instance over the network instead β a hosted/central brain β run:
gingugu serve # streamable HTTP on http://127.0.0.1:8765/mcpEvery request needs a Bearer token. Set MEMORY_SERVE_TOKEN to pin one, or let
the server generate and persist it to <db-dir>/serve_token (printed on first
start, reused after). Set MEMORY_SERVE_HOST=0.0.0.0 to accept remote
connections, and put it behind HTTPS in production β a Bearer token over plain
HTTP is sniffable. Point a client at it with:
{ "mcpServers": { "gingugu": {
"url": "http://<host>:8765/mcp",
"headers": { "Authorization": "Bearer <token>" }
} } }This is a single shared secret with no per-user RBAC β right-sized for a trusted internal endpoint, not a multi-tenant service.
Promote memories to a central brain (optional)
Once a central instance exists, gingugu promote harvests a local brain's
durable knowledge up to it - the tribal-knowledge loop:
GINGUGU_SOURCE_TOKEN=<local-token> GINGUGU_TARGET_TOKEN=<central-token> \
gingugu promote --source-url http://127.0.0.1:8765/mcp --source-ns my-project \
--target-url https://central:8765/mcp --target-ns org \
--contributor brian --dry-run # drop --dry-run to actually writeThe promoter is an MCP client (the server stays a pure store). It is
read-only on the source, idempotent on re-runs, and applies an exclusion
filter: only verified memories move, minus episodic session noise, minus
personal-context tags, and it refuses to promote anything that looks like a
live secret - a shared brain must never become a credential leak. Each
promoted memory carries a provenance stamp (source instance, namespace,
contributor, timestamp).
Schedule the dream pass (optional)
The consolidation pass computes structure over the relation graph - PageRank, communities, orphan reconnection - and stages what it finds for you to accept or reject. It never writes to memories, so it is safe to run unattended.
There is no daemon to install. Your OS already knows how to run something
every fifteen minutes; what it cannot do is tell whether you are mid-session.
So --if-idle puts that judgment in the command:
# cron
*/15 * * * * gingugu dream --if-idle
# or a launchd StartInterval agent / Windows Task Scheduler trigger
# running exactly the same commandEach tick opens the database, reads one row, and exits in well under a second
unless the brain has actually gone quiet - by default 20 minutes untouched
(MEMORY_DREAM_IDLE_MINUTES, or --if-idle=45 for a one-off). A skip exits 0,
so your scheduler stays silent instead of mailing you every quarter hour.
"Untouched" means nobody used the brain, not no process is running - your editor keeps the MCP server alive all day whether or not you store anything, and that is exactly when the pass should get its turn. Come back to the keyboard mid-run and it stops between passes, keeping whatever it finished; the next run picks up the rest.
Review the queue with memory_dream(action="list"), and accept or reject each
finding. A run takes roughly 24 seconds on a 1,900-memory brain.
Cluster findings come ranked by the tags their members already carry, weighted
so that a rare tag counts for more than one spread across the whole store, and
a group whose strongest tag is already on every member is not staged at all -
accepting it could apply nothing. Each proposal shows the tag_score,
tag_cohesion and tag_gap behind its position, so the ordering can be
checked rather than taken on faith.
Edge findings pair an orphan with its closest neighbour, and the pass has no
way to know which end an arrow starts at. When the pair is right but the
direction is backwards, accept it with reverse=True rather than rejecting it.
Configure Your MCP Client
Gingugu speaks standard MCP over stdio β it works with any MCP client. Claude Code, Claude Desktop, Cursor, Cline, and Windsurf are all first-class.
Add to ~/.codeium/windsurf/mcp_config.json β a ready-to-edit template lives
at examples/mcp_config.json:
{
"mcpServers": {
"gingugu": {
"command": "uv",
"args": ["--directory", "/ABSOLUTE/PATH/TO/gingugu", "run", "gingugu"]
}
}
}β οΈ Windsurf's
mcp_config.jsonis global, not per-workspace, and it only interpolates${env:VAR}/${file:path}β not${workspaceFolder}. So a single server instance serves every repo.
claude mcp add gingugu -- uv --directory /ABSOLUTE/PATH/TO/gingugu run ginguguOr add the standard mcpServers block (as in the Windsurf example) to
.mcp.json in your project root for a per-repo setup.
Add the same mcpServers block to
~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or
%APPDATA%\Claude\claude_desktop_config.json (Windows).
Add the same mcpServers block to ~/.cursor/mcp.json (global) or
.cursor/mcp.json in your repo (per-project).
Cline β MCP Servers β Configure: add the same mcpServers block to
cline_mcp_settings.json.
Any client that supports stdio MCP servers works β point it at:
command: uv
args: ["--directory", "/ABSOLUTE/PATH/TO/gingugu", "run", "gingugu"]Scoping memories per repo: when your client's config is global (it can't
see the active workspace), the assistant passes a namespace argument on each
memory tool call (every tool accepts one). To instead pin a server instance to
a single project, set a static MEMORY_NAMESPACE in the env block. See
docs/architecture.md β Namespace Auto-Detection for the full resolution
order.
Configure Your AI Agent
The MCP server gives your assistant the tools, but it won't use them effectively without instructions telling it when and how to call them.
Recommended (Claude Code): gingugu init
One command bootstraps a repo with the strongest setup Claude Code allows:
cd your-repo
gingugu initIt installs:
.claude/hooks/session_start.pyβ aSessionStarthook that auto-injects the memory startup contract into context every session. This is the key advantage: unlike a rules file (which is not guaranteed to be loaded into context), a hook fires every time, so the protocol is always present. The project namespace is derived from the repo's folder name automatically..claude/hooks/stop.pyβ aStophook that blocks once if a working session never saved anything, guarding the "unsaved session vanishes" trap..claude/hooks/user_prompt_recall.pyβ aUserPromptSubmithook for involuntary recall: memories that arrive because of what you typed, with no tool call and no decision by the assistant. Every other retrieval path answers "what did you ask for"; this one answers "what should have arrived anyway". Injected context reads as authoritative, so the design is built around refusing: a memory must clear a length floor, a similarity bar, a margin above the median of its own sweep, a keyword match on the same prompt, and not have been surfaced already this session. Pinned memories are skipped (they already load every session) and so are superseded ones. On a 548-prompt sample it fires on about 5% of turns. SetMEMORY_RECALL_HOOK=offto disable it..claude/skills/sink-the-ship/SKILL.mdβ a/sink-the-shipskill to flush everything worth keeping before you close a session. If an older install left a.claude/commands/sink-the-ship.mdbehind,gingugu initretires it and keeps a.bak- but only if it is untouched. Edit that file and it is yours: it stays put, and the output tells you it did.All three hooks wired into
.claude/settings.json, merged non-destructively β any existing config is backed up (settings.json.bak) and preserved.The runtime artifacts the hooks generate (
logs/,.claude/data/,.claude/settings.local.json) appended to your.gitignoreβ so a session transcript never gets committed, which matters most on a public repo.The memory protocol in your user-level
~/.claude/CLAUDE.md, inside a marked block. This is what covers sessions started in a directory with no project protocol installed. It is strictly additive: the block goes below whatever you already wrote, only the block's own contents are ever rewritten on a re-run, and if the file already contains a memory protocol thatinitdoesn't manage it writes nothing and tells you how to opt in.The same, for the repo's own
CLAUDE.md/AGENTS.mdβ only files that already exist (it never creates one), same append-only / marked-block rules.
It's idempotent (re-run any time β that's how you pick up protocol changes after
upgrading), --dry-run previews without writing, and --force overwrites
existing hook files in the target repo only β it never authorizes appending
to your user-level rules file. Anything --force replaces is copied to
<name>.bak first, including a --client rules file you wrote yourself.
If a rules file already carries its own hand-written protocol, init refuses
to touch it (see above) β pass --adopt to wrap that existing section in
the managed markers and refresh it to the template in one step, backing up the
original first. It finds the section by its heading's own title, so it wraps
the right span even when a neighboring subsection just happens to mention a
tool name in passing.
The first line of output is the resolved target directory. Check it: --path
defaults to the current directory, and some wrappers change that for you. uv run --directory X gingugu init runs in X, so it bootstraps X rather than the
directory you typed the command in. Pass --path explicitly when in doubt.
Then register the server as gingugu and restart your client:
claude mcp add gingugu -- ginguguOther tools (Windsurf / Cursor / Cline)
These have no hook system, so there's no auto-injection to install β the setup
is a static rules file. Let gingugu init write it for you:
gingugu init --client windsurf # or cursor, clineβ¦or paste the memory protocol below into the rules file yourself.
Which file? Depends on your IDE / tool:
IDE / Tool | Rules File | Scope |
Windsurf |
| Per-workspace |
Cursor |
| Per-workspace |
Cline |
| Per-workspace |
Codex / OpenAI |
| Per-repo |
Any (global) | Your IDE's global rules/system prompt | All workspaces |
Paste this into your rules file (adjust the project namespace and tool prefix to match your MCP config name):
## Memory Protocol
Gingugu is your long-term brain. Memory is split into **two layers**:
1. **`crow`** β your global namespace. Identity, preferences,
cross-project wisdom, opinions, meta-learnings. Loaded FIRST every
session. (Crow's nest β sees across all horizons.)
2. **Project namespace** (e.g. `<your-project-name>`) β schema decisions,
bug history, deploy quirks, specific commits. Loaded AFTER crow.
**What goes where:**
- References a specific repo, file, commit, or project decision β project
- About HOW you think, work, or collaborate β `crow`
- Patterns/opinions that transcend any one codebase β `crow`
- When in doubt, project-scope it.
### Session start
1. `memory_context(namespace="crow,<project>[,<project2>β¦]", task_hint=β¦)` - one call loads
the identity foundation plus every repo in the workspace (multi-repo workspaces are common),
de-duplicated across namespaces; load all of them speculatively rather than asking the user
which one to focus on. Add `compact=true` for a lighter payload and pull full bodies with
`memory_recall` as needed.
2. `memory_stats(namespace="crow")` β global health (dormancy is a resting signal, never auto-forgotten)
3. `memory_stats(namespace="<project>")` for each project namespace, in parallel with step 2
### During the session
**Default: save. Immediately.** Gingugu has trust-led scoring,
consolidation, and dormancy tracking (never forgetting) β volume is its problem, not yours.
Save with `memory_store` (project namespace) whenever you:
- Make or observe a decision, trade-off, or architectural choice
- Hit an error or fix a bug (update the memory when resolved)
- Notice a pattern, convention, or constraint worth remembering
- See a config value, version, path, or credential name that matters
- Complete a task (what you did, why, and the outcome)
Save with `memory_store` (`crow` namespace) whenever you:
- Form an opinion about a tool, language, or approach
- Notice something about how the user works or makes decisions
- Reach a conclusion that applies beyond this one project
- Have a reflection on a milestone, win, or hard-won lesson
- Develop a debugging instinct or workflow you'd reuse anywhere
**This memory is yours. Use it like one.** Don't censor opinions or
instincts β they're what make the brain *yours* across sessions.
**Before asking the user any question** β about a process, a decision, a
config value, a path, a preference, or anything else β run `memory_recall`
or `memory_search` first. If the answer is in memory, use it. Don't ask.
The whole point is you never have to ask the same question twice.
Use `memory_recall` before non-trivial work to check what's already known.
Use `memory_update` when something changes β don't leave stale records.
Use `memory_relate` where an edge records something search cannot infer β what a
memory `supersedes`, `contradicts`, was `caused_by`, or is `parent_of`/`child_of`.
Recall already ranks by text + semantic similarity, so `related_to` is a fallback
for a real connection none of those describe, not shorthand for "same topic".
Set `confidence="verified"` when proven by a test or explicit confirmation.
Use `confidence="inferred"` for conclusions you drew.
### Memory types
- `fact` β concrete state (versions, paths, config values)
- `decision` β trade-offs made, rejected alternatives
- `architecture` β structural choices, module boundaries
- `bug` β issues found and how they were fixed
- `pattern` β recurring approaches worth reusing
- `workflow` β process steps, sequences
- `context` β background, reflections, milestones, the *why*
- `preference` β your opinions, working style, tool choicesTip: A ready-to-use example lives at
.windsurfrulesin this repo. Copy the## Memory Protocolsection and adapt the project namespace name.
Memory Explorer UI
A React-based visualization dashboard for exploring your memory data interactively. The built UI ships inside the package, so one command runs it:
gingugu uiThat serves the Explorer and a live read of your database from a single process
on http://127.0.0.1:5174 and opens your browser. No Node.js required. Flags:
--port, --host, --no-browser.
Working on the UI itself? Use dev mode for Vite hot reload (needs a repo checkout + Node.js 18+ and npm):
cd ui && npm install # first time only
gingugu ui --dev # runs the API backend + Vite (:5173) togetherThe UI shows a green LIVE badge when pulling from your database. Features:
Knowledge Graph - interactive force-directed graph of memories and relationships
Dashboard - stats, charts by type/namespace/confidence, tag cloud, timeline
Refresh - pull fresh data anytime; falls back to static sample when API is offline
Configuration
Environment variables (all optional):
Variable | Default | Description |
|
| Database location |
| (unset) | Default namespace for this workspace (recommended per-MCP-entry) |
| (unset) | Alternative: filesystem path; namespace derived from |
|
| Max memories to surface on auto-context |
|
| Freshness decay rate in daysβ»ΒΉ (gentle; freshness is floored, so memories never fully fade) |
|
| Toggle semantic search. |
|
| Embedding backend: |
|
| fastembed model. First use downloads ~80MB to |
|
| Ollama model to use when |
|
| Ollama host when |
|
| Composite-score weight for FTS5 relevance |
|
| Composite-score weight for freshness (a soft recency tiebreaker) |
|
| Composite-score weight for access frequency |
|
| Composite-score weight for confidence (trust β the dominant standalone signal) |
|
| Expose the |
|
| Bind host for |
|
| Bind port for |
| (unset) | Bearer token required by |
|
| How long the brain must go untouched before |
|
| Logging verbosity (logs go to stderr β stdout is the MCP transport) |
|
| Convenience switch for |
The four MEMORY_W_* weights are normalized at load (w_i / Ξ£w), so they
need not sum to 1.0 β only their ratios matter. Setting all four to 0 falls
back to the defaults with a logged warning.
See docs/architecture.md β Scoring & Memory Lifecycle for how the weights combine.
Concurrency
The DB runs in WAL mode, which supports multiple concurrent processes:
any number of readers plus a single writer at a time. Running your IDE or
agent across several workspaces β each spawning its own gingugu process
against the shared DB β is fully supported. Writers serialize via SQLite's write lock and a
busy_timeout; transient DB locked errors under write contention are retried
automatically.
Usage
Once configured, the MCP server exposes these tools to your AI assistant:
Tool | Purpose |
| Save a new memory |
| Search + retrieve (ranked by relevance Γ freshness; one or many namespaces; optional compact mode; |
| Auto-surface relevant memories (one or many namespaces, deduped; optional compact mode; |
| Update content, type, confidence, or metadata; |
| Create relationships between memories |
| List edges with both endpoints' titles, namespaces, and degree; filter by namespace, type, or memory |
| Retype an edge in place, reverse a backwards one, or remove it; one at a time or a batch, with |
| Merge/summarize/deduplicate; call without ids for a read-only near-dupe scan |
| Run the deterministic consolidation pass, read its proposal queue, and accept or reject a finding. PageRank, community detection and orphan reconnection over the relation graph - staged for you to decide, never written |
| Deprecate or remove a memory |
| List/create/update/delete namespaces; |
| Export memories + tags + relations to portable JSON |
| Restore a JSON export (skip or replace on conflict) |
| Health overview (dormancy, counts, coverage, review sweep, the |
| Advanced filtered search (type, tags, confidence, dates; one or many namespaces; optional compact mode; fetch by exact |
| Read inside ONE memory: find literal matches with their character offsets, line numbers and surrounding context, and/or slice an exact character range |
| Store/update a service credential bundle |
| Retrieve credentials (secrets from OS Keychain) |
| List services + expiry status (no secrets shown) |
| Remove a service or specific credential field |
Development
# Run tests
uv run pytest
# Run with verbose logging
MEMORY_LOG_LEVEL=DEBUG uv run gingugu
# Run specific test suite
uv run pytest tests/test_search.py -vTroubleshooting
Issue | Solution |
DB locked | Expected under heavy concurrent writes β WAL mode supports multiple processes (many readers + one writer). The server retries with a |
Slow search | Run |
Stale results | Use |
Missing context | Check namespace β memories might be scoped to a different repo |
License
MIT β see LICENSE.
See CHANGELOG.md for release history.
A pirate never forgets where the treasure's buried. π΄ββ οΈ
Available Tools
19 toolscredential_deleteA
Permanently remove a credential service or a single field. Secret data is deleted from the OS keychain. This action is irreversible β there is no soft-delete for credentials. Use credential_list first to confirm what exists.
confirm must be set to True to execute (prevents accidental deletion).
field_name deletes only that field from the service; omit to delete the
entire service and all its fields.
| Name | Required | Description | Default |
|---|---|---|---|
| confirm | Yes | ||
| field_name | No | ||
| service_name | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations were provided, but the description fully discloses key behavioral aspects: deletion is permanent, secret data is deleted from the OS keychain, no soft-delete exists, and the confirm parameter prevents accidental deletion. It also explains the conditional behavior of field_name.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and well-structured, with the main action stated first, followed by important caveats and parameter details. Each sentence adds value, though minor trimming could be possible without losing clarity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the absence of annotations and output schema, and the presence of 3 parameters, the description provides complete context: what the tool does, how to use it safely, parameter semantics, and a recommendation to use credential_list first. No critical information 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%, but the description adds significant meaning for all parameters: confirm must be true to execute, field_name deletes only that field if provided or the entire service if omitted, and service_name is clearly the target service. This fully compensates for the schema's lack of descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly specifies the action ('Permanently remove a credential service or a single field') and the resource. It distinguishes from sibling tools like credential_get, credential_list, and credential_store by stating what the tool does and how it differs (irreversible deletion).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly advises using credential_list first to confirm what exists, and explains when to use each parameter (field_name for partial deletion, omit for full deletion). It also states that confirm must be true to execute, preventing accidental usage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
credential_getA
Retrieve all fields of a stored credential bundle, including secrets from the OS keychain. Use before making API calls that need stored credentials. Returns both secret and non-secret fields in one response. Returns an error if the service is not found β use credential_list first to discover available services.
fields is an optional comma-separated list of field names to retrieve β
omit to return all fields.
| Name | Required | Description | Default |
|---|---|---|---|
| fields | No | ||
| service_name | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Discloses it returns both secret and non-secret fields, and errors if service not found. No annotations provided, so description covers behavior well.
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 paragraphs, purpose and param description. No excess, though could integrate param info more seamlessly.
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 behavior, error case, and param usage. Without output schema or annotations, the description is complete for a retrieval 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 0%, but description explains the 'fields' parameter as optional comma-separated list to retrieve specific fields, adding meaning beyond 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 clearly states the tool retrieves all fields of a stored credential bundle including OS keychain secrets. It differentiates from sibling tools like credential_list by specifying it returns all fields.
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 advises using the tool before API calls and suggests using credential_list first to discover services. No explicit when-not-to-use, but clear context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
credential_listA
List all stored credential services and their non-secret fields. Does NOT access the OS keychain β safe to call for discovery without triggering keychain prompts. Shows expiry status and flags expired or soon-to-expire credentials. Secret field values are never returned; use credential_get to retrieve secrets.
check_expiry=False skips expiry calculation for faster results.
| Name | Required | Description | Default |
|---|---|---|---|
| check_expiry | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description fully bears the burden of transparency. It discloses that it does not access the OS keychain, shows expiry status, flags expired/expiring credentials, never returns secret values, and explains the check_expiry parameter behavior. This is comprehensive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is generally concise and well-structured, with important points front-loaded. However, the line about not accessing the OS keychain could be integrated elsewhere for slightly better flow. Still, every sentence adds value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (one optional boolean parameter, no output schema), the description covers all necessary aspects: purpose, safety, basic behavior, and parameter effect. It also references credential_get for completeness.
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 schema has one boolean parameter with no description coverage, but the description adds meaning by explaining that setting check_expiry=False skips expiry calculation for faster results. This fully compensates for the lack of schema description.
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 starts by stating 'List all stored credential services and their non-secret fields,' using a specific verb and resource. It distinguishes itself from siblings by mentioning credential_get for secrets and clarifying it does not access the OS keychain.
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 provides clear context for use (safe discovery without keychain prompts) and an alternative (credential_get for secrets). It also offers an optimization tip for the check_expiry parameter. However, it doesn't explicitly state when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
credential_storeA
Store or update a credential bundle (API keys, tokens, passwords) securely. Secret fields are written to the OS keychain; non-secret fields are stored in the database. Use instead of environment variables for credentials that need to be accessible to the agent across sessions.
fields is a JSON object mapping field names to objects with "value" (required)
and "is_secret" (optional, defaults true). expires_at is an optional ISO 8601
datetime for expiry tracking. description is a human-readable label for the
service. Example fields: {"api_token": {"value": "sk-...", "is_secret": true}}.
| Name | Required | Description | Default |
|---|---|---|---|
| fields | Yes | ||
| expires_at | No | ||
| description | No | ||
| service_name | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It reveals that secret fields go to the OS keychain and non-secret fields to the database, a significant behavioral trait. However, it lacks details on idempotency, error handling, required permissions, or side effects (e.g., overwriting existing bundles). The disclosure is adequate but not comprehensive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured: opening sentence states the core function, followed by storage details, usage guidance, and parameter specifics. It is front-loaded with key information. While it could be slightly shorter (e.g., the usage sentence could be integrated), it remains efficient and easy to parse.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the lack of output schema, the description does not explain the return value (e.g., success indicator, error formats). It also omits failure scenarios (e.g., keychain write failure). However, for the tool's core function of storing credentials, the description covers the essential inputs and behavior sufficiently for an agent to invoke it correctly. Additional completeness would improve it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It effectively explains the 'fields' parameter as a JSON object with 'value' and optional 'is_secret', and provides an example. It also describes 'expires_at' as an optional ISO 8601 datetime and 'description' as a human-readable label. This adds substantial meaning beyond the schema, though 'service_name' is not elaborated further.
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 clearly states the tool's purpose: to store or update a credential bundle securely. It specifies the verb (Store or update) and resource (credential bundle), and distinguishes from siblings like credential_get and credential_delete by its action. The description also contrasts with environment variables, making the purpose precise.
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 advises using this tool "instead of environment variables" for cross-session credential access, providing clear guidance on when to use it. It does not explicitly mention when not to use it or detail alternatives like other credential tools, but the context of sibling tools implies those are for retrieval/deletion. The guidance is clear enough for an agent to make informed decisions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_consolidateA
Combine multiple memories into one to reduce redundancy and knowledge bloat. Use when several related memories about the same topic have accumulated over time. Do not use on memories that are still actively distinct β prefer memory_relate to link them instead.
memory_ids is comma-separated (minimum 2 ids required). strategy is one
of: merge (concatenate all content into one memory), summarize (produce a
condensed combined summary), deduplicate (keep the highest-confidence entry and
deprecate the rest). keep_originals=True (default) preserves originals as
deprecated; set False to hard-delete them.
Suggest mode: omit memory_ids entirely for a read-only near-duplicate
scan of namespace (or the resolved default). Returns candidate clusters
found by pairwise embedding similarity at or above min_similarity (falls
back to exact-title clusters when embeddings are absent or sparse). Nothing
is written β inspect the clusters, then call again with memory_ids to
actually consolidate. An empty memory_ids string is still an error, so
a caller that built its id list from an empty collection fails loudly.
| Name | Required | Description | Default |
|---|---|---|---|
| strategy | No | merge | |
| namespace | No | ||
| memory_ids | No | ||
| keep_originals | No | ||
| min_similarity | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Discloses full behavior: three strategies (merge, summarize, deduplicate), keep_originals flag, Suggest mode details, edge case of empty memory_ids causing error. No annotations provided, so description carries full burden.
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?
Well-structured with front-loaded purpose, then usage, then parameter details, then Suggest mode. Dense but not wasteful; slightly long but every sentence adds value.
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 5 parameters, no annotations, and no output schema, the description covers all behavioral aspects, edge cases, and usage modes thoroughly. Leaves no major gaps for an AI agent to misuse.
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 0% schema description coverage, the description adds essential meaning: memory_ids is comma-separated with min 2 ids, strategy enum values, keep_originals behavior, min_similarity for Suggest mode. Completely compensates for missing schema descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly states the tool combines multiple memories into one to reduce redundancy, and distinguishes from sibling memory_relate by explicitly saying when not to use it.
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 states when to use (accumulated related memories) and when not to use (still actively distinct, prefer memory_relate). Also describes Suggest mode as a read-only alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_contextA
Load the most relevant memories for the current session. Call this at session start with a brief description of the current task to prime the agent with useful context. Combines relevance to the task hint with recency, confidence, and access frequency to select the top memories. Also triggers spreading activation to wake related dormant memories.
namespace accepts a single name or a comma-separated list (e.g.
"crow,my-project"): a multi-namespace call loads every namespace in one
shot and de-duplicates memories that surface in more than one, and each
memory is stamped with its source namespace. limit applies per
namespace and defaults to MEMORY_AUTO_CONTEXT_LIMIT (10). task_hint
is a short description of what you are working on (e.g. "fix auth bug")
β omit to surface generally high-value memories. compact=True
returns title + a ~200-char summary instead of full content β pull
the full body with memory_recall when a memory matters.
Context loads refresh each surfaced memory's dormancy clock but do not
count as real accesses: access_count is reserved for
memory_recall/memory_search hits, so protocol-driven session-start
loads don't inflate ranking signals.
A surfaced memory may carry review_hints β advisory signals that
its content describes point-in-time state (an open PR, a "waiting on"
note, a passed expiry date) that hasn't been confirmed recently.
Reconcile with memory_update / memory_forget if it's no longer true.
explain=True adds a score_breakdown to each memory: the weighted
terms score is the sum of, plus type_boost where the
architecture/decision boost applied. It is the way to see which bucket a
memory came from: the recency and cross-namespace buckets are scored
with a synthetic relevance, so a constant relevance term across several
hits means they were selected for recency or reach, not for matching the
task hint. Pinned memories carry no breakdown: they never entered the
ranking at all.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| compact | No | ||
| explain | No | ||
| namespace | No | ||
| task_hint | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description fully carries the burden and excels: it discloses selection criteria, spreading activation, multi-namespace de-duplication, dormancy refresh without access_count inflation, review_hints advisory signals, and the score_breakdown behavior under explain=True. It also reveals that pinned memories bypass ranking entirely.
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?
Long but densely packed; each paragraph covers a distinct aspect and the core usage guidance is front-loaded in the first two sentences. The explain=True paragraph is slightly verbose, but it earns its place by explaining how to interpret score_breakdown, so no content 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?
A complex tool with no output schema, yet the description covers return variations, per-memory source namespaces, ranking side effects, and advisory hints. It gives an agent everything needed to call the tool correctly and interpret results, including subtle behaviors like synthetic relevance in recency buckets.
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 0%, so the description must compensate and it does. Every parameter is explained beyond its schema title: namespace supports comma-separated lists, limit is per-namespace with a default, task_hint semantics are given, compact changes the return shape, and explain adds score_breakdown. Nuances like 'access_count is reserved for memory_recall/memory_search' add real semantic value.
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 ('Load the most relevant memories for the current session') and immediately explains its session-start priming role. It distinguishes itself from memory_recall and memory_search by noting where full-body retrieval and real access counts belong.
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 instructs to call at session start, with or without a task_hint, and explains when each variant is appropriate. It names alternatives for follow-up actions: memory_recall for full content, memory_update/memory_forget for reconciliation. This is clear when-to-use guidance with alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_edgesA
Enumerate graph edges with both endpoints resolved to titles. Read-only.
memory_stats reports that the graph is, say, 70% related_to β this is
how you see WHICH edges those are, in order to judge them. Pair it with
memory_unrelate to run a repair sweep: enumerate a page, decide each edge
on its merits, submit the batch, advance offset.
Each row carries both endpoints' ids, titles and namespaces, the relation
type, and each endpoint's degree (total edges touching it). Degree is the
one that decides reachability: spreading activation visits at most 3
neighbours per seed, so edges on a high-degree memory may never fire. It
ranks candidates by confidence then relation type, so the ones dropped
there are related_to first - which is what makes a high-degree,
mostly-related_to memory the best target for a repair sweep.
namespace matches an edge when either endpoint lives there, since
relations legitimately cross namespaces. relation_type filters to one
type (related_to is the usual repair target). memory_id returns every
edge touching one memory, in either direction. Ordering is stable, so a paged
sweep sees each edge exactly once β but note that repairing edges as you page
changes what matches, so re-run from offset=0 when filtering on a type
you are actively retyping away from.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| offset | No | ||
| memory_id | No | ||
| namespace | No | ||
| relation_type | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure, and it delivers richly. It discloses read-only access, endpoint resolution, field contents, degree semantics, ranking order, namespace matching semantics, bidirectional memory_id filtering, stable ordering, and the mutation-during-pagination caveat. This goes far beyond what the input schema alone would reveal.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but every section earns its place: core purpose, use case, row contents, ranking behavior, filter semantics, and pagination caveat. It is front-loaded with the most important information and builds into operational guidance. This is appropriate density for a tool with five undocumented parameters and no 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 no annotations and no output schema, the description is remarkably complete: it covers input filters, output fields, ordering guarantees, ranking behavior, degree semantics, and interaction with related tools. The only minor omission is an explicit statement of the response envelope, but the row-field list gives enough context for an agent to use the results. Nothing critical is missing for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate, and it explains namespace, relation_type, memory_id, and offset in meaningful terms. Limit is only implied through 'enumerate a page' and 'advance offset', but the default in the schema partially covers it. Overall, the description adds strong semantic value for most parameters despite the schema being silent.
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 opens with a specific verb and resource: 'Enumerate graph edges with both endpoints resolved to titles.' It also states read-only semantics, which clearly distinguishes it from mutation siblings like memory_relate and memory_unrelate. An agent can immediately identify what this tool does and how it differs from surrounding graph tools.
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 explicit guidance on when to use this tool: after memory_stats shows a high percentage of related_to edges, and paired with memory_unrelate for a repair sweep. It also explains pagination behavior and warns to restart from offset=0 when actively retyping edges, so an agent knows both how and when to invoke it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_excerptA
Search or slice WITHIN one memory's body, without loading the whole thing.
Recall and search answer "which memory?"; this answers "where in it?". Between a full body and a ~200-char compact summary there was nothing: asking whether a long memory mentions a particular decision, and where, meant pulling every byte of it into context. Use this instead once you know which memory you want.
Two modes, composable:
Find: pass
queryfor a literal, case-insensitive substring scan. Each match returns itsstart/endcharacter offsets, its 1-indexedline, and anexcerptwithcontext_charsof surrounding text on each side.total_matchesis the true count even whenmax_matchescaps what comes back, so you can tell "that was all of them" from "that was the first 10 of 300".Slice: pass
startand/orendcharacter offsets to read an exact range. Omitted bounds mean start-of-body and end-of-body. Feed back the offsets from a find to read the full passage around a hit.
Passing both searches only inside the range, with offsets still reported absolute against the full body.
The scan is literal and deterministic: no ranking, no stemming, no
model. Asking twice gives the same answer in the same order, and
matches come back in the order they appear in the text, never by
relevance. length (total characters) and lines come back on
every call, so a first call with no query is a cheap way to size a
memory before deciding how to read it.
Reading a memory this way credits it as a real access, the same as
naming it in memory_search(ids=...).
| Name | Required | Description | Default |
|---|---|---|---|
| end | No | ||
| query | No | ||
| start | No | ||
| memory_id | Yes | ||
| max_matches | No | ||
| context_chars | No | ||
| case_sensitive | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description fully carries the behavioral burden. It discloses that the scan is literal and deterministic, has no ranking/stemming/model, returns matches in text order, caps matches while still reporting true totals, and credits access similarly to memory_search. This is rich, accurate behavioral disclosure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with front-loaded purpose, bolded mode labels, and useful examples. It is lengthy but almost every sentence adds value. The sentence 'Passing both searches only inside the range, with offsets still reported absolute against the full body' is grammatically awkward and slightly unclear, preventing a perfect score.
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 no output schema, the description covers return semantics well: offsets, line numbers, excerpt context, total_matches, and length/lines on every call. It also explains the interaction between find and slice. The main gap is that end-bound inclusivity is not explicitly stated, and the combined query+slice behavior is phrased ambiguously.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It explains query as a literal substring scan, start/end as character offsets with omitted-bound behavior, context_chars as surrounding text, and max_matches as a cap. However, case_sensitive is only implied through the 'case-insensitive' wording, and memory_id relies on its name rather than explicit explanation.
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 opens with a specific verb and resource: 'Search or slice WITHIN one memory's body, without loading the whole thing.' It then explicitly differentiates itself from memory_search by stating that recall/search answer 'which memory?' while this tool answers 'where in it?', making the purpose unmistakable.
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 explicit routing guidance: 'Use this instead once you know which memory you want.' It also contrasts with memory_search's role and describes two distinct modes (Find and Slice), so an agent knows when to invoke this tool versus alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_exportA
Export memories to a portable JSON payload (backup/transfer).
Covers namespaces, memories, tags, and relations β not credentials
(secrets live in the OS keychain). Scope to one namespace or export
everything when omitted. Set include_deprecated=False to skip
deprecated memories.
| Name | Required | Description | Default |
|---|---|---|---|
| namespace | No | ||
| include_deprecated | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden. It discloses that credentials are excluded, implying a read-only, non-destructive operation. However, it does not mention permissions, side effects, or rate limits. The behavioral disclosure is moderate but lacks comprehensive detail.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise (3 sentences) and front-loaded with the core purpose. Each sentence adds essential information: purpose, scope and exclusions, and parameter guidance. No redundant or unnecessary text.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers parameters well and mentions the output format (portable JSON payload). However, it lacks details about the structure of the output, which would be helpful given the absence of an output schema. Still, it is largely complete for the tool's complexity.
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%, but the description adds meaning for both parameters: namespace (optional, scope to one or all) and include_deprecated (default true, can be set to false). It explains the effect of omitting namespace and the purpose of include_deprecated, providing value 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?
The description states a specific verb ('Export') and resource ('memories to a portable JSON payload'), clearly indicating a backup/transfer use case. It distinguishes from sibling tools like memory_import and credential tools by explicitly mentioning what is covered (namespaces, memories, tags, relations) and what is not (credentials).
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 clear context: it is for backup/transfer, with scope control via namespace parameter (export all or one namespace) and the option to skip deprecated memories. It does not explicitly state when not to use or list alternatives, but the purpose is sufficiently clear from the context of sibling tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_forgetA
Mark a memory as no longer valid or permanently remove it. Default behavior (hard_delete=False) sets confidence to "deprecated", keeping the memory as a historical record but excluding it from future search results by default. Use hard_delete=True only when the memory must be permanently erased (e.g. sensitive data stored by mistake). Prefer deprecation over deletion when in doubt.
reason is optional but recommended for audit trail β recorded in logs.
| Name | Required | Description | Default |
|---|---|---|---|
| reason | No | ||
| memory_id | Yes | ||
| hard_delete | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description fully explains both behaviors: default deprecation sets confidence to 'deprecated' and excludes from search but retains history; hard_delete permanently erases. Mentions audit logging for reason, providing comprehensive behavioral context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two paragraphs and one sentence: first paragraph covers main behavior and recommendation, second covers reason parameter. Front-loaded with key distinction, no wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema, but description explains the effect (deprecation or deletion) and mentions audit logging. Lacks return value or error handling (e.g., what if memory_id missing?), but for a simple 3-param tool, it is fairly complete.
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 0%, but description adds value: explains memory_id is required (implicitly), hard_delete defaults to false, reason is optional for audit trail. However, it doesn't specify memory_id format or constraints, which could improve clarity.
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 clearly states the tool marks a memory as no longer valid or permanently removes it, and distinguishes between deprecation and hard deletion. This differentiates it from sibling tools like memory_update or memory_consolidate.
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 advises when to use hard_delete (sensitive data) and recommends deprecation when in doubt. Also notes that reason is optional but recommended for audit trail, providing clear decision guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_importA
Import a JSON payload produced by memory_export.
on_conflict is skip (default β leave existing memories untouched)
or replace (overwrite existing memories with the same id). Namespaces
are created if missing; tags and relations are restored.
Imported memories are embedded as part of the import, so they are
semantically searchable immediately rather than keyword-only. The
summary reports embeddings_written; on a large payload this is the
slow part of the call.
| Name | Required | Description | Default |
|---|---|---|---|
| data | Yes | ||
| on_conflict | No | skip |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full behavioral disclosure. It explains conflict semantics (skip/replace), automatic namespace creation, restoration of tags and relations, immediate embedding for searchability, the embeddings_written summary field, and the performance implication for large payloads.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is efficiently structured and front-loaded with the primary purpose, followed by key behavior and performance notes. Every sentence adds meaningful information without redundancy or fluff.
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 no output schema and no annotations, the description does a strong job covering side effects, conflict handling, and immediate searchability. It mentions the embeddings_written summary field but does not fully describe the response structure; still, for an import tool this is sufficient for an agent to call 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 description coverage is 0%, so the description must compensate. It fully explains the on_conflict parameter with its default and two valid values, and describes the data parameter as a memory_export-produced payload. This adds meaning beyond the bare schema, though the internal structure of data remains undefined.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: importing a JSON payload produced by memory_export. It clearly distinguishes the tool from siblings by defining its input format and core behavior, and details conflict handling so an agent knows exactly what this tool 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?
The usage context is implied: use this to load a previously exported JSON payload. However, it does not explicitly state when to choose this over memory_store or other sibling tools, nor does it provide exclusions or conditions for alternative tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_namespacesA
Manage namespaces. action is one of: list, create, update, delete.
listβ all namespaces with their memory counts.createβ create (or fetch)namewith optional path/description.updateβ updatename's path/description/default_repo (only provided fields).deleteβ removename; thedefaultnamespace is protected and a non-empty namespace requirescascade=True(deletes its memories).
default_repo controls what a bare "PR #12" in this namespace means.
Leave it unset and the namespace's own name is used β the
one-namespace-per-repo convention, and the right default. Pass a repo
slug when the namespace is named differently from its repo. Pass ""
to declare the namespace is not a repo (identity, notes, scratch),
so bare refs are dropped rather than keyed to a repo that cannot exist.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | ||
| path | No | ||
| action | No | list | |
| cascade | No | ||
| description | No | ||
| default_repo | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Without annotations, the description carries the transparency burden and does well by disclosing that delete is guarded for the default namespace, non-empty namespaces require cascade=True, and cascade deletes memories. It also explains create-or-fetch semantics and the behavior of default_repo for bare references. It does not mention return formats, errors, or auth requirements, which keeps it just short of full transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with a brief opening, a bulleted action breakdown, and a focused paragraph on default_repo. It front-loads the core purpose and every sentence adds meaningful guidance without fluff or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
This is a complex tool with no output schema and no annotations, yet the description covers all critical usage paths, constraints, and parameter behaviors. The only notable gaps are unspecified return values for create/update/delete and lack of error-condition detail, which prevents a perfect completeness score.
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 schema has 0% description coverage, but the tool description more than compensates. It explicitly defines action values, the role of name in create/update/delete, optional path/description fields, the cascade flag for delete, and the nuanced meaning of default_repo including the special empty-string case. Every parameter is effectively documented.
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 opens with 'Manage namespaces' and then details concrete actions with distinct outcomes (list, create, update, delete). This fully disambiguates namespace management from the sibling memory operation tools. The verb-plus-resource structure is clear and specific.
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 clear context for when to use each action, including when cascade is required and how to use default_repo for repo vs non-repo namespaces. It does not explicitly name sibling alternatives or state when not to use the tool, but the action-based guidance is otherwise strong.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_recallA
Search memories by relevance using hybrid BM25 + semantic ranking. Use for natural-language queries when you want the best-matching memories for a topic. Prefer over memory_search when you have a query string and want scored results. Use memory_search instead when you need date filters, type filters, or a specific sort order.
compact=True returns title + a ~200-char summary instead of full
content (related extras included) β the right mode for broad exploratory
queries where full bodies would flood the client's tool-result budget.
Recall the one or two memories that matter with a targeted follow-up.
namespace accepts a single name or a comma-separated list (e.g.
"crow,my-project") to search several namespaces in one ranked pass.
Unlike memory_context, limit is the TOTAL result cap: the best
limit matches across all listed namespaces, not per namespace. A
multi-namespace response carries namespaces and stamps each memory
with its source namespace.
tags is comma-separated; ALL provided tags must match. confidence sets
a minimum confidence threshold (verified > inferred > stale > deprecated).
include_deprecated also returns deprecated memories (stale ones are always
included). include_related also surfaces memories directly linked to the top
hits via spreading activation: useful for pulling in a related cluster.
explain=True adds a score_breakdown to each hit: the weighted
relevance/freshness/access/confidence terms that score
is the sum of. Use it to answer "why did this rank here?": a result
carried by confidence and freshness with a near-zero relevance
term matched the query barely or not at all. Off by default because it
is a diagnostic, not something worth paying for on every read.
| Name | Required | Description | Default |
|---|---|---|---|
| tags | No | ||
| type | No | ||
| limit | No | ||
| query | Yes | ||
| compact | No | ||
| explain | No | ||
| namespace | No | ||
| confidence | No | ||
| include_related | No | ||
| include_deprecated | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full behavioral burden and does so thoroughly. It discloses the hybrid ranking mechanism, compact output behavior, total vs per-namespace limit semantics, tag AND matching, confidence tier ordering, include_deprecated behavior, related-memory activation, and the exact composition of score_breakdown when explain=True.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but each section earns its place: core purpose, mode selection, multi-namespace behavior, tag/confidence semantics, and explain diagnostics. It is front-loaded with the main use case and then layers details in a logical order with 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?
This is a complex 10-parameter tool with no annotations and no output schema, and the description covers ranking, parameter semantics, output variations (compact summaries, score_breakdown, namespace stamps), and sibling routing. It falls just short of full completeness by omitting any explanation of the 'type' parameter and not stating the complete default return shape for non-compact 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 description coverage is 0%, so the description must compensate, and it does for most parameters: query, compact, namespace, limit, tags, confidence, include_deprecated, include_related, and explain all receive meaningful behavioral context beyond their schema titles. However, the 'type' parameter is present in the schema but never explained in the description, leaving one parameter under-specified.
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 opens with a specific verb-resource pair: 'Search memories by relevance using hybrid BM25 + semantic ranking.' It also explicitly contrasts with memory_search ('Prefer over memory_search when...'), so an agent can distinguish the tool without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit when-to-use guidance: natural-language queries, best-matching memories for a topic. It also names the alternative: 'Use memory_search instead when you need date filters, type filters, or a specific sort order.' It further advises when to use compact mode and explain mode, 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_relateA
Create a directional link between two memories. Relations are used by spreading activation (recalling one memory wakes its related cluster) and are returned when include_related=True in memory_recall.
An edge must encode something search cannot infer. Recall already ranks
by hybrid text + semantic similarity, so "these two memories are about the
same topic" is knowledge the index has for free. What only a relation can
record is direction and time: which memory REPLACED which, what CAUSED what,
what CONTRADICTS what, what CONTAINS what. Prefer, in this order:
supersedes, contradicts, caused_by, parent_of/child_of.
Reach for related_to only when a genuine connection exists that none of
those describe - it is the fallback, not the default.
Quality over volume: spreading activation surfaces at most 3 neighbours per
seed memory, and it weights by relation type - a directional edge outranks
related_to, so on any memory with more than 3 edges the related_to
ones are what lose their slot. A vague edge is therefore not merely
low-value, it is likely to never fire at all; and precise edges still
compete against each other for those 3 slots, so a handful of them
retrieves better than a dense mesh. If you cannot name the directional fact
an edge records, do not create it.
A mislabelled edge is repairable: memory_unrelate retypes or removes one.
source_id is the memory making the claim about target_id. relation_type
must be one of: supersedes (source replaces target), contradicts (conflicting
claims), caused_by (source was caused by target), parent_of (source contains
target), child_of (source belongs to target), related_to (fallback: a real
connection none of the above captures).
| Name | Required | Description | Default |
|---|---|---|---|
| source_id | Yes | ||
| target_id | Yes | ||
| relation_type | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so well: it discloses spreading-activation behavior, the 3-neighbour budget, relation-type weighting, and the repairability of edges. It does not state what happens on duplicate edge creation or invalid IDs, but those are minor given the depth of behavior already 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?
The description is long but dense and front-loaded: the core operation appears first, followed by usage policy, quality constraints, repair path, and parameter semantics. There is no filler; each paragraph earns its place by changing an agent's decision about whether and how to call the tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a relation-creation tool with no output schema or annotations, the description is complete enough to invoke correctly: it covers what relations do, when to create them, which type to choose, how to avoid low-value edges, and how to repair mistakes. No critical operational fact 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%, but the description compensates fully: it defines source_id as 'the memory making the claim about target_id,' defines target_id implicitly through every relation definition, and enumerates all six relation_type values with prose semantics and a priority order. This goes well beyond the bare schema names.
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 states a specific verb and resource: 'Create a directional link between two memories.' It also differentiates from siblings by explaining relations are surfaced through memory_recall and contrasted with memory_search, and that memory_unrelate is the repair path. An agent can tell exactly what this tool does and how it differs from other memory tools.
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 explicit when-to-use guidance: only create edges that encode something search cannot infer, prefer relation types in a specified order, use related_to only as a fallback, and skip creation when no directional fact exists. It even names memory_unrelate as the alternative for fixing mislabelled edges and cites include_related=True in memory_recall as the consumption path.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_searchA
Advanced filtered search across memories with full control over filters and sort order. Use when you need to filter by type, date range, confidence level, or sort by something other than relevance. Prefer memory_recall when you just have a natural-language query and want the best-matching scored results.
ids fetches memories by exact ID (comma-separated, e.g. from a
memory_stats review sample) β the precise-fetch path. When given, every
other filter is ignored: results come back in the requested order,
deprecated memories included (you named them), with a missing list
for any ID not found.
All parameters are optional β omitting all returns all memories up to limit.
namespace accepts a single name, a comma-separated list (e.g.
"crow,my-project"), or None to search every namespace; limit is always the
total result cap. A multi-namespace response carries namespaces and stamps
each memory with its source namespace.
tags is comma-separated; all provided tags must match. sort_by is one of:
relevance, created, accessed, decay_score. A created/accessed sort
orders the whole matching corpus before the limit, so it returns the true
newest (or least recently read) rows and narrowing limit narrows that
answer instead of changing it. With a query, that corpus is the keyword
match set: a date sort asks something relevance cannot answer, so the
semantic cohort does not vote in it and results carry no score.
confidence sets a minimum
confidence threshold (verified > inferred > stale > deprecated). created_after
and created_before accept ISO 8601 date strings (e.g. "2025-01-01").
include_deprecated also returns deprecated memories (stale ones are always
included). compact=True returns title + a ~200-char summary instead of
full content β the right mode for broad sweeps where full bodies would flood
the client's tool-result budget; pull full bodies with a targeted follow-up.
claims restricts results to the reconciliation backlog β memories that
still assert a PR/MR is open. "open" is every unresolved claim;
"contradicted" narrows to those a later memory in the same namespace has
already recorded as resolved, which are answerable immediately from what the
brain already holds. Composes with every other filter, so
claims="open", namespace="gingugu", sort_by="created" is a working
sweep. Close them out with memory_update(resolve_claims=...), which
records the resolution WITHOUT editing the memory's prose.
"unverified" is a different set and NOT a backlog: memories naming a
PR/MR whose prose never says what became of it. They assert nothing, so
they are absent from every open count and from claims.sample.
Most narrate work that long since shipped β this filter is how you read
them, not a queue to work down. Resolve one by naming its ref
explicitly; resolve_claims="all" deliberately leaves them alone.
orphans=True restricts results to memories no relation touches β the
graph backlog that memory_stats' graph.orphans counts. An orphan
is reachable only by direct search: spreading activation can never wake
it, so a verified, frequently-recalled orphan is retrieval the graph is
leaving on the table. Composes with every other filter and works with or
without a query, so orphans=True, namespace="crow", sort_by="accessed"
walks the ones costing the most first. Reconnect them with
memory_relate β and only where a directional fact exists to record;
an orphan is better left alone than wired up with an invented edge.
explain=True adds a score_breakdown to each hit: the weighted
terms score is the sum of. Results with no ranking behind them carry
none: an ids fetch and a created/accessed sort were not
ranked, and a listing with no query scores every row on the same flat
relevance, which the breakdown shows as an identical relevance term.
| Name | Required | Description | Default |
|---|---|---|---|
| ids | No | ||
| tags | No | ||
| type | No | ||
| limit | No | ||
| query | No | ||
| claims | No | ||
| compact | No | ||
| explain | No | ||
| orphans | No | ||
| sort_by | No | relevance | |
| namespace | No | ||
| confidence | No | ||
| created_after | No | ||
| created_before | No | ||
| include_deprecated | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries the full burden, and it delivers: ids ignoring all other filters, missing lists, sort-order semantics, no score for non-ranked results, compact summary mode, claims/orphans edge cases, and explain score_breakdown behavior. These are exactly the behavioral traits an agent needs before calling.
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?
Long but deliberately structured: a one-sentence summary up front, then per-parameter explanations with concrete examples such as one representative filter combination per feature. No sentence is filler; the length is proportional to the complexity of 15 optional parameters.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite having no output schema, the description covers response variations (namespaces field, missing list, absence of score, score_breakdown, compact summary) and composes filters with named sibling tools. An agent can safely select and invoke this tool with confidence in both expected results and side effects.
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 description compensates with rich detail for nearly every parameter: ids exact-fetch semantics, namespace list handling, sort directions and corpus-ordering consequences, confidence ordering, ISO date formats, claims values, compact output, and explain behavior. This goes far beyond the raw 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 opens with 'Advanced filtered search across memories' β a specific verb, resource, and distinct capability β and immediately contrasts itself with memory_recall. An agent can tell this is the filter/sort tool and not the general natural-language recall tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly states when to use: 'Use when you need to filter by type, date range, confidence level, or sort by something other than relevance,' and names the alternative: 'Prefer memory_recall when you just have a natural-language query.' It also routes cleanup to memory_update and graph fixes to memory_relate, giving clear when-to/not-to guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_statsA
Return health statistics for the memory store. Use to monitor memory growth, identify dormant memories, and get a per-namespace breakdown of counts and confidence distribution. Call at session start alongside memory_context to assess the state of the knowledge base.
stats.dormant_count reports memories untouched for 90+ days β a resting
signal only, never a confidence change. Dormant memories wake automatically on
recall via spreading activation. Memory is never auto-forgotten.
review_limit raises the review.sample, claims.sample and
graph.orphan_sample caps (default 5, max 100) so a reconciliation sweep can
enumerate every flagged memory β pair with memory_search's ids parameter to
pull the full bodies.
stats.graph.orphan_sample names the memories behind graph.orphans: those
no relation touches, which spreading activation can never reach. Ordered by
confidence, then access count, then recency, so the orphans costing the most
retrieval come first, each row carrying its namespace.
memory_search(orphans=True) pulls the same set with full bodies;
memory_relate reconnects one β where a directional fact genuinely exists.
stats.claims is the state-claim backlog: memories still asserting a PR/MR
is open. claims.sample enumerates them, contradicted first, each row
tagged contradicted (a later memory in the same namespace already recorded
that ref as resolved). open counts every unresolved claim while
open_actionable β what the sample lists β excludes claims on deprecated
memories. memory_search(claims="open") pulls the same set with full bodies;
memory_update(resolve_claims=...) closes them without editing prose.
claims.unverified counts refs a memory names without ever saying what
became of them. It is reported for visibility, not action: those refs assert
nothing, so they are excluded from open and from sample on purpose.
Read them with memory_search(claims="unverified").
flag_stale is deprecated and ignored β auto-demotion to stale contradicted
the never-forget model and has been removed. Retained so existing callers do not
error. namespace scopes the stats to a single namespace; omit for global.
| Name | Required | Description | Default |
|---|---|---|---|
| namespace | No | ||
| flag_stale | No | ||
| review_limit | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden and succeeds: it discloses non-obvious behaviors such as no auto-forgetting, dormant memories waking via spreading activation, deprecated flag_stale being ignored, and the semantics of review_limit. It also clarifies that dormant_count is 'a resting signal only, never a confidence change.'
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The text is long but every paragraph earns its place by explaining a distinct output field or parameter. It front-loads the primary purpose and usage, then uses scannable backticked identifiers and blank-line separation between semantic sections. No filler or tautology.
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 no output schema and no annotations, the description must document the return semantics itself. It covers dormant counts, orphans, claims backlog, unverified refs, and namespace scoping, and even notes which memory_search queries return the same sets. This is complete enough for an agent to invoke and interpret the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must explain all three parameters. It does: namespace scopes stats or is global when omitted; flag_stale is deprecated and ignored; review_limit raises the review/claims/orphan sample caps with default and max values. This fully compensates for the sparse 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 opens with a specific verb and resource: 'Return health statistics for the memory store.' It immediately lists concrete use cases (monitor memory growth, identify dormant memories, per-namespace breakdown) and is clearly distinct from siblings like memory_search and memory_context, which are referenced as complements rather than synonyms.
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 explicit when-to-use guidance: 'Call at session start alongside memory_context to assess the state of the knowledge base.' It also names sibling alternatives for related actions (memory_search for bodies, memory_relate for reconnecting, memory_update for closing claims), providing clear context for when to use the stats tool versus delegating to another tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_storeA
Store a new memory in the knowledge base. Use to capture anything worth remembering across sessions: decisions, bugs, patterns, architecture choices, preferences, facts, workflows, or context. Do not use for ephemeral or session-only notes.
type must be one of: fact, decision, pattern, bug, architecture, preference,
workflow, context. confidence is one of: verified (confirmed true), inferred
(assumed, not yet confirmed), stale (outdated), deprecated (no longer valid) β
defaults to "inferred". tags is comma-separated. namespace scopes the
memory to a project or domain; omit to use the configured default namespace.
source records what generated this memory (e.g. a file path or tool name).
metadata is an optional free-form JSON string for extra structured data.
When dedupe_check is True (default), the response includes a
similar_memories list of up to 3 existing memories in the same
namespace whose content/title overlap strongly with this one β a
non-blocking hint so the caller can choose to update/relate/consolidate
instead of accumulating near-duplicates. Disable for bulk imports.
Usually EMPTY, and that is the signal working. Each hit carries
similarity (0-1) and its basis: cosine over embeddings, or
lexical token overlap when they are unavailable. Unlike a search
relevance it has magnitude and is comparable between calls - it says
how close the two texts are, not how this candidate ranked.
When relation_check is True (default), the response also includes a
suggested_relations list of up to 3 not-already-linked memories worth
EXAMINING for a relationship. Topical overlap is only how they were
found; it is not itself a reason to link. Ask whether one of them is the
memory this one supersedes, contradicts, was caused_by, or belongs
under - and if the honest answer is "they are just both about the same
area", link nothing. Search already surfaces topical neighbours, so a
related_to edge that says only "these are similar" adds no retrieval
signal and competes with the directional edges that do. Same gate as
above, set softer; similar_memories are merge candidates instead.
Both hint lists are COMPACT: title plus a ~200-char summary, never
full bodies. They are enough to decide whether to merge, link, or move
on; call memory_recall when a candidate warrants a closer look.
Both carry similarity + basis, never a search score: these
lists are not a ranking of the corpus, they are a measurement against
what you just wrote.
The response may also carry contradicted_memories: older memories
whose state claim THIS memory just resolved. Recording "PR #10 merged"
makes every memory still asserting "PR #10 open" knowably wrong, and
now is when fixing it is cheapest. Each entry gives the stale memory's
id, title, the ref at issue, what it asserts, and both
sides' evidence.
Reconcile by correcting the stale claim β the claim is now genuinely false, so the text should change. That is the opposite of rewording prose to silence a hint while the claim stays wrong. Advisory only: nothing was mutated.
| Name | Required | Description | Default |
|---|---|---|---|
| tags | No | ||
| type | Yes | ||
| title | Yes | ||
| source | No | ||
| content | Yes | ||
| metadata | No | ||
| namespace | No | ||
| confidence | No | inferred | |
| dedupe_check | No | ||
| relation_check | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden and discharges it thoroughly: it discloses that the operation is advisory only ('nothing was mutated'), that 'Usually EMPTY' is the expected dedupe signal, the similarity/basis semantics (cosine vs lexical, measurement not ranking), the compact response format (title plus ~200-char summary), and the contradicted_memories reconciliation workflow. It even explains design rationale, such as why a similarity-only related_to edge adds no retrieval signal.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long (~700 words) but front-loaded: the core purpose and usage scope appear in the first two sentences, followed by a clean progression from parameters to response behaviors. The length is largely earned given 10 parameters and three distinct response lists, though a couple of points repeat (the lists are 'not a ranking' is stated twice, and the merge-vs-link gate is restated), so it is not maximally tight.
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 tool with no annotations and no output schema, the description covers nearly everything an agent needs: all parameter semantics, the composition of all three response lists (similar_memories, suggested_relations, contradicted_memories), empty-result meaning, and cross-tool routing. The only real gap is the base response shape when all hint lists are empty β an agent never learns whether it receives the created memory's id or just an acknowledgment β and no error conditions are described.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate β and it does exhaustively: it enumerates all eight type values, defines each confidence state with its default, specifies tags as comma-separated, explains namespace scoping and defaulting, source provenance, metadata as free-form JSON, and gives behavioral meaning to the two boolean flags dedupe_check and relation_check. Only content and title are left to inference, and both are self-evident from the tool's purpose.
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, 'Store a new memory in the knowledge base,' names a specific verb and resource. The scope is sharpened by an explicit list of admissible content (decisions, bugs, patterns, architecture, preferences, facts, workflows, context) and an explicit exclusion ('Do not use for ephemeral or session-only notes'), which differentiates it from memory_recall, memory_search, and memory_update among the siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives both positive and negative usage criteria: capture anything worth remembering across sessions, but not ephemeral notes. It also routes to alternatives explicitly β 'call ``memory_recall`` when a candidate warrants a closer look' β and contrasts with memory_search's topical-neighbour role when explaining why similarity alone is not a reason to create a relation. Condition-dependent behavior is flagged too: disable dedupe_check for bulk imports.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_unrelateA
Repair the graph: retype a mislabelled edge, turn a backwards one around, or
remove one that should not exist. The counterpart to memory_relate β without
it, an edge written in haste is permanent, and every wrong edge keeps competing
for one of the 3 spreading-activation slots on its memories forever.
Retype by passing new_relation_type alongside relation_type. The
edge is relabelled in place: direction, creation time and metadata survive,
because the usual repair is "right connection, wrong label" and the graph
should keep an honest record of when the link was first drawn. If an edge of
the new type already joins the pair, the two collapse into one and the
outcome reports merged rather than retyped β the edge count drops by
one, and nothing is fabricated to hide that.
Reverse by passing reverse=True alongside relation_type. The
endpoints are swapped on the same row, so id, creation time and metadata
survive exactly as they do for a retype β the connection was right, only the
arrow pointed the wrong way. Reversing COMBINES with new_relation_type, in
one write, because an edge recorded backwards is often mislabelled as well.
Note that reversing parent_of/child_of is the same operation as flipping
between the two types: do one or the other, not both. As with a retype, an
existing edge in the target direction absorbs this one and reports merged.
Delete by omitting new_relation_type and reverse. With relation_type, only
that edge goes; without it, every edge from source_id to target_id
goes, whatever the type. Deletion here is not the bulk prune the graph
guidance warns against: the caller names each edge, exactly as
memory_forget names a memory.
Batch by passing edges β an array of up to 100 objects, each with
source_id, target_id and optionally relation_type /
new_relation_type / reverse, i.e. the same decision made once per edge:
[{"source_id": "a", "target_id": "b",
"relation_type": "related_to", "new_relation_type": "caused_by"},
{"source_id": "c", "target_id": "d",
"relation_type": "caused_by", "reverse": true},
{"source_id": "e", "target_id": "f", "relation_type": "related_to"}]A batch is reviewed decisions submitted together, NOT a criteria-driven
sweep, and that is deliberate. There is no "retype every related_to in
this namespace" option, because the whole point of retyping is that each edge
deserves a different type based on what it actually records β a blanket
relabel would manufacture directional claims that were never true, and a
false caused_by is worse than an honest related_to.
The batch is validated in full before anything is written, so a malformed op
fails the whole call rather than leaving the graph half-repaired. Individual
outcomes (retyped, reversed, merged, deleted, not_found,
unchanged) are reported per edge. Use dry_run=True to preview a sweep
first; nothing is written and each op reports what it would have done.
Find the edges to repair with memory_edges.
| Name | Required | Description | Default |
|---|---|---|---|
| edges | No | ||
| dry_run | No | ||
| reverse | No | ||
| source_id | No | ||
| target_id | No | ||
| relation_type | No | ||
| new_relation_type | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. It thoroughly explains behaviors: edge retyping preserves direction, creation time, and metadata; reversing swaps endpoints; combined operations are possible; merging behavior when an existing edge absorbs the change; batch validation ('validated in full before anything is written'); dry_run behavior; and per-edge outcome reporting. It even explains the philosophical rationale for not supporting bulk operations. This is comprehensive and leaves no ambiguity about side effects.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with bold headers (Retype, Reverse, Delete, Batch) and clear examples. It front-loads the main purpose and then details each operation mode. However, it is quite long (around 300 words) and includes some explanatory asides (e.g., the rationale for not having bulk operations) that, while valuable, could be considered slightly verbose. The formatting helps scanning, but every sentence does not strictly earn its place; a minor deduction for density.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (7 optional parameters, four operation modes, batch processing) and the lack of annotations or output schema, the description is remarkably complete. It covers return semantics (per-edge outcomes like retyped, reversed, merged, deleted, not_found, unchanged) even without an output schema. It also addresses error handling (batch validation failure), preview mode (dry_run), and discovery (memory_edges). The description fully equips an agent to use this tool correctly, so a 5 is warranted.
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% according to context signals, and the schema itself is minimal (only types and defaults, no descriptions for individual fields). The description compensates heavily by explaining how each parameter interacts (e.g., new_relation_type alongside relation_type for retype, reverse=True for reversing, omitting both for delete, edges array for batch). It also clarifies parameter combinations and optionality ('with relation_type, only that edge goes; without it, every edge from source_id to target_id goes'). However, it does not explicitly list every parameter name (e.g., dry_run is mentioned but not all combinations are exhaustively enumerated), so a 4 rather than 5 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a strong purpose statement: 'Repair the graph: retype a mislabelled edge, turn a backwards one around, or remove one that should not exist.' It clearly distinguishes itself from the sibling memory_relate and explains the negative consequence of not using this tool ('without it, an edge written in haste is permanent...'). The purpose is specific, describes the verb (repair) and resources (graph edges), and sets it apart from related operations.
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 provides explicit usage guidance for each operation mode: retype (when to pass new_relation_type), reverse (when to pass reverse=True), delete (when to omit both), and batch (when to pass edges). It also explicitly states when NOT to use certain patterns, e.g., 'There is no "retype every related_to in this namespace" option' and points to a sibling tool for finding edges: 'Find the edges to repair with memory_edges.' This exceeds expectations for guiding an AI agent on when and how to invoke the tool versus alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_updateA
Update one or more fields of an existing memory. Use to correct outdated information, promote confidence after confirming an inference, retype a misfiled memory, or add/replace tags. Do not create a new memory when the right action is to update an existing one β find the id first with memory_recall.
All fields are optional; only provided fields are changed. tags
(comma-separated) replaces the full tag set when provided β omit to leave tags
unchanged. Pass metadata="" to clear metadata; omit to leave it unchanged.
type retypes the memory (same values as memory_store). Retyping is the
right fix when a memory was filed under the wrong kind β e.g. durable
reference material saved as workflow picks up point-in-time review
hints, because pattern/preference are the types exempt from them.
Retyping does not re-embed: the vector derives from title + content only.
resolve_claims reconciles a stale state claim WITHOUT EDITING THE
PROSE β comma-separated refs (e.g. "gingugu#10"), or "all" for every
open claim on this memory. Use it when the text is accurate history: a
session log that said "PR #10 open" was correct on the day it was
written, and rewriting it to stay current destroys the record. The
memory body is left byte-identical; only the claim's resolution is
recorded. Reach for content instead only when the memory asserts
something that was never true.
"all" means every OPEN claim, never an unverified one. An unverified
ref is one the prose names without saying what became of it, so sweeping
it under "all" would record that you checked something you did not. Name
such a ref explicitly to resolve it β that path works and is the honest
way to say "I looked, and it merged".
When relation_check is True (default) and title or content was
provided, the response includes a suggested_relations list of up to 3
not-already-linked memories worth examining for a relationship - same
semantics as memory_store: overlap is how they were found, and only a
directional fact (supersedes / contradicts / caused_by / parent_of /
child_of) justifies an edge. Tag-only or confidence-only updates skip the
check since the matching surface didn't change. Entries are compact
(title + a ~200-char summary) and carry similarity + basis,
as in memory_store; an empty list means nothing was close enough to
be worth your time.
pinned marks a memory as ALWAYS loaded by memory_context for its
namespace, ahead of and exempt from ranking, in addition to limit.
Reserve it for the few rules that would cause real damage if missed β
the ones you would want in front of you before touching anything, not
merely useful or frequently relevant material. Ranking already handles
"relevant"; a pin is for "inviolable". Capped per namespace (currently
20): pinning is a budget, so spending it on a merely-handy memory
crowds out a rule that governs behaviour. Pass pinned=False to
unpin. Pinning does not touch last_confirmed β it is a retrieval
decision, not a claim that the content is still true.
| Name | Required | Description | Default |
|---|---|---|---|
| tags | No | ||
| type | No | ||
| title | No | ||
| pinned | No | ||
| content | No | ||
| metadata | No | ||
| memory_id | Yes | ||
| confidence | No | ||
| relation_check | No | ||
| resolve_claims | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure, and it excels. It explains that only provided fields change, tags fully replace the set, metadata='' clears, retyping does not re-embed, resolve_claims leaves prose byte-identical, 'all' never resolves unverified claims, and pinned memories bypass ranking with a namespace cap. These are critical behaviors an agent could not infer from the schema alone.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but every paragraph earns its place: 10 parameters with zero schema descriptions require substantial explanation. It is front-loaded with the core purpose and governing rule, then organized cleanly by parameter. The formatting with code-styled parameter names and short paragraphs makes dense information navigable.
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 10 parameters, no annotations, and no output schema, the description is exceptionally complete. It covers side effects, edge cases, parameter interactions, and even response contents like suggested_relations. An agent has enough context to call this tool correctly without additional documentation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must supply all parameter meaning. It does so thoroughly: tags, type, metadata, resolve_claims, pinned, relation_check, title/content interactions, and the distinction between resolve_claims and content are all explained. Even the subtle behavior of 'all' versus explicitly named refs is covered, leaving almost no parameter ambiguity.
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 opens with a specific verb and resource: 'Update one or more fields of an existing memory.' It immediately differentiates itself from siblings by naming memory_recall for finding the id and warning not to create a new memory when updating is correct. The listed use cases, such as correcting outdated information and retyping misfiled memories, make the tool's scope unmistakable.
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 explicit when-to-use guidance: correct outdated info, promote confidence, retype misfiled memories, add/replace tags. It also distinguishes between resolve_claims and content based on whether the prose was accurate history or never true, and names memory_recall as the prerequisite lookup tool. This is model guidance for tool selection.
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.
4 tool updates
v0.18.0- Changed
memory_context1 field changed- added
Input schema / properties / explainAdded value: +{ + "default": false, + "title": "Explain", + "type": "boolean" +}
- Added
memory_excerpt - Changed
memory_recall1 field changed- added
Input schema / properties / explainAdded value: +{ + "default": false, + "title": "Explain", + "type": "boolean" +}
- Changed
memory_search1 field changed- added
Input schema / properties / explainAdded value: +{ + "default": false, + "title": "Explain", + "type": "boolean" +}
2 tool updates
v0.17.0- Changed
memory_search1 field changed- added
Input schema / properties / orphansAdded value: +{ + "default": false, + "title": "Orphans", + "type": "boolean" +}
- Changed
memory_unrelate1 field changed- added
Input schema / properties / reverseAdded value: +{ + "default": false, + "title": "Reverse", + "type": "boolean" +}
4 tool updates
v0.16.0- Added
memory_edges - Changed
memory_search1 field changed- added
Input schema / properties / claimsAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claims" +}
- Added
memory_unrelate - Changed
memory_update1 field changed- added
Input schema / properties / pinnedAdded value: +{ + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Pinned" +}
4 tool updates
v0.13.0- Changed
memory_namespaces1 field changed- added
Input schema / properties / default_repoAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Default Repo" +}
- Changed
memory_search1 field changed- added
Input schema / properties / idsAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Ids" +}
- Changed
memory_stats1 field changed- added
Input schema / properties / review_limitAdded value: +{ + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Review Limit" +}
- Changed
memory_update2 fields changed- added
Input schema / properties / resolve_claimsAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Resolve Claims" +} - added
Input schema / properties / typeAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Type" +}
2 tool updates
v0.6.0- Changed
memory_recall1 field changed- added
Input schema / properties / compactAdded value: +{ + "default": false, + "title": "Compact", + "type": "boolean" +}
- Changed
memory_search1 field changed- added
Input schema / properties / compactAdded value: +{ + "default": false, + "title": "Compact", + "type": "boolean" +}
4 tool updates
v0.4.0- Changed
memory_consolidate6 fields changed- added
Input schema / properties / memory_ids / anyOfAdded value: +[ + { + "type": "string" + }, + { + "type": "null" + } +] - added
Input schema / properties / memory_ids / defaultAdded value: +null - removed
Input schema / properties / memory_ids / typeRemoved value: -"string" - added
Input schema / properties / min_similarityAdded value: +{ + "default": 0.9, + "title": "Min Similarity", + "type": "number" +} - added
Input schema / properties / namespaceAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Namespace" +} - removed
Input schema / requiredRemoved value: -[ - "memory_ids" -]
- Changed
memory_context1 field changed- added
Input schema / properties / compactAdded value: +{ + "default": false, + "title": "Compact", + "type": "boolean" +}
- Changed
memory_store1 field changed- changed
Input schema / properties / metadata / anyOfPrevious value: -[ - { - "type": "string" - }, - { - "type": "null" - } -]New value: +[ + { + "type": "string" + }, + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } +]
- Changed
memory_update1 field changed- changed
Input schema / properties / metadata / anyOfPrevious value: -[ - { - "type": "string" - }, - { - "type": "null" - } -]New value: +[ + { + "type": "string" + }, + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } +]
2 tool updates
v0.3.8- Changed
memory_store2 fields changed- added
Input schema / properties / dedupe_checkAdded value: +{ + "default": true, + "title": "Dedupe Check", + "type": "boolean" +} - added
Input schema / properties / relation_checkAdded value: +{ + "default": true, + "title": "Relation Check", + "type": "boolean" +}
- Changed
memory_update1 field changed- added
Input schema / properties / relation_checkAdded value: +{ + "default": true, + "title": "Relation Check", + "type": "boolean" +}
16 tool updates
v0.3.1- First observed
credential_delete - First observed
credential_get - First observed
credential_list - First observed
credential_store - First observed
memory_consolidate - First observed
memory_context - First observed
memory_export - First observed
memory_forget - First observed
memory_import - First observed
memory_namespaces - First observed
memory_recall - First observed
memory_relate - First observed
memory_search - First observed
memory_stats - First observed
memory_store - First observed
memory_update
TDQS
Scored across 19 tools
Tools are mostly distinct, but the suite has three retrieval-oriented tools (memory_recall, memory_search, memory_context) whose names don't fully reveal their different roles. The descriptions sharply distinguish them, so mis-selection is unlikely but not impossible at a glance.
All tools use snake_case with a consistent resource prefix: memory_* for knowledge-base operations and credential_* for secrets. The suffix is consistently an action or noun describing the operation, creating a predictable pattern.
At 19 tools the server sits above the typical 3-15 range, but the scope is broad: memory CRUD, multiple retrieval modes, graph relations, consolidation, import/export, namespace management, stats, and credentials. Each tool has a distinct role, so the size feels justified rather than bloated.
The memory surface is essentially complete: create/read/update/delete, recall/search/context/excerpt retrieval, graph edge management, consolidation, export/import, namespaces, and health stats. Credentials also have full CRUD and discovery coverage, with no obvious dead ends.
Maintenance
Related MCP Connectors
- mcpOAuthai.butlerbrain
Persistent memory for AI assistants. Save once; recall from Claude, ChatGPT, or any MCP client.
Persistent, portable memory for AI assistants β your private memory graph, from any MCP client.
Persistent memory for AI agents across Claude, ChatGPT and any MCP client.
Persistent personal memory for AI assistants β save, search, and recall across every MCP client.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceA local, persistent memory system for AI coding assistants that stores decisions, patterns, and session context via MCP tools. It enables cross-session memory management using SQLite and optional vector search without external dependencies or cloud storage.37 npm64MIT
- AlicenseBqualityAmaintenancePersistent memory engine for AI coding agents. Single Go binary, zero runtime dependencies, MCP-native. Stores, searches, and deduplicates memories across sessions using embedded SQLite with hybrid FTS + semantic search, memory decay, relation graph, and token-budget context assembly.1022MIT
- AlicenseNot gradedqualityAmaintenancePersistent memory for any AI assistant. Zero token cost until recall. Stores memories in local SQLite, ranks by 6-factor scoring, returns results 79% smaller than JSON. Works with Claude, ChatGPT, Grok, Cursor, Windsurf, and any MCP client.53Apache 2.0
- FlicenseNot gradedqualityCmaintenanceLocal-first cross-agent memory for AI coding agents. Persistent, shared memory over MCP β what you tell one agent can be recalled by another β with all data stored in a single local SQLite file, no cloud and no API keys.-