ihmt-memory
This server gives AI coding agents a persistent, cross-session long-term memory plus project-indexing tools, exposed as nine MCP tools.
Search long-term memory (
search_memory): walk the hierarchical memory tree for decisions, setup, preferences, people and past sessions; supports acluefor ambiguous queries and compact/full detail.Save durable knowledge (
save_memory): store decisions, environment details, preferences, people, projects and procedures; auto-classifies domain/type, extracts dated facts, and reports contradictions with earlier memories.Correct outdated memories (
mark_outdated): flag an older memory as superseded so searches surface the current one first while keeping the history.Map a codebase (
project_map): get a compact file map with token sizes, optionally symbols with line ranges, with checksum-based resync.Find specific code (
find_code): retrieve just the method or class answering a query, with scope (main/test/all), subpath, clue and token-cap options.Read files efficiently (
read_file): read a file (or line range) once per session; repeats returnUNCHANGEDor a diff, withforceto bypass.Take session notes (
note): keep findings in scratch memory that survives context compaction but disappears at session end.Recall session notes (
recall): search what was noted or digested earlier in the session.Condense long output (
digest_output): reduce build logs or test reports to first lines, errors/failures/warnings/totals, and last lines, keeping the full text recallable.
IHMT — Infinite Hierarchical Memory Tree
Long-term memory for your AI coding agents. Tell your agent something once — a decision, how your setup works, a correction — and it remembers it in every future session, in any project, with any of your agents.
What IHMT does
Remembers across sessions. Decisions and their reasons, your environment, your preferences, people and projects, corrections. Your agent searches the memory before answering and saves what lasts, so you stop repeating yourself.
One memory for all your agents and models. Claude Code, Codex and opencode can share the same memory: what one saves, the others find. Tested with models from Anthropic, OpenAI, Google and Meta.
Saves tokens. Instead of pasting your notes or re-explaining context every session, the agent retrieves only what the question needs — typically 200–900 tokens, whether the memory holds 50 entries or 50,000, because search walks a tree instead of reading everything. Honest numbers, including where it does not save.
Understands time. When something changes ("I moved to Valencia", "staging is on PostgreSQL 17 now"), the old memory is kept as history, flagged
OUTDATED, and searches answer with the current one first. Where you live, where you work and your stack are tracked automatically; any other correction is linked when the agent saves it withreplaces. When a question is ambiguous ("Luis" — which one?), it asks instead of guessing.Portable. Your memory is one folder of plain text files. Copy it to another computer, back it up, or put it under version control — it works wherever you put it.
Local, private and readable. No cloud, no database, no account: IHMT stores everything on your disk and sends nothing anywhere. (The memories your agent retrieves reach its model like any other context.) Every memory is a text file you can open, and each person who installs IHMT starts with their own, empty memory.
Compatibility. Officially supported: Claude Code. Also tested: Codex (CLI and the ChatGPT desktop app — setup) and opencode (setup). IHMT is a standard stdio MCP server, so any agent that supports local MCP servers should work — GitHub Copilot, Antigravity, Cursor, Windsurf, Gemini CLI, Claude Desktop… — and
INSTALL.mdknows how to configure them, but we have not tested those yet. All of them can share one memory.
Related MCP server: Stoa
Install
Before you start
You need | Why |
Python 3.10 or newer | IHMT is written in Python |
git | to download IHMT and keep it updated |
An AI agent that can run commands (Claude Code, Codex, opencode, Copilot in agent mode…) | it installs IHMT and then uses the memory |
Internet, during the installation | to download the code and the MCP package; not needed afterwards |
Missing Python or git? Your AI agent installs them for you (it is instructed to ask you first). Python goes in your user folder, with no administrator password, so nothing system-wide changes. On a brand-new Mac, git may need one click: Apple shows a window asking to install its command-line tools.
On a Mac, note that the python3 that comes with macOS is version 3.9, which is too old — that is why
your agent may say Python is missing even though python3 exists.
You do not need administrator rights, a database, an account, or any paid service beyond your agent. Tested on macOS and Linux (Ubuntu); on Windows the instructions are included but not tested yet. Details: GUIDE.md §3.
Let your AI agent install it
Paste this into the AI agent you want to give a memory to — Claude Code, Codex and opencode are tested; GitHub Copilot, Antigravity, Cursor, Windsurf, Gemini CLI, Claude Desktop and other MCP clients should work too:
Install the IHMT memory MCP server for me from https://github.com/gonzaroman/IHMT-MEMORY — follow the instructions in its INSTALL.md.The agent follows INSTALL.md: it downloads IHMT to ~/IHMT-MEMORY, keeps your
memory in ~/.ihmt, registers the server with itself only, adds the usage instructions, and
tells you what it did. Then start a new session so the memory tools load.
Using several agents? Paste the same prompt in each one, whenever you want. If IHMT is already installed — say you have used it with Claude for months and now want it in Codex — the agent finds that installation, updates it if it safely can, and connects to the same memory, so it knows what you told the others from day one.
It needs an agent that can run terminal commands or edit files; chat-only assistants in a browser cannot install anything.
Requirements: Python 3.10+, git, and your agent's CLI.
git clone https://github.com/gonzaroman/IHMT-MEMORY.git ~/IHMT-MEMORY
cd ~/IHMT-MEMORY
python3 -m venv .venv
.venv/bin/pip install -r requirements-mcp.txt
mkdir -p ~/.ihmtClaude Code
claude mcp add ihmt-memory -s user -e IHMT_HOME="$HOME/.ihmt" -- "$PWD/.venv/bin/python" "$PWD/mcp_server.py"
claude mcp list # ihmt-memory … ✔ ConnectedThe server name must come before -e. Then append
templates/memory-instructions.md to ~/.claude/CLAUDE.md.
Codex — codex mcp add ihmt-memory --env IHMT_HOME="$HOME/.ihmt" -- "$PWD/.venv/bin/python" "$PWD/mcp_server.py",
then add default_tools_approval_mode = "approve" to the [mcp_servers.ihmt-memory] table in
~/.codex/config.toml (above its env table) and append the template to ~/.codex/AGENTS.md.
Details.
opencode — add an "ihmt-memory" entry ("type": "local", "command": [<python>, <mcp_server.py>],
"environment": {"IHMT_HOME": <memory folder>}) to the "mcp" object of
~/.config/opencode/opencode.json, and append the template to ~/.config/opencode/AGENTS.md.
Details.
Windows, the project scope, the graphical setup and troubleshooting are all in the guide.
No clone and no venv: uv downloads and runs the
ihmt-memory package. The memory goes to ~/.ihmt; set
IHMT_HOME to use another folder (for example, a memory you already have).
Claude Code
claude mcp add ihmt-memory -s user -- uvx ihmt-memory
claude mcp list # ihmt-memory … ✔ Connected
uvx ihmt-memory --instructions >> ~/.claude/CLAUDE.mdCodex — codex mcp add ihmt-memory -- uvx ihmt-memory, add
default_tools_approval_mode = "approve" to the [mcp_servers.ihmt-memory] table in
~/.codex/config.toml, and run uvx ihmt-memory --instructions >> ~/.codex/AGENTS.md.
opencode — add an "ihmt-memory" entry ("type": "local", "command": ["uvx", "ihmt-memory"]) to
the "mcp" object of ~/.config/opencode/opencode.json, and run
uvx ihmt-memory --instructions >> ~/.config/opencode/AGENTS.md.
The last step matters with any install: the instructions are what make the agent search before
answering and save corrections. pipx install ihmt-memory works too, with ihmt-memory in place of
uvx ihmt-memory.
New here? Read GUIDE.md — everyday use, step by step, with real outputs. The rest
of this README is the technical reference.
How it works
A universal, domain-agnostic long-term memory for LLMs, stored as a recursive tree of plain files on the local disk. No vector database, no server, no third-party dependencies — Python 3.10+ and the standard library.
Instead of embedding everything into one flat index and scanning it, IHMT organizes knowledge into a
tree: raw text leaves at the bottom, recursive JSON summaries above them, and a single root.json
trunk at the top. A query walks that tree — root → branch → branch → leaf — so the number of files
opened grows with the depth of the tree (≈ beam × log_B(n)), not with the amount stored.
Flat RAG | IHMT | |
Retrieval cost | scan / ANN over all n chunks |
|
Structure | none — a bag of vectors | explicit hierarchy, inspectable |
Chunking | fixed character windows | syntax-, scene- and date-aware |
Stale facts | served silently | superseded, dated, and flagged |
Ambiguity | returns a plausible guess | asks you for a clue |
Storage | binary index | UTF-8 |
Quick start
python3 gui.py # graphical interface: set up, browse, inspect
python3 init_ihmt.py # or from the terminal: create ./ihmt_memory
python3 main.py demo # full walkthrough in ./demo_workspace
python3 -m unittest discover -v # stdlib only; MCP tests skip without the SDKThen use it on your own material:
python3 main.py ingest ~/notes ~/project/src/Main.java
python3 main.py consolidate --force
python3 main.py search "how did we handle stock reservations"
python3 main.py ask "Luis" # interactive clue loop
python3 main.py conflicts # what changed over timeAs a library:
from ihmt import IHMT
memory = IHMT.initialize("./workspace")
memory.ingest_file("examples/InventoryService.java")
memory.ingest_file("examples/journal_personal.txt")
memory.flush() # close the tree up to the root
answer = memory.search("reserveStock soft hold")
print(answer.best.content) # the leaf
print(answer.best.path) # ['root', 'N1-software.java-…', 'L-software.java-…']
print(answer.node_reads) # how many branch files were opened
for notice in memory.notices():
print(notice) # "On 2024-03-11 you said user location = 'Madrid', but on 2026-02-03 you updated to 'Valencia'."Graphical interface
python3 gui.py # opens a browser at 127.0.0.1
python3 gui.py --path ~/my-memory --port 8765 --no-browserStill zero dependencies — the server is http.server from the standard library, it listens only on
the loopback interface, and every /api/* call needs the random token carried in the URL it opens.
Four screens: Set up (pick the memory folder with the system dialog, create the store, choose between per-project and global registration, preview the exact command or JSON before anything is written), Explore (collapsible tree down to the stored text, with supersession notices), Diagnose (a search that reports confidence, files opened vs. total, and the descent path), and Timeline (active vs. historical values and the detected contradictions). The interface is bilingual (ES/EN) and read-only over the memory: it never deletes or edits a leaf.
Use it from Claude Code (MCP)
mcp_server.py exposes the tree to Claude Code as nine tools in three families: long-term memory,
project indexes and session scratch memory. The core stays dependency-free; the
SDK is an optional extra:
python3 -m venv .venv
.venv/bin/pip install -r requirements-mcp.txt # mcp[cli]>=2.0For a single project, copy .mcp.json.example to that project's .mcp.json and fill in the absolute
paths; Claude Code asks you to approve it on the next session there (claude mcp list shows it as
Pending approval until then):
{
"mcpServers": {
"ihmt-memory": {
"command": "/absolute/path/to/IHMT-MEMORY/.venv/bin/python",
"args": ["/absolute/path/to/IHMT-MEMORY/mcp_server.py"],
"env": { "IHMT_HOME": "/absolute/path/to/IHMT-MEMORY" }
}
}
}or in one command:
claude mcp add ihmt-memory --scope user \
-e IHMT_HOME=/absolute/path/to/IHMT-MEMORY \
-- /absolute/path/to/IHMT-MEMORY/.venv/bin/python /absolute/path/to/IHMT-MEMORY/mcp_server.pyIHMT_HOME selects the store ($IHMT_HOME/ihmt_memory), created on first use. Point every project at
one shared directory for a single cross-project memory, or give each project its own.
Tool | Behaviour |
| Walks the tree. Compact output: the best memory with its date and |
| Classifies, splits and stores the text, extracts dated facts, and keeps the tree consolidated. Reports how it was filed and — if the save contradicts something remembered earlier — the notice to relay to the user. With |
| Flags one memory as corrected by another, when |
| Compact map of a codebase: files with their size in tokens and, with |
| Returns only the symbol that answers the query, as |
| Reads a file and remembers what it handed out this session: a repeated read answers |
| Session scratch memory: survives a context compaction, disappears when the session ends. |
| Condenses a long log to its first lines, errors, failures, test totals and last lines; the full text stays recallable. |
Saving tokens inside a session
Long-term memory saves tokens between sessions. The project tools save them within one, where the
cost is reading the same files again and again. ProjectIndex (ihmt/project_index.py) keeps a
private store per project under $IHMT_PROJECTS_DIR (default $IHMT_HOME/ihmt_projects):
one leaf per symbol —
code_chunk_mode="symbol", so a lookup returns a method, not a file;checksum sync on every call — size and mtime first, SHA-256 only for what moved; changed files are re-ingested, removed ones deleted, and the branches rebuilt. Code is never served stale;
path-ordered branches — each file is stamped with its rank in path order, so every branch covers neighbouring files and its summary stays meaningful for the descent;
code-aware ranking — the navigator filters by
scope/path_prefixfrom the catalog, prefers the file a query names, demotes tests unless asked and demotes import lines.
Measured on a 55-file Spring Boot project (8 typical questions): reading the files that hold the
answers costs 3,613 tokens; find_code returns the exact method for all 8 in 1,071. The map of the
project costs 660 tokens against 13,157 to read it whole.
Those savings are against an agent that reads whole files. In an A/B test with 22 real headless
Claude Code sessions, Claude preferred batched grep/sed -n and never called the project tools on
its own; forcing them made sessions 42–71 % more expensive. Keeping the server enabled costs about
460 tokens per conversation, since Claude Code loads MCP tools on demand. IHMT's main value is memory
between sessions; treat the project tools as optional, and do not mandate them in CLAUDE.md.
The server transparently supports MCP SDK 2.x (MCPServer), 1.x (FastMCP) and the standalone
fastmcp package.
The usage instructions in your ~/.claude/CLAUDE.md (template) tell Claude Code when to reach for each tool: search before answering anything that
depends on earlier sessions, save durable facts with their date, never guess on AMBIGUOUS, always
relay OUTDATED, and never store secrets.
Storage layout
Everything lives in one relocatable directory:
ihmt_memory/
root.json # the trunk: domains, topics, top branches, counters
layer_0/<domain>/*.txt # the leaves: raw UTF-8 text + a strict JSON header
layers/1/*.json # branches: summaries of leaves
layers/2..N/*.json # branches: summaries of summaries
state/catalog.json # index: id -> path, domain, parent, timestamp
state/facts.json # the fact timeline
ihmt.config.json # branch factor, token budgets, backendroot.json lives inside ihmt_memory/ so the store is self-contained: copy the directory and the
memory travels with it.
A leaf is a normal text file that describes itself, so it stays meaningful even if the catalog is lost:
<<<IHMT-META
{
"leaf_id": "L-software.java-0001-84130ee123",
"timestamp": "2026-09-09T17:45:00Z",
"data_type": "CODE",
"domain": "software.java",
"tags": ["method:reserveStock", "class:InventoryService", "lang:java", "type:code"],
"parent_id": "N1-software.java-5571a7baac",
"span": {"start_line": 43, "end_line": 68},
"checksum": "sha256:…",
"extra": {"context": "public final class InventoryService {"}
}
IHMT-META>>>
public Optional<String> reserveStock(Sku sku, int quantity) {
…A branch node embeds each child's title, excerpt and keywords. That is the detail that makes the descent cheap: a branch can be ranked without opening any of its children.
The five components
1. UniversalIngestor — detect, split, enrich, store
DomainDetector classifies each document by type (CODE, NARRATIVE, CLINICAL, PERSONAL,
PROCESS, GENERIC) and domain (software.java, medicine.clinical, process.cooking,
personal, …) from its extension plus lexical signatures in English and Spanish. Both can be
overridden with --domain / --type.
The type selects the splitter, and every splitter obeys one invariant:
A logical block is never cut. If a single block exceeds
max_tokensit is stored whole and flaggedoversized. Correctness of the block beats hitting the token budget.
Code (
chunkers/code.py) — Python via the stdlibast; Java/JS/TS/C/C++/C#/Go/Rust/Kotlin/ Swift/PHP viaBraceScanner, a character-level scanner that tracks brace depth while skipping comments, string literals, char literals, template literals and preprocessor lines. Imports coalesce; each class/function is a block; an oversized class splits per member, and the enclosing class header travels in the leaf'sextra.contextrather than being spliced into the text. Concatenating a file's leaves reproduces the file byte for byte — asserted in the tests.Narrative — paragraph-atomic, with
***,---,Chapter/Capítuloas hard boundaries. Only a paragraph larger thanmax_tokensis split, and then at sentence boundaries.Temporal (journals, chats, clinical records) — one dated entry is atomic and a change of date is a hard boundary, so a leaf never mixes two encounters. The date found in the text becomes the leaf's timestamp, which is what makes recency weighting mean when something was true rather than when it was ingested.
Process (recipes, protocols, runbooks) — steps and ingredient lists stay attached to their heading.
Leaf ids are derived from (domain, source, position, content), so re-ingesting an unchanged
document rewrites the same leaves instead of duplicating them.
2. RecursiveSummarizer — the Summarization Event
It watches layer 0. When branch_factor leaves of one domain have no parent, it fires a
Summarization Event: they are condensed into a layer-1 node, the node is written, and only then
are the children stamped with their parent_id — so an interrupted run re-processes a group instead
of orphaning it. The same rule applies from layer 1 to layer 2, and so on, until the tree converges;
then root.json is rewritten.
consolidate() is idempotent. flush() (--force) also promotes partial groups so the tree closes
completely. Anything still unconsolidated is referenced directly by the trunk, so nothing in the
store is ever unreachable from the root.
3. SemanticNavigator — descent and the Interactive Clue Loop
Ranking uses Okapi BM25 over each candidate's title, keywords, tags and excerpt, with field weights
and document frequencies computed across the siblings of the current level — exactly the
discrimination the descent needs, at no extra I/O cost. The walk keeps a beam of beam_width
branches per level.
Confidence blends two independent signals:
confidence = 0.6 × coverage + 0.4 × marginCoverage asks "does this leaf actually contain what was asked?"; margin asks "is it distinguishable from its rivals?". A common first name scores high on the first and near zero on the second — which is precisely when the system must not guess:
$ python main.py ask "Luis"
"Luis" is ambiguous (3 memories match this query equally well, confidence 0.62).
It could belong to any of these branches:
1. [personal] journal_personal.txt · 2024-07-22 — Vacaciones en Benidorm con Luis, mi primo…
2. [personal] journal_personal.txt · 2026-08-30 — Fin de semana en la playa de El Saler con Luis…
3. [personal] journal_personal.txt · 2024-11-30 — Cierre de trimestre… Luis Marín revisó el pull request…
Give me a clue to narrow it down (e.g. a place, a date, a project):
> vacaciones en Benidorm
query: "Luis + vacaciones en Benidorm" · confidence 0.74 · 5 node reads, 3 leaf reads, depth 2
1. [personal] journal_personal.txt · 2024-07-22
path root → N2-personal-ea34db33ae → N1-personal-59bf8bc291 → L-personal-0002-a17b3c8f35The clue triggers a joint cross-reference: candidates matching both term groups are boosted
(×1.6), candidates matching only one are demoted (×0.7). The loop runs up to max_clue_rounds
times, stops early if the user declines, and never silently converts an ambiguous query into a
confident answer.
clue_provider is any callable, so the loop works for a human at a terminal (input) or for an
agent that lets the LLM supply its own follow-up.
4. ConflictResolver — recency weighting and the timeline
Facts are (subject, attribute, value, timestamp, source_leaf), recorded programmatically via
record_fact() or extracted at ingest time by pattern rules (vivo en X / I live in X,
mi stack es Y, trabajo en Z, Diagnóstico:, Tratamiento:, Medicación: …; extend with
add_pattern).
Each (subject, attribute) keeps a dated timeline. The newest value is ACTIVE; every earlier one
becomes HISTORICAL with superseded_by and a valid_from/valid_to interval. Nothing is
deleted, so both questions stay answerable:
memory.resolver.active_state()["user::location"].value # 'Valencia' (now)
memory.resolver.state_at("2024-12-31")["user::location"].value # 'Madrid' (back then)Repeating a value at a later date is a confirmation, not a contradiction. A genuine change produces a
transparent notice — "On 2024-03-11 you said user location = 'Madrid', but on 2026-02-03 you updated to
'Valencia'." — and the superseded leaf is annotated, so retrieving outdated material always arrives
with its correction attached (SearchResult.notices).
A leaf itself stays ACTIVE: what it says was true on its own date, and that remains the right
answer to a historical question. What changes is that it can no longer be read as current.
5. Summarization backends
class SummarizerBackend(Protocol):
name: str
def summarize(self, children, *, domain: str, layer: int) -> NodeSummary: ...HeuristicSummarizer(default) — stdlib extractive summarization: TF term ranking with EN/ES stop words plus representative-sentence selection. Offline, deterministic, which is what lets the test suite assert on tree shape.AnthropicSummarizer(optional) — used only when selected and theanthropicpackage andANTHROPIC_API_KEYare both present. Every failure path (missing SDK, missing key, network error, unparseable reply) falls back to the heuristic backend, so a consolidation is never lost because a model was unreachable.
python3 init_ihmt.py --backend anthropic # model set by summarizer_model in ihmt.config.jsonAny other model or local runtime plugs in by implementing the same protocol and passing it as
IHMT(..., backend=MyBackend()).
CLI reference
Command | Purpose |
| create the store |
| ingest files, directories or stdin |
| run pending Summarization Events |
| walk the tree |
| search with the clue loop |
| outline of the hierarchy |
| inspection |
| rebuild catalog, timeline and trunk from the files |
| end-to-end walkthrough |
--path selects the store directory and --json emits machine-readable output; both work before or
after the subcommand.
Configuration
ihmt_memory/ihmt.config.json:
Key | Default | Meaning |
| 8 | children per branch; the log base of retrieval cost |
| 2000 / 3000 | leaf size target and oversize threshold |
| 3 | branches kept alive per level |
| 0.45 | below this, ask for a clue |
| 0.18 | score gap under which candidates count as tied |
| 3 | clue-loop iterations |
|
| summarization |
|
|
|
Small corpora deserve a small branch factor — the demo uses branch_factor=4, target_tokens=400 so a
handful of documents still builds a genuine multi-layer tree.
Tests
python3 -m unittest discover -v # from the project root187 tests — 25 of them for the MCP server, skipped without the SDK — covering: byte-exact reconstruction and boundary-depth invariants for Java and Python, scene/date/section atomicity, oversized-block handling, leaf header round-trips, catalog recovery, summarization thresholds, upward propagation, idempotence, full reachability from the root, descent cost bounds, the clue loop, recency weighting, historical preservation, the project indexes, the MCP tools, the graphical interface and the CLI.
Design notes and limits
Retrieval is a descent, not a scan. That is the whole point, and it means a branch pruned at the trunk is not revisited. Domain-level pruning only happens when a query has actual signal at the trunk; if it has none, every domain stays in play and the beam applies one level down. The clue loop is the recovery mechanism when the descent goes wide.
Lexical, not semantic. Matching is BM25 over accent-folded, CamelCase-split tokens: it works in any language and needs no model, but it will not match a synonym. Plugging an embedding re-ranker into
BM25Rankeris the natural upgrade; the tree structure does not change.Token counts are estimated at ~4 characters per token. Budgets only need to be consistent, not exact.
Fact extraction is pattern-based. The bundled rules cover common English/Spanish phrasings and clinical headers;
record_fact()is the reliable path, andadd_pattern()extends the rules.Single-writer. Writes are atomic (
tmp+os.replace) and catalog rebuilds take a lock file, but the store assumes one writer at a time.initialize(force=True)discards derived state only — branches, catalog, timeline — and detaches the surviving leaves so the next consolidation rebuilds the hierarchy. Leaf content is never deleted.
Layout
ihmt/
api.py IHMT facade wiring everything together
config.py IHMTConfig
models.py MemoryLeaf, BranchNode, ChildRef, RootIndex, Fact, Contradiction
storage.py MemoryStore: atomic I/O, catalog, recovery
textutils.py tokenizing, keywords, entities, extractive summary, timestamps
detectors.py DomainDetector
chunkers/ base · code · narrative · temporal · process · generic
summarizers.py SummarizerBackend · Heuristic · Anthropic
universal_ingestor.py UniversalIngestor
recursive_summarizer.py RecursiveSummarizer
semantic_navigator.py SemanticNavigator, BM25Ranker, ClueRequest, scope/path filters
project_index.py ProjectIndex: per-project code cache with checksum sync
conflict_resolver.py ConflictResolver + timeline manager
ihmt_gui/ local graphical interface (stdlib only)
mcp_server.py MCP server: the nine tools
ihmt_launcher.py the `ihmt-memory` command of the PyPI package (~/.ihmt by default)
pyproject.toml · server.json PyPI package · MCP Registry entry
init_ihmt.py · main.py · gui.py · examples/ · tests/
GUIDE.md installation and usage guide
INSTALL.md installation instructions for AI agents
templates/ memory-instructions.md: the usage rules agents append to CLAUDE.md / AGENTS.mdLicense
MIT © 2026 Gonzalo Román Márquez (gonzaroman)
Available Tools
9 toolsdigest_outputA
Condense a long command output (build log, test report) and keep the full text for recall.
Returns the first lines, every line that mentions errors, failures, warnings or test totals, and the last lines. The whole output stays queryable with recall(" ...") this session.
Args: text: The raw output. label: A short name to recall it by, e.g. "maven-build".
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | ||
| label | No | output |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
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, and it does disclose substantive behavior: what is kept (first lines, error/failure/warning/test-total lines, last lines) and that the full text remains queryable via recall this session. It does not discuss side effects on existing memory, permissions, or size limits, so it is strong but not exhaustive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and an explicit breakdown of what is returned, followed by a compact Args section. Every sentence carries information; the Args block mildly duplicates the schema but adds the example and rationale.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter read-only-style tool with an output schema, the description covers purpose, return composition, and retention semantics. With no annotations, it could say more about session scope and side effects, but nothing critical to correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% and both properties are bare, but the description compensates: text is identified as the raw output and label as a short recall key with a concrete example ("maven-build"). It adds real meaning beyond the schema, though it doesn't note the default value or label uniqueness.
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 (condense) plus resource (long command output such as build logs/test reports) and immediately clarifies the retention side effect. An agent can distinguish this from siblings like save_memory or recall because the description frames it as summarization-plus-retention rather than storing or fetching.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear context: use it on long command output (build log, test report). It references recall("<label> ...") for later retrieval, letting the agent infer the workflow, but it names no explicit when-not or alternative tool for the same job, so it stops just short of 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
find_codeA
Find the method or class that answers a question about a codebase; returns only that symbol.
Output: "file:first-last Symbol" and its code, instead of whole files. Name the class or
method if you know it ("PedidoJpaMapper aDominio"). AMBIGUOUS lists candidates in different
files: refine the query or pass clue. The index resyncs by checksum, so code is never stale.
Args: query: What you are looking for: identifiers plus a few words. path: Project root directory (absolute). scope: "main" (skip tests, default), "test" or "all". subpath: Restrict to a directory inside the project. clue: Extra detail after an AMBIGUOUS reply. max_tokens: Cap on the returned code.
| Name | Required | Description | Default |
|---|---|---|---|
| clue | No | ||
| path | Yes | ||
| query | Yes | ||
| scope | No | main | |
| subpath | No | ||
| max_tokens | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden and does well: it discloses the return shape, the AMBIGUOUS state and how to respond, and that the index resyncs by checksum so code is never stale. It omits permission/error behavior, but the key behavioral traits of this search tool are covered.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and output format are front-loaded, followed by an Args block that parses cleanly. It is slightly long, but each sentence adds operational value (output shape, ambiguity handling, param meanings) rather than filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a six-parameter search tool with an output schema already covering return values, the description supplies everything an agent needs to call it correctly: scope defaults, subpath restriction, ambiguity recovery, and token capping.
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 fully and does: every one of the six parameters is explained, including scope's valid values ('main' default skipping tests, 'test', 'all'), subpath's containment, clue's role after an AMBIGUOUS reply, and max_tokens' cap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (find the method or class answering a question) and its scope, and distinguishes itself from siblings by returning only the symbol 'instead of whole files', which implicitly separates it from read_file and project_map.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear context: name the class/method when known, handle AMBIGUOUS by refining the query or passing `clue`. It does not explicitly name sibling alternatives or state when NOT to use it, so it stops short of a full when/when-not routing rule.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
mark_outdatedA
Flag one memory as corrected by another, after save_memory listed candidates.
The old memory is kept (it was true on its date) but carries an OUTDATED notice, and searches answer with the new one first. Use the ids save_memory or a full search printed.
Args: old_id: Id of the memory that is no longer current. new_id: Id of the memory that replaces it.
| Name | Required | Description | Default |
|---|---|---|---|
| new_id | Yes | ||
| old_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations present, the description carries the burden and does real work: it discloses that the old memory is not deleted (kept because it was true on its date) and that it carries an OUTDATED notice, plus that searches surface the new memory first. It omits whether the operation is idempotent or requires prior save_memory output, but the destructive/ordering semantics are clearly communicated.
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 behaviour and the tool-flow context are front-loaded in the first two sentences, then the args are documented compactly. Slightly more text than strictly needed for two parameters, but nothing is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no explanation, and the description covers purpose, precondition flow, and both params. The only gap is the absence of any note on failure cases (e.g. hub id not found or already outdated).
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 both parameters are bare strings, so the description must supply meaning — which it does by defining old_id as 'the memory that is no longer current' and new_id as 'the memory that replaces it'. It does not specify id format or where to literally find them beyond the tool reference, so not a full 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Flag one memory as corrected by another') plus the exact effect on the memory store. It also implicitly distinguishes itself from siblings save_memory and search_memory by naming them as the upstream steps, so an agent can tell it apart 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?
Gives a clear when-to-use context ('after save_memory listed candidates') and where the ids come from ('save_memory or a full search printed'). It does not state when NOT to use it or what to do if only one id is known, so it stops short of explicit alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
noteA
Keep something you learned in this session (where a thing lives, what a method does, a result).
Session notes are cheap to recall later and survive a context compaction; they vanish when the session ends. Include file:line when relevant. Durable facts belong in save_memory instead.
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | 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 well: it discloses lifecycle semantics that are not derivable from the schema — notes survive context compaction but vanish when the session ends. It also advises including file:line. It stops short of stating whether notes are mutable, deduplicated, or how they surface on recall, which leaves a small gap for a persistence tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the core action, then persistence behavior, then the routing rule to save_memory. No filler; every sentence adds a distinct fact.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained. For a one-parameter persistence tool with no annotations, the description covers purpose, lifecycle, content guidance, and the sibling boundary — everything an agent needs to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The single `text` parameter has 0% schema description coverage, but the description compensates by explaining what the content should be (a learning, with file:line when relevant). That is meaningful guidance beyond the bare string type, though it does not discuss length limits or formatting.
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 action and resource: keeping a learning from the current session, with concrete examples of what counts (where a thing lives, what a method does, a result). It explicitly contrasts itself with save_memory for durable facts, so an agent can separate it from siblings like save_memory and recall without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use (session-scoped learnings), when-not (durable facts belong in save_memory), and names the alternative tool. The condition that selects between this and save_memory is stated outright rather than inferred.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
project_mapA
Compact map of a codebase: files with their size in tokens, optionally their symbols and line ranges.
Call it before exploring a project instead of listing directories and opening files. Indexes the project on first use and resyncs changed files by checksum on every call.
Args: path: Project root directory (absolute). detail: "files" (cheapest) or "symbols" (adds methods/classes with first-last line). subpath: Restrict to a directory inside the project, e.g. "src/main".
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | ||
| detail | No | files | |
| subpath | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | 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 disclose non-obvious runtime behavior: it indexes the project on first use and resyncs changed files by checksum on every call. It does not discuss cost/latency on large repos, read-only guarantees, or failure modes for an invalid path, so it is strong but not complete.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded purpose sentence, then the behavioral/usage line, then a compact Args block. Every sentence earns its place and nothing is repeated between the prose and the parameter list.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no explanation; the description covers the remaining agent-relevant questions, namely when to reach for it and what each parameter controls, including the cost trade-off between detail levels.
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 compensation is required and the Args block delivers it: path is the absolute project root, detail distinguishes 'files' (cheapest) from 'symbols' (adds methods/classes with first-last line), and subpath is scoped with a concrete example ('src/main'). This adds real meaning the bare schema does not carry.
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 artifact (a compact map of a codebase: files with token sizes, optionally symbols and line ranges) rather than a vague action. The line 'Call it before exploring a project instead of listing directories and opening files' implicitly separates it from siblings like find_code and read_file, so an agent can route correctly without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly prescribes the situation to use it ('before exploring a project') and names the alternative behaviors it replaces (listing directories, opening files). It stops short of when-not-to-use guidance (e.g. single-file lookups where read_file suffices), but the intended context is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
read_fileA
Read a text file, remembering what you were given this session.
Reading it again returns "UNCHANGED" (a few tokens) or only a unified diff against your earlier copy. Prefer it over re-reading a file you already read in this session. Pass force=true if the earlier copy is no longer in your context (e.g. after a context compaction). With start_line/end_line (e.g. a range from project_map) only those lines are returned.
Args: path: Absolute path of the file. force: Return the full content even if it has not changed. start_line: First line to return (1-based); 0 for the whole file. end_line: Last line to return (inclusive); 0 for the end of the file.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | ||
| force | No | ||
| end_line | No | ||
| start_line | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | 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 disclose meaningful behavior beyond the schema: repeat reads return 'UNCHANGED' or a unified diff, and force bypasses that optimization. It does not cover error behavior (missing path, non-text/binary files) or any permission/size constraints, but the caching semantics are unusually well surfaced.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the most decision-relevant fact (session caching and the UNCHANGED/diff behavior) before the parameter block, and every sentence earns its place. The Args list duplicates the schema field names, but with 0% schema description coverage that repetition is functional rather than wasteful.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be described, yet the description still explains the two non-obvious return forms (UNCHANGED, unified diff). Given no annotations and a four-parameter tool, the only real gap is failure-mode behavior, which is minor for a read operation.
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, and it does: path is absolute, force returns full content, start_line is 1-based with 0 meaning whole file, end_line is inclusive with 0 meaning end of file. This fully compensates for the empty schema, though it mostly restates the documented defaults rather than adding edge-case guidance (e.g. start_line > end_line).
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 (read a text file) and adds a non-obvious scope trait: session-scoped memory of prior reads. It references project_map as a source of line ranges, but it does not explicitly differentiate itself from other retrieval siblings like find_code or recall, which are plausible alternatives for getting code into context.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear when-to-use guidance: prefer this over re-reading a file already read in the session, and use force=true specifically when the earlier copy was lost after a context compaction. It stops short of naming an explicit alternative tool or stating when this tool is the wrong choice.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
recallA
Search what you kept earlier in this session with note or digest_output (not long-term memory).
Cheaper than re-reading files or re-running commands to remember what you already found out.
| Name | Required | Description | Default |
|---|---|---|---|
| clue | No | ||
| query | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations, so the description carries the burden. It usefully discloses scope (session-only, not long-term) and a cost/benefit trait (cheaper than re-reading/re-running), but says nothing about permissions, rate limits, or mutation behavior. Adequate but not rich for an annotation-free tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences with zero filler, and the essential scope constraint is front-loaded ahead of the cost rationale.
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 output schema covers return values and the description covers scope well, but the unexplained 'clue' parameter and the absence of any annotations leave real gaps. Complete enough to attempt a call, not complete enough to call confidently.
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% with two parameters ('query' required, 'clue' optional), neither documented in the schema. The description implies a search query but gives no meaning for 'clue' and no syntax/format guidance, so it fails to compensate for the coverage gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Search) and a precise resource (things kept earlier in this session via note or digest_output), and explicitly distinguishes it from long-term memory. An agent can separate it from sibling search_memory without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear context (recall session-stored notes rather than long-term memory) and a when-to-use rationale (cheaper than re-reading files or re-running commands). It implicitly routes long-term lookups to search_memory but never names that sibling as the alternative, so the exclusion is stated but the target tool is not.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
save_memoryA
Store durable knowledge in the user's long-term memory (IHMT).
Save decisions and why, setup, preferences, people and projects, procedures. Not transient chat, not secrets. Write it to make sense months later, and start with the date ("2026-02-03: ...") when it belongs to one. Reports how it was filed and any contradiction with an earlier memory — relay that notice.
Args:
content: The text to remember, self-contained.
domain: Leave "general" to let IHMT classify it, or e.g. "software.java".
content_type: "auto" (recommended), "code", "narrative", "clinical", "personal",
"process" or "generic".
replaces: When this corrects or updates something saved earlier, a few distinctive
words describing that earlier memory ("RainDesktop version 1.3"). It is then
flagged OUTDATED and searches answer with this one first. If several memories
fit, nothing is flagged and the candidates are listed for mark_outdated.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | No | general | |
| content | Yes | ||
| replaces | No | ||
| content_type | No | auto |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | 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: it discloses the side effect that 'replaces' flags the earlier memory OUTDATED and that searches then answer with the new one first, and the failure path where nothing is flagged and candidates are listed. It also states the tool reports filing location and contradictions that should be relayed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads purpose and scope in the first sentence, then the inclusion/exclusion rule, then a compact per-argument block. Given zero schema coverage, the args section is necessary rather than redundant, and no sentence is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
A four-parameter write tool with no annotations and no output schema explanation needed; the description still notes the return signal to relay. Everything an agent needs to invoke it correctly, including the cross-memory side effect, is present.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate, and it does for all four parameters: content (self-contained, date-prefixed), domain (default 'general' with a concrete example 'software.java'), content_type (enumerates values with 'auto' recommended), and replaces (meaning plus example 'RainDesktop version 1.3' and multi-match behavior).
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Store durable knowledge in the user's long-term memory (IHMT)') and immediately scopes it with what belongs and what does not. The 'IHMT' naming and the 'replaces' semantics clearly separate it from search_memory/recall/mark_outdated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use ('decisions and why, setup, preferences, people and projects, procedures'), when-not ('not transient chat, not secrets'), plus formatting rules (self-contained, date prefix) and a named fallback to mark_outdated when several memories match. Routing is fully specified.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_memoryA
Search the user's long-term memory (IHMT): decisions, setup, preferences, people, earlier sessions.
Use several distinctive words, not a bare name. Returns the best memory with its date
(plus one line per other match). AMBIGUOUS means several memories fit equally: ask the
user or call again with clue (a place, date, project). Always relay OUTDATED notices.
Args: query: What to look for, in any language. clue: Distinguishing detail, only after an AMBIGUOUS reply. detail: "compact" (default) or "full" (adds ids, tree paths and excerpts).
| Name | Required | Description | Default |
|---|---|---|---|
| clue | No | ||
| query | Yes | ||
| detail | No | compact |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | 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 largely meets it: it discloses the return shape (best memory plus its date, one line per other match), the meaning of an AMBIGUOUS result and the recovery path, the obligation to relay OUTDATED notices, and the two `detail` modes. It never states whether the call has side effects, permission requirements, or result limits, which keeps it out of 5 territory.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The opening sentence front-loads the scope, the ambiguity/outdated handling follows, and the Args block is compact and scannable. It is slightly longer than necessary given an output schema already exists, since part of the return-format sentence restates what the schema exposes.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 3-parameter retrieval tool with no annotations and a documented output schema, the description covers the essentials: scope, query phrasing, ambiguity workflow, and outdated handling. Missing only edge-case behavior such as empty results, permission assumptions, or result caps.
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 does: each of the three parameters is explained with meaning beyond its title, including the conditional trigger for `clue` ('only after an AMBIGUOUS reply') and the actual difference between `detail` values ('compact' default vs 'full' adding ids, tree paths and excerpts).
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 ('Search the user's long-term memory (IHMT)') and enumerates the content it covers: decisions, setup, preferences, people, earlier sessions. That is far more than a tautology. It stops short of a 5 because it never distinguishes itself from the closest sibling, `recall`, which an agent must disambiguate on its own.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives concrete procedural guidance: use several distinctive words rather than a bare name, and pass `clue` only after an AMBIGUOUS reply. That is clear context for how and when to call it. It does not name any alternative tool or state when NOT to use this one, so it misses the 5 bar.
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.
9 tool updates
v0.1.0- First observed
digest_output - First observed
find_code - First observed
mark_outdated - First observed
note - First observed
project_map - First observed
read_file - First observed
recall - First observed
save_memory - First observed
search_memory
TDQS
Scored across 9 tools
Tools are largely distinct and descriptions explicitly delineate the tricky boundaries (search_memory vs recall: long-term vs session; note vs save_memory: session vs durable). The pairs digest_output/note and recall/search_memory could still be momentarily confused, so it falls just short of perfect.
Seven of nine tools follow a clear verb_noun snake_case pattern (search_memory, save_memory, mark_outdated, project_map, find_code, read_file, digest_output). The bare 'note' and 'recall' deviate from that pattern but remain readable and unambiguous.
Nine tools is well-scoped: a compact memory lifecycle (search, save, note, recall, mark_outdated) plus a small, focused code-exploration set (project_map, find_code, read_file, digest_output). Each tool earns its place with no filler.
Memory lifecycle is well covered (capture, retrieve across sessions/session, supersede via replaces/mark_outdated), and code exploration has map, symbol lookup and file read. Minor gaps remain: no explicit forgetting/deleting of memories and no way to list or browse stored memories beyond search.
Maintenance
Related MCP Connectors
Long-term memory for AI coding agents: durable project facts, recalled by every MCP client.
Persistent memory for Claude Code, Cursor and Codex. Facts retire when they change.
Shared memory for coding agents. Stop re-explaining your codebase every session.
Persistent memory for AI agents. Search and store durable facts, preferences and decisions.
Related MCP Servers
- AlicenseAqualityAmaintenanceLocal, searchable project memory for AI coding agents. Markdown source of truth, MCP interface, safe structured updates313Apache 2.0
- AlicenseNot gradedqualityCmaintenancePersistent shared memory for AI coding agents that turns a folder of markdown files into searchable memory across sessions, repos, and machines.10 npmFunctional Source , Version 1.1, MIT Future
- AlicenseAqualityAmaintenanceProvides coding agents with persistent, evidence-backed project memory and knowledge across sessions, using a structured memory tree and local knowledge base.6126MIT
- AlicenseNot gradedqualityAmaintenancePersistent memory for AI coding agents that knows when it has gone stale.3MIT