MemAI
MemAI is a long-term memory MCP server for agentic coding: it stores typed memories in one SQLite file and retrieves them by keyword (FTS5 BM25) across sessions.
Write typed memories —
note(facts/decisions),checkpoint(working state),anti_pattern(pitfalls),reasoning(analyses),task(goal + checklist),diagram(process flows), each with title, content, domain, tags, cross-listings, review dates and source refs.Read memories back —
search(BM25 over content/tags/domain),recall(notes only),get_memory,list_by_domain,list_recent,timeline(what was written around one memory),pending(open items per category) andpulse(session warm-up: latest checkpoint, pending counts, read-next).Organize by domains — hierarchical path scoping (a read of
acmecoversacme/checkout/billing), cross-listing viaalso_domain/unfile_domain, tree inspection withlist_domains, casing policy viaget_domain_case/set_domain_case.Work tasks —
task,task_add,task_item(todo/doing/done/dropped, comments, linked memories),task_comment; tasks self-archive when all items close.Document flows as diagrams —
diagram,diagram_node,diagram_edge,diagram_link(attach prose to a step),diagram_jump(continue into another flow),diagram_relayout,get_diagram(svg-interactive, svg, mermaid, text, json).Link and curate —
link_memories,get_relations,set_confidence,edit_memory(replace/append body, rename, retag, set source_ref),forget(soft archive) andpurge_memory(permanent, guarded by an exact user-typed confirm phrase).Plan curation passes —
dedup_scan(near-duplicate pairs),optimize_scan(compact corpus dump with hints),optimize_stage(stage suggestions for human review),optimize_runs/optimize_status(track review progress).Manage projects —
list_projectsandmove_to_project(dry-run by default, backup then purge), one SQLite file per project with dashboard-driven switching.Get help —
helpprints tool summaries or the full docstring for any command.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@MemAIremember that my name is Alice"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Agents call MemAI's MCP tools to write memories — facts, decisions, checkpoints, pitfalls, documented flows — during a session and read them back in later ones, which is the state an MCP server's own process does not keep between conversations.
The tools answer any MCP host. What surrounds them targets Claude Code: the hook events that put the store in front of a session, the bundled skills, and the warden subagent that consults it on a session's behalf.
Highlights
Types, not one blob.
note,reasoning,anti_pattern,checkpoint,task,diagram— a pitfall is read back by the tool that asks for pitfalls, not found by luck among everything else. Ataskis a goal and a checklist: items move throughtodo,doing,doneanddropped, each carries its own comments and linked memories, and the task archives itself once every item is closed.Domains are paths. A memory filed on
acme/checkout/billingstill answers a read ofacme, andalsocross-lists it under the subjects that cut across that tree.Keyword retrieval, nothing to download. SQLite FTS5 with BM25 over title, content, tags and domain. No embedding model, no network call, no GPU.
The store reaches a session by itself. Hook events warm a cold session and prompt it to write; the warden subagent reports only the memories that bear on what is actually happening.
Curation stays a person's. Confidence, decay dates, dedup and staged suggestions: an agent proposes, a human applies them in the dashboard.
One file holds a project. Rows, keyword index, edit history, relations, diagrams: a project's whole memory in one SQLite file. Keep one for everything, or one per project and switch between them from the dashboard. Copy it, back it up, delete it.
Related MCP server: heropen
What it looks like
Mid-task, an agent writes down what it just paid for:
note(
title="Stripe sends charge.succeeded twice for one charge",
domain="acme/checkout/billing",
tags="idempotency, webhook, retry, duplicate delivery",
content="A retry carries the same event id, so the handler has to key off "
"the event id. Keying off the charge id lets the second delivery "
"book the order again.",
)Days later a cold session opens on that subject and asks for its bearing:
pulse("acme/checkout")It gets the latest checkpoint in full and a count of what is pending anywhere under that path: open tasks, pitfalls, handoffs, notes and flows. The session asks for the category it needs, and gets headers it can open:
must_read("acme/checkout", type="note") # titles and uids, that note among them
get_memory(uid) # the one the work touches, in fullA task is how work reaches the next session. The agent files it with a goal and one item per line, and works it as it goes:
made = task(
title="Move billing webhooks to the idempotent handler",
goal="Every billing webhook is deduplicated by event id.",
items="Key charge.succeeded by event id\nCover refunds and disputes\n"
"Remove the charge-id lookup",
domain="acme/checkout/billing",
)
uid = made["uid"]
charge, refunds, lookup = (i["id"] for i in made["items"]) # each is {id, n}
task_item(uid, charge, state="done", comment="Handler keys off the event id.")
task_note(uid, title="Refund replay", items=str(refunds),
goal="Replay a refund once, however often it arrives.",
context=f"Refunds arrive twice on retry; [[#{charge}]] shows the key.",
steps="Key refunds by event id.",
pitfalls="A dispute reuses the refund's event id.", done_when="The replay test passes.",
depends_on=str(charge))An item is a short label, at most 80 characters; its detail goes in a brief.
What only makes sense inside the task — an item's brief, a rule several items
share — is a task note, not a memory. A note on items is a brief: GOAL, CONTEXT,
STEPS, PITFALLS, DONE WHEN and DEPENDS ON, with EXTRA INFO for anything else.
Every tool names an item by its id; the number a list shows is only its place.
A person never sees the id, so an agent names an item to one as item n of
the task: the task's content lists each item as its number, text and id, every
task result carries n beside each id it names, and a foot_note on each
restates the rule.
Free text cites an item as [[#id]], which reads back as the item's current
number and label, and the dashboard inserts one when # is typed in a task's
text. task_item also renames an
item or deletes one, and edit_memory(uid, goal=...) rewrites the goal, so a
task is corrected in place. Search, recall and the session brief never return
a note. get_memory(uid) on a
task returns its head (goal, progress, counts), and task_read(uid, part)
reads its items, notes, comments and links one page at a time. Every tool
result stays under the size Claude Code shows inline: what can grow comes back
in pages with a next_offset. memai-store task-adopt turns memories linked to
a task's items into its notes, and refuses one that would land on items
without being a brief.
Open tasks come first in the session-start brief. The PreToolUse hook notes the
domains a session names in its memai calls, and at the end of a turn the stop
hook blocks once per interval to ask the agent to update the open tasks of those
domains, and to check similar domains for a task filed under another path. A
session that named no domain is not asked. The
dashboard's Maintenance view switches that reminder off and sets its interval;
a task's checklist, comments and linked memories are worked there as well. A
closed task is an archived memory, so list_by_domain(domain, type="task", status="archived") lists the completed and cancelled ones.
Quickstart
python -m venv .venv
.venv/Scripts/pip install --no-deps -e . # .venv/bin/pip off Windows
.venv/Scripts/pip install --require-hashes -r requirements-dev.txt
.venv/Scripts/python tools/install-webui.py # the admin dashboard
.venv/Scripts/python -m pytest
npm run typecheck && npm test # the dashboard's own checksRegister the server with your host, then let it reach a session by itself — the hooks put the store in front of an agent that did not ask for it, and the bundled skills and subagent teach it what to do with them:
claude mcp add --scope user memai C:\path\to\MemAI\.venv\Scripts\memai-mcp.exe
memai-hook install # the four hook events
memai-hook install --skills # the bundled skills
memai-hook install --agents # the warden subagent
memai-hook install --check # what is registered, and what is out of dateSee Hooks and the warden for what each event emits and how to turn the warden off.
Two hosts, two different files. Neither reads the other's, so a server registered in one is invisible to the other, and an empty list in one says nothing about the other.
host | the file it reads | how to write it |
Claude Code CLI — |
|
|
Claude desktop app — Chat and the Code tab | Windows: | edit the file, or Settings → Developer → Edit configuration |
Both hosts take the same block, pointing at the console script the install put in the environment:
{
"mcpServers": {
"memai": {
"command": "memai-mcp"
}
}
}A bare memai-mcp resolves only if that environment's Scripts\ (bin/ off
Windows) is on the PATH of the process that launches the server — and a GUI app
inherits the desktop session's PATH, not your shell's. Unless you know it is
there, give the absolute path instead:
{
"mcpServers": {
"memai": {
"command": "C:\\path\\to\\MemAI\\.venv\\Scripts\\memai-mcp.exe"
}
}
}claude mcp list reports what the CLI loaded; the desktop app lists what it
loaded under Settings → Developer → local MCP servers. A host reads its config
once, at startup, so restart it after an edit.
On Windows, install.bat does the venv, install and dashboard-build steps,
update.bat pulls the checkout and then runs install.bat, and run-admin.bat
starts the dashboard (it activates .venv itself; extra arguments pass
through, e.g. run-admin.bat --port 8890). stop-mcp.bat and stop-admin.bat
stop what is running. install.bat and update.bat refuse to start while an
MCP server or the dashboard still runs from the checkout, list what is open,
and offer to close it.
Windows locks an .exe while a process is running it, so apip install cannot
rewrite .venv\Scripts until every MCP server and the dashboard are down.
An agent installing MemAI on a new machine follows .agents/install.md: requirements, the order that keeps a running server from breaking the install, both MCP config files, and the checks that confirm the result.
Staying current. The stop hook asks GitHub, at most once per interval
(a day unless chosen otherwise), which releases are published and caches them —
tag, page and notes, one record per release — in MEMAI_HOME/update.json. A session that starts behind is told which version it
runs, how many releases came after it, what each of them changed (their notes,
flattened to a few plain lines) and the commands that update this checkout
— for the person to run once every session and the dashboard are closed, for
the reason above. The dashboard shows the same thing at leisure: the version
mark in its app bar carries the count and opens Releases, which renders the
packaged CHANGELOG.md with the running version marked and anything published
since it at the top. There, Check now asks GitHub at once, and Check every
sets the interval, from an hour to a week (the server accepts up to 30 days);
the choice is kept in MEMAI_HOME/update-settings.json and holds for every
project. memai-hook install --check prints the same comparison.
MEMAI_UPDATE_CHECK=0 stops the request, and belongs in the environment the
host itself runs in: the hook and the dashboard make it, not the MCP server,
which only reads what they cached.
The dashboard
memai-admin (or python -m memai.admin) serves the store at
http://127.0.0.1:8888 — loopback only; --host / --port /
MEMAI_ADMIN_PORT to change. It is where memories are read, edited, triaged and
curated by a person, where the diagrams are arranged, and — behind the version
mark in its app bar — where the release history is read.
memai-admin --status says where it is, memai-admin --stop stops it.
The dashboard is a Vue 3 and TypeScript app that Vite builds into
src/memai/webui/dist/. Without Node 22.18+ or a reachable npm registry, the
install takes the prebuilt one from the release instead. On start, memai-admin
rebuilds it when its sources differ from the ones the build was stamped with,
running npm ci too when the lockfile changed; it serves the build it has when
npm is missing or fails. MEMAI_ADMIN_BUILD=0 turns that off.
A memory can be pinned from its record: for every domain, or for its own
domain only (its subdomains and cross-listed paths included). must_read() and
pulse() count pinned memories beside the categories, the session brief
counts the global ones, and an agent lists them with
must_read(type=..., pinned=true) and reads every one before acting.
A host starts several MCP servers per session, so the dashboard is started once
and shared: each server asks /api/ping whether one already answers before
trying to bind, and the one that wins keeps the port. It is detached on purpose,
so it outlives the session that opened it.
{
"mcpServers": {
"memai": {
"command": "memai-mcp",
"env": {
"MEMAI_HOME": "/path/to/your/memai-store",
"MEMAI_ADMIN_AUTOSTART": "1",
"MEMAI_ADMIN_PORT": "8888"
}
}
}
}Every variable MemAI reads belongs in that block: a server the host launches
sees this environment and no other, not your shell's. MEMAI_HOME is a
placeholder — drop the line to keep the store at ~/.memai, and on Windows mind
that JSON wants its backslashes doubled.
Where the data lives
Under $MEMAI_HOME if it is set, otherwise ~/.memai. Not tracked in git —
user data, created on first run.
path | what it is |
| the |
| every other project, one file each, named as you named it |
| one line naming the project in use; absent means |
|
|
| generated SVGs, and the warden's per-session state |
A project is one whole memory: its own domains, relations, diagrams and
settings. Any name that works as a Windows file name works as a project
name, and two names that differ only in case are one project. The switch is
in the dashboard's top bar, and every MCP server, hook and dashboard on the
machine opens the active project on its next call — no restart. Every
write's result and every pulse() name the project they touched, and
list_projects() lists them all.
Memories move between projects from the dashboard — a selection in
Memories, or a whole domain in Domains — with move_to_project(), or with
memai-store move. A move copies each memory with its history into the
target, checks it there and only then removes the original, after a backup
of the source is written. What the copy cannot carry — a relation to a
memory outside the selection, a diagram jump across it — is reported before
anything moves.
Documentation
How the parts work lives in the wiki:
section | pages |
getting started | |
concepts | How a session uses memory · Memory types · Domains · Projects |
guides | Tasks · Diagrams · Curation · Dashboard · Backups and export |
reference | Tools · Hooks and the warden · Configuration · Storage · Retrieval |
Licence
MemAI is MIT. Roboto is bundled in webui/fonts/ under the SIL Open Font
License 1.1 (webui/fonts/OFL.txt), separate from MemAI's own licence.
Available Tools
43 toolsalso_domainAIdempotent
Cross-list an existing memory into one more domain path.
For the membership a memory picks up after the fact: it was filed where
it lives, and later turns out to be part of a subject that cuts across
the tree. Every read scoped to domain returns it from now on, without
moving it -- use the dashboard's re-home for that.
Returns {"uid": ..., "also": [...]} with the whole resulting set. A path the memory's own domain already sits under is dropped as redundant, so the echo is what actually holds.
| Name | Required | Description | Default |
|---|---|---|---|
| uid | Yes | the memory. | |
| domain | Yes | the path to cross-list it into. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With annotations only declaring write/idempotent/non-destructive, the description carries real weight: it discloses the durable effect (every read scoped to `domain` returns it), that nothing is moved, the return shape, and the dedup rule that a redundant ancestor path is dropped. This is behavior an agent cannot infer from the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The action is front-loaded in the first sentence and the rest elaborates behavior. Slightly prose-y and indirect in places ('the echo is what actually holds'), but every clause contributes information 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?
Though there is no output schema, the description spells out the return shape ({uid, also: [...]}) and the dedup semantics, covering both the call and its result for a simple two-parameter tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% so the baseline is 3, but the description adds semantic depth: `domain` is a path in a tree, and paths already subsumed by the memory's own domain are silently dropped. That redundancy rule is meaning beyond the schema's one-line 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?
States a specific verb and resource ('cross-list an existing memory into one more domain path') and immediately distinguishes the semantics from moving ('without moving it -- use the dashboard's re-home for that'). An agent can tell this apart from move_to_project or unfile_domain without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a concrete when-to-use scenario: a memory filed elsewhere that later proves to belong to a cross-cutting subject. It also carves out when NOT to use it (re-homing/moving) by pointing at the dashboard. No sibling tool is named as an alternative, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
anti_patternA
Record a pitfall: a move that looks right, why it fails, and what to do instead.
For a mistake worth not repeating. A fact that simply holds is a note(); how an analysis ran and what it settled is a reasoning(). Stored as type='anti_pattern' and read back under TEMPTATION / WHY WRONG / INSTEAD; pulse() counts the open ones for a domain and must_read(type='anti_pattern') lists them.
ONE pitfall per memory: a second temptation from the same session is its own anti_pattern(), connected with link_memories().
Returns the new uid and the project it landed in, plus similar when
the store already holds something close: correct, drop or link it as
similar_hint says. A field over its ceiling is refused and nothing is
written.
| Name | Required | Description | Default |
|---|---|---|---|
| also | No | other domain paths this belongs to, comma-separated: the subjects that cut across the tree `domain` sits in, such as the end-to-end flow a routine is one step of. Every read scoped to one of them returns it. A path `domain` already sits under is dropped as redundant. At most 200 characters each. | |
| tags | No | comma-separated keywords and synonyms. Retrieval is BM25 over content, tags and domain paths, and tags weigh second only to the body, so they make a memory findable by words its own text never uses: the identifier, the error string, the plain phrasing someone will type. A memory with none is reachable only by quoting itself. At most 1000 characters. | |
| title | Yes | one line naming what this memory is about, in the words someone would look for it by. A list shows it instead of the opening of the body, and it outweighs every other field in search, so a title that repeats the type ("note about the parser") names nothing. At most 120 characters; a name that needs more is summarizing the body. | |
| domain | No | the subject this belongs to, as a path from the outermost scope in ('acme/x100/p200'). File it as deep as the fact is specific -- a note about one routine goes on the routine, and still comes back when someone asks about the module or the product above it. At most 200 characters. | |
| instead | Yes | what to do, concrete enough to act on. | |
| pattern | Yes | the temptation, as the next agent will meet it: the move that looks right at the time. At most 800 characters. | |
| session | No | groups what one conversation writes. Leave it empty to use this server process's own stamp. | |
| why_wrong | Yes | the mechanism that makes it fail, specific enough to recognise the next time. | |
| source_ref | No | what the fact came FROM -- a path, a URL, a table name -- so a later pass can check the claim against the thing itself instead of inferring what to check from the wording. At most 500 characters. | |
| review_after | No | when this stops being safe to trust unchecked, as a date ('2026-11-01') or a span from today ('90d'). pulse() counts what is overdue in a scope as `scope.stale` and optimize_scan lists it. Leave it empty for anything that does not go stale -- most facts do not, and a date nobody meant is worse than none. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare this is a non-read-only, non-idempotent, non-destructive write. The description goes beyond them by disclosing write semantics an agent could not infer: a field over its ceiling is refused and nothing is written, and a near-duplicate in the store returns `similar` with a `similar_hint` to correct/drop/link. This is meaningful behavioral context beyond the annotation set.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and the primary sibling distinction are front-loaded in the first two sentences, followed by storage/read-back, sequencing, and return behavior. It is dense and every paragraph carries information, though the prose is leisurely enough that a point or two could be tightened.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, 10 parameters and a mutating operation, the description carries the needed load: it states the return shape (uid, project, similar), the atomic refusal behavior, and the read-back labels. Combined with 100% schema coverage, an agent has enough to call and interpret it; only return-field detail is left implicit.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the property descriptions are themselves rich, so the schema does the heavy lifting (baseline 3). The description adds marginal value by mapping stored fields to their read-back labels (TEMPTATION / WHY WRONG / INSTEAD) and naming the type='anti_pattern' discriminator, which clarifies how the required fields behave downstream.
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 ('Record a pitfall: a move that looks right, why it fails, and what to do instead') and explicitly disambiguates from siblings note() and reasoning() by describing what each captures. An agent can tell this apart from the other memory-writing tools without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives the trigger condition ('For a mistake worth not repeating') and contrasts it with the alternatives: a plain fact belongs in note(), a settled analysis in reasoning(). It also supplies operational guidance — one pitfall per memory, link a second temptation with link_memories() — which is explicit when-to-use and how-to-sequence advice.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
checkpointA
Snapshot current working state (intent/established/pursuing/open_questions).
A summary of where the work stands, so the next session picks up the right bearing via pulse(). Fields are free-length; still prefer a readable summary here and put timeless detail into note() -- checkpoints are read for bearing, not as an archive. One fact per note(), each cited back here by [[uid]] and linked with link_memories(); pulse() returns the latest checkpoint IN FULL, so every session pays for whatever was parked in these fields. Stored as type='checkpoint'.
A domain holds ONE active checkpoint. While one is already filed at
domain, the call is refused and nothing is written: the refusal
lists it under checkpoints. Read it with get_memory(uid) and decide
whether its work is done. Done: forget(uid, reason='...'), then call
again. Not done: carry what still holds into these fields and call
again with supersedes='', which archives it as superseded by the
new one. A checkpoint past the age limit set in the dashboard refuses
every write under its domain the same way, flagged overdue, until
it is settled.
| Name | Required | Description | Default |
|---|---|---|---|
| also | No | other domain paths this belongs to, comma-separated: the subjects that cut across the tree `domain` sits in, such as the end-to-end flow a routine is one step of. Every read scoped to one of them returns it. A path `domain` already sits under is dropped as redundant. At most 200 characters each. | |
| tags | No | comma-separated keywords and synonyms. Retrieval is BM25 over content, tags and domain paths, and tags weigh second only to the body, so they make a memory findable by words its own text never uses: the identifier, the error string, the plain phrasing someone will type. A memory with none is reachable only by quoting itself. At most 1000 characters. | |
| title | Yes | one line naming what this memory is about, in the words someone would look for it by. A list shows it instead of the opening of the body, and it outweighs every other field in search, so a title that repeats the type ("note about the parser") names nothing. At most 120 characters; a name that needs more is summarizing the body. | |
| domain | No | the subject this belongs to, as a path from the outermost scope in ('acme/x100/p200'). File it as deep as the fact is specific -- a note about one routine goes on the routine, and still comes back when someone asks about the module or the product above it. At most 200 characters. | |
| intent | Yes | what the work is for, in a sentence or two. | |
| session | No | groups what one conversation writes. Leave it empty to use this server process's own stamp. | |
| pursuing | Yes | what comes next, specific enough to start on. | |
| supersedes | No | the active checkpoints this one replaces, comma-separated uids: every one already filed at `domain`, and every overdue one above it that a refusal named. Each is archived with this one as its successor. | |
| established | Yes | what is done and what was decided, with the [[uid]] of each note that holds the detail. | |
| open_questions | Yes | what is still undecided or unverified. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false, destructiveHint=false, and non-idempotency, so this is a write tool with tame safety semantics. The description adds real behavioral value beyond that: it discloses the refusal path, the single-active-checkpoint constraint, the `overdue` age-limit refusal that blocks all writes under a domain, and the archival-by-supersedes behavior. It does not describe the return/refusal payload shape beyond naming the `checkpoints` key.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose, then constraints, then the recovery workflow, so the critical constraint is reachable early. It is long for a description and repeats "call again" and the supersede instruction several times, but nearly every sentence carries a rule an agent needs; the redundancy is mild rather than padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 10-param write tool with no output schema and rich annotations, the description covers purpose, write semantics, refusal handling, alternative tools, and storage type. An agent could execute the refusal-recovery loop correctly from this text alone, which is the main failure mode for this tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description nonetheless adds operational meaning the schema does not carry: that these five required fields are consumed in full by every pulse() call, that they should be short and bearings-oriented, that detail belongs in note() cited via [[uid]], and how supersedes is populated from refusal output. That lifts it above the schema-only baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource ("Snapshot current working state") and immediately enumerates the fields that constitute the snapshot. It explicitly distinguishes itself from sibling note() by contrasting bearing-reading checkpoints with timeless archive detail, so an agent can separate the two without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when/when-not routing: one active checkpoint per domain, refusal when one is already filed, and the exact decision tree (done -> forget then retry; not done -> supersede with the uid). It also names the sibling read path (pulse(), get_memory()) and the archive escape hatches, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
dedup_scanARead-onlyIdempotent
Surface likely-duplicate/contradictory memory pairs.
Lexical overlap over near-identical text -- each pair carries its
method. Two takes on one subject in different words do not surface
here. Same-domain/session checkpoint pairs are excluded (timelines, not
dups)
and checkpoint pairs rank below durable-type pairs. Not an automatic
merge -- returns candidate pairs + similarity score for the agent to
review and decide (link_memories / edit_memory / forget as
appropriate).
| Name | Required | Description | Default |
|---|---|---|---|
| type | No | one memory type, as search() takes it; empty is every type. | |
| limit | No | the most pairs to return. | |
| domain | No | scans a path and everything nested under it, which is usually what you want: near-duplicates collect between a module and its own routines. | |
| offset | No | where the page starts; `next_offset`, when present, starts the next. | |
| threshold | No | the similarity, 0 to 1, a pair must reach to be listed. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish the read-only, idempotent, non-destructive safety profile, and the description adds real value beyond that: the exclusion rules, the ranking behavior, and the fact that it returns candidates plus a similarity score for human/agent judgment rather than merging. This is exactly the useful context annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in the first line, and each subsequent sentence adds a distinct constraint (exclusions, ranking, non-merge semantics). The parenthetical density adds minor friction but nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, but the description compensates by describing the return shape (candidate pairs, similarity score, method field) and the intended follow-up actions. Combined with the strong annotation set, an agent has enough to call and act on the result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the parameters are already documented; the description only adds a modest hint for domain (nested-path behavior) and references the method field on returned pairs (an output detail, not a param). Baseline 3 is appropriate when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (surface duplicate/contradictory memory pairs) and immediately scopes what it will and will not return: lexical-overlap near-identical text only, with different-words takes explicitly excluded. This distinguishes it from siblings like search, recall, and timeline without requiring schema inspection.
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 negative guidance (same-domain/session checkpoint pairs excluded, checkpoint pairs rank below durable-type pairs) and clarifies it is not an automatic merge, routing the agent to link_memories/edit_memory/forget afterward. It falls short of explicitly naming the alternative tool for other scanning needs, so it lands at 4 rather than 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
diagramA
Document what a routine does, start to end, as a graph. Stored as type='diagram'.
For a PROCESS, not a fact: note() records what is true, checkpoint() where the work stands, this one how a routine runs. Every step is a separate object that can carry its own explanation and its own links to other memories, which is what makes a diagram the source of truth for its domain instead of one more wall of prose.
Keep every label objective -- what happens at that step, nothing
more. The reasoning, caveats and history belong in that node's
note, where they explain without cluttering the flow.
review_after and source_ref matter most for a flow: it describes code, and the code moves.
Returns {"uid": ...}, or {"ok": False, "errors": [...]} with nothing written at all. Node positions are computed and stored server-side, so the flow renders identically for every reader -- see get_diagram().
| Name | Required | Description | Default |
|---|---|---|---|
| also | No | other domain paths this flow belongs to, comma-separated. `domain` is the routine's own place in the tree; `also` is for the flows that run ACROSS routines -- several of them can be steps of one end-to-end process without any of them being the parent of the others. Cross-list each into that process's path and asking about it returns all of them, instead of hoping one search phrasing reaches every one. | |
| kind | No | 'flowchart', the only kind. | flowchart |
| tags | No | comma-separated keywords and synonyms. Retrieval is BM25 over content, tags and domain paths, and tags weigh second only to the body, so they make a memory findable by words its own text never uses: the identifier, the error string, the plain phrasing someone will type. A memory with none is reachable only by quoting itself. At most 1000 characters. | |
| edges | Yes | the wires between steps, as [{"from": "load", "to": "check", "label": "optional branch"}]. | |
| nodes | Yes | the steps, as [{"key": "load", "label": "Read the export window", "shape": "step", "note": "optional long explanation"}]. key is a stable id the edges refer to (letters, digits, '_' or '-'); shape is start|step|decision|io|end. Exactly one 'start' is required and every node must be reachable from it. Cycles are allowed -- a retry loop is a real flow, not a mistake. | |
| title | Yes | one line naming what this memory is about, in the words someone would look for it by. A list shows it instead of the opening of the body, and it outweighs every other field in search, so a title that repeats the type ("note about the parser") names nothing. At most 120 characters; a name that needs more is summarizing the body. | |
| domain | No | the subject this belongs to, as a path from the outermost scope in ('acme/x100/p200'). File it as deep as the fact is specific -- a note about one routine goes on the routine, and still comes back when someone asks about the module or the product above it. At most 200 characters. | |
| session | No | groups what one conversation writes. Leave it empty to use this server process's own stamp. | |
| summary | No | a few sentences on what the routine is for, indexed with the flow. | |
| source_ref | No | what the fact came FROM -- a path, a URL, a table name -- so a later pass can check the claim against the thing itself instead of inferring what to check from the wording. At most 500 characters. | |
| review_after | No | when this stops being safe to trust unchecked, as a date ('2026-11-01') or a span from today ('90d'). pulse() counts what is overdue in a scope as `scope.stale` and optimize_scan lists it. Leave it empty for anything that does not go stale -- most facts do not, and a date nobody meant is worse than none. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With annotations already declaring the write/safe/idempotency profile, the description adds real behavior beyond them: 'Returns {"uid": ...}, or {"ok": False, "errors": [...]} with nothing written at all' discloses atomic all-or-nothing semantics, and 'Node positions are computed and stored server-side' explains layout determinism. It stops short of touching auth, quota, or conflict handling, 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?
Purpose and the sibling contrast are front-loaded, and the guidance paragraphs are separated cleanly. It is on the long side, though: the aside that a diagram becomes 'the source of truth for its domain instead of one more wall of prose' is rhetorical padding that does not help an agent 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 an 11-parameter create tool with full schema coverage and no output schema, the description supplies what the schema cannot: the process-vs-fact routing, atomic failure behavior, and server-side layout. Nothing essential is missing, though it leaves session/domain interaction and the meaning of the required 'edges' shape entirely to the schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description adds meaning on top by instructing that 'label' be objective and that reasoning/caveats/history belong in that node's 'note', and by flagging that 'review_after and source_ref matter most for a flow: it describes code, and the code moves.' That is genuine parameter guidance rather than restatement of 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?
Opens with a specific verb and resource: 'Document what a routine does, start to end, as a graph. Stored as type='diagram'.' It then directly names the two nearest siblings (note(), checkpoint()) and the distinct resource each owns, so an agent can separate this from them 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 frames the when/when-not: 'For a PROCESS, not a fact: note() records what is true, checkpoint() where the work stands, this one how a routine runs.' That is an explicit alternative-selection rule plus an implied exclusion (do not use this for facts or status), and it points to get_diagram() for the read side.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
diagram_edgeADestructiveIdempotent
Wire two steps of a diagram together, relabel that wire, or remove it.
Calling again with the same endpoints updates the label instead of adding a second edge between them.
| Name | Required | Description | Default |
|---|---|---|---|
| uid | Yes | the diagram. | |
| label | No | the condition on a branch out of a decision node ('yes', 'no', 'on timeout'). | |
| delete | No | removes the edge between from_key and to_key. | |
| to_key | Yes | the step it reaches. | |
| from_key | Yes | the step the edge leaves. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and idempotentHint=true; the description reinforces this by disclosing the upsert rule (re-calling with the same endpoints updates the label rather than adding a duplicate edge). It stops short of describing failure behavior, e.g. what happens when the edge or endpoints do not exist, or whether delete requires the label.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with the multi-mode capability front-loaded and the upsert caveat immediately after; no filler. Slightly dense phrasing ('wire ... that wire') but nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with no output schema, the description covers the three operations and the key idempotency behavior, and annotations carry the safety profile. Gaps are minor: error conditions and the relationship to diagram_link are not covered.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so every parameter, including the branch-condition semantics of label and the removal semantics of delete, is already documented in the schema. The description adds no syntax, format, or default details beyond that, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States concrete verbs (wire, relabel, remove) and the resource (two steps of a diagram), covering all three modes of the tool. It does not distinguish itself from the sibling diagram_link, which sounds like it could do something similar, so an agent cannot fully rule siblings in or out from the description alone.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no guidance on when to choose this over diagram_link, diagram_jump, or diagram_node, and no mention of prerequisites (e.g. that the referenced nodes must already exist). Usage is only implied by the verb list; the alternative tools with adjacent-sounding names are never addressed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
diagram_jumpADestructiveIdempotent
Continue one step of a flow into ANOTHER flow, optionally at one of its steps.
Not the same statement as diagram_link: that attaches prose explaining a step, this says the rest of this branch is documented elsewhere. Use it where a routine hands off -- a sub-process, an error path owned by another flow, a variant of the same job.
Stored once and read from both ends, so the return trip already exists and get_diagram(format='json') reports it on both diagrams.
| Name | Required | Description | Default |
|---|---|---|---|
| uid | Yes | this diagram; on a delete, either end's diagram. | |
| label | No | what the hand-off is, shown on the jump. | |
| delete | No | removes the jump. | |
| node_key | Yes | this diagram's step the branch leaves from; on a delete from the receiving end, that end's step. | |
| peer_uid | Yes | the diagram the branch continues in. | |
| peer_node | No | the step it arrives at there; empty arrives at the diagram as a whole. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and idempotentHint=true, so the safety profile is covered. The description adds genuine non-obvious behavior: the jump is stored once and read from both ends, so the return trip already exists and get_diagram reports it on both diagrams. It stops short of describing the delete path or any permission requirements, keeping it from a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the verb and resource, then differentiation, use cases, and storage semantics in a logical order. Slightly longer than strictly necessary, but each sentence carries distinct information 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?
For a 6-parameter mutation tool with no output schema, the description covers purpose, sibling differentiation, use cases and the symmetric storage model. It omits deletion semantics and permission needs, which the delete parameter and destructiveHint leave partially addressed but not fully explained.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all six parameters are already documented, including uid, node_key, peer_uid, peer_node and delete. The description only implies that the arrival step is optional ('optionally at one of its steps'), adding little beyond the schema. Baseline 3 applies when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Continue one step of a flow into ANOTHER flow') with the scope of the target (optionally a specific step). It also explicitly distinguishes itself from the sibling diagram_link by contrasting what each attaches, so an agent can route between them 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?
Names the alternative (diagram_link) and the exact semantic difference, then gives concrete when-to-use scenarios: a routine handing off to a sub-process, an error path owned by another flow, or a variant of the same job. Nothing about selection is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
diagram_linkADestructiveIdempotent
Attach another memory to one specific step of a diagram.
What turns a diagram into an index of its domain: the step states what happens, the linked note/anti_pattern/reasoning states why it is that way. Point at the step the memory actually concerns -- for an edge to the diagram as a whole use link_memories() instead, and to say the branch continues in another flow, diagram_jump().
get_memory() on the linked memory reports the diagrams that reference it, so the connection is visible from both ends.
Returns {"ok": True}, or {"ok": False, "errors": [...]} for an unknown diagram, step or memory, a link from a diagram to itself, or a delete with no such link.
| Name | Required | Description | Default |
|---|---|---|---|
| uid | Yes | the diagram. | |
| delete | No | removes the link between node_key and target_uid. | |
| node_key | Yes | the step the memory explains. | |
| target_uid | Yes | the memory to attach. | |
| relation_type | No | how the memory relates to the step; 'explains' unless given. Linking the same step and memory again replaces it. | explains |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and idempotentHint=true, so safety is partly covered; the description adds real value on top by enumerating failure modes (unknown diagram/step/memory, self-link, delete with no such link) and the exact return shape {ok, errors}. It does not spell out permission or reversibility implications of the destructive delete path beyond what the schema states, so it falls short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The action statement is front-loaded, followed by usage context, alternatives, and error/return behavior in logical order. The 'what turns a diagram into an index of its domain' framing is mildly rhetorical but does convey the why, so it mostly earns its place; only slightly longer than needed.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 5-param mutation tool with no output schema, the description covers purpose, alternatives, error conditions on invalid inputs, and the return envelope, plus the bidirectional visibility via get_memory. Nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds conceptual meaning the schema lacks: node_key is the step the memory 'actually concerns' and relation_type defaults to 'explains' with replacement semantics on re-linking. These clarify intent beyond the terse schema strings.
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?
Opening sentence gives a specific verb+resource: attach a memory to one specific step of a diagram. It then explicitly differentiates from the nearest siblings (link_memories for whole-diagram edges, diagram_jump for branch continuation), so an agent can route correctly 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?
Names the alternatives and the exact condition that selects each one ('for an edge to the diagram as a whole use link_memories()', 'to say the branch continues in another flow, diagram_jump()'). It also explains the intended granularity: point at the step the memory actually concerns, not the diagram.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
diagram_nodeADestructiveIdempotent
Add, patch or remove one step of a diagram.
Only the arguments you pass are touched, so patching a note leaves the label alone; pass note="" to clear one.
The whole-graph rules are relaxed here on purpose: a step may sit unattached until you add its edges, which is what lets a flow be built up across several calls. diagram() enforces them.
| Name | Required | Description | Default |
|---|---|---|---|
| key | Yes | the step's id; a new key adds a step. | |
| uid | Yes | the diagram. | |
| note | No | the step's explanation: reasoning, caveats, history. | |
| label | No | what happens at the step, objectively. | |
| shape | No | start|step|decision|io|end. | |
| delete | No | removes the step together with its edges and its memory links. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes beyond the annotations by disclosing partial-update semantics ('only the arguments you pass are touched'), the empty-string clear convention, and the deliberate relaxation of whole-graph validation versus diagram(). It leaves the destructive scope to the schema's delete description rather than restating it, which is acceptable given destructiveHint=true already flags the risk.
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 action, then two short paragraphs that each carry distinct value (patch semantics, validation relaxation). Slightly longer than strictly necessary but no sentence 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?
With all six parameters documented and annotations carrying the safety profile, the description supplies the remaining behavioral context an agent needs (partial updates, clearing, relaxed invariants). No output schema exists, so return-value disclosure is not required.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: merge-style patching and the note="" clear idiom are behaviors the schema alone does not convey. It does not cover the required uid/key semantics beyond what the schema states.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence names a specific verb triad (add/patch/remove) and resource (one step of a diagram), which an agent can act on immediately. It implicitly separates 'step' from edge/link siblings but never names diagram_edge or diagram_link to sharpen the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explains the intended usage pattern (build a flow up across several calls, leaving steps unattached until edges are added) and points at the alternative diagram() for whole-graph enforcement. No explicit 'when not to use' for the edge/link siblings, but the incremental-vs-atomic contrast is genuinely useful.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
diagram_relayoutADestructiveIdempotent
Recompute a diagram's stored node positions from scratch.
Positions live in the store, not in a viewer, so every reader sees the same picture and positions hand-adjusted in the admin dashboard persist. This discards those adjustments and rebuilds the layered arrangement -- the fix for a diagram dragged into a mess.
| Name | Required | Description | Default |
|---|---|---|---|
| uid | Yes | the diagram. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and idempotentHint=true, but the description goes further by naming exactly what is destroyed: hand-adjusted positions stored server-side and edited in the admin dashboard. The explanation that positions live in the store rather than the viewer meaningfully explains the persistence model. It still says nothing about return shape, timing, or permissions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The action is front-loaded and there is no filler, but the middle sentence about store-vs-viewer persistence is a long clause whose job could be done more briefly. It earns most of its place by justifying the destructive warning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter mutation with no output schema, the description covers what it does, what it overwrites, and when to reach for it. The only real gap is what the caller gets back or how to confirm the relayout succeeded.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is a single parameter (uid) and schema description coverage is 100%, so the schema already carries the meaning; the description adds no syntax, format, or identifier-source detail. Baseline 3 applies when structured fields do the work.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a precise verb+resource: 'Recompute a diagram's stored node positions from scratch.' That is unmistakably different from siblings like get_diagram (read) or diagram_node/diagram_edge (sub-resource editing), so an agent can route correctly without inspecting another 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?
It gives a clear usage context -- 'the fix for a diagram dragged into a mess' -- and implicitly cautions that manual adjustments will be lost, which steers the agent away from calling it casually. It stops short of naming when-not-to-use or an alternative tool, so it is not a full 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
edit_memoryADestructive
Correct a memory's content or its source reference, keeping the previous version.
Corrections are common in append-only memory stores that only support delete, not edit; this preserves the old content instead of losing it. Each field is settable on its own; passing none of new_content, source_ref, title, tags and goal is an error rather than a silent no-op.
Refuses to rewrite a diagram's content: that is generated from the
graph, so a hand-written replacement would be silently overwritten by
the next structural change -- edit the flow through
diagram_node/diagram_edge. Its source_ref is ordinary metadata and is
editable here like any other memory's. A task's content is generated
from its goal and items the same way: rewrite its goal with goal,
and its items through task_item().
| Name | Required | Description | Default |
|---|---|---|---|
| uid | Yes | the memory. | |
| goal | No | a task's new goal, held to the rules task() states; the previous goal stays in the edit history. Refused on any other type. | |
| mode | No | 'replace' or 'append'. 'append' adds `new_content` as a new line at the end instead of replacing the body. Use it when a memory gains a fact rather than turning out to be wrong: the alternative is reading the whole thing, restating it and sending it back, which pays for the body twice and stakes the existing text on it being copied faithfully. Append what THIS memory gained. A fact about a further subject is a new memory plus an edge, not a line at the bottom -- appended text is ranked as part of the body it lands in and comes back with it. | replace |
| note | No | why it changed, kept with the previous version in the edit history. | |
| tags | No | REPLACES the tag set, comma-separated: pass the whole set that should survive, not the one being added. Indexed, so this is how an untagged memory becomes findable by the words its body never uses. Empty leaves the stored tags alone -- clearing them, like clearing a source_ref, is a dashboard edit. | |
| title | No | renames the memory: the one line a list shows it by, and the field weighing most in search, at most 120 characters. A diagram is renamed through its graph instead -- its title is part of what generates the body, so a rename here would be overwritten by the next structural change. | |
| source_ref | No | points the memory at what its claim came from -- the field note() takes at write time, and the one a later pass checks the claim against. Settable with no `new_content`, for the common case of a body that is right and a reference that is missing or has moved; empty leaves the stored one alone, and clearing one is a dashboard edit. | |
| new_content | No | the corrected body, or with mode='append' the line to add. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations (destructive/non-idempotent), disclosing that the previous version is preserved in edit history, that no-op calls with all fields empty are an error rather than silent success, that empty tag/source_ref values leave stored values alone (clearing is a dashboard edit), and that diagram/task bodies are generated and would be silently overwritten.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core operation, and the modal/refusal guidance is dense and useful. The rationale sentence about append-only stores is justificatory filler, and three paragraphs is on the long side, so it stops short of maximal conciseness.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 8-parameter mutation tool with no output schema, the description covers modes, partial-field semantics, the all-empty error case, and which memory types are editable. Combined with 100% schema coverage and annotations carrying the safety profile, an agent has everything needed to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3 and the per-parameter descriptions already carry most meaning. The prose adds one genuinely new rule not in the schema ('passing none of new_content, source_ref, title, tags and goal is an error'), which lifts it slightly above baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource+scope: 'Correct a memory's content or its source reference, keeping the previous version.' It also distinguishes itself from siblings by noting it is not delete (which it contrasts against the append-only store) and not the diagram/task editors, so an agent can route correctly.
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 routing: use mode='append' when a memory gains a fact vs. mode='replace' when it turns out wrong; rewrite a diagram's flow via diagram_node/diagram_edge; rewrite a task's goal with `goal` and its items through task_item(). Both when-to-use and when-not are present.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
forgetAIdempotent
Archive a memory (soft delete -- content is kept, just excluded from default search/list).
The call for a memory that is wrong, stale or a copy. It is reversible: the dashboard's restore brings an archived memory back, and list_by_domain(status='archived') still reads it. purge_memory() is the irreversible delete, only on the user's explicit request; to correct a memory instead of retiring it, edit_memory(). Archiving an open task cancels it; its items keep their states.
Returns {"ok": True}, or {"ok": False} for an unknown uid.
| Name | Required | Description | Default |
|---|---|---|---|
| uid | Yes | the memory. | |
| reason | No | why it is archived, recorded as a status-change audit entry without touching the content. | |
| superseded_by | No | the uid of the memory that replaces this one, kept on the archived record. To mark a memory that stays active as replaced, draw link_memories(new, old, 'supersedes') instead: search then flags the old one `succeeded_by`. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare a non-destructive, idempotent write; the description goes well beyond that by explaining reversibility (dashboard restore, list_by_domain visibility), the side effect that archiving an open task cancels it while items keep states, and the exact return shapes {ok: True} / {ok: False} for an unknown uid. No contradiction with destructiveHint=false or idempotentHint=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?
Front-loaded with the core definition in the first sentence, then routing and side-effect details. Information-dense with minimal waste, though the parenthetical-heavy, multi-clause third sentence is slightly heavier than needed.
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 exists, yet the description supplies the return contract and error case, the reversibility model, and the task-cancellation side effect. Nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so uid, reason and superseded_by (including the detailed superseded_by vs link_memories guidance) are already documented in the schema. The description adds no parameter-level syntax or format detail beyond that, so the baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Archive a memory') and immediately defines the semantics ('soft delete -- content is kept, just excluded from default search/list'), which cleanly separates it from purge_memory and edit_memory. An agent can distinguish it from every sibling 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 names the trigger ('a memory that is wrong, stale or a copy') and routes to alternatives: purge_memory for irreversible deletion only on explicit user request, edit_memory to correct rather than retire. It even names the read path for archived items, list_by_domain(status='archived').
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_diagramARead-onlyIdempotent
Read a diagram back: format='svg-interactive' to show it, 'json' to reason about it.
Formats: 'svg-interactive' (canvas drawing in a pan/zoom shell -- the one to SHOW), 'svg' (same drawing as a plain file, to attach or link), 'mermaid' (portable, but re-lays out and DISCARDS the arrangement the user made), 'text' (the prose projection), 'json' (the full graph with positions, notes and links -- the only round-trippable one, and the one to reason over).
Both SVG formats write the markup to a file and return its path plus a
thin index of the steps; the payload is deliberately too small to draw
from. The returned next_step says what to do with the path, at the
point where it matters: when the user asked to SEE the flow, reading the
file and emitting it inline is the work, not a cost to avoid.
| Name | Required | Description | Default |
|---|---|---|---|
| uid | Yes | the diagram. | |
| format | No | one of the formats above. | mermaid |
| offset | No | where a long `body`, or the SVG step index, starts; `next_offset`, when present, starts the next page. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, and the description adds real behavioral context on top: both SVG formats write markup to a file and return only a path plus a thin step index 'deliberately too small to draw from', and the returned next_step tells the agent to read and emit the file inline. This is substantive disclosure the annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the action and the two primary formats, then layered detail. The third paragraph is somewhat editorial ('reading the file and emitting it inline is the work, not a cost to avoid'), but each sentence still conveys actionable behavior, so efficiency is good though not maximal.
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, the description shoulders the return contract and does so well: it names the returned path, the thin index, next_step and (via the schema) next_offset paging. An agent has everything needed to call it and act on the result correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, but the schema's own param text is thin ('one of the formats above', 'the diagram.'), so the description deliberately carries the meaning of each format value and how it relates to round-tripping and layout fidelity. It adds little on `offset` beyond what the schema says, keeping it just under a 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource ('Read a diagram back') and immediately anchors the two headline formats to their purpose. An agent understands the tool's job without the schema. It does not, however, explicitly distinguish itself from read-oriented siblings like 'diagram' or 'recall', so a 4 rather than a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use guidance per format: svg-interactive 'to SHOW', json 'to reason about it', mermaid 'portable, but re-lays out and DISCARDS the arrangement', and flags json as 'the only round-trippable one'. This is exactly the decision an agent faces when choosing a format, with the trade-off for each stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_domain_caseARead-onlyIdempotent
Report the store's domain-casing policy.
Returns {"mode": "preserve"|"lower"|"upper"}. 'preserve' stores
domains as written; 'lower'/'upper' coerce every domain to that case
on write (a non-conforming domain is adjusted, not rejected, and the
writer's result carries a domain_adjusted note). Read this before
coining a new domain so its casing matches what will be stored.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, and the description adds substantial non-annotation context: the exact return shape, the meaning of each mode, and crucially the write-side consequence that non-conforming domains are coerced rather than rejected, with a `domain_adjusted` note surfaced on the writer's result.
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 single-sentence purpose, then the return contract, then the usage rule. Every sentence carries information an agent cannot get from the empty schema or the annotations.
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?
There is no output schema, so the description correctly carries the return shape itself, and with no parameters and full annotation coverage, nothing needed to invoke this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4; there is nothing for the description to disambiguate and it appropriately spends no words on parameters.
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: 'Report the store's domain-casing policy', and the enumerated return modes make the scope unambiguous. It does not explicitly name the counterpart setter (set_domain_case), so it stops short of full sibling differentiation, but the read-vs-write split is obvious from the verb.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit usage directive with rationale: 'Read this before coining a new domain so its casing matches what will be stored.' That tells the agent when to call it, but offers no exclusions or named alternative for changing the policy (set_domain_case).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_memoryARead-onlyIdempotent
Fetch one memory: its fields, and counts of what is linked to it.
next names the call that pages each part: get_relations() for
relations and diagrams, get_diagram() for a diagram's graph,
task_read() for a task's items, notes and comments, edits_offset for
the edit history and content_offset for a body too long for one
response.
| Name | Required | Description | Default |
|---|---|---|---|
| uid | Yes | the memory. | |
| edits_offset | No | from -1 to a page start, reads the edit history instead of the record, bodies cut to 4000 characters. | |
| content_offset | No | from -1 to a character offset, reads that stretch of the body instead of the record. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, closed-world), and the description adds real behavioral detail: that linked data is only counted, that parts are paged via 'next', and that bodies can exceed one response. It stops short of describing error behavior when a uid is missing.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose in one sentence, then a compact routing sentence. The second sentence is dense with call names but every clause carries usable information; no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description must carry return-value semantics, and it does: fields, counts, and how each paginated part is retrieved. The only gap is that the shape of 'fields' and the count keys themselves are left unspecified.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds genuine meaning: edits_offset switches to edit history with bodies cut to 4000 characters, and content_offset reads a character stretch of the body. This clarifies the mode-switching behavior of the two optional params beyond the schema's own wording.
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 ('Fetch one memory') plus the scope of what is returned ('its fields, and counts of what is linked to it'), which cleanly separates it from sibling list/search tools like recall, search, and list_recent.
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 second sentence explicitly routes the agent to the correct follow-up calls for each paginated part (get_relations() for relations/diagrams, get_diagram() for a graph, task_read() for task items). It does not, however, say when to prefer get_memory over siblings such as search or recall when the uid is unknown.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_relationsARead-onlyIdempotent
List a memory's links, one page at a time; follow next_offset.
| Name | Required | Description | Default |
|---|---|---|---|
| uid | Yes | the memory. | |
| part | No | 'relations' (edges, both ways) or 'diagrams' (flows pointing at it). | relations |
| offset | No | where the page starts; `next_offset`, when present, starts the next. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false, so the safety profile is covered. The description adds that results are paginated and driven by next_offset, which is genuinely useful behavioral context, but that same mechanism is already spelled out in the offset schema description, so the marginal value is modest. No error or empty-result behavior is described.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single compact sentence that front-loads the core action ('List a memory's links') and ends with the actionable pagination hint. 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?
For a simple three-parameter read tool with full schema coverage and annotations covering safety, the description is nearly complete. The one remaining gap is return shape — there is no output schema, and while 'follow next_offset' hints that next_offset appears in the response, the description does not describe the returned link records.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% — uid, part (with its enum-like values 'relations'/'diagrams'), and offset are all documented in the schema. The description adds no syntax, format, or defaulting detail beyond that, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'List a memory's links'. This is clearly distinguishable from write-oriented siblings like link_memories or get_memory, though it never names an alternative explicitly. The 'one page at a time' scope note sharpens the purpose further.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the purpose (use it when you need a memory's links) and the pagination instruction tells the agent how to continue iterating. However, there is no explicit when-to-use/when-not guidance, no statement of prerequisites (e.g., a valid uid), and no pointer to alternatives like search or get_memory for related lookups.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
link_memoriesAIdempotent
Create a queryable edge between two memories.
This is what splitting a body into several memories costs: a [[uid]] written inside prose is a reference a reader follows, and only an edge created here is visible to get_relations() and to the graph.
Refuses an unknown uid, a memory related to itself, and an edge that already exists with that same type -- each as {"ok": False, "errors": [...]}, so a typo comes back as something to fix instead of a dangling edge or a raw database error.
| Name | Required | Description | Default |
|---|---|---|---|
| note | No | why the two are related, kept on the edge. | |
| to_uid | Yes | the memory it points to. | |
| from_uid | Yes | the memory the edge starts at. | |
| relation_type | Yes | free text, but keep it consistent, e.g. 'supersedes', 'relates_to', 'contradicts', 'links_to'. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the safety profile (not read-only, not destructive, idempotent, closed-world), so the bar is lower. The description adds real value beyond that: the exact error contract ({"ok": False, "errors": [...]}) and the three validation rejections. It's consistent with idempotentHint since a refused duplicate leaves state unchanged. It doesn't describe the success return shape, which is the only notable gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core action is front-loaded in the first sentence, followed by a short rationale and then the error behavior. The middle paragraph is slightly literary ('This is what splitting a body into several memories costs') and indirect, but it earns its place by justifying when the tool matters.
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 create-link tool with full schema coverage and annotations, the description covers purpose, validation errors, and the differentiator from prose references. There is no output schema, so a brief note on the success response would round it out, but nothing essential 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 description coverage is 100%, so all four parameters are already documented in the schema (including the note field's purpose and the relation_type advice). The description adds conceptual framing of the edge's directionality but no syntax or format detail beyond what the schema provides. Baseline 3 is correct here.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Create a queryable edge between two memories') and immediately distinguishes it from an adjacent concept: a [[uid]] in prose versus an edge, the latter being what get_relations() and the graph can see. An agent can tell this apart from sibling tools like get_relations or diagram_edge without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear reason to choose this tool over the prose-reference alternative by naming the downstream consumer (get_relations(), the graph). It also enumerates the refusal conditions (unknown uid, self-relation, duplicate edge), which effectively tells the agent what inputs are out of scope. It stops short of naming sibling tools to prefer for other linking needs, so it's not a full when/when-not.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_by_domainARead-onlyIdempotent
List memories for a domain and its subdomains, most recent first.
Fallback when search misses. A task row carries state (open,
completed or cancelled) and progress {done, total}.
Returns {"results": [...], "est_tokens": N}. Content is
snippet-truncated per result -- call get_memory(uid) for the full
record; a result's est_tokens estimates what that full record costs,
and the top-level est_tokens is the sum over the results.
| Name | Required | Description | Default |
|---|---|---|---|
| type | No | one memory type, as search() takes it; empty is every type. | |
| limit | No | the most results to return. | |
| domain | Yes | a path, matched from the outermost segment in: 'acme/x100' lists the module's own memories plus every routine under it. A domain that matches no path is retried as a run of segments INSIDE one, so list_by_domain('p200') still finds the routine once it lives at 'acme/x100/p200'. The literal reading wins whenever it has rows, and an ambiguous name (the same code under two modules) covers both branches rather than picking one -- each row's `domain` says which branch it came from. list_domains() is the way to see the paths first. | |
| offset | No | where the page starts; `next_offset`, when present, starts the next. | |
| status | No | 'active', 'archived' or 'all'. Closing a task archives its memory, so list_by_domain(domain, type='task', status='archived') returns the completed and cancelled tasks. | active |
| subtree | No | False lists what is filed at exactly that path and nowhere deeper. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, and the description adds real behavioral context on top: return shape {'results': [...], 'est_tokens': N}, snippet truncation, the need to call get_memory(uid) for full records, and the meaning of both the per-result and top-level est_tokens. This is exactly the kind of value structured fields don't carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded purpose followed by usage, then return contract — good ordering with no filler sentences. The long parenthetical clauses (est_tokens, truncation) are dense but each earns its place; slightly verbose overall.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and rich annotation coverage, the description carries the return-format burden and does so fully: result shape, truncation behavior, token estimation, and the follow-up get_memory call. Nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all six parameters are already documented in the schema (including the subtle domain retry/ambiguity semantics). The description adds no parameter-level meaning beyond that; the task-row 'state'/'progress' note describes return values, not inputs. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource with scope and ordering: 'List memories for a domain and its subdomains, most recent first.' It also positions itself against a named sibling ('Fallback when search misses'), so an agent can distinguish it from search without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Fallback when search misses' gives an explicit trigger condition, and the domain parameter routes the agent to list_domains() to discover paths first. It does not spell out the inverse (when search is preferable) or exclusion cases, so it falls short of a full 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_domainsARead-onlyIdempotent
List the domain tree: every path with its counts and latest activity.
Warm-up discovery. domain is free text and drifts over time (e.g. 'proj-1042' vs 'proj-1042-cache-warmup'), so this surfaces the paths actually in use instead of leaving you to guess one. Ordered by most recent activity.
Per entry: domain (the full path), parent, depth, count (filed
at exactly this path), subtree (that plus everything nested under
it), children, and implicit -- true for a level that exists only
because something deeper is filed under it. Read subtree to pick the
scope worth warming up: a parent holding nothing of its own can still
be where the work is.
also and subtree_also are the same two counts for memories
CROSS-LISTED here rather than filed here -- the cross-cutting subjects.
A path with count 0 and also above it is one of those and nothing
else: an end-to-end flow whose steps all live under other branches.
Reads scoped to it return them all.
Casing may be enforced store-wide -- call get_domain_case() to see the active policy before coining a new domain.
| Name | Required | Description | Default |
|---|---|---|---|
| offset | No | where the page starts; `next_offset`, when present, starts the next. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, and the description still adds substantial behavioral context beyond them: ordering by most recent activity, the meaning of implicit levels, and the cross-listed vs filed distinction for `also`/`subtree_also`. This is genuinely useful disclosure the structured fields do not carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the one-line purpose before the field glosses, and every sentence carries load (field definitions, cross-listing, casing). It is dense and long, but not padded; the length is justified by the undocumented return shape.
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 exists, so the description takes on explaining the return fields and it does so completely: domain/parent/depth/count/subtree/children/implicit plus cross-listed counts. It also covers the store-wide casing dependency, leaving nothing an agent needs in order to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter (offset) with 100% schema coverage, so the schema does the heavy lifting. The description says nothing extra about offset syntax, but it compensates by thoroughly defining the shape of the returned entries, which is the real semantic payload of this tool.
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 ('List the domain tree') with scope ('every path with its counts and latest activity') and immediately frames it as warm-up discovery. An agent can distinguish it from list_by_domain, list_projects, and also_domain 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?
Explains the motivating context well: domain is free text that drifts, so this surfaces actual paths instead of guessing, and it routes to get_domain_case() before coining a new domain. It gives clear when-to-use guidance but no explicit exclusion of alternatives or when-not condition.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_projectsARead-onlyIdempotent
The projects in this home, and which one every call here reads and writes.
A project is one SQLite file with its own memories, domains, relations
and diagrams. The active one is switched in the admin dashboard, and a
running server follows on its next call -- so every write's result names
the project it landed in, and pulse() names the one it read. Each entry
carries name, memories (the active rows) and active. Names are
matched without regard to case wherever a tool takes one.
| Name | Required | Description | Default |
|---|---|---|---|
| offset | No | where the page starts; `next_offset`, when present, starts the next. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With readOnly/idempotent/destructive annotations already covering the safety profile, the description adds genuine behavior: the active project is switched externally in the admin dashboard and a running server follows on its next call, and writes/pulse name the project they touched. It also discloses the entry shape (`name`, `memories`, `active`), which is valuable given there is no output schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded in the first sentence, but the passage is discursive and includes material that doesn't apply to this tool — the case-insensitive name matching note is irrelevant here since list_projects takes no project-name parameter, and the SQLite-file explanation is tangential. Several sentences do not earn their place for a one-parameter list call.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only listing tool with no output schema, the description compensates well by describing the returned entry fields and the meaning of `active`. The one gap is that pagination (offset/next_offset) is never mentioned in prose, though the schema covers 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 coverage is 100% and the single `offset` parameter is already documented in the schema (including the `next_offset` continuation note). The description adds nothing about pagination, so the schema does the entire job. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the resource (the projects in this home) and its central purpose (showing which project every call reads/writes), and explains what a project actually is. It stops short of a verb-led statement like 'list,' but no sibling tool enumerates projects, so an agent can still place it correctly.
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 implies the use case (discovering the active project and the available projects) but never states explicitly when to call this versus alternatives such as list_domains, nor any exclusions. The relevance of the active project is explained, which is useful contextual guidance, but usage is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_recentARead-onlyIdempotent
List the most recent active memories, optionally filtered by type/domain.
Returns {"results": [...], "est_tokens": N}. Content is
snippet-truncated per result -- call get_memory(uid) for the full
record; a result's est_tokens estimates what that full record costs,
and the top-level est_tokens is the sum over the results.
| Name | Required | Description | Default |
|---|---|---|---|
| type | No | one memory type, as search() takes it; empty is every type. | |
| limit | No | the most results to return. | |
| domain | No | covers its subdomains, and a bare deep segment resolves to the branches holding it (see list_by_domain). | |
| offset | No | where the page starts; `next_offset`, when present, starts the next. | |
| subtree | No | False narrows to the exact domain path. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, idempotent, non-destructive behavior, so safety is covered. The description adds genuinely non-obvious behavior: results are snippet-truncated, per-result est_tokens estimates the cost of the full record, and the top-level est_tokens is the sum -- context the annotations and schema do not carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded in the first sentence, and the second sentence is dense but justified because it explains the return shape and token semantics that have no output schema to carry them. Slightly long but no empty sentences.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description usefully documents the return envelope and token-cost semantics, and it points to get_memory for full records. It is complete enough to call correctly, though it omits pagination behavior (next_offset) beyond what the schema hints at and does not clarify sibling selection.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already explains type, limit, domain, offset, and subtree in detail. The description only adds 'optionally filtered by type/domain', which is weaker than the schema text itself, so it does not meaningfully enrich parameter meaning beyond the baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List the most recent active memories') plus a scope qualifier (recent/active) and optional filters. It is clear what the tool returns, though it does not explicitly contrast itself with close siblings like search, recall, or timeline.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides one useful downstream pointer -- call get_memory(uid) for the full record because results are snippet-truncated -- which tells the agent how to follow up. However it gives no guidance on when to choose this over 'search', 'recall', 'timeline', or 'list_by_domain', so the core selection decision is left implicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
move_to_projectADestructive
Carry memories from the active project into another one, and remove them here.
Each memory travels whole -- body, cross-listings, usage counts, edit
history, the relations and diagram graph inside the slice -- into
target, is checked there, and only then purged from the active
project, after a backup of it is written.
| Name | Required | Description | Default |
|---|---|---|---|
| uids | No | comma-separated memories to move; give uids, domain or both. | |
| create | No | makes a `target` that does not exist yet. | |
| domain | No | a path to move, its subdomains and archived rows included. | |
| target | Yes | the project to move into; list_projects() names the projects there are. | |
| dry_run | No | the default, and moves nothing: it reports what would move, `conflicts` (uids `target` already holds, which stay here), `unknown` (uids asked for that this project does not hold) and `outside` -- the relations, diagram links and jumps, `superseded_by` marks and [[uid]] references that cross the edge of the slice, all of which the move drops. Each comes as `count`, the whole number, and up to 20 `items`. Read that report with the user, then widen the slice or accept the loss BEFORE calling again with dry_run=False: the purge is irreversible short of the backup. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare destructiveHint=true and readOnlyHint=false, but the description goes well beyond: it explains the copy-then-verify-then-purge sequencing, what gets dropped on crossing the slice boundary (relations, diagram links, jumps, superseded_by marks, [[uid]] references), that conflicts/unknown/outside items are reported, and that the purge is irreversible short of the backup. This is rich behavioral context annotations alone cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two well-structured sentences that front-load the core action and then disclose the staging behavior. Slightly dense but every clause carries weight; 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?
For a destructive 5-param move tool with no output schema, the description covers the lifecycle (move, verify, purge, backup) and the drop semantics, and it points to list_projects for target discovery via the schema. It stops short of describing the backup location/format or what 'checked there' concretely validates, leaving a small gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so each parameter already carries its own description. The description adds framing (the dry_run workflow and the meaning of the report) but doesn't enrich individual field semantics beyond what the schema provides. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb ('carry', 'remove') plus resource ('memories') plus explicit source/target scoping ('from the active project into another one'). Clearly distinguished from siblings like forget, purge_memory, and list_projects, which don't move memories across projects.
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?
Establishes a clear workflow: dry_run defaults to true, read the report, then call again with dry_run=False. This implicitly tells the agent when to proceed vs. pause. However, it does not name alternative siblings (e.g., why not forget + note) or state exclusions, so it falls short of 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
must_readARead-onlyIdempotent
What is still open in a scope: counts per category, or one category's headers.
Without type: {"categories": [{"type", "count"}, ...]} for task,
anti_pattern, handoff, note and diagram, in that order, leaving out the
empty ones, plus "pinned" -- the same shape, counting the memories a
person pinned as mandatory reading -- when any pin is in scope. A pinned
memory still counts in its category. With type: {"type", "total",
"items", "next_offset"} -- one page of headers (uid, title, domain,
tags, est_tokens; a task adds progress {done, total} and doing, its
items in progress as {id, n}), newest first, a task by its latest item
update. Open a header with get_memory(uid). A page holds at most limit
headers and ends early at the size budget; next_offset is absent on
the last page.
Every pin listed is read with get_memory(uid) before acting, none skipped.
Pending means: a task that is open; an active anti_pattern, handoff or note that is not contradicted; an active diagram.
overdue, present only when non-empty, lists the checkpoints in scope
that stayed open past the age limit, with an alert to relay to the
user: memai refuses new writes under each until it is settled.
| Name | Required | Description | Default |
|---|---|---|---|
| type | No | task, anti_pattern, handoff, note or diagram; any other type is an error. Empty returns the counts. | |
| limit | No | headers per page, 1 to 50. | |
| domain | No | covers its subdomains and what is cross-listed there; empty is the whole project. A pin is in scope when it is global, or when the memory's domain or one of its also paths is the asked domain or above it; the whole project counts global pins only. | |
| offset | No | where the page of headers starts. | |
| pinned | No | true narrows the page to the pins of that type, and also accepts checkpoint and reasoning. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/destructive=false, but the description adds substantial non-obvious behavior: the exact semantics of 'pending', that 'overdue' appears only when non-empty and carries an alert to relay, and critically that 'memai refuses new writes under each until it is settled' — a side effect an agent cannot get from the annotations or schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose and the primary return shape, then the typed variant, then edge cases (pending, overdue). It is dense and long, but the telegraphic JSON-shape notation keeps it information-dense rather than padded; only a small amount of the later prose could be trimmed.
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?
There is no output schema, so the description carries the full burden of describing returns — and it does so field by field (categories, count, type, total, items, next_offset, pinned, overdue). For a zero-required-parameter query tool, nothing an agent needs to call it or interpret results is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description reinforces the empty-type behavior and the domain/pin scoping rules, but does not add syntax or format detail beyond what the schema already documents for each parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific scope and resource: 'What is still open in a scope: counts per category, or one category's headers', and lays out the exact response shapes for both modes. It is clear what the tool returns, but it never names or distinguishes itself from plausible siblings like list_recent, list_by_domain, timeline or search, so an agent must infer the boundary 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?
Usage is implied rather than stated: 'Open a header with get_memory(uid)' gives the follow-up step, and 'Every pin listed is read with get_memory(uid) before acting' prescribes behavior. However there is no explicit when-to-use-this vs when-to-use list_recent/search/recall, and no exclusion criteria.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
noteA
Save a general long-term memory (fact, decision, finding). Stored as type='note'.
Timeless knowledge -- retrieved by relevance, not recency. Bring it back with recall() (or search(type='note')); must_read(type='note') lists the most recent ones as headers.
| Name | Required | Description | Default |
|---|---|---|---|
| also | No | other domain paths this belongs to, comma-separated: the subjects that cut across the tree `domain` sits in, such as the end-to-end flow a routine is one step of. Every read scoped to one of them returns it. A path `domain` already sits under is dropped as redundant. At most 200 characters each. | |
| tags | No | comma-separated keywords and synonyms. Retrieval is BM25 over content, tags and domain paths, and tags weigh second only to the body, so they make a memory findable by words its own text never uses: the identifier, the error string, the plain phrasing someone will type. A memory with none is reachable only by quoting itself. At most 1000 characters. | |
| title | Yes | one line naming what this memory is about, in the words someone would look for it by. A list shows it instead of the opening of the body, and it outweighs every other field in search, so a title that repeats the type ("note about the parser") names nothing. At most 120 characters; a name that needs more is summarizing the body. | |
| domain | No | the subject this belongs to, as a path from the outermost scope in ('acme/x100/p200'). File it as deep as the fact is specific -- a note about one routine goes on the routine, and still comes back when someone asks about the module or the product above it. At most 200 characters. | |
| content | Yes | ONE fact, and what a reader needs to use it -- what holds, where it holds, what it rules out. Retrieval ranks whole memories, so a body answering four questions comes back for all four and is read for one: write the second subject as its own memory, on its own domain, and connect the two with link_memories(). A [[uid]] typed inside a body is a reference a reader can follow, not an edge -- get_relations() and the graph do not see it until link_memories() creates one. Past a couple of thousand characters, a body is usually several memories written as one. | |
| session | No | groups what one conversation writes. Leave it empty to use this server process's own stamp. | |
| source_ref | No | what the fact came FROM -- a path, a URL, a table name -- so a later pass can check the claim against the thing itself instead of inferring what to check from the wording. At most 500 characters. | |
| review_after | No | when this stops being safe to trust unchecked, as a date ('2026-11-01') or a span from today ('90d'). pulse() counts what is overdue in a scope as `scope.stale` and optimize_scan lists it. Leave it empty for anything that does not go stale -- most facts do not, and a date nobody meant is worse than none. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false, idempotentHint=false and destructiveHint=false; the description adds the useful trait "timeless knowledge -- retrieved by relevance, not recency," which explains how it will resurface. It does not disclose that repeat saves create separate memories (non-idempotent) or anything about the write's side effects, so with annotations carrying the safety profile this is a moderate add.
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 purpose and the type marker before the retrieval guidance. There is no padding, though the retrieval sentence could be tightened slightly.
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 exists, but the tool is a write operation whose result is well understood, and all 8 parameters are fully documented in the schema. The description covers purpose, storage type and retrieval path, leaving only the non-idempotent write behavior unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and each of the 8 parameters has a rich, self-contained description, so the baseline is 3. The description adds only the implicit type='note' value, which corresponds to no actual parameter, so it does not extend parameter meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ("Save a general long-term memory (fact, decision, finding)") and pins the stored type as type='note', which separates it from type-specific siblings like task_note and anti_pattern. It is clear, but it never explicitly contrasts itself against the save-side siblings (checkpoint, reasoning, anti_pattern), so it stops short of full sibling differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear retrieval context and names the alternatives for reading it back (recall(), search(type='note'), must_read(type='note')), so an agent knows the round-trip. It does not say when to prefer note over other save tools, so the when-to-write guidance is implied rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
optimize_runsARead-onlyIdempotent
List optimization runs with their review progress.
Read-only companion to optimize_stage: after staging, use this to see whether the user has applied/rejected your suggestions in the admin dashboard. Each run carries total/pending/applied/rejected counts, its note, and the safety-backup path once the first apply happened. Applying/rejecting stays in the dashboard by design -- the agent proposes, the human disposes.
| Name | Required | Description | Default |
|---|---|---|---|
| offset | No | where the page starts; `next_offset`, when present, starts the next. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive/closed-world, so the safety profile is covered. The description still adds real context: what each run carries (total/pending/applied/rejected counts, note, safety-backup path once the first apply happened) and the human-in-the-loop design ('the agent proposes, the human disposes').
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in the first sentence, followed by the workflow context and return-content summary. Every sentence carries information; nothing is filler or restated from the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates by enumerating the fields each run returns (counts, note, backup path) and by clarifying the workflow position and human-approval boundary. Nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one optional parameter (offset) with 100% schema description coverage, so the schema already documents its meaning and the next_offset paging contract. The description adds no parameter-level detail beyond that, making the baseline 3 correct.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('List optimization runs with their review progress') and immediately differentiates from the sibling by calling itself the 'Read-only companion to optimize_stage'. An agent can distinguish it from optimize_scan/optimize_stage/optimize_status 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 the explicit triggering condition ('after staging, use this to see whether the user has applied/rejected your suggestions') and names the sibling (optimize_stage) whose output it follows up on. It also states the boundary that applying/rejecting stays in the dashboard, so the agent knows what NOT to attempt.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
optimize_scanARead-onlyIdempotent
Dump the memory corpus compactly so you can plan a curation pass.
Step 1 of the "optimize my memories" workflow: every memory's
curation-relevant fields, the relation edges among them, usage counts,
dedup and domain hints, and per-memory anchors (URLs, paths,
identifiers) to check against live facts. Read it, then stage what you
decided with optimize_stage.
Start with what the store already says is suspect: due: true on a
memory means its own writer dated it for a recheck and the date has
passed, and source_ref says what to check it against.
recalls and stats.never_recalled are NOT that. A low count means
unproven, not useless -- a memory about a rare subject looks exactly
like a memory nobody wants, and the rare subject is frequently the
reason the store is there. Use the aggregate to judge the STORE and
never a single row: do not propose archiving something because it is
unread.
The listing is slim so a big store fits one response, and a page ends
early at an internal size budget -- truncated means page onward with
offset + count. relations_truncated means the page's first memory has
more edges than fit: get_relations(uid) lists them all. stats.by_domain
names the largest domains; stats.domains counts every one.
BEFORE PROPOSING ANY CHANGE, CHECK IT AGAINST LIVE FACTS, and record what
you checked in each suggestion's verified. Destructive kinds are
rejected without it: cross-check newer memories in the corpus, verify
code anchors against the live repo, web-check world facts.
| Name | Required | Description | Default |
|---|---|---|---|
| full | No | true keeps whole bodies instead of the slim listing. | |
| type | No | one memory type, as search() takes it; empty is every type. | |
| limit | No | the most memories per page. | |
| since | No | limits the scan to what changed after this date, for recurring passes. | |
| domain | No | scans a path and everything nested under it; empty is the whole project. | |
| offset | No | where the page starts; after a `truncated` page, offset + count. | |
| include_archived | No | true lists archived memories as well. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly/idempotent/non-destructive), and the description adds substantial operational detail beyond them: the listing is deliberately slim to fit one response, pages end early at an internal size budget, and the `truncated`/`relations_truncated` flags define exact recovery behavior. It also explains output semantics (due, source_ref, anchors) and warns that destructive changes are rejected without verification.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose and next-step routing are front-loaded in the first two sentences, and the paragraph blocks (suspect signals, output shape, verification rule) are logically ordered. It is longer than strictly needed for a 7-param scan and some guidance bleeds into downstream propose behavior, but every section carries usable information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the full burden and does so: it describes the return shape (slim listing, per-memory anchors, due, source_ref), the stats aggregates (by_domain, domains, never_recalled), and pagination/truncation recovery. Nothing an agent needs to call and interpret the scan is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all seven parameters (full, type, limit, since, domain, offset, include_archived) are already documented in the schema. The description adds only incremental meaning for offset ('after a truncated page, offset + count'); it does not explain full, since, or domain behavior beyond what the schema states, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (dump/scan) and resource (the memory corpus) and frames it as 'Step 1 of the optimize my memories workflow', which distinguishes it cleanly from siblings like search, list_recent, or list_by_domain. An agent can tell this is the bulk-scan entry point for curation without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit workflow routing: 'Read it, then stage what you decided with optimize_stage' names the follow-up tool, and 'get_relations(uid) lists them all' names the alternative for truncated relations. It also gives explicit when-NOT guidance ('do not propose archiving something because it is unread') with the reasoning, so an agent won't misuse the recalls signal.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
optimize_stageA
Stage a batch of curation suggestions for human review in the dashboard.
Step 2 of the "optimize my memories" workflow. NOT applied here: the user reviews and applies or rejects each one in the admin dashboard, which backs up before the first apply and can undo any of them.
Invalid suggestions are skipped and reported in errors, as many as fit
one page, with errors_total counting them all when some are left out;
the rest are staged. Returns {run_id, staged, errors}.
| Name | Required | Description | Default |
|---|---|---|---|
| note | No | one short summary of the pass, at most 250 characters; a longer one raises and stages nothing. What a single suggestion needs said belongs in its own `rationale` and `verified`, which are not capped. | |
| suggestions | Yes | each one {"kind", "target_uid", "payload", "rationale", "verified"}. Kinds: compact/reword {"new_content"}, retag {"tags"}, retitle {"title"}, redomain {"domain"}, crosslist {"also": [...]} (replaces the whole set), set_confidence {"confidence"}, review {"review_after"} (a date or a span like '180d'; '' clears it), archive {"reason"}, link {"from_uid","to_uid","relation_type"}, merge {"keep_uid","drop_uid"}, distill {"source_uids","new_type","new_content", "title"}, unleak {"field": "content|tags|source_ref"} (the repair is computed at staging). link/merge derive target_uid from the payload and distill creates its target -- omit it for those. Destructive kinds (archive, set_confidence=contradicted, merge, distill) require a non-empty `verified` describing the live-facts check behind them. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds substantial behavior beyond the annotations: staging is non-committal because the user applies or rejects in the dashboard, which backs up before the first apply and can undo any change — this explains the destructiveHint=false despite destructive kinds being stageable. It also discloses partial-failure semantics (invalid suggestions skipped, reported in `errors`, capped to one page with `errors_total` counting the rest) and the verified-required rule for destructive kinds.
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 purpose, then workflow position, then the non-application guarantee, then error handling — a logical order with no filler. It is dense and slightly long for a two-parameter tool, but every sentence carries information an agent needs.
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, the description supplies the return shape ({run_id, staged, errors}) and the truncated-error accounting. Combined with the staging/undo guarantee and the workflow position, nothing material 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 100%, so the schema already carries the full parameter burden, including the kind/payload matrix and the `verified` requirement for destructive kinds. The description's own parameter-adjacent content concerns return fields (`errors`, `errors_total`), not new input semantics, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (stage) and resource (a batch of curation suggestions) plus the destination (human review in the dashboard). It also positions itself in the optimize workflow, which cleanly separates it from optimize_scan, optimize_runs and optimize_status 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?
Explicitly says it is 'Step 2 of the "optimize my memories" workflow' and that nothing is applied here, so the agent knows when this tool belongs in a sequence. It never names the prerequisite sibling (e.g. optimize_scan) or states an explicit exclusion, so it stops short of a full when/when-not map.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
optimize_statusARead-onlyIdempotent
Inspect one optimization run: every suggestion and its decision.
Read-only. Returns the run header plus each suggestion's kind, target_uid, payload, rationale, verified, status (pending/applied/rejected) and decided_at -- so you can tell which proposals landed, follow up on rejected ones, or build on applied ones in a later pass.
| Name | Required | Description | Default |
|---|---|---|---|
| offset | No | where the page starts; `next_offset`, when present, starts the next. | |
| run_id | Yes | the run optimize_stage returned, or one optimize_runs lists. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so the 'Read-only' line is largely redundant. The description earns credit instead by disclosing the return shape (run header plus per-suggestion kind, target_uid, payload, rationale, verified, status, decided_at) and the status vocabulary, which is genuinely useful given there is no output schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in one line, then a short read-only note and the payoff. The field enumeration is a long clause but it substitutes for a missing output schema, so it earns its place rather than padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description does the heavy lifting by naming the returned fields and status values, and the schema covers pagination. Slightly incomplete in that the description never mentions paging, but nothing needed to call it correctly is absent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%: run_id and offset are both documented in the schema, including pagination via next_offset. The description adds no extra meaning about either parameter, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Inspect one optimization run') plus the scope ('every suggestion and its decision'), which cleanly separates it from optimize_runs (lists runs) and optimize_stage (produces runs). An agent can pick this tool without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete reasons to call it: tell which proposals landed, follow up on rejected ones, build on applied ones later. It does not state explicit when-not conditions, but the 'one run' scope implies alternatives already cover listing and staging.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pulseARead-onlyIdempotent
Session warm-up: the latest checkpoint, what is pending, and what to read next.
Returns {project, latest_checkpoint, must_read, pinned, read_next, scope},
plus overdue when a checkpoint in scope stayed open past the age
limit -- the same block must_read() carries, and read_next then puts
settling it first.
latest_checkpoint is picked by created_at DESC, never by similarity --
a similarity-ranked top-1 can return a stale checkpoint over a
same-day one, which is exactly the failure mode this avoids. It is
returned in full (that's the point of pulse), with its relations
attached so linked memories are visible without a separate
get_relations call, and carries est_tokens, what this response already
spent on it.
must_read is the categories list must_read(domain) returns without a
type: a count per category (task, anti_pattern, handoff, note, diagram),
leaving out the empty ones. read_next is the instruction to follow with
it, before acting: pinned memories, then open tasks, then
must_read(domain, type=...) for each other category, numbered when there
is more than one step. It is "" when nothing is pending. A pulse lists
no memories besides the checkpoint; must_read(domain, type=...) lists
headers and get_memory(uid) opens one.
pinned counts the pins in scope the same way (see must_read()); when it
is non-empty read_next asks for them before anything else.
scope is the rest of the brief: what the scope HOLDS. scope.by_type
counts every memory per type and scope.subdomains says which level it
is sitting in (own = filed there, subtree = with its descendants).
Read them as the drill-down plan: search(query, domain=...) or
list_by_domain(domain, type=..., limit=...) on the child that holds what
you need. A pulse is the state of a scope, never its contents.
scope.stale is the one thing here about DECAY rather than contents:
how many memories in the scope carry a review_after date that has
passed. Present only when non-zero. It means somebody who knew the
subject said when to look again and nobody has -- optimize_scan lists
which ones, with their source_ref.
A scope holds what is CROSS-LISTED into it as well as what is filed
there, so warming up an end-to-end flow brings back the routines that
are steps of it wherever they live. scope.also counts how much of the
brief arrived that way, and a subdomain carries its own also --
present only when non-zero, so a store that never cross-lists never
sees the field.
A long checkpoint is cut (next names the rest).
| Name | Required | Description | Default |
|---|---|---|---|
| domain | No | warms up a path and everything under it, so pulse('acme/x100') is the module-wide brief and pulse('acme/x100/p200') the routine's. A domain that names only the deep end of a path ('p200') is resolved to the branches it sits in -- `scope.paths` reports which, and an ambiguous name resolves to ALL of them. | |
| offset | No | where the page of `scope.subdomains` starts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnly, idempotent, non-destructive), and the description goes well beyond them: checkpoint selection is by created_at DESC 'never by similarity' with the rationale, relations are attached to avoid a get_relations call, est_tokens is disclosed, and truncation behavior is stated ('A long checkpoint is cut (`next` names the rest)'). Conditional fields (overdue, scope.stale, scope.also) and their presence rules are disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with a one-line summary, then organized field-by-field. It is long for a 2-param tool, but most sentences earn their place by explaining non-obvious return semantics. Minor redundancy in the repeated 'present only when non-zero' clauses keeps it from a 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the full burden and delivers: it enumerates the response keys (project, latest_checkpoint, must_read, pinned, read_next, scope, overdue) and explains each. An agent has everything needed to interpret the return value without a schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents `domain` (path resolution, scope.paths, ambiguity) and `offset` (subdomain paging). The prose adds context on how scope behaves but doesn't extend the parameter contract beyond the schema. Baseline 3 applies where the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource+scope: 'Session warm-up: the latest checkpoint, what is pending, and what to read next.' It explicitly differentiates from siblings, noting 'A pulse lists no memories besides the checkpoint; must_read(domain, type=...) lists headers and get_memory(uid) opens one.' An agent can distinguish it from search, must_read, and get_memory 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?
Explicit when-to-use and routing to alternatives: 'Read them as the drill-down plan: search(query, domain=...) or list_by_domain(domain, type=..., limit=...)'. It also names the follow-up tool ('optimize_scan lists which ones') and clarifies read_next sequencing. Nothing about tool selection is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
purge_memoryADestructiveIdempotent
PERMANENTLY delete a memory + its edit history + relations. Irreversible.
Use forget() instead unless the user explicitly asked to permanently remove data -- forget() is reversible (archived, content kept), this is not.
| Name | Required | Description | Default |
|---|---|---|---|
| uid | Yes | the memory. | |
| confirm_phrase | Yes | must exactly equal "DELETE <uid>", typed by the user in their own message. Do not construct this string yourself from an inferred "yes"/"confirm" -- it must come from the user actually stating the uid back. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and readOnlyHint=false, so the destructive nature is covered. The description adds genuine value beyond that: the destruction scope (edit history and relations), irreversibility, and the contrast with forget()'s reversible archive model. It does not surface the confirm_phrase user-typing guard, which is a meaningful behavioral requirement, so it stops short of 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, front-loaded with the PERMANENTLY/irreversible warning, then the routing rule. Every clause earns its place and there is no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive two-parameter tool with full annotations and full schema coverage, the description supplies the critical context: what is destroyed, that it is irreversible, and when to prefer the reversible alternative. Nothing an agent needs to call it safely is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so both parameters (uid and confirm_phrase) are fully documented in the schema, including the exact confirm_phrase construction rule. The description adds no parameter-level detail beyond what the schema already provides, so the baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('PERMANENTLY delete a memory') and immediately scopes what is removed ('+ its edit history + relations'). It explicitly distinguishes itself from the sibling forget(), so an agent can route correctly without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit when-to-use rule: prefer forget() 'unless the user explicitly asked to permanently remove data'. It names the alternative and the exact condition that selects this tool over it, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reasoningA
Record an analysis worth keeping: what was thought, and what it settled.
For the PROCESS, not the fact it produced -- note() takes the fact. Stored as type='reasoning'; filter search/list_* with type='reasoning' to get these back. ONE analysis per memory: a second hypothesis tested in the same session is its own reasoning().
| Name | Required | Description | Default |
|---|---|---|---|
| also | No | other domain paths this belongs to, comma-separated: the subjects that cut across the tree `domain` sits in, such as the end-to-end flow a routine is one step of. Every read scoped to one of them returns it. A path `domain` already sits under is dropped as redundant. At most 200 characters each. | |
| tags | No | comma-separated keywords and synonyms. Retrieval is BM25 over content, tags and domain paths, and tags weigh second only to the body, so they make a memory findable by words its own text never uses: the identifier, the error string, the plain phrasing someone will type. A memory with none is reachable only by quoting itself. At most 1000 characters. | |
| title | Yes | one line naming what this memory is about, in the words someone would look for it by. A list shows it instead of the opening of the body, and it outweighs every other field in search, so a title that repeats the type ("note about the parser") names nothing. At most 120 characters; a name that needs more is summarizing the body. | |
| domain | No | the subject this belongs to, as a path from the outermost scope in ('acme/x100/p200'). File it as deep as the fact is specific -- a note about one routine goes on the routine, and still comes back when someone asks about the module or the product above it. At most 200 characters. | |
| result | Yes | what came back. The measurement, not the interpretation. | |
| session | No | groups what one conversation writes. Leave it empty to use this server process's own stamp. | |
| next_time | Yes | what someone hitting this again should do differently. | |
| reasoning | Yes | how you tested it -- what you read, ran or compared. | |
| hypothesis | Yes | what you believed going in, as a claim that could be wrong. | |
| source_ref | No | what the fact came FROM -- a path, a URL, a table name -- so a later pass can check the claim against the thing itself instead of inferring what to check from the wording. At most 500 characters. | |
| review_after | No | when this stops being safe to trust unchecked, as a date ('2026-11-01') or a span from today ('90d'). pulse() counts what is overdue in a scope as `scope.stale` and optimize_scan lists it. Leave it empty for anything that does not go stale -- most facts do not, and a date nobody meant is worse than none. | |
| revised_belief | Yes | what you believe now, and where it differs from the hypothesis. Say plainly when the hypothesis survived unchanged. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare the write/non-idempotent profile. The description adds genuinely new behavior: the record is stored as type='reasoning' and retrievable by filtering search/list_* on that type, plus the one-analysis-per-memory cardinality constraint. It does not cover dedup or overwrite behavior, so it stops short of full 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?
Front-loaded with the core definition, then two tight sentences covering the note() contrast, storage/retrieval, and cardinality. No filler; every sentence changes how an agent would 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 6-required-parameter write tool with no output schema, the description covers purpose, sibling disambiguation, storage type, retrieval path, and granularity. It omits whether re-recording similar content is deduped or overwritten, a minor gap for an otherwise complete definition.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% with 12 richly documented parameters (hypothesis, result, revised_belief, review_after, tags, domain, etc.), so the schema already carries parameter meaning. The description adds the type='reasoning' retrieval hint but no field-level semantics, matching the baseline-3 rule for high schema coverage.
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 ('Record an analysis worth keeping: what was thought, and what it settled'), and immediately distinguishes itself from the closest sibling by naming note() as the fact-taker. An agent can tell reasoning apart from note/anti_pattern/checkpoint without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent: use this for the PROCESS, note() for the fact produced, and it states a granularity rule ('ONE analysis per memory; a second hypothesis is its own reasoning()'). It lacks exclusions against other memory-writing siblings (anti_pattern, checkpoint), so it is clear context without full alternative coverage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
recallARead-onlyIdempotent
Recall long-term knowledge saved with note() (type='note').
The dedicated verb for "bring back what I noted": a BM25 search scoped to type='note', ranked by relevance -- which is what you want for timeless facts/rules/decisions. This (or search(type='note')) is how notes come back by relevance; must_read(type='note') lists the newest.
Returns {"results": [...], "est_tokens": N}. Content is
snippet-truncated -- call get_memory(uid) for the full record; a
result's est_tokens estimates what that full record costs, and the
top-level est_tokens is the sum over the results.
Results carry the same succeeded_by / collapsed annotations
search() explains.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | the most results to return. | |
| query | Yes | the words to look for; as in search(), more terms find more. | |
| domain | No | scopes to a path and everything nested under it, and resolves a bare deep segment the same way search() does. | |
| offset | No | where the page starts; `next_offset`, when present, starts the next. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly/idempotent/non-destructive), yet the description adds substantial behavioral context: the return shape, snippet truncation, the need to call get_memory(uid) for full records, and what est_tokens means at both result and top level. This is real disclosure beyond structured data, with only a minor reliance on search() to explain succeeded_by/collapsed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose and routing, and every paragraph carries information. It is slightly longer than necessary, with some decorative phrasing (the quoted 'bring back what I noted'), which keeps it short of a 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite having no output schema, the description explains the return payload, the truncation model, and the follow-up call needed for full records. Combined with complete parameter coverage and clear safety annotations, an agent has everything needed to call and interpret this tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so query, limit, offset, and domain are already documented in the schema. The description restates relevance ranking but adds no new parameter-level syntax or format detail, making the baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (recall), resource (long-term notes), and mechanism (BM25 relevance-ranked search scoped to type='note'). It explicitly differentiates itself from search(type='note') and must_read(type='note'), 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?
Gives explicit when-to-use guidance (timeless facts/rules/decisions wanted by relevance) and names the alternatives with their conditions: search(type='note') as the equivalent path and must_read(type='note') for the newest entries. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
searchARead-onlyIdempotent
Keyword search over memory content+tags+domain: FTS5 BM25.
Each result is annotated with match_source ("fts", or "uid" for the row a pasted identifier names) and fts_rank (bm25, lower = better). The search only widens the candidate set -- judge the returned candidates yourself.
Only active memories by default.
Returns {"results": [...], "est_tokens": N}. Content is
snippet-truncated per result -- call get_memory(uid) for the full
record; a result's est_tokens estimates what that full record costs,
and the top-level est_tokens is the sum over the results.
Two annotations worth acting on. succeeded_by means something in the
store supersedes this memory: read that one instead. collapsed lists
near-identical results folded into this one, so a fact written five
times spends one slot -- raise limit if you want the copies.
A memory marked confidence='contradicted' sorts behind everything that still holds, but it does come back: knowing a claim was ruled out is worth a slot, and it is what stops it being written again.
A diagram ranks like any other memory: it comes back when it matches the query, in the position its score earns. Nothing lifts a type to the top, so a flow in the results is a flow this query actually hit -- and when one does show up it is worth opening first, because it states a whole routine the surrounding notes only annotate.
To recall note()'d knowledge specifically, recall() is the sugar for search(type='note') -- which also means recall() never surfaces a diagram; use search() for that.
| Name | Required | Description | Default |
|---|---|---|---|
| type | No | 'note', 'reasoning', 'checkpoint', 'anti_pattern', 'diagram', 'task' (one writer each) or 'handoff' (rows already stored; task() carries unfinished work to the next session); any other type is an error. Ask for type='diagram' to sweep the documented flows on purpose. | |
| limit | No | the most results to return. | |
| query | Yes | the words to look for. SPEND TERMS FREELY. Every space-separated term is asked for separately and a row matching more of them ranks higher, so piling on synonyms, the identifier, the routine name and the plain-language phrasing into one query costs one call and finds strictly more. Twenty terms beat ten. Write a sentence if that is what you have -- common words score near zero and cost nothing, so there is nothing to strip. | |
| domain | No | scopes to a path AND everything under it: domain='acme/x100' searches the module and each of its routines. Give more of the path to narrow it. A domain naming only the deep end of a path ('p200') is resolved to the branches it sits in -- every result carries its real `domain`, which is where to read what the filter actually covered. | |
| offset | No | where the page starts; `next_offset`, when present, starts the next. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover safety (readOnly, idempotent, non-destructive), and the description goes well beyond them: it discloses that snippets are truncated and est_tokens estimates the full-record cost, explains succeeded_by and collapsed annotations, and details that confidence='contradicted' rows sort last but still return. None of this contradicts the annotations; it materially enriches them.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core purpose and return format are front-loaded and the result-annotation semantics are necessary given there is no output schema. It runs long (~350 words) with a few discursively framed sentences about why contradicted memories deserve a slot and how diagrams rank, but almost every sentence carries usable behavioral information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the full burden of explaining the return value, and it does: results array, est_tokens at both levels, snippet truncation, match_source, fts_rank, succeeded_by, collapsed, and ranking order. Nothing an agent needs to interpret or act on results is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning beyond the schema: it says the search only widens the candidate set and that the agent must judge candidates, and it links `limit` to the collapsed-duplicate behavior. It adds modest value on top of an already verbose schema rather than fully re-explaining syntax.
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 with implementation detail: 'Keyword search over memory content+tags+domain: FTS5 BM25.' It also distinguishes itself from siblings by naming recall() explicitly and clarifying that recall() is just search(type='note') and never surfaces diagrams. An agent can route between search, recall, list_recent and list_by_domain 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?
Explicit when-to-use guidance is present throughout: call get_memory(uid) when the truncated snippet is insufficient, raise `limit` to see collapsed duplicates, and use recall() specifically to recall note()'d knowledge while using search() to sweep diagrams. It also states the default scope ('Only active memories by default'), so the agent knows what is excluded and how to widen.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_confidenceAIdempotent
Set a memory's confidence: unverified | confirmed | contradicted.
Call it once evidence settles a claim: the code, a run or a source checked against the memory. A contradicted memory sorts last in search and is left out of the notes, pitfalls and handoffs must_read() lists and of the checkpoint pulse() returns, so a claim known to be wrong stops steering work while it stays readable; unverified and confirmed rank alike. To correct the text, edit_memory(); to retire it, forget().
Now and then a result of any memai tool carries confidence_reminder:
memories still unverified past the span set in the dashboard, those in
the call's domain first. Settle the ones this session's evidence
reaches; it refuses nothing.
Returns {"ok": True}, {"ok": False} for an unknown uid, or an error for any other value.
| Name | Required | Description | Default |
|---|---|---|---|
| uid | Yes | the memory. | |
| confidence | Yes | unverified, confirmed or contradicted. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare idempotent, non-destructive and non-open-world, and the description goes well beyond them: contr adicted memories sort last in search, are excluded from must_read()/pulse() outputs, remain readable, and unverified vs confirmed rank alike. It also documents the return shapes and the unknown-uid failure mode. Slight markdown is the somewhat ambiguous 'it refuses nothing' line.
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 value set are front-loaded in the first clause, followed by consequences and alternatives. The middle paragraph about confidence_reminder on 'any memai tool' is useful but sits outside this tool's direct scope and lengthens the definition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, yet the description supplies the return contract ({ok: True}/{ok: False}/error). For a two-parameter, idempotent state-setter with full annotation coverage, nothing needed to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and both schema descriptions already name the parameters and the value set, so the baseline is 3. The description's added meaning for 'confidence' (the ranking/exclusion consequence of each value) is behavioral rather than syntactic, and adds nothing about uid beyond what the schema states.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Set a memory's confidence') and enumerates the exact value set. It also names the sibling boundaries explicitly — edit_memory() for text changes, forget() for retirement — so an agent can place it immediately among the 40+ 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?
Gives the trigger condition precisely: 'Call it once evidence settles a claim: the code, a run or a source checked against the memory.' It also routes to the two adjacent alternatives with their own conditions, plus guidance tied to the confidence_reminder signal, which is explicit when-to-act context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_domain_caseAIdempotent
Set the store's domain-casing policy for every domain written from now on.
This only governs new writes -- to bring already-stored domains into line, run the "Normalize domains" action in the admin dashboard (it previews collisions before merging variant spellings). Returns the stored {"mode": ...}.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | Yes | 'preserve' keeps free-text casing; 'lower' or 'upper' coerces every domain written to that case. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly=false, idempotent=true, destructive=false, so the safety profile is covered. The description adds genuinely useful behavior beyond that: the forward-only effect on future writes, the pre-merge collision preview in the dashboard path, and the return shape {"mode": ...}.
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 tight sentences with the scope constraint front-loaded and no filler. There is mild redundancy between 'for every domain written from now on' and 'This only governs new writes,' but nothing is padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter, non-destructive, idempotent setter with rich annotations, the description covers the forward-only semantics, the alternative path for existing data, and the return value despite no output schema. An agent has everything needed to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema itself enumerates 'preserve', 'lower', and 'upper' with their effects, so the description is not required to document mode. It adds no syntax or edge-case meaning beyond the schema, making the baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource — setting the store's domain-casing policy — and scopes it precisely to 'every domain written from now on.' It distinguishes this from the retrospective normalization path, though it never names its read-side sibling get_domain_case, leaving that pairing to inference.
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 bounds when this applies ('only governs new writes') and routes the agent elsewhere for the excluded case ('to bring already-stored domains into line, run the "Normalize domains" action in the admin dashboard'). That is a complete when/when-not with a named alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
taskA
Open a task: a goal and a checklist, kept until its items are closed.
Stored as type='task'. Work it with task_item(), grow it with task_add() and discuss it with task_comment(); it archives itself once every item is done or dropped, and must_read() lists the open ones.
Free text cites another item only as [[#id]], which reads back as its current number and label; a label -- a title, an item's text -- never carries one. To a person, name it item n of its task.
| Name | Required | Description | Default |
|---|---|---|---|
| also | No | other domain paths this belongs to, comma-separated: the subjects that cut across the tree `domain` sits in, such as the end-to-end flow a routine is one step of. Every read scoped to one of them returns it. A path `domain` already sits under is dropped as redundant. At most 200 characters each. | |
| goal | Yes | the brief an agent with none of this session's context works from: what the work is and why, where it lives, the decisions and constraints that bind it, and what done looks like. Short, but complete enough to act on -- a few compact paragraphs, at most 2000 characters. Plain prose: a task is not a sectioned type, so no `INTENT:` / `GOAL:` / `WHY:` labels -- those are how checkpoint, anti_pattern and reasoning bodies are read back. edit_memory(goal=...) rewrites it when the scope changes. | |
| tags | No | comma-separated synonyms the goal and items never use; retrieval is BM25 over content and tags. The type name is not added for you: a word every task carries ranks no task above another. | |
| items | Yes | one checklist item per line, blank lines ignored, at most 50. Each is a short label, verb first, at most 80 characters: lists and every DEPENDS ON that names it show it whole, so its detail goes in the item's brief (task_note). Each gets an id for task_item(); the result lists them in order, each as {id, n}. | |
| title | Yes | what the task delivers, in a few words someone would look for it by. At most 120 characters. | |
| domain | No | the subject this belongs to, as a path from the outermost scope in ('acme/x100/p200'). File it as deep as the fact is specific -- a note about one routine goes on the routine, and still comes back when someone asks about the module or the product above it. At most 200 characters. | |
| session | No | groups what one conversation writes. Leave it empty to use this server process's own stamp. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the write/non-destructive/non-idempotent profile, and the description adds real behavior: storage as type='task', self-archiving once every item is done or dropped, and the [[#id]] citation convention with its label rules. It stops short of describing permissions, limits, or failure modes, but the lifecycle disclosure is substantive context the annotations do not provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the definition, then the sibling routing, then the citation convention, with no filler sentences. Some phrasing ('To a person, name it item n of its task') is dense and slightly opaque, keeping it out of the top band.
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?
All 7 parameters are fully documented and the description supplies the lifecycle, storage type, and cross-tool workflow for a write tool with no output schema. Little is missing for an agent to invoke it correctly; return-shape detail is conveyed only briefly ('{id, n}').
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the per-parameter semantics are already carried by the schema and the baseline is 3. The description adds the cross-reference grammar ([[#id]] reads back as current number and label, labels never carry one) that the schema does not state, giving it genuine added 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?
Opens with a specific verb and resource — 'Open a task: a goal and a checklist' — and immediately differentiates itself from the task_item/task_add/task_comment siblings by naming what each one does. An agent can tell this is the creation entry point of the task family without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes follow-up work: task_item() to work it, task_add() to grow it, task_comment() to discuss it, must_read() to list the open ones. It lacks a comparative statement about when to open a task versus a note or checkpoint, so it is clear context rather than full when/when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
task_addA
Append items to a task, one per line; a closed task reopens.
For work the checklist is missing. To move or comment on an item that exists, task_item(); to give an item its detail, task_note().
Free text cites another item only as [[#id]], which reads back as its current number and label; a label -- a title, an item's text -- never carries one. To a person, name it item n of its task.
Returns {"uid", "items", "progress", "task_state", "archived"}: the new items as {id, n}, and the task as it stands.
| Name | Required | Description | Default |
|---|---|---|---|
| uid | Yes | the task. | |
| items | Yes | one item per line, blank lines ignored, each a short label as task() takes them. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnly=false, destructive=false, idempotent=false), so the description needn't restate them. It adds genuinely non-obvious behavior the annotations don't: appending to a closed task silently reopens it, and the exact return shape. It doesn't discuss permissions or failure modes, keeping it just short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core action and side effect in the first sentence, then layers routing and format rules. Every clause carries content, though the terse, aphoristic phrasing ("a label -- a title, an item's text -- never carries one") is denser than it needs to be for an agent to parse quickly.
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?
There is no output schema, so the description correctly supplies the return fields (uid, items, progress, task_state, archived) and the item shape. Combined with the reopen side effect and alternative routing, an agent has what it needs to call this correctly; only auth/permission prerequisites are unaddressed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description earns above that by explaining a meaningful content constraint on the items parameter — that free text may cite another item only via [[#id]], that a label never carries such a reference, and how to refer to a person by item number. That is real semantics the schema's terse "one item per line" 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 verb and resource ("Append items to a task"), plus the exact input granularity (one per line). It also, in the same breath, names what it is not (task_item for existing items, task_note for detail), so an agent can separate it from the sibling task_* tools without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives the precise selection condition ("For work the checklist is missing") and explicitly routes the agent to the correct alternatives with their own conditions: task_item() to move/comment on an existing item, task_note() to add detail. This is explicit when-to-use plus named alternatives, not inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
task_commentA
Comment on a task, or on one of its items when item names its id.
A comment never edits the task's content, so it carries what the
checklist cannot: why an item is blocked, what a review said. Text an
item is worked from -- its brief, a rule several items share -- is a
task_note(); a comment that goes with a change of state goes in
task_item()'s comment.
Free text cites another item only as [[#id]], which reads back as its current number and label; a label -- a title, an item's text -- never carries one. To a person, name it item n of its task.
Returns {"uid", "comment_id"}, plus item and n on an item.
| Name | Required | Description | Default |
|---|---|---|---|
| uid | Yes | the task. | |
| body | Yes | the comment. | |
| item | No | the item's id; 0, the default, comments on the task itself. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare a non-destructive, non-idempotent write (readOnlyHint=false). The description adds real behaviour beyond that: a comment never edits task content, free text only cites other items via [[#id]], and labels never carry a citation. It does not state permanence/deletion or auth requirements, so it stops short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action, then structured into distinguishable clauses for alternatives, citation syntax, and return shape. Some phrasing is ornate ('reads back as its current number and label') but no sentence is purely decorative.
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 exists, and the description compensates by naming the return shape ({"uid", "comment_id"}, plus `item` and `n` on an item). Combined with the sibling routing and citation rules, an agent has what it needs; only permission/error behaviour is unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description still adds value the schema does not: `item` names an item's id (default 0 comments on the task), and `body` supports the [[#id]] citation form which reads back as the item's current number and label.
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?
Opening sentence states a specific verb and resource ('Comment on a task, or on one of its items'), and immediately differentiates from siblings by naming task_note() and task_item()'s `comment` as the alternatives for adjacent behaviour. An agent can place this tool without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit contrastive guidance: a comment is for rationale the checklist cannot carry, whereas item briefs/shared rules belong in task_note(), and comments accompanying a state change belong in task_item()'s `comment`. That is a true when/when-not/alternative map.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
task_itemADestructive
Update one item of a task -- its text, its state, a comment on it, memories linked to it -- or delete it.
Give at least one of text, state, comment and related, or delete. They apply together, or not at all.
The result names the item's number n and the task's title.
Free text cites another item only as [[#id]], which reads back as its current number and label; a label -- a title, an item's text -- never carries one. To a person, name it item n of its task.
| Name | Required | Description | Default |
|---|---|---|---|
| uid | Yes | the task. | |
| item | Yes | the item's id, as task_read(part='items') lists it. | |
| text | No | the item's new text, a short label as task() takes it. The item keeps its id, state, brief, comments and links; the previous text stays in the edit history. | |
| state | No | todo, doing, done or dropped. The write that closes the last open item archives the task (`archived` in the result); one that reopens an item reopens the task. | |
| delete | No | removes the item with its comments, links and note attachments, alone in its call. No other item moves; a DEPENDS ON that named it keeps its text, marked deleted, and a brief on only that item stays, on the whole task. Delete a mistake or a duplicate; mark work decided against as dropped, which keeps it. | |
| comment | No | a remark on this item -- what blocked it, what was decided. | |
| related | No | comma-separated uids of memories this item produced or depends on. An unknown uid refuses the whole call, and nothing is written. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true, readOnlyHint=false and idempotentHint=false, but the description adds substantial extra behavior: closing the last open item archives the task and reopening reopens it; delete removes comments, links and note attachments and leaves DEPENDS ON referrers marked deleted; an unknown uid refuses the whole call with nothing written. This atomicity and side-effect disclosure goes well beyond the structured hints.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the verb and resource, then the calling contract, then the return shape and referencing rule. The prose is idiosyncratic ('a label -- a title, an item's text -- never carries one') and slightly verbose in places, but every paragraph carries distinct information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-parameter mutation tool with no output schema, the description covers the key gaps: which parameters coexist, delete side effects, task archiving/reopening, atomic failure on unknown uid, and the return contents ('the item's number n and the task's title'). Little an agent needs is missing, though delete-only exclusivity could be stated more sharply.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds meaning beyond the schema for the free-text fields: cross-item references must be written as [[#id]] and read back as a number and label, which no schema entry states. It also reinforces the 'all-or-nothing' coupling of the optional parameters.
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 pair (update/delete) and a precisely-scoped resource (one item of a task), enumerating the touchable fields (text, state, comment, related memories). An agent can place it apart from task_comment, task_note and task_add by the 'one item' scope, though it never names those siblings as alternatives.
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?
Explains the calling contract ('Give at least one of text, state, comment and related, or delete. They apply together, or not at all'), which is real operational guidance. However it offers no explicit when-to-use-this-vs-alternatives routing against siblings like task_comment or task_note, which overlap with the 'comment' field.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
task_noteBDestructive
A note a task owns: an item's brief, a rule its items share.
Not a memory: only task_read() returns it. A note on items is a brief:
goal, context, steps, pitfalls, done_when and depends_on are required,
extra_info is optional, and they read back under the labels GOAL: /
CONTEXT: / STEPS: / PITFALLS: / DONE WHEN: / DEPENDS ON: / EXTRA INFO:.
A note on the whole task is free text in body.
Free text cites another item only as [[#id]], which reads back as its current number and label; a label -- a title, an item's text -- never carries one. To a person, name it item n of its task.
| Name | Required | Description | Default |
|---|---|---|---|
| uid | Yes | the task. | |
| body | No | a note on the whole task, up to 4000 characters; it errors beside a brief field. | |
| goal | No | what the item must achieve. | |
| items | No | the ids of the items the note is on, such as "4812,4815"; empty or "-" is the whole task. | |
| steps | No | how to do it, in order. | |
| title | No | up to 120 characters. | |
| delete | No | with note_id, removes that note. | |
| context | No | what the work needs to know: where it lives, what binds it. | |
| note_id | No | 0 creates a note; another id edits that note, where an empty field keeps its text and a field given replaces only its own. | |
| pitfalls | No | what goes wrong, and how to avoid it. | |
| done_when | No | how to tell the item is finished. | |
| depends_on | No | none, or the ids of the items this one waits for, each with an optional reason in parentheses ("4812 (why), 4815"). A deleted item reads back as deleted "its text". | |
| extra_info | No | anything else worth knowing; optional. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true, idempotentHint=false, and non-read-only, so the safety profile is partly covered. The description adds real context ('only task_read() returns it', body 'errors beside a brief field'), but it never discloses the destructive/deletion behavior implied by the delete parameter.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The prose is dense and poetic rather than front-loaded with the tool's action; the opening sentence is a definition, not a verb. Most sentences carry substantive information (labels, [[#id]], body free-text rule), so it is not padded, but the cryptic phrasing costs 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?
For a 13-parameter mutation tool with no output schema, the description explains note structure and read-back format but leaves the create/edit/delete operations to the schema and never warns that deletion is destructive. It is adequate but not fully self-contained given 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 coverage is 100%, so the baseline is 3, and the description earns above that by adding semantics not in the schema: read-back labels (GOAL:/CONTEXT:/STEPS:/PITFALLS:/DONE WHEN:/DEPENDS ON:/EXTRA INFO:), the [[#id]] citation rule, and how labels never carry an id. These clarify how field values are interpreted and echoed back.
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 defines what a note is ('A note a task owns: an item's brief, a rule its items share') but never states the tool's action verb (create/edit/delete), which is only recoverable from the schema's note_id/delete fields. It does differentiate the resource by noting only task_read() returns it, but the core purpose is conceptual rather than operational.
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 line 'Not a memory: only task_read() returns it' gives some routing context away from the memory tools, and the required brief fields imply when a structured brief applies. However, there is no explicit when-to-use vs alternatives guidance against siblings like task_comment, note, or task_add.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
task_readARead-onlyIdempotent
Read one collection of a task, one page at a time.
Follow next_offset until it is absent.
| Name | Required | Description | Default |
|---|---|---|---|
| uid | Yes | the task. | |
| item | No | the item's id, for its notes, comments or links (the page adds its `n`); 0, the default, is the task's own. | |
| part | Yes | `items` (each with its id, its number on the list, its state and counts), `notes` and `comments` (the task's own; with `item`, that item's; a page that mentions items carries `refs`, what each [[#id]] names) or `links` (the memories linked to `item`). | |
| offset | No | where the page starts; `next_offset`, when present, starts the next. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so the safety profile is covered. The description usefully adds the pagination loop behavior, but says nothing about error handling, size limits, or what a page looks like when the collection is empty.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, zero filler, with the core action front-loaded ahead of the pagination rule. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The schema fully covers the non-trivial part/item relationship and annotations cover safety, so the description does not need to re-explain those. What is missing is routing guidance among the numerous task_* siblings, leaving the agent to guess which task tool to call.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all four parameters (uid, item, part, offset) are fully documented in the schema itself. The description adds no syntax or format detail beyond that, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Read one collection of a task") plus the pagination unit ("one page at a time"). It is clear what the tool does, but it does not explicitly differentiate itself from the many sibling task_* tools (task, task_item, task_note, task_comment).
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 instruction "Follow `next_offset` until it is absent" gives real pagination usage guidance, but there is no statement of when to reach for this tool versus task, task_item, or task_note. Usage is implied rather than scoped.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
timelineARead-onlyIdempotent
What else was being written around one memory, in creation order.
For the question search cannot ask: not what mentions this record, but what was being written when it was. Neighbours are picked by time alone, so they come back whether or not they share a word with the anchor -- around a checkpoint, that is the notes and pitfalls of the same stretch of work.
One of uid or query is required; give both and uid wins. The response
reports anchored_by ('uid' or 'query') and the whole anchor record,
so which record the timeline is built around is never a guess.
Returns {"anchored_by": ..., "anchor": {...}, "before": [...], "after": [...]}, both lists oldest first, so before + [anchor] + after reads straight down the clock. Neither list contains the anchor. domain and type narrow the NEIGHBOURHOOD, not the anchor, and archived records are left out of it, as everywhere else by default.
Each record is snippet-truncated with est_tokens for its full content
-- call get_memory(uid) to open one.
| Name | Required | Description | Default |
|---|---|---|---|
| uid | No | the anchor, named outright. | |
| type | No | one memory type, as search() takes it; empty is every type. | |
| after | No | how many records created immediately after it. | |
| query | No | searches for the anchor and takes the top hit (the same search search() runs, scoped by domain/type). | |
| before | No | how many records created immediately before the anchor. | |
| domain | No | covers a path and everything under it, plus what is cross-listed into it, and resolves a bare deep segment the way the other scoped reads do. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, and the description adds substantial non-structured behavior: neighbours are chosen by time alone regardless of term overlap, uid beats query, the response echoes `anchored_by` and the full anchor record, neither list contains the anchor, domain/type narrow the neighbourhood rather than the anchor, and archived records are excluded.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose, then escalation to mechanics, then return shape, then the follow-up tool. Dense and well-organized, though the stylized phrasing ('reads straight down the clock') adds a little flourish that a stricter tool description wouldn't need.
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, the description carries the full return contract: the exact object shape ({anchored_by, anchor, before, after}), list ordering (oldest first), anchor exclusion, and snippet truncation with `est_tokens`. Nothing needed to invoke or interpret the result is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real semantics beyond it: the uid-vs-query precedence rule, and the important clarification that `domain` and `type` constrain the neighbourhood and not the anchor. `before`/`after` counts and ordering intent are also reinforced in prose.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening line states a specific operation on a specific resource ('what else was being written around one memory, in creation order') and immediately distinguishes it from search: 'not what mentions this record, but what was being written when it was.' An agent can separate this from search, list_recent, and get_relations 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?
It names the alternative ('the question search cannot ask') and the condition that selects this tool over it, then states the anchor-selection rule ('One of uid or query is required; give both and uid wins'). It even routes the agent onward for full content via get_memory(uid).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
unfile_domainADestructiveIdempotent
Drop one of a memory's cross-listings. Does not touch where it is filed.
Returns {"uid": ..., "also": [...]} with what remains.
| Name | Required | Description | Default |
|---|---|---|---|
| uid | Yes | the memory. | |
| domain | Yes | the cross-listed path to drop, matched exactly: dropping 'acme' leaves a separate membership in 'acme/x100' alone, because that is a different scope. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and idempotentHint=true, so the safety profile is covered. The description adds genuinely non-derivable context: what is destroyed is only the cross-listing ('Does not touch where it is filed'), which annotations cannot convey, plus the response shape of what remains.
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 the scope constraint, then the return contract. Zero filler and nothing redundant with the schema or annotations.
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 exists, and the description compensates by stating the return payload. Safety/idempotency are covered by annotations. Minor gap: no mention of error behavior when the cross-listing does not exist or is a duplicate, which matters for an idempotent destroyer.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already carries full parameter meaning, including the exact-match/scope nuance for 'domain'. The description adds no parameter-level detail beyond the schema; the return-shape sentence is about output, not inputs. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb ('Drop') plus a precise resource ('one of a memory's cross-listings'), and the second sentence scopes it against the related operations (filing location, move/delete) by stating what it does not touch. It stops short of naming the inverse sibling (also_domain) for adding cross-listings, so sibling differentiation is implicit rather than explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the phrasing: use it when you want to remove a cross-listing while preserving the underlying filing. However, no alternative is named (e.g., also_domain to add, move_to_project to relocate) and no when-not condition is stated beyond the scope note.
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.
45 tool updates
v0.16.1- Changed
also_domain5 fields changed- added
Input schema / properties / domain / descriptionAdded value: +"the path to cross-list it into." - removed
Input schema / properties / domain / titleRemoved value: -"Domain" - added
Input schema / properties / uid / descriptionAdded value: +"the memory." - removed
Input schema / properties / uid / titleRemoved value: -"Uid" - removed
Input schema / titleRemoved value: -"also_domainArguments"
- Changed
anti_pattern21 fields changed- added
Input schema / properties / also / descriptionAdded value: +"other domain paths this belongs to, comma-separated: the subjects that cut across the tree `domain` sits in, such as the end-to-end flow a routine is one step of. Every read scoped to one of them returns it. A path `domain` already sits under is dropped as redundant. At most 200 characters each." - removed
Input schema / properties / also / titleRemoved value: -"Also" - added
Input schema / properties / domain / descriptionAdded value: +"the subject this belongs to, as a path from the outermost scope in ('acme/x100/p200'). File it as deep as the fact is specific -- a note about one routine goes on the routine, and still comes back when someone asks about the module or the product above it. At most 200 characters." - removed
Input schema / properties / domain / titleRemoved value: -"Domain" - added
Input schema / properties / instead / descriptionAdded value: +"what to do, concrete enough to act on." - removed
Input schema / properties / instead / titleRemoved value: -"Instead" - added
Input schema / properties / pattern / descriptionAdded value: +"the temptation, as the next agent will meet it: the move that looks right at the time. At most 800 characters." - removed
Input schema / properties / pattern / titleRemoved value: -"Pattern" - added
Input schema / properties / review_after / descriptionAdded value: +"when this stops being safe to trust unchecked, as a date ('2026-11-01') or a span from today ('90d'). pulse() counts what is overdue in a scope as `scope.stale` and optimize_scan lists it. Leave it empty for anything that does not go stale -- most facts do not, and a date nobody meant is worse than none." - removed
Input schema / properties / review_after / titleRemoved value: -"Review After" - added
Input schema / properties / session / descriptionAdded value: +"groups what one conversation writes. Leave it empty to use this server process's own stamp." - removed
Input schema / properties / session / titleRemoved value: -"Session" - added
Input schema / properties / source_ref / descriptionAdded value: +"what the fact came FROM -- a path, a URL, a table name -- so a later pass can check the claim against the thing itself instead of inferring what to check from the wording. At most 500 characters." - removed
Input schema / properties / source_ref / titleRemoved value: -"Source Ref" - added
Input schema / properties / tags / descriptionAdded value: +"comma-separated keywords and synonyms. Retrieval is BM25 over content, tags and domain paths, and tags weigh second only to the body, so they make a memory findable by words its own text never uses: the identifier, the error string, the plain phrasing someone will type. A memory with none is reachable only by quoting itself. At most 1000 characters." - removed
Input schema / properties / tags / titleRemoved value: -"Tags" - added
Input schema / properties / title / descriptionAdded value: +"one line naming what this memory is about, in the words someone would look for it by. A list shows it instead of the opening of the body, and it outweighs every other field in search, so a title that repeats the type (\"note about the parser\") names nothing. At most 120 characters; a name that needs more is summarizing the body." - removed
Input schema / properties / title / titleRemoved value: -"Title" - added
Input schema / properties / why_wrong / descriptionAdded value: +"the mechanism that makes it fail, specific enough to recognise the next time." - removed
Input schema / properties / why_wrong / titleRemoved value: -"Why Wrong" - removed
Input schema / titleRemoved value: -"anti_patternArguments"
- Changed
checkpoint20 fields changed- added
Input schema / properties / also / descriptionAdded value: +"other domain paths this belongs to, comma-separated: the subjects that cut across the tree `domain` sits in, such as the end-to-end flow a routine is one step of. Every read scoped to one of them returns it. A path `domain` already sits under is dropped as redundant. At most 200 characters each." - removed
Input schema / properties / also / titleRemoved value: -"Also" - added
Input schema / properties / domain / descriptionAdded value: +"the subject this belongs to, as a path from the outermost scope in ('acme/x100/p200'). File it as deep as the fact is specific -- a note about one routine goes on the routine, and still comes back when someone asks about the module or the product above it. At most 200 characters." - removed
Input schema / properties / domain / titleRemoved value: -"Domain" - added
Input schema / properties / established / descriptionAdded value: +"what is done and what was decided, with the [[uid]] of each note that holds the detail." - removed
Input schema / properties / established / titleRemoved value: -"Established" - added
Input schema / properties / intent / descriptionAdded value: +"what the work is for, in a sentence or two." - removed
Input schema / properties / intent / titleRemoved value: -"Intent" - added
Input schema / properties / open_questions / descriptionAdded value: +"what is still undecided or unverified." - removed
Input schema / properties / open_questions / titleRemoved value: -"Open Questions" - added
Input schema / properties / pursuing / descriptionAdded value: +"what comes next, specific enough to start on." - removed
Input schema / properties / pursuing / titleRemoved value: -"Pursuing" - added
Input schema / properties / session / descriptionAdded value: +"groups what one conversation writes. Leave it empty to use this server process's own stamp." - removed
Input schema / properties / session / titleRemoved value: -"Session" - added
Input schema / properties / supersedesAdded value: +{ + "default": "", + "description": "the active checkpoints this one replaces, comma-separated uids: every one already filed at `domain`, and every overdue one above it that a refusal named. Each is archived with this one as its successor.", + "type": "string" +} - added
Input schema / properties / tags / descriptionAdded value: +"comma-separated keywords and synonyms. Retrieval is BM25 over content, tags and domain paths, and tags weigh second only to the body, so they make a memory findable by words its own text never uses: the identifier, the error string, the plain phrasing someone will type. A memory with none is reachable only by quoting itself. At most 1000 characters." - removed
Input schema / properties / tags / titleRemoved value: -"Tags" - added
Input schema / properties / title / descriptionAdded value: +"one line naming what this memory is about, in the words someone would look for it by. A list shows it instead of the opening of the body, and it outweighs every other field in search, so a title that repeats the type (\"note about the parser\") names nothing. At most 120 characters; a name that needs more is summarizing the body." - removed
Input schema / properties / title / titleRemoved value: -"Title" - removed
Input schema / titleRemoved value: -"checkpointArguments"
- Changed
dedup_scan11 fields changed- added
Input schema / properties / domain / descriptionAdded value: +"scans a path and everything nested under it, which is usually what you want: near-duplicates collect between a module and its own routines." - removed
Input schema / properties / domain / titleRemoved value: -"Domain" - added
Input schema / properties / limit / descriptionAdded value: +"the most pairs to return." - removed
Input schema / properties / limit / titleRemoved value: -"Limit" - added
Input schema / properties / offsetAdded value: +{ + "default": 0, + "description": "where the page starts; `next_offset`, when present, starts the next.", + "type": "integer" +} - added
Input schema / properties / threshold / descriptionAdded value: +"the similarity, 0 to 1, a pair must reach to be listed." - removed
Input schema / properties / threshold / titleRemoved value: -"Threshold" - added
Input schema / properties / type / descriptionAdded value: +"one memory type, as search() takes it; empty is every type." - removed
Input schema / properties / type / titleRemoved value: -"Type" - removed
Input schema / titleRemoved value: -"dedup_scanArguments" - changed
Output schema / (root)Previous value: -{ - "properties": { - "result": { - "items": { - "additionalProperties": true, - "type": "object" - }, - "title": "Result", - "type": "array" - } - }, - "required": [ - "result" - ], - "title": "dedup_scanOutput", - "type": "object" -}New value: +null
- Changed
diagram23 fields changed- added
Input schema / properties / also / descriptionAdded value: +"other domain paths this flow belongs to, comma-separated. `domain` is the routine's own place in the tree; `also` is for the flows that run ACROSS routines -- several of them can be steps of one end-to-end process without any of them being the parent of the others. Cross-list each into that process's path and asking about it returns all of them, instead of hoping one search phrasing reaches every one." - removed
Input schema / properties / also / titleRemoved value: -"Also" - added
Input schema / properties / domain / descriptionAdded value: +"the subject this belongs to, as a path from the outermost scope in ('acme/x100/p200'). File it as deep as the fact is specific -- a note about one routine goes on the routine, and still comes back when someone asks about the module or the product above it. At most 200 characters." - removed
Input schema / properties / domain / titleRemoved value: -"Domain" - added
Input schema / properties / edges / descriptionAdded value: +"the wires between steps, as [{\"from\": \"load\", \"to\": \"check\", \"label\": \"optional branch\"}]." - removed
Input schema / properties / edges / titleRemoved value: -"Edges" - added
Input schema / properties / kind / descriptionAdded value: +"'flowchart', the only kind." - removed
Input schema / properties / kind / titleRemoved value: -"Kind" - added
Input schema / properties / nodes / descriptionAdded value: +"the steps, as [{\"key\": \"load\", \"label\": \"Read the export window\", \"shape\": \"step\", \"note\": \"optional long explanation\"}]. key is a stable id the edges refer to (letters, digits, '_' or '-'); shape is start|step|decision|io|end. Exactly one 'start' is required and every node must be reachable from it. Cycles are allowed -- a retry loop is a real flow, not a mistake." - removed
Input schema / properties / nodes / titleRemoved value: -"Nodes" - added
Input schema / properties / review_after / descriptionAdded value: +"when this stops being safe to trust unchecked, as a date ('2026-11-01') or a span from today ('90d'). pulse() counts what is overdue in a scope as `scope.stale` and optimize_scan lists it. Leave it empty for anything that does not go stale -- most facts do not, and a date nobody meant is worse than none." - removed
Input schema / properties / review_after / titleRemoved value: -"Review After" - added
Input schema / properties / session / descriptionAdded value: +"groups what one conversation writes. Leave it empty to use this server process's own stamp." - removed
Input schema / properties / session / titleRemoved value: -"Session" - added
Input schema / properties / source_ref / descriptionAdded value: +"what the fact came FROM -- a path, a URL, a table name -- so a later pass can check the claim against the thing itself instead of inferring what to check from the wording. At most 500 characters." - removed
Input schema / properties / source_ref / titleRemoved value: -"Source Ref" - added
Input schema / properties / summary / descriptionAdded value: +"a few sentences on what the routine is for, indexed with the flow." - removed
Input schema / properties / summary / titleRemoved value: -"Summary" - added
Input schema / properties / tags / descriptionAdded value: +"comma-separated keywords and synonyms. Retrieval is BM25 over content, tags and domain paths, and tags weigh second only to the body, so they make a memory findable by words its own text never uses: the identifier, the error string, the plain phrasing someone will type. A memory with none is reachable only by quoting itself. At most 1000 characters." - removed
Input schema / properties / tags / titleRemoved value: -"Tags" - added
Input schema / properties / title / descriptionAdded value: +"one line naming what this memory is about, in the words someone would look for it by. A list shows it instead of the opening of the body, and it outweighs every other field in search, so a title that repeats the type (\"note about the parser\") names nothing. At most 120 characters; a name that needs more is summarizing the body." - removed
Input schema / properties / title / titleRemoved value: -"Title" - removed
Input schema / titleRemoved value: -"diagramArguments"
- Changed
diagram_edge11 fields changed- added
Input schema / properties / delete / descriptionAdded value: +"removes the edge between from_key and to_key." - removed
Input schema / properties / delete / titleRemoved value: -"Delete" - added
Input schema / properties / from_key / descriptionAdded value: +"the step the edge leaves." - removed
Input schema / properties / from_key / titleRemoved value: -"From Key" - added
Input schema / properties / label / descriptionAdded value: +"the condition on a branch out of a decision node ('yes', 'no', 'on timeout')." - removed
Input schema / properties / label / titleRemoved value: -"Label" - added
Input schema / properties / to_key / descriptionAdded value: +"the step it reaches." - removed
Input schema / properties / to_key / titleRemoved value: -"To Key" - added
Input schema / properties / uid / descriptionAdded value: +"the diagram." - removed
Input schema / properties / uid / titleRemoved value: -"Uid" - removed
Input schema / titleRemoved value: -"diagram_edgeArguments"
- Changed
diagram_jump13 fields changed- added
Input schema / properties / delete / descriptionAdded value: +"removes the jump." - removed
Input schema / properties / delete / titleRemoved value: -"Delete" - added
Input schema / properties / label / descriptionAdded value: +"what the hand-off is, shown on the jump." - removed
Input schema / properties / label / titleRemoved value: -"Label" - added
Input schema / properties / node_key / descriptionAdded value: +"this diagram's step the branch leaves from; on a delete from the receiving end, that end's step." - removed
Input schema / properties / node_key / titleRemoved value: -"Node Key" - added
Input schema / properties / peer_node / descriptionAdded value: +"the step it arrives at there; empty arrives at the diagram as a whole." - removed
Input schema / properties / peer_node / titleRemoved value: -"Peer Node" - added
Input schema / properties / peer_uid / descriptionAdded value: +"the diagram the branch continues in." - removed
Input schema / properties / peer_uid / titleRemoved value: -"Peer Uid" - added
Input schema / properties / uid / descriptionAdded value: +"this diagram; on a delete, either end's diagram." - removed
Input schema / properties / uid / titleRemoved value: -"Uid" - removed
Input schema / titleRemoved value: -"diagram_jumpArguments"
- Changed
diagram_link11 fields changed- added
Input schema / properties / delete / descriptionAdded value: +"removes the link between node_key and target_uid." - removed
Input schema / properties / delete / titleRemoved value: -"Delete" - added
Input schema / properties / node_key / descriptionAdded value: +"the step the memory explains." - removed
Input schema / properties / node_key / titleRemoved value: -"Node Key" - added
Input schema / properties / relation_type / descriptionAdded value: +"how the memory relates to the step; 'explains' unless given. Linking the same step and memory again replaces it." - removed
Input schema / properties / relation_type / titleRemoved value: -"Relation Type" - added
Input schema / properties / target_uid / descriptionAdded value: +"the memory to attach." - removed
Input schema / properties / target_uid / titleRemoved value: -"Target Uid" - added
Input schema / properties / uid / descriptionAdded value: +"the diagram." - removed
Input schema / properties / uid / titleRemoved value: -"Uid" - removed
Input schema / titleRemoved value: -"diagram_linkArguments"
- Changed
diagram_node13 fields changed- added
Input schema / properties / delete / descriptionAdded value: +"removes the step together with its edges and its memory links." - removed
Input schema / properties / delete / titleRemoved value: -"Delete" - added
Input schema / properties / key / descriptionAdded value: +"the step's id; a new key adds a step." - removed
Input schema / properties / key / titleRemoved value: -"Key" - added
Input schema / properties / label / descriptionAdded value: +"what happens at the step, objectively." - removed
Input schema / properties / label / titleRemoved value: -"Label" - added
Input schema / properties / note / descriptionAdded value: +"the step's explanation: reasoning, caveats, history." - removed
Input schema / properties / note / titleRemoved value: -"Note" - added
Input schema / properties / shape / descriptionAdded value: +"start|step|decision|io|end." - removed
Input schema / properties / shape / titleRemoved value: -"Shape" - added
Input schema / properties / uid / descriptionAdded value: +"the diagram." - removed
Input schema / properties / uid / titleRemoved value: -"Uid" - removed
Input schema / titleRemoved value: -"diagram_nodeArguments"
- Changed
diagram_relayout3 fields changed- added
Input schema / properties / uid / descriptionAdded value: +"the diagram." - removed
Input schema / properties / uid / titleRemoved value: -"Uid" - removed
Input schema / titleRemoved value: -"diagram_relayoutArguments"
- Changed
edit_memory16 fields changed- added
Input schema / properties / goalAdded value: +{ + "default": "", + "description": "a task's new goal, held to the rules task() states; the previous goal stays in the edit history. Refused on any other type.", + "type": "string" +} - added
Input schema / properties / mode / descriptionAdded value: +"'replace' or 'append'. 'append' adds `new_content` as a new line at the end instead of replacing the body. Use it when a memory gains a fact rather than turning out to be wrong: the alternative is reading the whole thing, restating it and sending it back, which pays for the body twice and stakes the existing text on it being copied faithfully. Append what THIS memory gained. A fact about a further subject is a new memory plus an edge, not a line at the bottom -- appended text is ranked as part of the body it lands in and comes back with it." - removed
Input schema / properties / mode / titleRemoved value: -"Mode" - added
Input schema / properties / new_content / descriptionAdded value: +"the corrected body, or with mode='append' the line to add." - removed
Input schema / properties / new_content / titleRemoved value: -"New Content" - added
Input schema / properties / note / descriptionAdded value: +"why it changed, kept with the previous version in the edit history." - removed
Input schema / properties / note / titleRemoved value: -"Note" - added
Input schema / properties / source_ref / descriptionAdded value: +"points the memory at what its claim came from -- the field note() takes at write time, and the one a later pass checks the claim against. Settable with no `new_content`, for the common case of a body that is right and a reference that is missing or has moved; empty leaves the stored one alone, and clearing one is a dashboard edit." - removed
Input schema / properties / source_ref / titleRemoved value: -"Source Ref" - added
Input schema / properties / tags / descriptionAdded value: +"REPLACES the tag set, comma-separated: pass the whole set that should survive, not the one being added. Indexed, so this is how an untagged memory becomes findable by the words its body never uses. Empty leaves the stored tags alone -- clearing them, like clearing a source_ref, is a dashboard edit." - removed
Input schema / properties / tags / titleRemoved value: -"Tags" - added
Input schema / properties / title / descriptionAdded value: +"renames the memory: the one line a list shows it by, and the field weighing most in search, at most 120 characters. A diagram is renamed through its graph instead -- its title is part of what generates the body, so a rename here would be overwritten by the next structural change." - removed
Input schema / properties / title / titleRemoved value: -"Title" - added
Input schema / properties / uid / descriptionAdded value: +"the memory." - removed
Input schema / properties / uid / titleRemoved value: -"Uid" - removed
Input schema / titleRemoved value: -"edit_memoryArguments"
- Changed
forget7 fields changed- added
Input schema / properties / reason / descriptionAdded value: +"why it is archived, recorded as a status-change audit entry without touching the content." - removed
Input schema / properties / reason / titleRemoved value: -"Reason" - added
Input schema / properties / superseded_by / descriptionAdded value: +"the uid of the memory that replaces this one, kept on the archived record. To mark a memory that stays active as replaced, draw link_memories(new, old, 'supersedes') instead: search then flags the old one `succeeded_by`." - removed
Input schema / properties / superseded_by / titleRemoved value: -"Superseded By" - added
Input schema / properties / uid / descriptionAdded value: +"the memory." - removed
Input schema / properties / uid / titleRemoved value: -"Uid" - removed
Input schema / titleRemoved value: -"forgetArguments"
- Changed
get_diagram6 fields changed- added
Input schema / properties / format / descriptionAdded value: +"one of the formats above." - removed
Input schema / properties / format / titleRemoved value: -"Format" - added
Input schema / properties / offsetAdded value: +{ + "default": 0, + "description": "where a long `body`, or the SVG step index, starts; `next_offset`, when present, starts the next page.", + "type": "integer" +} - added
Input schema / properties / uid / descriptionAdded value: +"the diagram." - removed
Input schema / properties / uid / titleRemoved value: -"Uid" - removed
Input schema / titleRemoved value: -"get_diagramArguments"
- Changed
get_domain_case1 field changed- removed
Input schema / titleRemoved value: -"get_domain_caseArguments"
- Changed
get_memory5 fields changed- added
Input schema / properties / content_offsetAdded value: +{ + "default": -1, + "description": "from -1 to a character offset, reads that stretch of the body instead of the record.", + "type": "integer" +} - added
Input schema / properties / edits_offsetAdded value: +{ + "default": -1, + "description": "from -1 to a page start, reads the edit history instead of the record, bodies cut to 4000 characters.", + "type": "integer" +} - added
Input schema / properties / uid / descriptionAdded value: +"the memory." - removed
Input schema / properties / uid / titleRemoved value: -"Uid" - removed
Input schema / titleRemoved value: -"get_memoryArguments"
- Changed
get_relations6 fields changed- added
Input schema / properties / offsetAdded value: +{ + "default": 0, + "description": "where the page starts; `next_offset`, when present, starts the next.", + "type": "integer" +} - added
Input schema / properties / partAdded value: +{ + "default": "relations", + "description": "'relations' (edges, both ways) or 'diagrams' (flows pointing at it).", + "type": "string" +} - added
Input schema / properties / uid / descriptionAdded value: +"the memory." - removed
Input schema / properties / uid / titleRemoved value: -"Uid" - removed
Input schema / titleRemoved value: -"get_relationsArguments" - changed
Output schema / (root)Previous value: -{ - "properties": { - "result": { - "items": { - "additionalProperties": true, - "type": "object" - }, - "title": "Result", - "type": "array" - } - }, - "required": [ - "result" - ], - "title": "get_relationsOutput", - "type": "object" -}New value: +null
- Removed
help - Changed
link_memories9 fields changed- added
Input schema / properties / from_uid / descriptionAdded value: +"the memory the edge starts at." - removed
Input schema / properties / from_uid / titleRemoved value: -"From Uid" - added
Input schema / properties / note / descriptionAdded value: +"why the two are related, kept on the edge." - removed
Input schema / properties / note / titleRemoved value: -"Note" - added
Input schema / properties / relation_type / descriptionAdded value: +"free text, but keep it consistent, e.g. 'supersedes', 'relates_to', 'contradicts', 'links_to'." - removed
Input schema / properties / relation_type / titleRemoved value: -"Relation Type" - added
Input schema / properties / to_uid / descriptionAdded value: +"the memory it points to." - removed
Input schema / properties / to_uid / titleRemoved value: -"To Uid" - removed
Input schema / titleRemoved value: -"link_memoriesArguments"
- Changed
list_by_domain12 fields changed- added
Input schema / properties / domain / descriptionAdded value: +"a path, matched from the outermost segment in: 'acme/x100' lists the module's own memories plus every routine under it. A domain that matches no path is retried as a run of segments INSIDE one, so list_by_domain('p200') still finds the routine once it lives at 'acme/x100/p200'. The literal reading wins whenever it has rows, and an ambiguous name (the same code under two modules) covers both branches rather than picking one -- each row's `domain` says which branch it came from. list_domains() is the way to see the paths first." - removed
Input schema / properties / domain / titleRemoved value: -"Domain" - added
Input schema / properties / limit / descriptionAdded value: +"the most results to return." - removed
Input schema / properties / limit / titleRemoved value: -"Limit" - added
Input schema / properties / offsetAdded value: +{ + "default": 0, + "description": "where the page starts; `next_offset`, when present, starts the next.", + "type": "integer" +} - added
Input schema / properties / status / descriptionAdded value: +"'active', 'archived' or 'all'. Closing a task archives its memory, so list_by_domain(domain, type='task', status='archived') returns the completed and cancelled tasks." - removed
Input schema / properties / status / titleRemoved value: -"Status" - added
Input schema / properties / subtree / descriptionAdded value: +"False lists what is filed at exactly that path and nowhere deeper." - removed
Input schema / properties / subtree / titleRemoved value: -"Subtree" - added
Input schema / properties / type / descriptionAdded value: +"one memory type, as search() takes it; empty is every type." - removed
Input schema / properties / type / titleRemoved value: -"Type" - removed
Input schema / titleRemoved value: -"list_by_domainArguments"
- Changed
list_domains3 fields changed- added
Input schema / properties / offsetAdded value: +{ + "default": 0, + "description": "where the page starts; `next_offset`, when present, starts the next.", + "type": "integer" +} - removed
Input schema / titleRemoved value: -"list_domainsArguments" - changed
Output schema / (root)Previous value: -{ - "properties": { - "result": { - "items": { - "additionalProperties": true, - "type": "object" - }, - "title": "Result", - "type": "array" - } - }, - "required": [ - "result" - ], - "title": "list_domainsOutput", - "type": "object" -}New value: +null
- Changed
list_projects2 fields changed- added
Input schema / properties / offsetAdded value: +{ + "default": 0, + "description": "where the page starts; `next_offset`, when present, starts the next.", + "type": "integer" +} - removed
Input schema / titleRemoved value: -"list_projectsArguments"
- Changed
list_recent10 fields changed- added
Input schema / properties / domain / descriptionAdded value: +"covers its subdomains, and a bare deep segment resolves to the branches holding it (see list_by_domain)." - removed
Input schema / properties / domain / titleRemoved value: -"Domain" - added
Input schema / properties / limit / descriptionAdded value: +"the most results to return." - removed
Input schema / properties / limit / titleRemoved value: -"Limit" - added
Input schema / properties / offsetAdded value: +{ + "default": 0, + "description": "where the page starts; `next_offset`, when present, starts the next.", + "type": "integer" +} - added
Input schema / properties / subtree / descriptionAdded value: +"False narrows to the exact domain path." - removed
Input schema / properties / subtree / titleRemoved value: -"Subtree" - added
Input schema / properties / type / descriptionAdded value: +"one memory type, as search() takes it; empty is every type." - removed
Input schema / properties / type / titleRemoved value: -"Type" - removed
Input schema / titleRemoved value: -"list_recentArguments"
- Changed
move_to_project11 fields changed- added
Input schema / properties / create / descriptionAdded value: +"makes a `target` that does not exist yet." - removed
Input schema / properties / create / titleRemoved value: -"Create" - added
Input schema / properties / domain / descriptionAdded value: +"a path to move, its subdomains and archived rows included." - removed
Input schema / properties / domain / titleRemoved value: -"Domain" - added
Input schema / properties / dry_run / descriptionAdded value: +"the default, and moves nothing: it reports what would move, `conflicts` (uids `target` already holds, which stay here), `unknown` (uids asked for that this project does not hold) and `outside` -- the relations, diagram links and jumps, `superseded_by` marks and [[uid]] references that cross the edge of the slice, all of which the move drops. Each comes as `count`, the whole number, and up to 20 `items`. Read that report with the user, then widen the slice or accept the loss BEFORE calling again with dry_run=False: the purge is irreversible short of the backup." - removed
Input schema / properties / dry_run / titleRemoved value: -"Dry Run" - added
Input schema / properties / target / descriptionAdded value: +"the project to move into; list_projects() names the projects there are." - removed
Input schema / properties / target / titleRemoved value: -"Target" - added
Input schema / properties / uids / descriptionAdded value: +"comma-separated memories to move; give uids, domain or both." - removed
Input schema / properties / uids / titleRemoved value: -"Uids" - removed
Input schema / titleRemoved value: -"move_to_projectArguments"
- Added
must_read - Changed
note17 fields changed- added
Input schema / properties / also / descriptionAdded value: +"other domain paths this belongs to, comma-separated: the subjects that cut across the tree `domain` sits in, such as the end-to-end flow a routine is one step of. Every read scoped to one of them returns it. A path `domain` already sits under is dropped as redundant. At most 200 characters each." - removed
Input schema / properties / also / titleRemoved value: -"Also" - added
Input schema / properties / content / descriptionAdded value: +"ONE fact, and what a reader needs to use it -- what holds, where it holds, what it rules out. Retrieval ranks whole memories, so a body answering four questions comes back for all four and is read for one: write the second subject as its own memory, on its own domain, and connect the two with link_memories(). A [[uid]] typed inside a body is a reference a reader can follow, not an edge -- get_relations() and the graph do not see it until link_memories() creates one. Past a couple of thousand characters, a body is usually several memories written as one." - removed
Input schema / properties / content / titleRemoved value: -"Content" - added
Input schema / properties / domain / descriptionAdded value: +"the subject this belongs to, as a path from the outermost scope in ('acme/x100/p200'). File it as deep as the fact is specific -- a note about one routine goes on the routine, and still comes back when someone asks about the module or the product above it. At most 200 characters." - removed
Input schema / properties / domain / titleRemoved value: -"Domain" - added
Input schema / properties / review_after / descriptionAdded value: +"when this stops being safe to trust unchecked, as a date ('2026-11-01') or a span from today ('90d'). pulse() counts what is overdue in a scope as `scope.stale` and optimize_scan lists it. Leave it empty for anything that does not go stale -- most facts do not, and a date nobody meant is worse than none." - removed
Input schema / properties / review_after / titleRemoved value: -"Review After" - added
Input schema / properties / session / descriptionAdded value: +"groups what one conversation writes. Leave it empty to use this server process's own stamp." - removed
Input schema / properties / session / titleRemoved value: -"Session" - added
Input schema / properties / source_ref / descriptionAdded value: +"what the fact came FROM -- a path, a URL, a table name -- so a later pass can check the claim against the thing itself instead of inferring what to check from the wording. At most 500 characters." - removed
Input schema / properties / source_ref / titleRemoved value: -"Source Ref" - added
Input schema / properties / tags / descriptionAdded value: +"comma-separated keywords and synonyms. Retrieval is BM25 over content, tags and domain paths, and tags weigh second only to the body, so they make a memory findable by words its own text never uses: the identifier, the error string, the plain phrasing someone will type. A memory with none is reachable only by quoting itself. At most 1000 characters." - removed
Input schema / properties / tags / titleRemoved value: -"Tags" - added
Input schema / properties / title / descriptionAdded value: +"one line naming what this memory is about, in the words someone would look for it by. A list shows it instead of the opening of the body, and it outweighs every other field in search, so a title that repeats the type (\"note about the parser\") names nothing. At most 120 characters; a name that needs more is summarizing the body." - removed
Input schema / properties / title / titleRemoved value: -"Title" - removed
Input schema / titleRemoved value: -"noteArguments"
- Changed
optimize_runs3 fields changed- added
Input schema / properties / offsetAdded value: +{ + "default": 0, + "description": "where the page starts; `next_offset`, when present, starts the next.", + "type": "integer" +} - removed
Input schema / titleRemoved value: -"optimize_runsArguments" - changed
Output schema / (root)Previous value: -{ - "properties": { - "result": { - "items": { - "additionalProperties": true, - "type": "object" - }, - "title": "Result", - "type": "array" - } - }, - "required": [ - "result" - ], - "title": "optimize_runsOutput", - "type": "object" -}New value: +null
- Changed
optimize_scan15 fields changed- added
Input schema / properties / domain / descriptionAdded value: +"scans a path and everything nested under it; empty is the whole project." - removed
Input schema / properties / domain / titleRemoved value: -"Domain" - added
Input schema / properties / full / descriptionAdded value: +"true keeps whole bodies instead of the slim listing." - removed
Input schema / properties / full / titleRemoved value: -"Full" - added
Input schema / properties / include_archived / descriptionAdded value: +"true lists archived memories as well." - removed
Input schema / properties / include_archived / titleRemoved value: -"Include Archived" - added
Input schema / properties / limit / descriptionAdded value: +"the most memories per page." - removed
Input schema / properties / limit / titleRemoved value: -"Limit" - added
Input schema / properties / offset / descriptionAdded value: +"where the page starts; after a `truncated` page, offset + count." - removed
Input schema / properties / offset / titleRemoved value: -"Offset" - added
Input schema / properties / since / descriptionAdded value: +"limits the scan to what changed after this date, for recurring passes." - removed
Input schema / properties / since / titleRemoved value: -"Since" - added
Input schema / properties / type / descriptionAdded value: +"one memory type, as search() takes it; empty is every type." - removed
Input schema / properties / type / titleRemoved value: -"Type" - removed
Input schema / titleRemoved value: -"optimize_scanArguments"
- Changed
optimize_stage5 fields changed- added
Input schema / properties / note / descriptionAdded value: +"one short summary of the pass, at most 250 characters; a longer one raises and stages nothing. What a single suggestion needs said belongs in its own `rationale` and `verified`, which are not capped." - removed
Input schema / properties / note / titleRemoved value: -"Note" - added
Input schema / properties / suggestions / descriptionAdded value: +"each one {\"kind\", \"target_uid\", \"payload\", \"rationale\", \"verified\"}. Kinds: compact/reword {\"new_content\"}, retag {\"tags\"}, retitle {\"title\"}, redomain {\"domain\"}, crosslist {\"also\": [...]} (replaces the whole set), set_confidence {\"confidence\"}, review {\"review_after\"} (a date or a span like '180d'; '' clears it), archive {\"reason\"}, link {\"from_uid\",\"to_uid\",\"relation_type\"}, merge {\"keep_uid\",\"drop_uid\"}, distill {\"source_uids\",\"new_type\",\"new_content\", \"title\"}, unleak {\"field\": \"content|tags|source_ref\"} (the repair is computed at staging). link/merge derive target_uid from the payload and distill creates its target -- omit it for those. Destructive kinds (archive, set_confidence=contradicted, merge, distill) require a non-empty `verified` describing the live-facts check behind them." - removed
Input schema / properties / suggestions / titleRemoved value: -"Suggestions" - removed
Input schema / titleRemoved value: -"optimize_stageArguments"
- Changed
optimize_status4 fields changed- added
Input schema / properties / offsetAdded value: +{ + "default": 0, + "description": "where the page starts; `next_offset`, when present, starts the next.", + "type": "integer" +} - added
Input schema / properties / run_id / descriptionAdded value: +"the run optimize_stage returned, or one optimize_runs lists." - removed
Input schema / properties / run_id / titleRemoved value: -"Run Id" - removed
Input schema / titleRemoved value: -"optimize_statusArguments"
- Removed
pending - Changed
pulse4 fields changed- added
Input schema / properties / domain / descriptionAdded value: +"warms up a path and everything under it, so pulse('acme/x100') is the module-wide brief and pulse('acme/x100/p200') the routine's. A domain that names only the deep end of a path ('p200') is resolved to the branches it sits in -- `scope.paths` reports which, and an ambiguous name resolves to ALL of them." - removed
Input schema / properties / domain / titleRemoved value: -"Domain" - added
Input schema / properties / offsetAdded value: +{ + "default": 0, + "description": "where the page of `scope.subdomains` starts.", + "type": "integer" +} - removed
Input schema / titleRemoved value: -"pulseArguments"
- Changed
purge_memory5 fields changed- added
Input schema / properties / confirm_phrase / descriptionAdded value: +"must exactly equal \"DELETE <uid>\", typed by the user in their own message. Do not construct this string yourself from an inferred \"yes\"/\"confirm\" -- it must come from the user actually stating the uid back." - removed
Input schema / properties / confirm_phrase / titleRemoved value: -"Confirm Phrase" - added
Input schema / properties / uid / descriptionAdded value: +"the memory." - removed
Input schema / properties / uid / titleRemoved value: -"Uid" - removed
Input schema / titleRemoved value: -"purge_memoryArguments"
- Changed
reasoning25 fields changed- added
Input schema / properties / also / descriptionAdded value: +"other domain paths this belongs to, comma-separated: the subjects that cut across the tree `domain` sits in, such as the end-to-end flow a routine is one step of. Every read scoped to one of them returns it. A path `domain` already sits under is dropped as redundant. At most 200 characters each." - removed
Input schema / properties / also / titleRemoved value: -"Also" - added
Input schema / properties / domain / descriptionAdded value: +"the subject this belongs to, as a path from the outermost scope in ('acme/x100/p200'). File it as deep as the fact is specific -- a note about one routine goes on the routine, and still comes back when someone asks about the module or the product above it. At most 200 characters." - removed
Input schema / properties / domain / titleRemoved value: -"Domain" - added
Input schema / properties / hypothesis / descriptionAdded value: +"what you believed going in, as a claim that could be wrong." - removed
Input schema / properties / hypothesis / titleRemoved value: -"Hypothesis" - added
Input schema / properties / next_time / descriptionAdded value: +"what someone hitting this again should do differently." - removed
Input schema / properties / next_time / titleRemoved value: -"Next Time" - added
Input schema / properties / reasoning / descriptionAdded value: +"how you tested it -- what you read, ran or compared." - removed
Input schema / properties / reasoning / titleRemoved value: -"Reasoning" - added
Input schema / properties / result / descriptionAdded value: +"what came back. The measurement, not the interpretation." - removed
Input schema / properties / result / titleRemoved value: -"Result" - added
Input schema / properties / review_after / descriptionAdded value: +"when this stops being safe to trust unchecked, as a date ('2026-11-01') or a span from today ('90d'). pulse() counts what is overdue in a scope as `scope.stale` and optimize_scan lists it. Leave it empty for anything that does not go stale -- most facts do not, and a date nobody meant is worse than none." - removed
Input schema / properties / review_after / titleRemoved value: -"Review After" - added
Input schema / properties / revised_belief / descriptionAdded value: +"what you believe now, and where it differs from the hypothesis. Say plainly when the hypothesis survived unchanged." - removed
Input schema / properties / revised_belief / titleRemoved value: -"Revised Belief" - added
Input schema / properties / session / descriptionAdded value: +"groups what one conversation writes. Leave it empty to use this server process's own stamp." - removed
Input schema / properties / session / titleRemoved value: -"Session" - added
Input schema / properties / source_ref / descriptionAdded value: +"what the fact came FROM -- a path, a URL, a table name -- so a later pass can check the claim against the thing itself instead of inferring what to check from the wording. At most 500 characters." - removed
Input schema / properties / source_ref / titleRemoved value: -"Source Ref" - added
Input schema / properties / tags / descriptionAdded value: +"comma-separated keywords and synonyms. Retrieval is BM25 over content, tags and domain paths, and tags weigh second only to the body, so they make a memory findable by words its own text never uses: the identifier, the error string, the plain phrasing someone will type. A memory with none is reachable only by quoting itself. At most 1000 characters." - removed
Input schema / properties / tags / titleRemoved value: -"Tags" - added
Input schema / properties / title / descriptionAdded value: +"one line naming what this memory is about, in the words someone would look for it by. A list shows it instead of the opening of the body, and it outweighs every other field in search, so a title that repeats the type (\"note about the parser\") names nothing. At most 120 characters; a name that needs more is summarizing the body." - removed
Input schema / properties / title / titleRemoved value: -"Title" - removed
Input schema / titleRemoved value: -"reasoningArguments"
- Changed
recall8 fields changed- added
Input schema / properties / domain / descriptionAdded value: +"scopes to a path and everything nested under it, and resolves a bare deep segment the same way search() does." - removed
Input schema / properties / domain / titleRemoved value: -"Domain" - added
Input schema / properties / limit / descriptionAdded value: +"the most results to return." - removed
Input schema / properties / limit / titleRemoved value: -"Limit" - added
Input schema / properties / offsetAdded value: +{ + "default": 0, + "description": "where the page starts; `next_offset`, when present, starts the next.", + "type": "integer" +} - added
Input schema / properties / query / descriptionAdded value: +"the words to look for; as in search(), more terms find more." - removed
Input schema / properties / query / titleRemoved value: -"Query" - removed
Input schema / titleRemoved value: -"recallArguments"
- Changed
search10 fields changed- added
Input schema / properties / domain / descriptionAdded value: +"scopes to a path AND everything under it: domain='acme/x100' searches the module and each of its routines. Give more of the path to narrow it. A domain naming only the deep end of a path ('p200') is resolved to the branches it sits in -- every result carries its real `domain`, which is where to read what the filter actually covered." - removed
Input schema / properties / domain / titleRemoved value: -"Domain" - added
Input schema / properties / limit / descriptionAdded value: +"the most results to return." - removed
Input schema / properties / limit / titleRemoved value: -"Limit" - added
Input schema / properties / offsetAdded value: +{ + "default": 0, + "description": "where the page starts; `next_offset`, when present, starts the next.", + "type": "integer" +} - added
Input schema / properties / query / descriptionAdded value: +"the words to look for. SPEND TERMS FREELY. Every space-separated term is asked for separately and a row matching more of them ranks higher, so piling on synonyms, the identifier, the routine name and the plain-language phrasing into one query costs one call and finds strictly more. Twenty terms beat ten. Write a sentence if that is what you have -- common words score near zero and cost nothing, so there is nothing to strip." - removed
Input schema / properties / query / titleRemoved value: -"Query" - added
Input schema / properties / type / descriptionAdded value: +"'note', 'reasoning', 'checkpoint', 'anti_pattern', 'diagram', 'task' (one writer each) or 'handoff' (rows already stored; task() carries unfinished work to the next session); any other type is an error. Ask for type='diagram' to sweep the documented flows on purpose." - removed
Input schema / properties / type / titleRemoved value: -"Type" - removed
Input schema / titleRemoved value: -"searchArguments"
- Changed
set_confidence5 fields changed- added
Input schema / properties / confidence / descriptionAdded value: +"unverified, confirmed or contradicted." - removed
Input schema / properties / confidence / titleRemoved value: -"Confidence" - added
Input schema / properties / uid / descriptionAdded value: +"the memory." - removed
Input schema / properties / uid / titleRemoved value: -"Uid" - removed
Input schema / titleRemoved value: -"set_confidenceArguments"
- Changed
set_domain_case3 fields changed- added
Input schema / properties / mode / descriptionAdded value: +"'preserve' keeps free-text casing; 'lower' or 'upper' coerces every domain written to that case." - removed
Input schema / properties / mode / titleRemoved value: -"Mode" - removed
Input schema / titleRemoved value: -"set_domain_caseArguments"
- Changed
task15 fields changed- added
Input schema / properties / also / descriptionAdded value: +"other domain paths this belongs to, comma-separated: the subjects that cut across the tree `domain` sits in, such as the end-to-end flow a routine is one step of. Every read scoped to one of them returns it. A path `domain` already sits under is dropped as redundant. At most 200 characters each." - removed
Input schema / properties / also / titleRemoved value: -"Also" - added
Input schema / properties / domain / descriptionAdded value: +"the subject this belongs to, as a path from the outermost scope in ('acme/x100/p200'). File it as deep as the fact is specific -- a note about one routine goes on the routine, and still comes back when someone asks about the module or the product above it. At most 200 characters." - removed
Input schema / properties / domain / titleRemoved value: -"Domain" - added
Input schema / properties / goal / descriptionAdded value: +"the brief an agent with none of this session's context works from: what the work is and why, where it lives, the decisions and constraints that bind it, and what done looks like. Short, but complete enough to act on -- a few compact paragraphs, at most 2000 characters. Plain prose: a task is not a sectioned type, so no `INTENT:` / `GOAL:` / `WHY:` labels -- those are how checkpoint, anti_pattern and reasoning bodies are read back. edit_memory(goal=...) rewrites it when the scope changes." - removed
Input schema / properties / goal / titleRemoved value: -"Goal" - added
Input schema / properties / items / descriptionAdded value: +"one checklist item per line, blank lines ignored, at most 50. Each is a short label, verb first, at most 80 characters: lists and every DEPENDS ON that names it show it whole, so its detail goes in the item's brief (task_note). Each gets an id for task_item(); the result lists them in order, each as {id, n}." - removed
Input schema / properties / items / titleRemoved value: -"Items" - added
Input schema / properties / session / descriptionAdded value: +"groups what one conversation writes. Leave it empty to use this server process's own stamp." - removed
Input schema / properties / session / titleRemoved value: -"Session" - added
Input schema / properties / tags / descriptionAdded value: +"comma-separated synonyms the goal and items never use; retrieval is BM25 over content and tags. The type name is not added for you: a word every task carries ranks no task above another." - removed
Input schema / properties / tags / titleRemoved value: -"Tags" - added
Input schema / properties / title / descriptionAdded value: +"what the task delivers, in a few words someone would look for it by. At most 120 characters." - removed
Input schema / properties / title / titleRemoved value: -"Title" - removed
Input schema / titleRemoved value: -"taskArguments"
- Changed
task_add5 fields changed- added
Input schema / properties / items / descriptionAdded value: +"one item per line, blank lines ignored, each a short label as task() takes them." - removed
Input schema / properties / items / titleRemoved value: -"Items" - added
Input schema / properties / uid / descriptionAdded value: +"the task." - removed
Input schema / properties / uid / titleRemoved value: -"Uid" - removed
Input schema / titleRemoved value: -"task_addArguments"
- Changed
task_comment9 fields changed- added
Input schema / properties / body / descriptionAdded value: +"the comment." - removed
Input schema / properties / body / titleRemoved value: -"Body" - changed
Input schema / properties / item / defaultPrevious value: -""New value: +0 - added
Input schema / properties / item / descriptionAdded value: +"the item's id; 0, the default, comments on the task itself." - removed
Input schema / properties / item / titleRemoved value: -"Item" - changed
Input schema / properties / item / typePrevious value: -"string"New value: +"integer" - added
Input schema / properties / uid / descriptionAdded value: +"the task." - removed
Input schema / properties / uid / titleRemoved value: -"Uid" - removed
Input schema / titleRemoved value: -"task_commentArguments"
- Changed
task_item14 fields changed- added
Input schema / properties / comment / descriptionAdded value: +"a remark on this item -- what blocked it, what was decided." - removed
Input schema / properties / comment / titleRemoved value: -"Comment" - added
Input schema / properties / deleteAdded value: +{ + "default": false, + "description": "removes the item with its comments, links and note attachments, alone in its call. No other item moves; a DEPENDS ON that named it keeps its text, marked deleted, and a brief on only that item stays, on the whole task. Delete a mistake or a duplicate; mark work decided against as dropped, which keeps it.", + "type": "boolean" +} - added
Input schema / properties / item / descriptionAdded value: +"the item's id, as task_read(part='items') lists it." - removed
Input schema / properties / item / titleRemoved value: -"Item" - changed
Input schema / properties / item / typePrevious value: -"string"New value: +"integer" - added
Input schema / properties / related / descriptionAdded value: +"comma-separated uids of memories this item produced or depends on. An unknown uid refuses the whole call, and nothing is written." - removed
Input schema / properties / related / titleRemoved value: -"Related" - added
Input schema / properties / state / descriptionAdded value: +"todo, doing, done or dropped. The write that closes the last open item archives the task (`archived` in the result); one that reopens an item reopens the task." - removed
Input schema / properties / state / titleRemoved value: -"State" - added
Input schema / properties / textAdded value: +{ + "default": "", + "description": "the item's new text, a short label as task() takes it. The item keeps its id, state, brief, comments and links; the previous text stays in the edit history.", + "type": "string" +} - added
Input schema / properties / uid / descriptionAdded value: +"the task." - removed
Input schema / properties / uid / titleRemoved value: -"Uid" - removed
Input schema / titleRemoved value: -"task_itemArguments"
- Added
task_note - Added
task_read - Changed
timeline13 fields changed- added
Input schema / properties / after / descriptionAdded value: +"how many records created immediately after it." - removed
Input schema / properties / after / titleRemoved value: -"After" - added
Input schema / properties / before / descriptionAdded value: +"how many records created immediately before the anchor." - removed
Input schema / properties / before / titleRemoved value: -"Before" - added
Input schema / properties / domain / descriptionAdded value: +"covers a path and everything under it, plus what is cross-listed into it, and resolves a bare deep segment the way the other scoped reads do." - removed
Input schema / properties / domain / titleRemoved value: -"Domain" - added
Input schema / properties / query / descriptionAdded value: +"searches for the anchor and takes the top hit (the same search search() runs, scoped by domain/type)." - removed
Input schema / properties / query / titleRemoved value: -"Query" - added
Input schema / properties / type / descriptionAdded value: +"one memory type, as search() takes it; empty is every type." - removed
Input schema / properties / type / titleRemoved value: -"Type" - added
Input schema / properties / uid / descriptionAdded value: +"the anchor, named outright." - removed
Input schema / properties / uid / titleRemoved value: -"Uid" - removed
Input schema / titleRemoved value: -"timelineArguments"
- Changed
unfile_domain5 fields changed- added
Input schema / properties / domain / descriptionAdded value: +"the cross-listed path to drop, matched exactly: dropping 'acme' leaves a separate membership in 'acme/x100' alone, because that is a different scope." - removed
Input schema / properties / domain / titleRemoved value: -"Domain" - added
Input schema / properties / uid / descriptionAdded value: +"the memory." - removed
Input schema / properties / uid / titleRemoved value: -"Uid" - removed
Input schema / titleRemoved value: -"unfile_domainArguments"
7 tool updates
v0.6.0- Removed
handoff - Changed
list_by_domain1 field changed- added
Input schema / properties / statusAdded value: +{ + "default": "active", + "title": "Status", + "type": "string" +}
- Added
pending - Added
task - Added
task_add - Added
task_comment - Added
task_item
24 tool updates
v0.1.1- Added
also_domain - Changed
anti_pattern6 fields changed- added
Input schema / properties / alsoAdded value: +{ + "default": "", + "title": "Also", + "type": "string" +} - added
Input schema / properties / review_afterAdded value: +{ + "default": "", + "title": "Review After", + "type": "string" +} - added
Input schema / properties / source_refAdded value: +{ + "default": "", + "title": "Source Ref", + "type": "string" +} - added
Input schema / properties / tagsAdded value: +{ + "default": "", + "title": "Tags", + "type": "string" +} - added
Input schema / properties / titleAdded value: +{ + "title": "Title", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "pattern", - "why_wrong", - "instead" -]New value: +[ + "title", + "pattern", + "why_wrong", + "instead" +]
- Changed
checkpoint4 fields changed- added
Input schema / properties / alsoAdded value: +{ + "default": "", + "title": "Also", + "type": "string" +} - added
Input schema / properties / tagsAdded value: +{ + "default": "", + "title": "Tags", + "type": "string" +} - added
Input schema / properties / titleAdded value: +{ + "title": "Title", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "intent", - "established", - "pursuing", - "open_questions" -]New value: +[ + "title", + "intent", + "established", + "pursuing", + "open_questions" +]
- Added
diagram - Added
diagram_edge - Added
diagram_jump - Added
diagram_link - Added
diagram_node - Added
diagram_relayout - Changed
edit_memory6 fields changed- added
Input schema / properties / modeAdded value: +{ + "default": "replace", + "title": "Mode", + "type": "string" +} - added
Input schema / properties / new_content / defaultAdded value: +"" - added
Input schema / properties / source_refAdded value: +{ + "default": "", + "title": "Source Ref", + "type": "string" +} - added
Input schema / properties / tagsAdded value: +{ + "default": "", + "title": "Tags", + "type": "string" +} - added
Input schema / properties / titleAdded value: +{ + "default": "", + "title": "Title", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "uid", - "new_content" -]New value: +[ + "uid" +]
- Added
get_diagram - Added
get_domain_case - Changed
handoff4 fields changed- added
Input schema / properties / alsoAdded value: +{ + "default": "", + "title": "Also", + "type": "string" +} - added
Input schema / properties / tagsAdded value: +{ + "default": "", + "title": "Tags", + "type": "string" +} - added
Input schema / properties / titleAdded value: +{ + "title": "Title", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "content" -]New value: +[ + "title", + "content" +]
- Changed
list_by_domain2 fields changed- added
Input schema / properties / subtreeAdded value: +{ + "default": true, + "title": "Subtree", + "type": "boolean" +} - changed
Output schema / (root)Previous value: -{ - "properties": { - "result": { - "items": { - "additionalProperties": true, - "type": "object" - }, - "title": "Result", - "type": "array" - } - }, - "required": [ - "result" - ], - "title": "list_by_domainOutput", - "type": "object" -}New value: +null
- Added
list_projects - Changed
list_recent2 fields changed- added
Input schema / properties / subtreeAdded value: +{ + "default": true, + "title": "Subtree", + "type": "boolean" +} - changed
Output schema / (root)Previous value: -{ - "properties": { - "result": { - "items": { - "additionalProperties": true, - "type": "object" - }, - "title": "Result", - "type": "array" - } - }, - "required": [ - "result" - ], - "title": "list_recentOutput", - "type": "object" -}New value: +null
- Added
move_to_project - Changed
note5 fields changed- added
Input schema / properties / alsoAdded value: +{ + "default": "", + "title": "Also", + "type": "string" +} - added
Input schema / properties / review_afterAdded value: +{ + "default": "", + "title": "Review After", + "type": "string" +} - added
Input schema / properties / source_refAdded value: +{ + "default": "", + "title": "Source Ref", + "type": "string" +} - added
Input schema / properties / titleAdded value: +{ + "title": "Title", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "content" -]New value: +[ + "title", + "content" +]
- Changed
reasoning12 fields changed- added
Input schema / properties / alsoAdded value: +{ + "default": "", + "title": "Also", + "type": "string" +} - removed
Input schema / properties / contentRemoved value: -{ - "title": "Content", - "type": "string" -} - added
Input schema / properties / hypothesisAdded value: +{ + "title": "Hypothesis", + "type": "string" +} - added
Input schema / properties / next_timeAdded value: +{ + "title": "Next Time", + "type": "string" +} - added
Input schema / properties / reasoningAdded value: +{ + "title": "Reasoning", + "type": "string" +} - added
Input schema / properties / resultAdded value: +{ + "title": "Result", + "type": "string" +} - added
Input schema / properties / review_afterAdded value: +{ + "default": "", + "title": "Review After", + "type": "string" +} - added
Input schema / properties / revised_beliefAdded value: +{ + "title": "Revised Belief", + "type": "string" +} - added
Input schema / properties / source_refAdded value: +{ + "default": "", + "title": "Source Ref", + "type": "string" +} - added
Input schema / properties / tagsAdded value: +{ + "default": "", + "title": "Tags", + "type": "string" +} - added
Input schema / properties / titleAdded value: +{ + "title": "Title", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "content" -]New value: +[ + "title", + "hypothesis", + "reasoning", + "result", + "revised_belief", + "next_time" +]
- Changed
recall2 fields changed- changed
Input schema / properties / limit / defaultPrevious value: -20New value: +10 - changed
Output schema / (root)Previous value: -{ - "properties": { - "result": { - "items": { - "additionalProperties": true, - "type": "object" - }, - "title": "Result", - "type": "array" - } - }, - "required": [ - "result" - ], - "title": "recallOutput", - "type": "object" -}New value: +null
- Changed
search2 fields changed- changed
Input schema / properties / limit / defaultPrevious value: -30New value: +10 - changed
Output schema / (root)Previous value: -{ - "properties": { - "result": { - "items": { - "additionalProperties": true, - "type": "object" - }, - "title": "Result", - "type": "array" - } - }, - "required": [ - "result" - ], - "title": "searchOutput", - "type": "object" -}New value: +null
- Added
set_domain_case - Added
timeline - Added
unfile_domain
24 tool updates
v0.1.0- First observed
anti_pattern - First observed
checkpoint - First observed
dedup_scan - First observed
edit_memory - First observed
forget - First observed
get_memory - First observed
get_relations - First observed
handoff - First observed
help - First observed
link_memories - First observed
list_by_domain - First observed
list_domains - First observed
list_recent - First observed
note - First observed
optimize_runs - First observed
optimize_scan - First observed
optimize_stage - First observed
optimize_status - First observed
pulse - First observed
purge_memory - First observed
reasoning - First observed
recall - First observed
search - First observed
set_confidence
TDQS
Scored across 43 tools
The core write verbs (note, checkpoint, anti_pattern, reasoning) and the task_/diagram_ families are well separated, but the read surface overlaps heavily: recall is explicitly 'sugar for search(type="note")', and list_recent, list_by_domain, must_read, and pulse all return 'most recent memories' with only subtle scope differences. dedup_scan and optimize_scan also cross into the same 'find suspect memories' territory. Descriptions do a lot of work to disambiguate, but an agent still faces real misselection risk.
Within domains the prefixes are consistent (task_add/task_read/task_note, diagram_node/diagram_edge), but across the server conventions clash: bare nouns (note, checkpoint, task, diagram), bare verbs (search, forget, pulse), verb_noun (get_memory, list_domains), and noun_verb (task_add, diagram_link) all coexist. Generally readable, but not a single predictable pattern.
43 tools is a very heavy surface for a memory store and pushes well past the 'too many' threshold. Several clusters could be collapsed (four optimize_* tools, four separate diagram-edge/link/jump verbs, near-duplicate read tools), so the count feels inflated relative to what an agent can reliably choose among.
Coverage is genuinely thorough: create/read/update/delete across multiple memory types, soft vs hard delete, relations, edit history/versioning, confidence, domain and project management, plus a full curation workflow. Almost no obvious lifecycle gap remains for a memory-management domain.
Maintenance
Related MCP Connectors
An MCP memory server. One memory your agents share — across models, devices and apps.
- memnodeOAuthdev.memnode
Persistent, inspectable memory for AI agents with lineage, correction, and a hosted MCP endpoint.
Persistent memory, knowledge graph, task management and more for AI agents via MCP.
Cloud-hosted MCP server for durable AI memory
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceAn MCP server that provides persistent long-term memory for AI agents via local SQLite storage with low token overhead, enabling memory storage, retrieval, and management across sessions.1MIT
- AlicenseNot gradedqualityAmaintenanceA local memory server for AI agents that stores and retrieves information via MCP, keeping all data in SQLite on your machine.140 PyPI1Apache 2.0
- AlicenseAqualityCmaintenancePersistent memory MCP server for AI agents, using SQLite with hybrid keyword and semantic search for long-term memory storage.5Do What The F*ck You Want To Public
- AlicenseAqualityBmaintenanceMCP server for persistent, cross-session, local-first memory for AI agents, storing memories as Markdown files with SQLite indexing for hybrid search.24Apache 2.0