Skip to main content
Glama

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. A task is a goal and a checklist: items move through todo, doing, done and dropped, 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/billing still answers a read of acme, and also cross-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 full

A 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 checks

Register 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 date

See Hooks and the warden for what each event emits and how to turn the warden off.

NOTE

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 in a terminal

~/.claude.json, top-level mcpServers

claude mcp add --scope user memai <command>

Claude desktop app — Chat and the Code tab

Windows: %APPDATA%\Claude\claude_desktop_config.jsonmacOS: ~/Library/Application Support/Claude/claude_desktop_config.json

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.

IMPORTANT

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

memai.db

the General project, the one every install starts with

projects/<name>.db

every other project, one file each, named as you named it

active

one line naming the project in use; absent means General

backups/

VACUUM INTO copies of General, named General-<stamp>.db; any other project's go in backups/<name>/

renders/, warden/

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:

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 tools
also_domainA
Idempotent

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidYesthe memory.
domainYesthe path to cross-list it into.

TDQS

A4.6/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
alsoNoother 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.
tagsNocomma-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.
titleYesone 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.
domainNothe 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.
insteadYeswhat to do, concrete enough to act on.
patternYesthe temptation, as the next agent will meet it: the move that looks right at the time. At most 800 characters.
sessionNogroups what one conversation writes. Leave it empty to use this server process's own stamp.
why_wrongYesthe mechanism that makes it fail, specific enough to recognise the next time.
source_refNowhat 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_afterNowhen 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

A4.5/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
alsoNoother 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.
tagsNocomma-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.
titleYesone 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.
domainNothe 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.
intentYeswhat the work is for, in a sentence or two.
sessionNogroups what one conversation writes. Leave it empty to use this server process's own stamp.
pursuingYeswhat comes next, specific enough to start on.
supersedesNothe 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.
establishedYeswhat is done and what was decided, with the [[uid]] of each note that holds the detail.
open_questionsYeswhat is still undecided or unverified.

TDQS

A4.4/5.0
Behavior3/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_scanA
Read-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).

ParametersJSON Schema
NameRequiredDescriptionDefault
typeNoone memory type, as search() takes it; empty is every type.
limitNothe most pairs to return.
domainNoscans a path and everything nested under it, which is usually what you want: near-duplicates collect between a module and its own routines.
offsetNowhere the page starts; `next_offset`, when present, starts the next.
thresholdNothe similarity, 0 to 1, a pair must reach to be listed.

TDQS

A4.1/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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().

ParametersJSON Schema
NameRequiredDescriptionDefault
alsoNoother 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.
kindNo'flowchart', the only kind.flowchart
tagsNocomma-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.
edgesYesthe wires between steps, as [{"from": "load", "to": "check", "label": "optional branch"}].
nodesYesthe 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.
titleYesone 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.
domainNothe 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.
sessionNogroups what one conversation writes. Leave it empty to use this server process's own stamp.
summaryNoa few sentences on what the routine is for, indexed with the flow.
source_refNowhat 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_afterNowhen 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

A4.5/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_edgeA
DestructiveIdempotent

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidYesthe diagram.
labelNothe condition on a branch out of a decision node ('yes', 'no', 'on timeout').
deleteNoremoves the edge between from_key and to_key.
to_keyYesthe step it reaches.
from_keyYesthe step the edge leaves.

TDQS

A3.5/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines2/5

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_jumpA
DestructiveIdempotent

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidYesthis diagram; on a delete, either end's diagram.
labelNowhat the hand-off is, shown on the jump.
deleteNoremoves the jump.
node_keyYesthis diagram's step the branch leaves from; on a delete from the receiving end, that end's step.
peer_uidYesthe diagram the branch continues in.
peer_nodeNothe step it arrives at there; empty arrives at the diagram as a whole.

TDQS

A4.3/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_nodeA
DestructiveIdempotent

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
keyYesthe step's id; a new key adds a step.
uidYesthe diagram.
noteNothe step's explanation: reasoning, caveats, history.
labelNowhat happens at the step, objectively.
shapeNostart|step|decision|io|end.
deleteNoremoves the step together with its edges and its memory links.

TDQS

A4/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines4/5

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_relayoutA
DestructiveIdempotent

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidYesthe diagram.

TDQS

A4.1/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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_memoryA
Destructive

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().

ParametersJSON Schema
NameRequiredDescriptionDefault
uidYesthe memory.
goalNoa task's new goal, held to the rules task() states; the previous goal stays in the edit history. Refused on any other type.
modeNo'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
noteNowhy it changed, kept with the previous version in the edit history.
tagsNoREPLACES 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.
titleNorenames 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_refNopoints 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_contentNothe corrected body, or with mode='append' the line to add.

TDQS

A4.8/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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.

forgetA
Idempotent

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidYesthe memory.
reasonNowhy it is archived, recorded as a status-change audit entry without touching the content.
superseded_byNothe 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

A4.6/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_diagramA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidYesthe diagram.
formatNoone of the formats above.mermaid
offsetNowhere a long `body`, or the SVG step index, starts; `next_offset`, when present, starts the next page.

TDQS

A4.5/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines5/5

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_caseA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.4/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines4/5

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_memoryA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidYesthe memory.
edits_offsetNofrom -1 to a page start, reads the edit history instead of the record, bodies cut to 4000 characters.
content_offsetNofrom -1 to a character offset, reads that stretch of the body instead of the record.

TDQS

A4.3/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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_relationsA
Read-onlyIdempotent

List a memory's links, one page at a time; follow next_offset.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidYesthe memory.
partNo'relations' (edges, both ways) or 'diagrams' (flows pointing at it).relations
offsetNowhere the page starts; `next_offset`, when present, starts the next.

TDQS

A3.6/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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.

list_by_domainA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
typeNoone memory type, as search() takes it; empty is every type.
limitNothe most results to return.
domainYesa 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.
offsetNowhere the page starts; `next_offset`, when present, starts the next.
statusNo'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
subtreeNoFalse lists what is filed at exactly that path and nowhere deeper.

TDQS

A4.4/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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_domainsA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
offsetNowhere the page starts; `next_offset`, when present, starts the next.

TDQS

A4.6/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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_projectsA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
offsetNowhere the page starts; `next_offset`, when present, starts the next.

TDQS

A3.6/5.0
Behavior4/5

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.

Conciseness3/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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_recentA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
typeNoone memory type, as search() takes it; empty is every type.
limitNothe most results to return.
domainNocovers its subdomains, and a bare deep segment resolves to the branches holding it (see list_by_domain).
offsetNowhere the page starts; `next_offset`, when present, starts the next.
subtreeNoFalse narrows to the exact domain path.

TDQS

A3.7/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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_projectA
Destructive

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidsNocomma-separated memories to move; give uids, domain or both.
createNomakes a `target` that does not exist yet.
domainNoa path to move, its subdomains and archived rows included.
targetYesthe project to move into; list_projects() names the projects there are.
dry_runNothe 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

A4.3/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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_readA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
typeNotask, anti_pattern, handoff, note or diagram; any other type is an error. Empty returns the counts.
limitNoheaders per page, 1 to 50.
domainNocovers 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.
offsetNowhere the page of headers starts.
pinnedNotrue narrows the page to the pins of that type, and also accepts checkpoint and reasoning.

TDQS

A4/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
alsoNoother 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.
tagsNocomma-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.
titleYesone 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.
domainNothe 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.
contentYesONE 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.
sessionNogroups what one conversation writes. Leave it empty to use this server process's own stamp.
source_refNowhat 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_afterNowhen 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

A3.6/5.0
Behavior3/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines4/5

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_runsA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
offsetNowhere the page starts; `next_offset`, when present, starts the next.

TDQS

A4.5/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_scanA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
fullNotrue keeps whole bodies instead of the slim listing.
typeNoone memory type, as search() takes it; empty is every type.
limitNothe most memories per page.
sinceNolimits the scan to what changed after this date, for recurring passes.
domainNoscans a path and everything nested under it; empty is the whole project.
offsetNowhere the page starts; after a `truncated` page, offset + count.
include_archivedNotrue lists archived memories as well.

TDQS

A4.6/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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}.

ParametersJSON Schema
NameRequiredDescriptionDefault
noteNoone 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.
suggestionsYeseach 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

A4.4/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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_statusA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
offsetNowhere the page starts; `next_offset`, when present, starts the next.
run_idYesthe run optimize_stage returned, or one optimize_runs lists.

TDQS

A4.1/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

pulseA
Read-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).

ParametersJSON Schema
NameRequiredDescriptionDefault
domainNowarms 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.
offsetNowhere the page of `scope.subdomains` starts.

TDQS

A4.6/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_memoryA
DestructiveIdempotent

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidYesthe memory.
confirm_phraseYesmust 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

A4.5/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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().

ParametersJSON Schema
NameRequiredDescriptionDefault
alsoNoother 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.
tagsNocomma-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.
titleYesone 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.
domainNothe 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.
resultYeswhat came back. The measurement, not the interpretation.
sessionNogroups what one conversation writes. Leave it empty to use this server process's own stamp.
next_timeYeswhat someone hitting this again should do differently.
reasoningYeshow you tested it -- what you read, ran or compared.
hypothesisYeswhat you believed going in, as a claim that could be wrong.
source_refNowhat 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_afterNowhen 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_beliefYeswhat you believe now, and where it differs from the hypothesis. Say plainly when the hypothesis survived unchanged.

TDQS

A4.2/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

recallA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNothe most results to return.
queryYesthe words to look for; as in search(), more terms find more.
domainNoscopes to a path and everything nested under it, and resolves a bare deep segment the same way search() does.
offsetNowhere the page starts; `next_offset`, when present, starts the next.

TDQS

A4.6/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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.

set_confidenceA
Idempotent

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidYesthe memory.
confidenceYesunverified, confirmed or contradicted.

TDQS

A4.4/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_caseA
Idempotent

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": ...}.

ParametersJSON Schema
NameRequiredDescriptionDefault
modeYes'preserve' keeps free-text casing; 'lower' or 'upper' coerces every domain written to that case.

TDQS

A4.2/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines5/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
alsoNoother 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.
goalYesthe 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.
tagsNocomma-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.
itemsYesone 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}.
titleYeswhat the task delivers, in a few words someone would look for it by. At most 120 characters.
domainNothe 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.
sessionNogroups what one conversation writes. Leave it empty to use this server process's own stamp.

TDQS

A4.3/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidYesthe task.
itemsYesone item per line, blank lines ignored, each a short label as task() takes them.

TDQS

A4.5/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidYesthe task.
bodyYesthe comment.
itemNothe item's id; 0, the default, comments on the task itself.

TDQS

A4.5/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_itemA
Destructive

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidYesthe task.
itemYesthe item's id, as task_read(part='items') lists it.
textNothe 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.
stateNotodo, 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.
deleteNoremoves 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.
commentNoa remark on this item -- what blocked it, what was decided.
relatedNocomma-separated uids of memories this item produced or depends on. An unknown uid refuses the whole call, and nothing is written.

TDQS

A3.8/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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_noteB
Destructive

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidYesthe task.
bodyNoa note on the whole task, up to 4000 characters; it errors beside a brief field.
goalNowhat the item must achieve.
itemsNothe ids of the items the note is on, such as "4812,4815"; empty or "-" is the whole task.
stepsNohow to do it, in order.
titleNoup to 120 characters.
deleteNowith note_id, removes that note.
contextNowhat the work needs to know: where it lives, what binds it.
note_idNo0 creates a note; another id edits that note, where an empty field keeps its text and a field given replaces only its own.
pitfallsNowhat goes wrong, and how to avoid it.
done_whenNohow to tell the item is finished.
depends_onNonone, 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_infoNoanything else worth knowing; optional.

TDQS

B3.2/5.0
Behavior3/5

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.

Conciseness3/5

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.

Completeness3/5

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.

Parameters4/5

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.

Purpose3/5

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.

Usage Guidelines3/5

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_readA
Read-onlyIdempotent

Read one collection of a task, one page at a time.

Follow next_offset until it is absent.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidYesthe task.
itemNothe item's id, for its notes, comments or links (the page adds its `n`); 0, the default, is the task's own.
partYes`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`).
offsetNowhere the page starts; `next_offset`, when present, starts the next.

TDQS

A3.5/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness3/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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.

timelineA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidNothe anchor, named outright.
typeNoone memory type, as search() takes it; empty is every type.
afterNohow many records created immediately after it.
queryNosearches for the anchor and takes the top hit (the same search search() runs, scoped by domain/type).
beforeNohow many records created immediately before the anchor.
domainNocovers 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

A4.8/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_domainA
DestructiveIdempotent

Drop one of a memory's cross-listings. Does not touch where it is filed.

Returns {"uid": ..., "also": [...]} with what remains.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidYesthe memory.
domainYesthe cross-listed path to drop, matched exactly: dropping 'acme' leaves a separate membership in 'acme/x100' alone, because that is a different scope.

TDQS

A3.8/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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.

  1. 45 tool updatesv0.16.1
    • Changedalso_domain5 fields changed
      • addedInput schema / properties / domain / description
        Added value: +"the path to cross-list it into."
      • removedInput schema / properties / domain / title
        Removed value: -"Domain"
      • addedInput schema / properties / uid / description
        Added value: +"the memory."
      • removedInput schema / properties / uid / title
        Removed value: -"Uid"
      • removedInput schema / title
        Removed value: -"also_domainArguments"
    • Changedanti_pattern21 fields changed
      • addedInput schema / properties / also / description
        Added 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."
      • removedInput schema / properties / also / title
        Removed value: -"Also"
      • addedInput schema / properties / domain / description
        Added 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."
      • removedInput schema / properties / domain / title
        Removed value: -"Domain"
      • addedInput schema / properties / instead / description
        Added value: +"what to do, concrete enough to act on."
      • removedInput schema / properties / instead / title
        Removed value: -"Instead"
      • addedInput schema / properties / pattern / description
        Added value: +"the temptation, as the next agent will meet it: the move that looks right at the time. At most 800 characters."
      • removedInput schema / properties / pattern / title
        Removed value: -"Pattern"
      • addedInput schema / properties / review_after / description
        Added 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."
      • removedInput schema / properties / review_after / title
        Removed value: -"Review After"
      • addedInput schema / properties / session / description
        Added value: +"groups what one conversation writes. Leave it empty to use this server process's own stamp."
      • removedInput schema / properties / session / title
        Removed value: -"Session"
      • addedInput schema / properties / source_ref / description
        Added 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."
      • removedInput schema / properties / source_ref / title
        Removed value: -"Source Ref"
      • addedInput schema / properties / tags / description
        Added 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."
      • removedInput schema / properties / tags / title
        Removed value: -"Tags"
      • addedInput schema / properties / title / description
        Added 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."
      • removedInput schema / properties / title / title
        Removed value: -"Title"
      • addedInput schema / properties / why_wrong / description
        Added value: +"the mechanism that makes it fail, specific enough to recognise the next time."
      • removedInput schema / properties / why_wrong / title
        Removed value: -"Why Wrong"
      • removedInput schema / title
        Removed value: -"anti_patternArguments"
    • Changedcheckpoint20 fields changed
      • addedInput schema / properties / also / description
        Added 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."
      • removedInput schema / properties / also / title
        Removed value: -"Also"
      • addedInput schema / properties / domain / description
        Added 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."
      • removedInput schema / properties / domain / title
        Removed value: -"Domain"
      • addedInput schema / properties / established / description
        Added value: +"what is done and what was decided, with the [[uid]] of each note that holds the detail."
      • removedInput schema / properties / established / title
        Removed value: -"Established"
      • addedInput schema / properties / intent / description
        Added value: +"what the work is for, in a sentence or two."
      • removedInput schema / properties / intent / title
        Removed value: -"Intent"
      • addedInput schema / properties / open_questions / description
        Added value: +"what is still undecided or unverified."
      • removedInput schema / properties / open_questions / title
        Removed value: -"Open Questions"
      • addedInput schema / properties / pursuing / description
        Added value: +"what comes next, specific enough to start on."
      • removedInput schema / properties / pursuing / title
        Removed value: -"Pursuing"
      • addedInput schema / properties / session / description
        Added value: +"groups what one conversation writes. Leave it empty to use this server process's own stamp."
      • removedInput schema / properties / session / title
        Removed value: -"Session"
      • addedInput schema / properties / supersedes
        Added 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"
        +}
      • addedInput schema / properties / tags / description
        Added 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."
      • removedInput schema / properties / tags / title
        Removed value: -"Tags"
      • addedInput schema / properties / title / description
        Added 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."
      • removedInput schema / properties / title / title
        Removed value: -"Title"
      • removedInput schema / title
        Removed value: -"checkpointArguments"
    • Changeddedup_scan11 fields changed
      • addedInput schema / properties / domain / description
        Added 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."
      • removedInput schema / properties / domain / title
        Removed value: -"Domain"
      • addedInput schema / properties / limit / description
        Added value: +"the most pairs to return."
      • removedInput schema / properties / limit / title
        Removed value: -"Limit"
      • addedInput schema / properties / offset
        Added value: +{
        +  "default": 0,
        +  "description": "where the page starts; `next_offset`, when present, starts the next.",
        +  "type": "integer"
        +}
      • addedInput schema / properties / threshold / description
        Added value: +"the similarity, 0 to 1, a pair must reach to be listed."
      • removedInput schema / properties / threshold / title
        Removed value: -"Threshold"
      • addedInput schema / properties / type / description
        Added value: +"one memory type, as search() takes it; empty is every type."
      • removedInput schema / properties / type / title
        Removed value: -"Type"
      • removedInput schema / title
        Removed value: -"dedup_scanArguments"
      • changedOutput 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
    • Changeddiagram23 fields changed
      • addedInput schema / properties / also / description
        Added 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."
      • removedInput schema / properties / also / title
        Removed value: -"Also"
      • addedInput schema / properties / domain / description
        Added 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."
      • removedInput schema / properties / domain / title
        Removed value: -"Domain"
      • addedInput schema / properties / edges / description
        Added value: +"the wires between steps, as [{\"from\": \"load\", \"to\": \"check\", \"label\": \"optional branch\"}]."
      • removedInput schema / properties / edges / title
        Removed value: -"Edges"
      • addedInput schema / properties / kind / description
        Added value: +"'flowchart', the only kind."
      • removedInput schema / properties / kind / title
        Removed value: -"Kind"
      • addedInput schema / properties / nodes / description
        Added 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."
      • removedInput schema / properties / nodes / title
        Removed value: -"Nodes"
      • addedInput schema / properties / review_after / description
        Added 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."
      • removedInput schema / properties / review_after / title
        Removed value: -"Review After"
      • addedInput schema / properties / session / description
        Added value: +"groups what one conversation writes. Leave it empty to use this server process's own stamp."
      • removedInput schema / properties / session / title
        Removed value: -"Session"
      • addedInput schema / properties / source_ref / description
        Added 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."
      • removedInput schema / properties / source_ref / title
        Removed value: -"Source Ref"
      • addedInput schema / properties / summary / description
        Added value: +"a few sentences on what the routine is for, indexed with the flow."
      • removedInput schema / properties / summary / title
        Removed value: -"Summary"
      • addedInput schema / properties / tags / description
        Added 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."
      • removedInput schema / properties / tags / title
        Removed value: -"Tags"
      • addedInput schema / properties / title / description
        Added 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."
      • removedInput schema / properties / title / title
        Removed value: -"Title"
      • removedInput schema / title
        Removed value: -"diagramArguments"
    • Changeddiagram_edge11 fields changed
      • addedInput schema / properties / delete / description
        Added value: +"removes the edge between from_key and to_key."
      • removedInput schema / properties / delete / title
        Removed value: -"Delete"
      • addedInput schema / properties / from_key / description
        Added value: +"the step the edge leaves."
      • removedInput schema / properties / from_key / title
        Removed value: -"From Key"
      • addedInput schema / properties / label / description
        Added value: +"the condition on a branch out of a decision node ('yes', 'no', 'on timeout')."
      • removedInput schema / properties / label / title
        Removed value: -"Label"
      • addedInput schema / properties / to_key / description
        Added value: +"the step it reaches."
      • removedInput schema / properties / to_key / title
        Removed value: -"To Key"
      • addedInput schema / properties / uid / description
        Added value: +"the diagram."
      • removedInput schema / properties / uid / title
        Removed value: -"Uid"
      • removedInput schema / title
        Removed value: -"diagram_edgeArguments"
    • Changeddiagram_jump13 fields changed
      • addedInput schema / properties / delete / description
        Added value: +"removes the jump."
      • removedInput schema / properties / delete / title
        Removed value: -"Delete"
      • addedInput schema / properties / label / description
        Added value: +"what the hand-off is, shown on the jump."
      • removedInput schema / properties / label / title
        Removed value: -"Label"
      • addedInput schema / properties / node_key / description
        Added value: +"this diagram's step the branch leaves from; on a delete from the receiving end, that end's step."
      • removedInput schema / properties / node_key / title
        Removed value: -"Node Key"
      • addedInput schema / properties / peer_node / description
        Added value: +"the step it arrives at there; empty arrives at the diagram as a whole."
      • removedInput schema / properties / peer_node / title
        Removed value: -"Peer Node"
      • addedInput schema / properties / peer_uid / description
        Added value: +"the diagram the branch continues in."
      • removedInput schema / properties / peer_uid / title
        Removed value: -"Peer Uid"
      • addedInput schema / properties / uid / description
        Added value: +"this diagram; on a delete, either end's diagram."
      • removedInput schema / properties / uid / title
        Removed value: -"Uid"
      • removedInput schema / title
        Removed value: -"diagram_jumpArguments"
    • Changeddiagram_link11 fields changed
      • addedInput schema / properties / delete / description
        Added value: +"removes the link between node_key and target_uid."
      • removedInput schema / properties / delete / title
        Removed value: -"Delete"
      • addedInput schema / properties / node_key / description
        Added value: +"the step the memory explains."
      • removedInput schema / properties / node_key / title
        Removed value: -"Node Key"
      • addedInput schema / properties / relation_type / description
        Added value: +"how the memory relates to the step; 'explains' unless given. Linking the same step and memory again replaces it."
      • removedInput schema / properties / relation_type / title
        Removed value: -"Relation Type"
      • addedInput schema / properties / target_uid / description
        Added value: +"the memory to attach."
      • removedInput schema / properties / target_uid / title
        Removed value: -"Target Uid"
      • addedInput schema / properties / uid / description
        Added value: +"the diagram."
      • removedInput schema / properties / uid / title
        Removed value: -"Uid"
      • removedInput schema / title
        Removed value: -"diagram_linkArguments"
    • Changeddiagram_node13 fields changed
      • addedInput schema / properties / delete / description
        Added value: +"removes the step together with its edges and its memory links."
      • removedInput schema / properties / delete / title
        Removed value: -"Delete"
      • addedInput schema / properties / key / description
        Added value: +"the step's id; a new key adds a step."
      • removedInput schema / properties / key / title
        Removed value: -"Key"
      • addedInput schema / properties / label / description
        Added value: +"what happens at the step, objectively."
      • removedInput schema / properties / label / title
        Removed value: -"Label"
      • addedInput schema / properties / note / description
        Added value: +"the step's explanation: reasoning, caveats, history."
      • removedInput schema / properties / note / title
        Removed value: -"Note"
      • addedInput schema / properties / shape / description
        Added value: +"start|step|decision|io|end."
      • removedInput schema / properties / shape / title
        Removed value: -"Shape"
      • addedInput schema / properties / uid / description
        Added value: +"the diagram."
      • removedInput schema / properties / uid / title
        Removed value: -"Uid"
      • removedInput schema / title
        Removed value: -"diagram_nodeArguments"
    • Changeddiagram_relayout3 fields changed
      • addedInput schema / properties / uid / description
        Added value: +"the diagram."
      • removedInput schema / properties / uid / title
        Removed value: -"Uid"
      • removedInput schema / title
        Removed value: -"diagram_relayoutArguments"
    • Changededit_memory16 fields changed
      • addedInput schema / properties / goal
        Added 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"
        +}
      • addedInput schema / properties / mode / description
        Added 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."
      • removedInput schema / properties / mode / title
        Removed value: -"Mode"
      • addedInput schema / properties / new_content / description
        Added value: +"the corrected body, or with mode='append' the line to add."
      • removedInput schema / properties / new_content / title
        Removed value: -"New Content"
      • addedInput schema / properties / note / description
        Added value: +"why it changed, kept with the previous version in the edit history."
      • removedInput schema / properties / note / title
        Removed value: -"Note"
      • addedInput schema / properties / source_ref / description
        Added 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."
      • removedInput schema / properties / source_ref / title
        Removed value: -"Source Ref"
      • addedInput schema / properties / tags / description
        Added 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."
      • removedInput schema / properties / tags / title
        Removed value: -"Tags"
      • addedInput schema / properties / title / description
        Added 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."
      • removedInput schema / properties / title / title
        Removed value: -"Title"
      • addedInput schema / properties / uid / description
        Added value: +"the memory."
      • removedInput schema / properties / uid / title
        Removed value: -"Uid"
      • removedInput schema / title
        Removed value: -"edit_memoryArguments"
    • Changedforget7 fields changed
      • addedInput schema / properties / reason / description
        Added value: +"why it is archived, recorded as a status-change audit entry without touching the content."
      • removedInput schema / properties / reason / title
        Removed value: -"Reason"
      • addedInput schema / properties / superseded_by / description
        Added 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`."
      • removedInput schema / properties / superseded_by / title
        Removed value: -"Superseded By"
      • addedInput schema / properties / uid / description
        Added value: +"the memory."
      • removedInput schema / properties / uid / title
        Removed value: -"Uid"
      • removedInput schema / title
        Removed value: -"forgetArguments"
    • Changedget_diagram6 fields changed
      • addedInput schema / properties / format / description
        Added value: +"one of the formats above."
      • removedInput schema / properties / format / title
        Removed value: -"Format"
      • addedInput schema / properties / offset
        Added value: +{
        +  "default": 0,
        +  "description": "where a long `body`, or the SVG step index, starts; `next_offset`, when present, starts the next page.",
        +  "type": "integer"
        +}
      • addedInput schema / properties / uid / description
        Added value: +"the diagram."
      • removedInput schema / properties / uid / title
        Removed value: -"Uid"
      • removedInput schema / title
        Removed value: -"get_diagramArguments"
    • Changedget_domain_case1 field changed
      • removedInput schema / title
        Removed value: -"get_domain_caseArguments"
    • Changedget_memory5 fields changed
      • addedInput schema / properties / content_offset
        Added value: +{
        +  "default": -1,
        +  "description": "from -1 to a character offset, reads that stretch of the body instead of the record.",
        +  "type": "integer"
        +}
      • addedInput schema / properties / edits_offset
        Added 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"
        +}
      • addedInput schema / properties / uid / description
        Added value: +"the memory."
      • removedInput schema / properties / uid / title
        Removed value: -"Uid"
      • removedInput schema / title
        Removed value: -"get_memoryArguments"
    • Changedget_relations6 fields changed
      • addedInput schema / properties / offset
        Added value: +{
        +  "default": 0,
        +  "description": "where the page starts; `next_offset`, when present, starts the next.",
        +  "type": "integer"
        +}
      • addedInput schema / properties / part
        Added value: +{
        +  "default": "relations",
        +  "description": "'relations' (edges, both ways) or 'diagrams' (flows pointing at it).",
        +  "type": "string"
        +}
      • addedInput schema / properties / uid / description
        Added value: +"the memory."
      • removedInput schema / properties / uid / title
        Removed value: -"Uid"
      • removedInput schema / title
        Removed value: -"get_relationsArguments"
      • changedOutput 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
    • Removedhelp
    • Changedlink_memories9 fields changed
      • addedInput schema / properties / from_uid / description
        Added value: +"the memory the edge starts at."
      • removedInput schema / properties / from_uid / title
        Removed value: -"From Uid"
      • addedInput schema / properties / note / description
        Added value: +"why the two are related, kept on the edge."
      • removedInput schema / properties / note / title
        Removed value: -"Note"
      • addedInput schema / properties / relation_type / description
        Added value: +"free text, but keep it consistent, e.g. 'supersedes', 'relates_to', 'contradicts', 'links_to'."
      • removedInput schema / properties / relation_type / title
        Removed value: -"Relation Type"
      • addedInput schema / properties / to_uid / description
        Added value: +"the memory it points to."
      • removedInput schema / properties / to_uid / title
        Removed value: -"To Uid"
      • removedInput schema / title
        Removed value: -"link_memoriesArguments"
    • Changedlist_by_domain12 fields changed
      • addedInput schema / properties / domain / description
        Added 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."
      • removedInput schema / properties / domain / title
        Removed value: -"Domain"
      • addedInput schema / properties / limit / description
        Added value: +"the most results to return."
      • removedInput schema / properties / limit / title
        Removed value: -"Limit"
      • addedInput schema / properties / offset
        Added value: +{
        +  "default": 0,
        +  "description": "where the page starts; `next_offset`, when present, starts the next.",
        +  "type": "integer"
        +}
      • addedInput schema / properties / status / description
        Added 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."
      • removedInput schema / properties / status / title
        Removed value: -"Status"
      • addedInput schema / properties / subtree / description
        Added value: +"False lists what is filed at exactly that path and nowhere deeper."
      • removedInput schema / properties / subtree / title
        Removed value: -"Subtree"
      • addedInput schema / properties / type / description
        Added value: +"one memory type, as search() takes it; empty is every type."
      • removedInput schema / properties / type / title
        Removed value: -"Type"
      • removedInput schema / title
        Removed value: -"list_by_domainArguments"
    • Changedlist_domains3 fields changed
      • addedInput schema / properties / offset
        Added value: +{
        +  "default": 0,
        +  "description": "where the page starts; `next_offset`, when present, starts the next.",
        +  "type": "integer"
        +}
      • removedInput schema / title
        Removed value: -"list_domainsArguments"
      • changedOutput 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
    • Changedlist_projects2 fields changed
      • addedInput schema / properties / offset
        Added value: +{
        +  "default": 0,
        +  "description": "where the page starts; `next_offset`, when present, starts the next.",
        +  "type": "integer"
        +}
      • removedInput schema / title
        Removed value: -"list_projectsArguments"
    • Changedlist_recent10 fields changed
      • addedInput schema / properties / domain / description
        Added value: +"covers its subdomains, and a bare deep segment resolves to the branches holding it (see list_by_domain)."
      • removedInput schema / properties / domain / title
        Removed value: -"Domain"
      • addedInput schema / properties / limit / description
        Added value: +"the most results to return."
      • removedInput schema / properties / limit / title
        Removed value: -"Limit"
      • addedInput schema / properties / offset
        Added value: +{
        +  "default": 0,
        +  "description": "where the page starts; `next_offset`, when present, starts the next.",
        +  "type": "integer"
        +}
      • addedInput schema / properties / subtree / description
        Added value: +"False narrows to the exact domain path."
      • removedInput schema / properties / subtree / title
        Removed value: -"Subtree"
      • addedInput schema / properties / type / description
        Added value: +"one memory type, as search() takes it; empty is every type."
      • removedInput schema / properties / type / title
        Removed value: -"Type"
      • removedInput schema / title
        Removed value: -"list_recentArguments"
    • Changedmove_to_project11 fields changed
      • addedInput schema / properties / create / description
        Added value: +"makes a `target` that does not exist yet."
      • removedInput schema / properties / create / title
        Removed value: -"Create"
      • addedInput schema / properties / domain / description
        Added value: +"a path to move, its subdomains and archived rows included."
      • removedInput schema / properties / domain / title
        Removed value: -"Domain"
      • addedInput schema / properties / dry_run / description
        Added 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."
      • removedInput schema / properties / dry_run / title
        Removed value: -"Dry Run"
      • addedInput schema / properties / target / description
        Added value: +"the project to move into; list_projects() names the projects there are."
      • removedInput schema / properties / target / title
        Removed value: -"Target"
      • addedInput schema / properties / uids / description
        Added value: +"comma-separated memories to move; give uids, domain or both."
      • removedInput schema / properties / uids / title
        Removed value: -"Uids"
      • removedInput schema / title
        Removed value: -"move_to_projectArguments"
    • Addedmust_read
    • Changednote17 fields changed
      • addedInput schema / properties / also / description
        Added 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."
      • removedInput schema / properties / also / title
        Removed value: -"Also"
      • addedInput schema / properties / content / description
        Added 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."
      • removedInput schema / properties / content / title
        Removed value: -"Content"
      • addedInput schema / properties / domain / description
        Added 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."
      • removedInput schema / properties / domain / title
        Removed value: -"Domain"
      • addedInput schema / properties / review_after / description
        Added 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."
      • removedInput schema / properties / review_after / title
        Removed value: -"Review After"
      • addedInput schema / properties / session / description
        Added value: +"groups what one conversation writes. Leave it empty to use this server process's own stamp."
      • removedInput schema / properties / session / title
        Removed value: -"Session"
      • addedInput schema / properties / source_ref / description
        Added 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."
      • removedInput schema / properties / source_ref / title
        Removed value: -"Source Ref"
      • addedInput schema / properties / tags / description
        Added 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."
      • removedInput schema / properties / tags / title
        Removed value: -"Tags"
      • addedInput schema / properties / title / description
        Added 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."
      • removedInput schema / properties / title / title
        Removed value: -"Title"
      • removedInput schema / title
        Removed value: -"noteArguments"
    • Changedoptimize_runs3 fields changed
      • addedInput schema / properties / offset
        Added value: +{
        +  "default": 0,
        +  "description": "where the page starts; `next_offset`, when present, starts the next.",
        +  "type": "integer"
        +}
      • removedInput schema / title
        Removed value: -"optimize_runsArguments"
      • changedOutput 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
    • Changedoptimize_scan15 fields changed
      • addedInput schema / properties / domain / description
        Added value: +"scans a path and everything nested under it; empty is the whole project."
      • removedInput schema / properties / domain / title
        Removed value: -"Domain"
      • addedInput schema / properties / full / description
        Added value: +"true keeps whole bodies instead of the slim listing."
      • removedInput schema / properties / full / title
        Removed value: -"Full"
      • addedInput schema / properties / include_archived / description
        Added value: +"true lists archived memories as well."
      • removedInput schema / properties / include_archived / title
        Removed value: -"Include Archived"
      • addedInput schema / properties / limit / description
        Added value: +"the most memories per page."
      • removedInput schema / properties / limit / title
        Removed value: -"Limit"
      • addedInput schema / properties / offset / description
        Added value: +"where the page starts; after a `truncated` page, offset + count."
      • removedInput schema / properties / offset / title
        Removed value: -"Offset"
      • addedInput schema / properties / since / description
        Added value: +"limits the scan to what changed after this date, for recurring passes."
      • removedInput schema / properties / since / title
        Removed value: -"Since"
      • addedInput schema / properties / type / description
        Added value: +"one memory type, as search() takes it; empty is every type."
      • removedInput schema / properties / type / title
        Removed value: -"Type"
      • removedInput schema / title
        Removed value: -"optimize_scanArguments"
    • Changedoptimize_stage5 fields changed
      • addedInput schema / properties / note / description
        Added 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."
      • removedInput schema / properties / note / title
        Removed value: -"Note"
      • addedInput schema / properties / suggestions / description
        Added 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."
      • removedInput schema / properties / suggestions / title
        Removed value: -"Suggestions"
      • removedInput schema / title
        Removed value: -"optimize_stageArguments"
    • Changedoptimize_status4 fields changed
      • addedInput schema / properties / offset
        Added value: +{
        +  "default": 0,
        +  "description": "where the page starts; `next_offset`, when present, starts the next.",
        +  "type": "integer"
        +}
      • addedInput schema / properties / run_id / description
        Added value: +"the run optimize_stage returned, or one optimize_runs lists."
      • removedInput schema / properties / run_id / title
        Removed value: -"Run Id"
      • removedInput schema / title
        Removed value: -"optimize_statusArguments"
    • Removedpending
    • Changedpulse4 fields changed
      • addedInput schema / properties / domain / description
        Added 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."
      • removedInput schema / properties / domain / title
        Removed value: -"Domain"
      • addedInput schema / properties / offset
        Added value: +{
        +  "default": 0,
        +  "description": "where the page of `scope.subdomains` starts.",
        +  "type": "integer"
        +}
      • removedInput schema / title
        Removed value: -"pulseArguments"
    • Changedpurge_memory5 fields changed
      • addedInput schema / properties / confirm_phrase / description
        Added 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."
      • removedInput schema / properties / confirm_phrase / title
        Removed value: -"Confirm Phrase"
      • addedInput schema / properties / uid / description
        Added value: +"the memory."
      • removedInput schema / properties / uid / title
        Removed value: -"Uid"
      • removedInput schema / title
        Removed value: -"purge_memoryArguments"
    • Changedreasoning25 fields changed
      • addedInput schema / properties / also / description
        Added 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."
      • removedInput schema / properties / also / title
        Removed value: -"Also"
      • addedInput schema / properties / domain / description
        Added 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."
      • removedInput schema / properties / domain / title
        Removed value: -"Domain"
      • addedInput schema / properties / hypothesis / description
        Added value: +"what you believed going in, as a claim that could be wrong."
      • removedInput schema / properties / hypothesis / title
        Removed value: -"Hypothesis"
      • addedInput schema / properties / next_time / description
        Added value: +"what someone hitting this again should do differently."
      • removedInput schema / properties / next_time / title
        Removed value: -"Next Time"
      • addedInput schema / properties / reasoning / description
        Added value: +"how you tested it -- what you read, ran or compared."
      • removedInput schema / properties / reasoning / title
        Removed value: -"Reasoning"
      • addedInput schema / properties / result / description
        Added value: +"what came back. The measurement, not the interpretation."
      • removedInput schema / properties / result / title
        Removed value: -"Result"
      • addedInput schema / properties / review_after / description
        Added 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."
      • removedInput schema / properties / review_after / title
        Removed value: -"Review After"
      • addedInput schema / properties / revised_belief / description
        Added value: +"what you believe now, and where it differs from the hypothesis. Say plainly when the hypothesis survived unchanged."
      • removedInput schema / properties / revised_belief / title
        Removed value: -"Revised Belief"
      • addedInput schema / properties / session / description
        Added value: +"groups what one conversation writes. Leave it empty to use this server process's own stamp."
      • removedInput schema / properties / session / title
        Removed value: -"Session"
      • addedInput schema / properties / source_ref / description
        Added 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."
      • removedInput schema / properties / source_ref / title
        Removed value: -"Source Ref"
      • addedInput schema / properties / tags / description
        Added 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."
      • removedInput schema / properties / tags / title
        Removed value: -"Tags"
      • addedInput schema / properties / title / description
        Added 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."
      • removedInput schema / properties / title / title
        Removed value: -"Title"
      • removedInput schema / title
        Removed value: -"reasoningArguments"
    • Changedrecall8 fields changed
      • addedInput schema / properties / domain / description
        Added value: +"scopes to a path and everything nested under it, and resolves a bare deep segment the same way search() does."
      • removedInput schema / properties / domain / title
        Removed value: -"Domain"
      • addedInput schema / properties / limit / description
        Added value: +"the most results to return."
      • removedInput schema / properties / limit / title
        Removed value: -"Limit"
      • addedInput schema / properties / offset
        Added value: +{
        +  "default": 0,
        +  "description": "where the page starts; `next_offset`, when present, starts the next.",
        +  "type": "integer"
        +}
      • addedInput schema / properties / query / description
        Added value: +"the words to look for; as in search(), more terms find more."
      • removedInput schema / properties / query / title
        Removed value: -"Query"
      • removedInput schema / title
        Removed value: -"recallArguments"
    • Changedsearch10 fields changed
      • addedInput schema / properties / domain / description
        Added 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."
      • removedInput schema / properties / domain / title
        Removed value: -"Domain"
      • addedInput schema / properties / limit / description
        Added value: +"the most results to return."
      • removedInput schema / properties / limit / title
        Removed value: -"Limit"
      • addedInput schema / properties / offset
        Added value: +{
        +  "default": 0,
        +  "description": "where the page starts; `next_offset`, when present, starts the next.",
        +  "type": "integer"
        +}
      • addedInput schema / properties / query / description
        Added 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."
      • removedInput schema / properties / query / title
        Removed value: -"Query"
      • addedInput schema / properties / type / description
        Added 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."
      • removedInput schema / properties / type / title
        Removed value: -"Type"
      • removedInput schema / title
        Removed value: -"searchArguments"
    • Changedset_confidence5 fields changed
      • addedInput schema / properties / confidence / description
        Added value: +"unverified, confirmed or contradicted."
      • removedInput schema / properties / confidence / title
        Removed value: -"Confidence"
      • addedInput schema / properties / uid / description
        Added value: +"the memory."
      • removedInput schema / properties / uid / title
        Removed value: -"Uid"
      • removedInput schema / title
        Removed value: -"set_confidenceArguments"
    • Changedset_domain_case3 fields changed
      • addedInput schema / properties / mode / description
        Added value: +"'preserve' keeps free-text casing; 'lower' or 'upper' coerces every domain written to that case."
      • removedInput schema / properties / mode / title
        Removed value: -"Mode"
      • removedInput schema / title
        Removed value: -"set_domain_caseArguments"
    • Changedtask15 fields changed
      • addedInput schema / properties / also / description
        Added 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."
      • removedInput schema / properties / also / title
        Removed value: -"Also"
      • addedInput schema / properties / domain / description
        Added 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."
      • removedInput schema / properties / domain / title
        Removed value: -"Domain"
      • addedInput schema / properties / goal / description
        Added 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."
      • removedInput schema / properties / goal / title
        Removed value: -"Goal"
      • addedInput schema / properties / items / description
        Added 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}."
      • removedInput schema / properties / items / title
        Removed value: -"Items"
      • addedInput schema / properties / session / description
        Added value: +"groups what one conversation writes. Leave it empty to use this server process's own stamp."
      • removedInput schema / properties / session / title
        Removed value: -"Session"
      • addedInput schema / properties / tags / description
        Added 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."
      • removedInput schema / properties / tags / title
        Removed value: -"Tags"
      • addedInput schema / properties / title / description
        Added value: +"what the task delivers, in a few words someone would look for it by. At most 120 characters."
      • removedInput schema / properties / title / title
        Removed value: -"Title"
      • removedInput schema / title
        Removed value: -"taskArguments"
    • Changedtask_add5 fields changed
      • addedInput schema / properties / items / description
        Added value: +"one item per line, blank lines ignored, each a short label as task() takes them."
      • removedInput schema / properties / items / title
        Removed value: -"Items"
      • addedInput schema / properties / uid / description
        Added value: +"the task."
      • removedInput schema / properties / uid / title
        Removed value: -"Uid"
      • removedInput schema / title
        Removed value: -"task_addArguments"
    • Changedtask_comment9 fields changed
      • addedInput schema / properties / body / description
        Added value: +"the comment."
      • removedInput schema / properties / body / title
        Removed value: -"Body"
      • changedInput schema / properties / item / default
        Previous value: -""New value: +0
      • addedInput schema / properties / item / description
        Added value: +"the item's id; 0, the default, comments on the task itself."
      • removedInput schema / properties / item / title
        Removed value: -"Item"
      • changedInput schema / properties / item / type
        Previous value: -"string"New value: +"integer"
      • addedInput schema / properties / uid / description
        Added value: +"the task."
      • removedInput schema / properties / uid / title
        Removed value: -"Uid"
      • removedInput schema / title
        Removed value: -"task_commentArguments"
    • Changedtask_item14 fields changed
      • addedInput schema / properties / comment / description
        Added value: +"a remark on this item -- what blocked it, what was decided."
      • removedInput schema / properties / comment / title
        Removed value: -"Comment"
      • addedInput schema / properties / delete
        Added 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"
        +}
      • addedInput schema / properties / item / description
        Added value: +"the item's id, as task_read(part='items') lists it."
      • removedInput schema / properties / item / title
        Removed value: -"Item"
      • changedInput schema / properties / item / type
        Previous value: -"string"New value: +"integer"
      • addedInput schema / properties / related / description
        Added value: +"comma-separated uids of memories this item produced or depends on. An unknown uid refuses the whole call, and nothing is written."
      • removedInput schema / properties / related / title
        Removed value: -"Related"
      • addedInput schema / properties / state / description
        Added 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."
      • removedInput schema / properties / state / title
        Removed value: -"State"
      • addedInput schema / properties / text
        Added 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"
        +}
      • addedInput schema / properties / uid / description
        Added value: +"the task."
      • removedInput schema / properties / uid / title
        Removed value: -"Uid"
      • removedInput schema / title
        Removed value: -"task_itemArguments"
    • Addedtask_note
    • Addedtask_read
    • Changedtimeline13 fields changed
      • addedInput schema / properties / after / description
        Added value: +"how many records created immediately after it."
      • removedInput schema / properties / after / title
        Removed value: -"After"
      • addedInput schema / properties / before / description
        Added value: +"how many records created immediately before the anchor."
      • removedInput schema / properties / before / title
        Removed value: -"Before"
      • addedInput schema / properties / domain / description
        Added 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."
      • removedInput schema / properties / domain / title
        Removed value: -"Domain"
      • addedInput schema / properties / query / description
        Added value: +"searches for the anchor and takes the top hit (the same search search() runs, scoped by domain/type)."
      • removedInput schema / properties / query / title
        Removed value: -"Query"
      • addedInput schema / properties / type / description
        Added value: +"one memory type, as search() takes it; empty is every type."
      • removedInput schema / properties / type / title
        Removed value: -"Type"
      • addedInput schema / properties / uid / description
        Added value: +"the anchor, named outright."
      • removedInput schema / properties / uid / title
        Removed value: -"Uid"
      • removedInput schema / title
        Removed value: -"timelineArguments"
    • Changedunfile_domain5 fields changed
      • addedInput schema / properties / domain / description
        Added 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."
      • removedInput schema / properties / domain / title
        Removed value: -"Domain"
      • addedInput schema / properties / uid / description
        Added value: +"the memory."
      • removedInput schema / properties / uid / title
        Removed value: -"Uid"
      • removedInput schema / title
        Removed value: -"unfile_domainArguments"
  2. 7 tool updatesv0.6.0
    • Removedhandoff
    • Changedlist_by_domain1 field changed
      • addedInput schema / properties / status
        Added value: +{
        +  "default": "active",
        +  "title": "Status",
        +  "type": "string"
        +}
    • Addedpending
    • Addedtask
    • Addedtask_add
    • Addedtask_comment
    • Addedtask_item
  3. 24 tool updatesv0.1.1
    • Addedalso_domain
    • Changedanti_pattern6 fields changed
      • addedInput schema / properties / also
        Added value: +{
        +  "default": "",
        +  "title": "Also",
        +  "type": "string"
        +}
      • addedInput schema / properties / review_after
        Added value: +{
        +  "default": "",
        +  "title": "Review After",
        +  "type": "string"
        +}
      • addedInput schema / properties / source_ref
        Added value: +{
        +  "default": "",
        +  "title": "Source Ref",
        +  "type": "string"
        +}
      • addedInput schema / properties / tags
        Added value: +{
        +  "default": "",
        +  "title": "Tags",
        +  "type": "string"
        +}
      • addedInput schema / properties / title
        Added value: +{
        +  "title": "Title",
        +  "type": "string"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "pattern",
        -  "why_wrong",
        -  "instead"
        -]New value: +[
        +  "title",
        +  "pattern",
        +  "why_wrong",
        +  "instead"
        +]
    • Changedcheckpoint4 fields changed
      • addedInput schema / properties / also
        Added value: +{
        +  "default": "",
        +  "title": "Also",
        +  "type": "string"
        +}
      • addedInput schema / properties / tags
        Added value: +{
        +  "default": "",
        +  "title": "Tags",
        +  "type": "string"
        +}
      • addedInput schema / properties / title
        Added value: +{
        +  "title": "Title",
        +  "type": "string"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "intent",
        -  "established",
        -  "pursuing",
        -  "open_questions"
        -]New value: +[
        +  "title",
        +  "intent",
        +  "established",
        +  "pursuing",
        +  "open_questions"
        +]
    • Addeddiagram
    • Addeddiagram_edge
    • Addeddiagram_jump
    • Addeddiagram_link
    • Addeddiagram_node
    • Addeddiagram_relayout
    • Changededit_memory6 fields changed
      • addedInput schema / properties / mode
        Added value: +{
        +  "default": "replace",
        +  "title": "Mode",
        +  "type": "string"
        +}
      • addedInput schema / properties / new_content / default
        Added value: +""
      • addedInput schema / properties / source_ref
        Added value: +{
        +  "default": "",
        +  "title": "Source Ref",
        +  "type": "string"
        +}
      • addedInput schema / properties / tags
        Added value: +{
        +  "default": "",
        +  "title": "Tags",
        +  "type": "string"
        +}
      • addedInput schema / properties / title
        Added value: +{
        +  "default": "",
        +  "title": "Title",
        +  "type": "string"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "uid",
        -  "new_content"
        -]New value: +[
        +  "uid"
        +]
    • Addedget_diagram
    • Addedget_domain_case
    • Changedhandoff4 fields changed
      • addedInput schema / properties / also
        Added value: +{
        +  "default": "",
        +  "title": "Also",
        +  "type": "string"
        +}
      • addedInput schema / properties / tags
        Added value: +{
        +  "default": "",
        +  "title": "Tags",
        +  "type": "string"
        +}
      • addedInput schema / properties / title
        Added value: +{
        +  "title": "Title",
        +  "type": "string"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "content"
        -]New value: +[
        +  "title",
        +  "content"
        +]
    • Changedlist_by_domain2 fields changed
      • addedInput schema / properties / subtree
        Added value: +{
        +  "default": true,
        +  "title": "Subtree",
        +  "type": "boolean"
        +}
      • changedOutput 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
    • Addedlist_projects
    • Changedlist_recent2 fields changed
      • addedInput schema / properties / subtree
        Added value: +{
        +  "default": true,
        +  "title": "Subtree",
        +  "type": "boolean"
        +}
      • changedOutput 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
    • Addedmove_to_project
    • Changednote5 fields changed
      • addedInput schema / properties / also
        Added value: +{
        +  "default": "",
        +  "title": "Also",
        +  "type": "string"
        +}
      • addedInput schema / properties / review_after
        Added value: +{
        +  "default": "",
        +  "title": "Review After",
        +  "type": "string"
        +}
      • addedInput schema / properties / source_ref
        Added value: +{
        +  "default": "",
        +  "title": "Source Ref",
        +  "type": "string"
        +}
      • addedInput schema / properties / title
        Added value: +{
        +  "title": "Title",
        +  "type": "string"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "content"
        -]New value: +[
        +  "title",
        +  "content"
        +]
    • Changedreasoning12 fields changed
      • addedInput schema / properties / also
        Added value: +{
        +  "default": "",
        +  "title": "Also",
        +  "type": "string"
        +}
      • removedInput schema / properties / content
        Removed value: -{
        -  "title": "Content",
        -  "type": "string"
        -}
      • addedInput schema / properties / hypothesis
        Added value: +{
        +  "title": "Hypothesis",
        +  "type": "string"
        +}
      • addedInput schema / properties / next_time
        Added value: +{
        +  "title": "Next Time",
        +  "type": "string"
        +}
      • addedInput schema / properties / reasoning
        Added value: +{
        +  "title": "Reasoning",
        +  "type": "string"
        +}
      • addedInput schema / properties / result
        Added value: +{
        +  "title": "Result",
        +  "type": "string"
        +}
      • addedInput schema / properties / review_after
        Added value: +{
        +  "default": "",
        +  "title": "Review After",
        +  "type": "string"
        +}
      • addedInput schema / properties / revised_belief
        Added value: +{
        +  "title": "Revised Belief",
        +  "type": "string"
        +}
      • addedInput schema / properties / source_ref
        Added value: +{
        +  "default": "",
        +  "title": "Source Ref",
        +  "type": "string"
        +}
      • addedInput schema / properties / tags
        Added value: +{
        +  "default": "",
        +  "title": "Tags",
        +  "type": "string"
        +}
      • addedInput schema / properties / title
        Added value: +{
        +  "title": "Title",
        +  "type": "string"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "content"
        -]New value: +[
        +  "title",
        +  "hypothesis",
        +  "reasoning",
        +  "result",
        +  "revised_belief",
        +  "next_time"
        +]
    • Changedrecall2 fields changed
      • changedInput schema / properties / limit / default
        Previous value: -20New value: +10
      • changedOutput schema / (root)
        Previous value: -{
        -  "properties": {
        -    "result": {
        -      "items": {
        -        "additionalProperties": true,
        -        "type": "object"
        -      },
        -      "title": "Result",
        -      "type": "array"
        -    }
        -  },
        -  "required": [
        -    "result"
        -  ],
        -  "title": "recallOutput",
        -  "type": "object"
        -}New value: +null
    • Changedsearch2 fields changed
      • changedInput schema / properties / limit / default
        Previous value: -30New value: +10
      • changedOutput schema / (root)
        Previous value: -{
        -  "properties": {
        -    "result": {
        -      "items": {
        -        "additionalProperties": true,
        -        "type": "object"
        -      },
        -      "title": "Result",
        -      "type": "array"
        -    }
        -  },
        -  "required": [
        -    "result"
        -  ],
        -  "title": "searchOutput",
        -  "type": "object"
        -}New value: +null
    • Addedset_domain_case
    • Addedtimeline
    • Addedunfile_domain
  4. 24 tool updatesv0.1.0
    • First observedanti_pattern
    • First observedcheckpoint
    • First observeddedup_scan
    • First observededit_memory
    • First observedforget
    • First observedget_memory
    • First observedget_relations
    • First observedhandoff
    • First observedhelp
    • First observedlink_memories
    • First observedlist_by_domain
    • First observedlist_domains
    • First observedlist_recent
    • First observednote
    • First observedoptimize_runs
    • First observedoptimize_scan
    • First observedoptimize_stage
    • First observedoptimize_status
    • First observedpulse
    • First observedpurge_memory
    • First observedreasoning
    • First observedrecall
    • First observedsearch
    • First observedset_confidence

TDQS

A3.6/5.0

Scored across 43 tools

Disambiguation3/5

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.

Naming Consistency3/5

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.

Tool Count2/5

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.

Completeness5/5

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

ActivityActive
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    An 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.
    1
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    A local memory server for AI agents that stores and retrieves information via MCP, keeping all data in SQLite on your machine.
    140 PyPI
    1
    Apache 2.0
  • A
    license
    A
    quality
    B
    maintenance
    MCP server for persistent, cross-session, local-first memory for AI agents, storing memories as Markdown files with SQLite indexing for hybrid search.
    24
    Apache 2.0