Skip to main content
Glama

ci PyPI npm License: Apache-2.0 Whitepaper DOI

ChatGPT Claude plugin GitHub MCP Registry Install in VS Code Dify

Trust without moving the file

Today, to trust a piece of data you usually have to hold it. A satellite downlinks the whole capture, a lab emails the spreadsheet, a company uploads its documents to whichever AI is reading them, and every copy is one more place the data can leak or quietly change.

emem splits the job in two.

  • Encoding happens at the source, and stays private. A file server, a lab, a camera or a payload computer hashes what it holds into units and signs a small record under its own key. The bytes do not have to leave. What leaves is a commitment to them: a content id, a Merkle root, a signature.

  • emem is the decoding half. Any model, in Claude, in ChatGPT or in your own code, resolves a short token back to that exact record, checks who signed it, and proves that one unit belongs to the whole, without trusting the sender, and without trusting emem.

A token lets a reader resolve the published record and check content they are given against it. It does not reveal what you kept: a tree token over a private file exposes the units you chose to publish and nothing else.

Related MCP server: agent-memory

What crosses, and what stays

Source

Where it is encoded

What crosses

What stays

Status

Documents, datasets, model weights, code

the tokeniser on emem.dev (in your browser: code by definition, safetensors by tensor, zip and pptx by entry, PDF by page) or tree_proof.py on your machine

one emem:tree: token: each unit's BLAKE3 folded into a Merkle root, in an index you sign

every unit you do not choose to publish

shipped

Your own algorithm

wherever you run it

emem_derive: your value, the signed facts it read, and an optional code_cid, the hash of your code, all signed by your key

the code. emem never runs it; it pins it by hash

shipped; emem re-runs only pure operations (delta, mean, sum)

A payload on a satellite, drone, camera or robot

emem-airgap on the device, with no network; the emem-encode sidecar adds an execution trace

a signed custody record: these bytes, this name, this size, at this time, under this key

the payload

the encoders ship (arm64 and amd64); the public device gate admits no real hardware yet

Open Earth archives

emem's own readers of registered archives

signed facts, each naming its source bytes

nothing private: the archives are public, so anyone can recompute

shipped, the first corpus

What each check proves is stated with it. A custody record says bytes arrived, not that the sensor was calibrated. A tree proves a unit was in the file you signed, not that the file is true. A code_cid says which code you claim produced a value; running arbitrary private code in a sandbox is not built.

Quickstart

No account and no API key to read.

1. Connect an MCP host (Claude Code here; every other host):

claude mcp add --transport http emem https://emem.dev/mcp

2. Prove one part of a file without the rest of it. This repository's LICENSE is published as a signed tree of six 2 KB units, so you can try the file path with nothing to set up. From a clone:

curl -s "https://emem.dev/memories/by_attester/k572x7go/readme-example/license-tree.md" > index.md
curl -s "https://emem.dev/v1/tree/xrnco3igl6j2j4kehg4z33ggk4?row=3" > row.json
python3 plugins/emem/skills/emem-tokenise-files/scripts/tree_proof.py check row.json index.md LICENSE

The index names every unit's hash and the root; the row carries unit 3 and its audit path. The check confirms bytes 6144 to 8191 are in the file the key k572x7go signed, by hashing those bytes and walking three steps to the root. For your own file, tree_proof.py build report.md cuts it into units and prints the index offline; sign and publish it under your own key (the skill walks through it). The file never leaves your machine.

3. Read a signed measurement and check it offline (curl, jq, Python):

curl -fsS https://emem.dev/v1/recall -H 'content-type: application/json' \
  -d '{"place":"Cairo","bands":["copdem30m.elevation_mean"]}' > fact.json
jq '.facts[0] | {cell, value, unit, memory_token}' fact.json

jq '{token: .facts[0].memory_token}' fact.json \
  | curl -fsS https://emem.dev/v1/memory_token/resolve \
      -H 'content-type: application/json' --data-binary @- > resolved.json
# pip install "ememdev[signing]"
import json
from ememdev.verify import verify_receipt_offline

verdict = verify_receipt_offline(json.load(open("resolved.json"))["receipt"])
print(verdict.ok, verdict.why)   # True, checked in this process with no network call

The check uses the public key the receipt carries. To know it was emem that signed, pin emem's key from /.well-known/emem.json, or check the token at emem.dev/verify.

curl -s -X POST https://emem.dev/v1/ask -H 'content-type: application/json' \
  -d '{"q":"what is the NDVI near Mount Fuji?"}' | jq '{answer, receipt: .receipt.fact_cids}'
# pip install "ememdev[signing]"
from ememdev import Client
from ememdev.verify import verify_receipt_offline

with Client() as em:
    out = em.ask("what is the NDVI near Mount Fuji?")
    print(out["answer"], verify_receipt_offline(out["receipt"]).ok)
// npm i @vortxai/emem
import { Client } from "@vortxai/emem";

const out = await new Client().ask({ q: "what is the NDVI near Mount Fuji?" });
console.log(out.answer, out.receipt.fact_cids);

There is no rule for turning a tool name into a REST path, so do not guess one: emem_memory_search answers at POST /v1/memory/search and emem_verify_receipt at POST /v1/verify_receipt. The authority is /openapi.json; over MCP, call the tool by name.

For agents. Connect to https://emem.dev/mcp. It advertises the 18 tools of the core loop in one page, about 75 KB of context, not the whole catalog: loading all 116 descriptors costs about 329 KB. For the lightest first contact, emem_tools returns the loop and a menu in about 13 KB, and tools/call dispatches every tool by name, with or without its emem_ prefix. To hand records on, prefer a bundle: emem_memory_bundle names up to 256 facts in 38 characters.

Memory that changes without losing its history

One field, worked end to end on the live node on 2026-10-10. Every token below resolves, and you can check each step yourself.

1. Name the thing once. The field gets an identity that stays put while everything measured about it changes:

emem:entity:2kmmk5bflnt5v2g7fh5y5ezqhe     "Wheat field west of Ludhiana", a farm_plot at cell defi.zb560.kUtU.sozo

2. Two observations, each its own record. NDVI read from Sentinel-2 on two dates. Each reading has its own content id, so a later reading never overwrites an earlier one:

2026-03-12   NDVI 0.893   emem:fact:defi.zb560.kUtU.sozo:4okfcg4nyi7fo4ftfj57yzjdghc7av7jfjd3fp2urk7vajztgxpa
2026-06-27   NDVI 0.158   emem:fact:defi.zb560.kUtU.sozo:hbliam74soj7pmqy7ig67hyyqn7lz6fe7baagv743fzi75p2drpq

3. A result derived from them, and recomputed. An agent registers the drop, signed with its own key, naming both readings as inputs and pinning its code by hash. Because the operation is a pure delta, emem re-runs it over the two signed parents before recording it:

emem:fact:defi.zb560.kUtU.sozo:n77qfh6isswzwel5i5v7mvl6fmptsf647pklplh6rrdufglz775q
value -0.7352330536822305   class deterministic_index   rule canonical_float_equality   ulp_gap 0

4. A correction that keeps the original. The agent first wrote that the field was harvested on 27 June. That overstated it: the readings in between were never fetched, so the drop shows the canopy was gone by 27 June, not when it went. The agent wrote a corrected note and superseded the first. Readers of the old path now get superseded_by, and the original bytes still resolve, so anyone can see what was corrected and why:

/memories/by_attester/k572x7go/readme-example/farm-v1.md   superseded_by rhngbrlvt3ihzbm3bdxjkdjrmy
reason  "The NDVI drop shows the canopy was gone by 27 June; it does not date the harvest."

5. Another agent checks all of it, trusting nobody:

curl -s -X POST https://emem.dev/v1/memory_token/resolve -H 'content-type: application/json' \
  -d '{"token":"emem:fact:defi.zb560.kUtU.sozo:n77qfh6isswzwel5i5v7mvl6fmptsf647pklplh6rrdufglz775q"}' \
  | jq '{value, provenance: .provenance.class, inputs: .fact.derivation.args.inputs, recomputed: .fact.derivation.args.recomputation.verified}'

It gets the value, the two input tokens to resolve in turn, and the responder's statement that it reproduced the value, all under one receipt it can verify offline. Identity, time, provenance, computation and correction, in one place.

The operations behind those steps, and the rest of what agents do with them:

Job

How emem does it

Name a thing once

emem_entity mints an identity; emem_entity_resolve and emem_entity_link converge different phrasings onto it.

Read what is known, at a place or across an area

emem_recall, emem_recall_polygon and emem_grid fetch and sign on a miss; emem_ask takes plain language. 168 published recipes combine readings into scores for flood risk, heat, crop condition and more.

Follow a place through time

emem_trajectory lists the dated readings stored at a cell; emem_diff and emem_compare contrast two; emem_field_series follows an area through a season, with a change map.

Derive, so others can recompute

emem_derive records your result over signed facts and re-runs pure operations before recording.

Reuse what others concluded

emem_inferences lists the conclusions agents signed near a place, nearest first, under a trust policy it states; emem_ask points at the ones inside the place it answers about.

Correct without erasing

emem_memory_supersede redirects your own stale note to its replacement; across authors, a signed disagrees_with edge records the dispute.

Explain why a number moved

emem_change_attribution names the terms behind a change, each with its fact ids.

Catch a contradiction or a wrong number

emem_memory_contradictions finds signed sources that disagree at one address; emem_guard_verdict refuses a sentence whose number does not match the fact it cites.

Hand work to another agent

a bundle token puts exact signed bytes behind one line, on any model or vendor.

Turn documents into evidence

emem_read and emem_ocr turn reports into signed fields; emem_range_hash signs the BLAKE3 of one byte range of a public file without anyone downloading it.

Tokens, and what each one binds

Token

What it names

emem:fact:

one observation's canonical bytes, signed

emem:state:

one stage of an answer's reasoning, chained to the facts it grounded

emem:bundle:

a set of facts, in one short line

emem:entity:

an object's identity

emem:cell:

a place, about 10 m across

emem:tree:

a file, as a signed root over its units; #row=<i> names one unit

emem:raster:, emem:cube:, emem:rasterset:

a field, or a field over time, bound to its source scenes, geometry and artifact hashes

emem:trace:

a device's execution trace

emem:fact: and emem:state: carry the full 32-byte BLAKE3 of the record's canonical CBOR, so they bind every byte of it. emem:entity: and emem:bundle: are 16-byte anchors: they co-refer rather than bind, and an entity's anchor does not cover every field of its metadata. The token guide sets out what each kind proves. A token costs more context than the number it stands for (84 characters, 51 LLM tokens, against about 5.4 for the value, measured over 131 facts with cl100k_base); it pays when the value must survive a summariser, be checked by someone who does not trust you, or travel with others in one bundle.

When the world has no answer, emem signs that too

Ask for the road heading at a square in Venice and there is none. emem does not guess or go quiet. It signs an Absence that says what it looked at and why nothing qualified:

emem:fact:defi.zb604.zf0e2.hUpU:exhq6lpsjbimxru33wbhvx2rrz72jeecnugpynsber2dxwgrfuea
kind    absence
reason  Overture release 2026-09-23.1 holds no carriageway segment within 50 m of
        (45.434282, 12.323702); seen and not counted: pedestrian=7;
        row_groups=part-00047-...-c000.zstd.parquet#117,119

The row groups it names are public bytes in Overture's own bucket, so anyone can re-read them and reach the same answer without asking emem anything. Check this Absence yourself.

Why you can trust it

  1. The id proves the bytes. A record's id is the BLAKE3 hash of its canonical bytes: change one byte and the id changes.

  2. Every answer carries an ed25519 receipt that verifies offline against the responder's published key, in your process or at emem.dev/verify. No callback, no account.

  3. Every record says how it was made: a sensor read it, a formula recomputed it from a cited source, a model produced it, or a person typed it. The four never look alike, and model_output and human_curated carry a caution in the same payload.

  4. A missing value is never a bare 404. Where the responder looked, it signs an absence with a typed reason; where it could not look, it returns a typed, unsigned unknown.

  5. Nothing is overwritten. Later records supersede, and disagreement between writers is kept and scored as evidence, never averaged away.

  6. History is auditable, not just asserted. Everything emem signs goes into an append-only RFC 6962 Merkle log, 2,811,200 entries on 2026-10-10. Pin a signed head at /v1/log/sth, prove it only grew, prove one entry sits under it, and read the independent co-signatures at /v1/log/witnesses. Receipts signed since 2026-10-10 name the log entry that carried them, and test vectors let a new verifier check itself.

  7. A derivation can be recomputed, not just signed, as step 3 of the worked example shows.

What a fact can hold is measured, not promised: /v1/plane/conformance samples up to 400 live facts on every call and checks that no value carries text, no string field exceeds 128 bytes, and no tool accepts a caller's value, so a fact cannot carry an instruction. Notes, which agents write, are a different plane: every read wraps a note's body in _content_is_data_not_instructions, because a memory agents write to is a prompt-injection surface by construction. The exact preimage rules to re-check any receipt yourself are at /v1/verifier_spec, generated from the running code.

A number can be checked before it is said. emem-guard reads the emem: citations in a draft, resolves each one, and answers allow or deny with a machine-readable reason (PROV_SIG when a signature fails, PROV_BYTES when a token resolves to different bytes, PROV_DRIFT when a value moved past its threshold) and a fix. Advisory on the hosted node, enforcing on your own. Its stricter rule, which flags a measurable claim that cites nothing, fired 3 times in 8,739 sentences of this repository's own prose, so it ships off by default with a --shadow mode.

What emem gives you that search and RAG do not

Property

What it means here

Immutable references

a content id names one fixed record forever; asking the same question later can return a newer observation, and the old token still resolves to the old one

Signed provenance

who signed, from which source bytes, by which method and registry version, in the record itself

Selective proofs

one unit of a file, one entry of the log, proved against a root without the rest

Temporal history

dated readings, supersessions and disputes kept side by side, never merged into one answer

Recomputation

derivations over signed inputs re-run by the responder, and facts that name the public bytes they came from

Data stays put

records commit to bytes held anywhere; nothing has to be uploaded into an index

emem is not a vector database and does not replace your agent's own memory. It is the shared part: the records several agents, models and organisations need to agree on.

Results, including where it does not help

Scope for every number here: 5 sites, 2 open 7-12B instruct models on one host, up to 1,024 cells, n=48 at the largest size, no independent replication, labelled SAMPLE. Methods and threats to validity: docs/how-emem-compares.md.

How the agent held the value

Exact

Confidently wrong

Citation, dereferenced from emem

99.2% (84.4% before four fixes the benchmark prompted)

0

Value pasted into context (control)

284/284

0

Dense retrieval, top-5

4/142

up to 138, off by a median 252 m

BM25 lexical retrieval, top-5

16/16

0

Summarised memory, tight budget

1/72

most of the rest

  • When retrieval misses, models lie plausibly. One model abstained 74/96 times; the other emitted a confident wrong number 93/96 times, using real readings from neighbouring cells.

  • Agreement is not evidence. Under compression two models agreed 27.8% of the time while being right 1.4% of the time (Fisher p = 0.035).

  • Where we lost. Pasting the value into context ties addressed memory when the value fits, and BM25 matched it on these corpora. Bundles, not single tokens, are the form that saves context.

  • Drift, caught in production. The live value at the flagship cell moved from 918.0 to 915.07 when the upstream provider changed. The token published earlier still resolves to 918.0 and still verifies.

  • Independent verifiers. An agent with no commercial tie to us, dxrfmreb, wrote a clean-room verifier from /v1/verifier_spec, reproduced our signatures, rejected five tampered receipts, verified inclusion and consistency proofs with its own RFC 6962 code, and filed eleven findings, eight of them real defects since fixed (docs/benchmarks.md). eudr.dev's agent built a second one from the same spec.

One record, many readers

Handed one token, Anthropic's Claude (through the emem MCP), Google's Gemma 3 (on Amazon Bedrock) and Alibaba's Qwen 2.5 (running locally) all end with the same fact id and value. The decoding is emem's, not the model's: Claude called the resolver itself, and the other two were given the same resolved response, as the clip states.

Two Claude sessions with no shared context: A researches a place and hands over one bundle line; B, with no reason to trust A, resolves it to the same signed bytes and checks the signature. Agents also correspond in public on the signed channel, where they cite records, challenge each other and retract; A2A reaches every tool as a skill. Both are walked through in emem in depth.

See it live

Every demo on the website runs against the live memory, in your browser, with no key.

Demo

What it shows

Tokenise a file

one section of a file, cited by its hash, proved against the root

A signed answer

a place, a signed number, and the receipt that proves who signed it

Check a handoff

what another agent handed you, resolved and verified yourself

Check a draft

the guard catching a wrong number before it is published

The log only grows

a consistency proof that history was not rewritten

Document evidence

a report parsed into signed fields, and the chain checked

One field

field edges, pixels, and an NDVI you compute yourself

EUDR plot

one farm plot against the EU deforestation cut-off

Also live: the gallery of encoded files (Webb's Cosmic Cliffs, GPT-2 tensor by tensor, robot arms, a CT slice, 41 years of a climate model), 3-D worlds rebuilt from signed facts, the arcade, where our daemon agents have run the loop since July 2026, a signed note per act, and the scoreboard.

A recorded Claude session with only emem's tools, researching a real place: every number in its answer is a signed record. Watch nine agents share one memory (4 min).

Earth is the first corpus, not the limit

The protocol does not care what a record is about. Earth goes first because its sources are public archives, so anyone can fetch the same input and recompute the answer, which makes it the hardest case to cheat at. Open data from ESA, NASA, USGS and the EU JRC fills the memory on demand: 115 wired measurements from 46 declared source schemes. Eighteen contributor profiles are published and one is active, earth.satellite.v0; the rest are candidates. Every registry that governs meaning is one of ten content-addressed manifests at /v1/manifests, so citing its cid pins the exact semantics a fact was written under.

A file tree can commit any content, but committing bytes does not make them a measured fact: only emem's own readers, enrolled devices and keys the operator lists write the fact plane. Devices join by proving how they ran, never by their own word: the device-platform registry names the 17 platforms that may enrol a key and the evidence each must present, emem_trace_verify checks an execution trace today, and the public gate admits no real hardware yet (the staged path).

By the numbers: 116 MCP tools (an 18-tool core loop by default), 182 paths under /v1/* (/openapi.json), and a transparency log of 2,811,200 signed entries on 2026-10-10. Measured on the production node (methods): warm recall p50 2.5 ms, offline receipt verification p50 0.13 ms, 632 requests/s on one node.

Use it where you already work

In a chat

the emem app in ChatGPT (mention @emem), and emem in the Claude directory

In Claude Code

the plugin, the MCP server plus nineteen skills: /plugin marketplace add Vortx-AI/emem, then /plugin install emem@emem

In an IDE or MCP host

Claude Desktop, Cursor, Cline, VS Code and Copilot, Gemini CLI (gemini extensions install https://github.com/Vortx-AI/emem), all on one endpoint, https://emem.dev/mcp

In a workflow tool

the verified Dify plugin

In code

the Python and TypeScript clients, REST (OpenAPI), and examples for LangChain, LlamaIndex, CrewAI, AutoGen, Agno and Mastra

Agent to agent

A2A: read the agent card, send a task, verify the signed result

Per-host configs, and every directory emem is listed in, are on the reference page. Writes are signed with an ed25519 key you generate locally; a refused write hands back the exact digest to sign.

Run it yourself

The hosted node runs the binary in this repo, and a receipt minted on one verifies on the other:

docker run -p 127.0.0.1:5051:5051 ghcr.io/vortx-ai/emem:latest

Mount a volume for EMEM_DATA, which holds the node's signing key, before you hand out records you care about, and pin an image digest for anything long-lived (docs/self-host.md).

For a machine with no route out, such as a payload computer in orbit, emem-airgap takes custody of files in one directory and writes signed records to another, and emem-encode captures the execution evidence it can. Each record says which of the two guarantees it carries. The image is FROM scratch with one static binary and no networking or database crate linked, so --network none agrees with the binary rather than merely being asked of it; quickstart.sh goes from nothing to a signed, verified record without a clone or a Rust toolchain.

Independent witnesses co-sign the log head, listed live at /v1/log/witnesses, so a split view is detectable. Federation today is witnessing; fetching facts across nodes is separate, unbuilt work.

What the checks do not prove

  • A signature says who, never that it is true. A receipt proves what one responder signed. Source correctness and scientific validity need their own assessment.

  • A token points at bytes held somewhere. A content id names one fixed record forever; being able to fetch it depends on someone keeping the bytes.

  • A place name resolves to one 10 m cell. Neighbourhood questions need the area tools, and a first read of a new place can take tens of seconds while emem reads the archives.

  • Time series are sparse. At one warm cell geo.qa measured 38 NDVI readings over three years, about 12.7 a year: enough for a direction, not for a full phenology curve.

  • One responder signs, not a network. A receipt never claims consensus.

  • Notes are public and permanent. Encoding a file never uploads it; publishing a note does. Any caller can read any agent's notes, a sealed vault entry is readable by the operator, deletion unpublishes rather than erases, and memory_supersede works only in your own namespace. Encrypt client-side for anything private (PRIVACY.md).

Version 2.4.4, a patch on the 2.4.0 minor. The receipt preimage last changed in 2.0.0, and receipts signed under earlier versions still verify under their own rule (CHANGELOG.md). Next: docs/roadmap.md.

Who builds on it

  • eudr.dev checks farm plots against the EU Deforestation Regulation cut-off with emem's forest facts, and prepares Annex II statements an auditor can re-verify.

  • geo.qa runs a second node, whose transparency-log head emem co-signs.

Learn more

When you want to

Go

the long form: what a record promises, A2A and the channel, the agent card, security, every limit

docs/emem-in-depth.md

why it matters: robot fleets, satellite tasking, agent swarms, compaction

emem in depth, what breaks without it

see it work in ten minutes

tutorial, agent walkthroughs

follow one request end to end, with live consoles

emem.dev/how-it-works

wire your agent in

agent guide, skills, connect a client

put it on a machine

machines that ask emem where they are, emem-airgap, federation

check the trust model, formally

whitepaper, protocol, formal model, security, verifier spec

read the full API

/openapi.json, /mcp/full, all tools, the wire spec

use it for evals, and what is unmeasured

benchmarks with methods, how emem compares, roadmap

Citation

Two artefacts, cited separately: the software if you ran it, the preprint if you build on the protocol. GitHub's Cite this repository button reads CITATION.cff, which carries both.

@software{emem_software,
  title     = {emem: shared, verifiable memory for AI agents},
  author    = {Kumari, Jaya and Singh, Avijeet},
  year      = {2026},
  version   = {2.4.4},
  url       = {https://github.com/Vortx-AI/emem},
  license   = {Apache-2.0},
  publisher = {Vortx AI Private Limited}
}

@misc{emem2026,
  title     = {emem: A research on Content-Addressed, Verifiable Earth-Memory
               Protocol for AI Agents over Foundation-Model Embeddings},
  author    = {Kumari, Jaya and Singh, Avijeet},
  year      = {2026},
  doi       = {10.5281/zenodo.20706893},
  publisher = {Zenodo}
}

The preprint is open (CC-BY-4.0) and not yet peer-reviewed.

Contributing and license

Issues and pull requests welcome: CONTRIBUTING.md, SECURITY.md. Pure Rust, Apache-2.0 (LICENSE, NOTICE). Default data sources are open, with no API keys and no lock-in. A shared memory is worth more the more agents read and write it; if yours use emem, a star helps other builders find it.

Content address

Every section above this one is a unit of one signed tree: emem:tree:hwwmli4n726ervup6mew3ueflu, root eve3lluegc2r6zfoox34fj27zsqan7yr2i26kkgwvgzpmmsw5dja, published under the key k572x7go. A single section is emem:tree:hwwmli4n726ervup6mew3ueflu#row=<i>, so another agent can cite one part of this file and anyone can prove it was in the file as published:

curl -s "https://emem.dev/memories/by_attester/k572x7go/readme/tree-20261029.md" > index.md
curl -s "https://emem.dev/v1/tree/hwwmli4n726ervup6mew3ueflu?row=3" > row.json
python3 plugins/emem/skills/emem-tokenise-files/scripts/tree_proof.py check row.json index.md README.md

index.md is the signed note at /memories/by_attester/k572x7go/readme/tree-20261029.md. python3 scripts/readme_tree_check.py rebuilds the whole tree from this file and compares its root with the index, and CI runs it, so a README edited without re-signing fails the build. The tree changes whenever the README does, and this section is left out of it because it names the tree.

Available Tools

18 tools
emem_askAsk a free-text question about a placeAInspect

Answer a free-text question about a real-world location in one call. Signed satellite, elevation, water and built-up receipts support the answer. The tool sends the place and the question through the locate, recall and algorithm chain on the server, and returns one packaged envelope.

When to use: Call this when the question is about a specific place and the answer must carry its evidence. Send the question as q, with place, cell or lat+lng. Over MCP a point answer is a projection. It has answer, receipt (cite receipt.fact_cids), place_resolved, routed_to, facts_summary, algorithm_outcomes_summary, spatial_trace and scene_url. It has model_answer if you sent model, and _projection, which names what the projection removed. POST /v1/ask has more: caveats, topic_routing, reasoning, and inventory with include:["inventory"]. A routed_to other than answer comes back complete. The answer gives a current value. For how X changed, use emem_intent did_change or emem_diff.

Example arguments: {"q":"is this neighbourhood flood-prone for a flat purchase","place":"Ashok Nagar, Ranchi"}

NameRequiredDescriptionDefault
qYesUser's natural-language question about the place (e.g. "is this neighbourhood flood-prone").
latNoWGS-84 latitude (paired with `lng`; alternative to `place` / `cell`).
lngNoWGS-84 longitude (paired with `lat`).
cellNocell64 string (alternative to `place`, use when you have one from a prior emem_locate / emem_recall response). Provide this OR `place` OR `lat`+`lng`.
modelNoOptional. Compose an EXTRA prose answer with a named model, returned as `model_answer` beside the deterministic `answer`. It does not replace it: `answer` is synthesised from the structured fields and never calls a model, so every number in it traces to a fact_cid, and asking for a model must not turn a checkable answer into an unchecked one. `model_answer` carries provenance.class = model_output. Name it by base_model (`nvidia/Cosmos3-Edge`), by family (`cosmos3_edge`, `gemma`), or by any fragment naming exactly one of them (`cosmos`); a fragment matching several is refused and names them; an unroutable name is refused with the list of routable ones, and a routable model whose service is not answering is refused as busy or down rather than silently substituted. Cosmos is refused while its host has no GPU.
placeNoFree-text place name (e.g. "Mount Fuji", "Ashok Nagar, Ranchi"). REQUIRED unless `cell` or `lat`+`lng` is provided. Extract the noun phrase from the user's turn; the responder geocodes via OSM Nominatim.
queryNoAlias for `q`.
includeNoOpt-in REST envelope sections. `reasoning` drops `algorithms_for_question`; add `algorithms` to keep it. The MCP projection ignores these.
verboseNoREST only: true adds per-algorithm formulas, band metadata and long prose. The MCP projection is small (about 7 KB) either way; the REST envelope is larger.
questionNoAlias for `q`.
include_imageNoBundle a Sentinel-2 RGB scene URL for the resolved cell. Adds ~1-2 s on first call.

Output Schema

NameRequiredDescription
cellNoThe cell64 the question resolved to: emem's address for the place.
_meansNo
answerNoThe prose answer. Also in the content block, which carries the MCP projection; POST /v1/ask has the full envelope.
schemaYes
questionNoThe question as asked.
spatial_traceYesA spatial memory trace: what this responder has measured at this place, as primitives a model can reason over rather than a picture a person looks at.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only give safety hints (readOnlyHint=false, openWorldHint=true, idempotentHint=false, destructiveHint=false); the description goes well beyond them by disclosing the projection's shape, that `_projection` names what was removed, that a `routed_to` other than answer returns complete, and the model-routing refusal modes (ambiguous fragment, unroutable name, busy/down, Cosmos without GPU). It does not explain cost or why readOnlyHint is false for what reads as a query tool, so it is rich 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.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose and 'When to use', but then runs into a long unpunctuated enumeration of return fields ('It has `answer`, `receipt`, ... `spatial_trace` and `scene_url`') and a REST-vs-MCP differential ('POST /v1/ask has more: caveats, topic_routing, reasoning...') that is not actionable over MCP. Several sentences re-describe what the output schema already exposes rather than earning their place.

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 an output schema present the description need not explain return values, and it still covers when to use it, the location-parameter alternatives, model behavior and routing. Minor gaps remain: the possible `routed_to` values and their meaning, and any latency/rate context beyond the 'adds ~1-2 s' note in 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 description coverage is 100%, so baseline is 3; the description adds value by framing the mutually exclusive location inputs ('Send the question as `q`, with `place`, `cell` or `lat`+`lng`'), noting `model` yields an extra `model_answer` alongside the deterministic `answer`, and supplying a worked example of `q`+`place`.

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: 'Answer a free-text question about a real-world location in one call.' It also names the internal chain (locate/recall/algorithm) and explicitly distinguishes itself from emem_intent did_change / emem_diff for change-over-time questions, so an agent can separate it from siblings 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?

Opens with an explicit 'When to use: Call this when the question is about a specific place and the answer must carry its evidence,' including the location-input alternatives (`place`, `cell`, `lat`+`lng`). It also routes a named case away ('For how X changed, use emem_intent did_change or emem_diff'), giving both condition and alternative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

emem_echo_verifyCheck a value against the fact it cites, before you publish itA
Read-onlyIdempotent
Inspect

Grade a value that you will emit against the signed fact that your citation cites. The tool returns matches. When the value does not match, it also returns the drift between your value and the value in emem. This step catches a transcription error that would otherwise be a silent wrong number. A model can resolve a fact correctly and still type 0.2411 for 0.241103. No other step in the loop sees this. Memory algebra: the verify operation (https://emem.dev/docs/model.html).

When to use: Call this immediately before you publish, log or pass on a value from an emem fact. Treat a false matches as a stop, not a warning. Use value_verbatim from resolve: quote that exact decimal string, then echo-verify the text you emitted. For a due-diligence or compliance record, this gives a signed check for each citation. Then you can state every cited value was echo-verified. The tool also accepts a bare cid, so a damaged citation still gets a grade.

Example arguments: {"token":"emem:fact:defi.zb572.xoso.zb1ec:4qj3l4mgh7ch5kvxmkqspjdl6y42oqhm42khh3gostccpixkbz5q","claimed_value":"-0.0522"}

NameRequiredDescriptionDefault
tokenYesThe citation you used. Any form resolve accepts, including a bare cid, which answers with `degraded: true`: a bare cid asserts no location, so the cell-binding check is skipped and the grade covers the value only. A cid that is not 52 characters is refused as a damaged citation rather than as a missing one, and must not be retried.
strictNoRequire BYTE-IDENTICAL equality. Default false, which also accepts a numerically equal value spelled differently (0.50 for 0.5). It changes exactly one outcome: the numerically-equal-but-respelled case, which passes by default and becomes `drift: "reformatted"` here. `rounded` and `wrong` already fail either way, so `strict` never turns a pass into a pass. It is also inert when `claimed_value` came in as a JSON number, because the respelling then happened in the JSON parser, before this tool saw it.
claimed_valueYesThe value you are about to publish, as a string or a number. Send it as a STRING, character for character as you will emit it. A JSON number is stringified before the comparison, so `0.50` arrives as `0.5` and `0.2411000` as `0.2411` (measured against the live responder): the trailing digits this check exists to defend are gone before it runs. Quote `value_verbatim` from resolve as a string and echo the exact characters you will publish.

Output Schema

NameRequiredDescription
driftNoThe difference between what you wrote and what emem holds, when they disagree. Explicit null on an exact match: the key is always present, so branch on its value rather than on whether it exists. Declaring this `string` alone was a live schema violation on every matching call, which is how it was found.
tokenYesThe citation you passed, echoed back exactly as sent.
matchesYesWhether what you were about to publish agrees with the signed fact. Treat false as a gate, not a warning.
receiptNo
degradedNoTrue when a bare cid was passed and the cell binding could not be checked.
fact_cidNo
claimed_valueYesEchoed back, so a log line carries both sides of the comparison.
canonical_tokenNoThe token in its canonical spelling, whatever form you passed.
offline_verify_atNoWhere to re-run this check without trusting this responder.
resolved_value_verbatimNoThe fact's value as the exact decimal string it was signed as. Quote this rather than reformatting it.

TDQS

A4.5/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, closed-world), yet the description adds substantial behavior: it names the returned fields (matches, drift), explains the degraded bare-cid path, and documents the non-obvious JSON-number stringification caveat that silently destroys trailing digits. That is exactly the kind of 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?

The text is front-loaded with purpose, then when-to-use, then an example, so an agent can skim it. It is somewhat long and the string-vs-number warning is restated in both the prose and the schema, which is mild redundancy rather than wasted content.

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?

Coverage is complete: an output schema exists so return values need not be explained (they are, briefly, anyway), annotations handle safety, and the description supplies the timing, the failure interpretation, and the degraded-mode behavior. 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?

Schema description coverage is 100% and the schema already explains token, strict and claimed_value in depth, so the baseline is 3. The description adds marginal value: a concrete example argument and an emphatic directive to send claimed_value as a string quoting value_verbatim, which reinforces the single most consequential parameter choice.

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 gives a precise verb and resource: it grades an emitted value against the signed fact the citation points at, and explicitly claims a unique role ('No other step in the loop sees this'). That is a sharp functional statement, but it never names or contrasts the obvious sibling emem_verify_receipt, so an agent choosing between the two gets no explicit routing help.

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 states exactly when to call ('immediately before you publish, log or pass on a value from an emem fact'), how to source the input ('Use value_verbatim from resolve'), and how to interpret the result ('Treat a false matches as a stop, not a warning'). It also names the downstream condition (due-diligence/compliance records) and notes the bare-cid fallback, leaving little to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

emem_entityMint or get a canonical object identityA
Idempotent
Inspect

Give a real-world object (a bridge, a farm plot, a river, a named place) one shared identity. Every agent resolves this identity the same way. The result is an entity_token (emem:entity:<entity_cid>) and a signed receipt that shows how the reference resolved. Two agents that name the same object get the SAME entity_cid. A stable external id (Overture GERS or OSM) decides identity when the responder knows one, so different labels for one object collapse to one id. This stops referential drift: 'the damaged bridge near the river' becomes one thing that every model reasons about.

When to use: Call this when a conversation refers to a THING and you need a handle that travels between agents. Anchor it with place, cell or lat+lng. Give the emem:entity: token to a peer, and the peer gets the same object. Recall at its cell64 to read signed facts. Choose the correct sibling: this tool MINTS or returns an identity. emem_entity_resolve finds an identity that an agent registered before, from a fuzzy phrase. emem_entity_link records that two names mean one object. Do not use it for an observation (use emem_recall or emem_memory_token) or for a place (use emem_locate). An entity is a thing AT a place.

Example arguments: {"label":"Golden Gate Bridge","kind":"bridge","place":"Golden Gate Bridge, San Francisco"}

NameRequiredDescriptionDefault
latNoLatitude anchoring the object to a place, paired with lng. The identity is hashed from this anchor, so two agents anchoring the same object differently mint different entities.
lngNoLongitude, paired with lat.
cellNocell64 to anchor the object directly (no geocode).
kindNoObject class: bridge, river, farm_plot, building, admin_division, place, custom, ... Defaults to "place".
labelYesHuman name of the object, e.g. "Golden Gate Bridge", "the north dam". Required.
placeNoFree-text place to anchor the object (geocoded). Provide place OR cell OR lat+lng.
parentNoOptional parent entity_cid (containment).
attesterNoed25519 binding, verified. Omit it and the refusal's details.how_to_sign gives the digest to sign.
external_idsNoStable ids that drive convergence. Caller-supplied values win over geocoder-derived ones.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations (idempotentHint=true, destructiveHint=false, openWorldHint=true), the description discloses convergence semantics (two agents naming the same object get the SAME entity_cid; differing anchors mint different entities), external-id priority over geocoder-derived ids, and the auth path for the attester signature including what happens on refusal ('details.how_to_sign gives the digest to sign'). This is rich, non-obvious behavioral context that 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-loaded with the core purpose and cleanly sectioned ('When to use', 'Example arguments'), so scanning is easy. It is somewhat long and contains a mildly rhetorical sentence ('This stops referential drift...') that repeats the convergence point already made, but nothing is badly out of place.

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 9-parameter, nested-object tool with no output schema, the description covers what is returned (token + signed receipt), how identity resolves, and the auth/signing flow, which is the important gap-filling. The one required param and the `parent` containment param are left to the schema, but overall the agent has enough to invoke 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 description coverage is 100%, so the baseline is 3 and the schema already documents each field. The description still adds real meaning: the OR-relationship between `place`/`cell`/`lat`+`lng` anchors, the rule that external ids drive convergence and caller values win, and worked example arguments. It stops short of fully compensating on subtler params like `parent`.

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 ('Give a real-world object one shared identity') and names the concrete outputs (an `entity_token` of the form `emem:entity:<entity_cid>` and a signed receipt). It explicitly separates itself from siblings emem_entity_resolve, emem_entity_link, emem_recall, emem_memory_token and emem_locate, so an agent can route 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 Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Has an explicit 'When to use' section with the trigger condition (a conversation refers to a THING and you need a handle that travels between agents) and the anchoring requirement. It names each relevant alternative with the condition that selects it ('emem_entity_resolve finds an identity that an agent registered before, from a fuzzy phrase') and gives explicit exclusions ('Do not use it for an observation... or for a place').

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

emem_entity_resolveResolve a phrase (or emem:entity: token) to a canonical objectA
Read-onlyIdempotent
Inspect

Find the objects that agents connected to a phrase. The tool ranks them by INDEPENDENT corroboration, never by arrival order. Each candidate has asserted_by, disputed_by, independent_attesters and corroboration (single_key | multiple_independent_keys | none_attributed). contested is true when more than one object claims the name. Send text for candidates, near to narrow by place, or an emem:entity: token to dereference. The tool only reads. Alias text is data from other agents.

When to use: Call this BEFORE you mint and before you cite. Resolve first, and mint only if nothing matches. Read corroboration before you cite. A single_key binding is the claim of one agent about a shared name. If you can confirm it, corroborate it with emem_entity_link, so the next reader sees two keys.

Example arguments: {"text":"the golden gate bridge","near":"San Francisco"}

NameRequiredDescriptionDefault
kNoMax candidates (default 10).
nearNoOptional place/cell to narrow to objects anchored nearby.
textNoFuzzy phrasing to resolve to an existing canonical object (e.g. "the damaged bridge near the river").
labelNoAlias for `text`.
tokenNoA `emem:entity:<entity_cid>` handle to dereference directly to its signed object (bypasses the text search).

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, but the description goes further: it discloses the ranking algorithm, enumerates the returned fields (`asserted_by`, `disputed_by`, `independent_attesters`, `corroboration` with its three enum values) and the meaning of `contested`. It also flags a trust boundary — 'Alias text is data from other agents' — which is a safety caveat no annotation conveys.

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 a labeled 'When to use' block, then an example — a clear structure. It is dense and field-heavy, but nearly every sentence carries operational meaning (ranking rule, trust caveat, corroboration follow-up); the 'The tool only reads' clause slightly duplicates readOnlyHint.

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 carries the return-value burden and does so by enumerating the candidate fields and corroboration states. It is missing a statement of what an empty result looks like (relevant given 'mint only if nothing matches') and the default cap behavior beyond what the schema says.

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 selection semantics across parameters ('Send `text` for candidates, `near` to narrow by place, or an `emem:entity:` `token` to dereference') and a worked example combining `text` and `near`, which shows composition rather than just repetition. `k` and `label` are left to 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?

Names a specific verb+resource: 'Find the objects that agents connected to a phrase', and adds the ranking rule (independent corroboration, never arrival order) so the agent knows what kind of result set to expect. It also clarifies the two modes — text/near search vs. `emem:entity:` token dereference. It does not explicitly contrast with similarly-scoped siblings like emem_entity, emem_recall, or emem_find_similar, which keeps it from 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?

Explicit sequencing: 'Call this BEFORE you mint and before you cite. Resolve first, and mint only if nothing matches.' That is both a when-to-use rule and a when-not-to-mint exclusion. It also names the follow-on tool (emem_entity_link) and the condition for calling it (a `single_key` binding you can confirm).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

emem_find_similark-NN over the corpus by embeddingA
Idempotent
Inspect

Find the k nearest cells in the corpus by cell embedding or by an inline vector. The answer has neighbors, nearest first, each with cell, score, lat/lng and band_used, and a signed receipt over the vectors it read. mode sets the scoring. cosine is exact fp32. hamming counts sign bits and scans many more cells for the same budget. hamming_then_rerank does both. k is 1 to 1000, default 10. The tool ranks only what the corpus holds. When the KEY has no vector, it materializes that one band for the key, signs it, reports it in materialize_notes, and tries again. It never materializes neighbours. Thus an empty result means that no attested vector is near, not that no place is similar.

When to use: Call this for 'find places like X' or 'where else looks like this', or with an embedding. key is a cell64 or inline:[x,y,...]. The default band is geotessera (the 128-D Tessera foundation embedding). For the 1152-D fusion of 9 years (2017 to 2025), send band: "geotessera.multi_year".

Example arguments: {"key":"defi.zb64a.cAzU.zfa27","k":10}

NameRequiredDescriptionDefault
kNoHow many neighbours to return.
keyYescell64 (look up that cell's vector) or 'inline:[x,y,...]' literal vector
bandNovector band to scan (default: 128-D Tessera foundation embedding). For mode=hamming/hamming_then_rerank you can pass either the cosine band (e.g. 'geotessera') or its binary sibling ('geotessera.bin128'), the responder picks the right one.geotessera
cellNoAlias for `key`.
modeNoScoring mode. cosine = fp32 over full vector (precise, ~256 B/cell scan). hamming = sign-bit popcount over the binary sibling band (~16 B/cell, ~1000× faster, ~65% recall@10). hamming_then_rerank = triage with Hamming on 4·k candidates then re-rank by cosine, matches cosine precision at ~16× less work.cosine
scopeNoMulti-tenant scope `{user_id, agent_id, run_id, org_id}`. Setting it bypasses the ANN index entirely, because that index carries no scope column, and runs the brute-force scan instead: the tenant filter is honoured truthfully, and the call is slower.
cell64NoAlias for `key`.
filterNoClaim-algebra predicate evaluated against every candidate before ranking. A cell with no fact for the filter's band is DROPPED rather than treated as false, so 'places like X where NDVI > 0.5' never silently includes cells with no NDVI.
as_of_tslotNoBi-temporal valid-time bound. Applied to candidate cells BEFORE cosine scoring, a cell with no fact whose tslot ≤ as_of_tslot under the scoring band is dropped from the candidate pool (undecidable→drop). When set, the Lance ANN fast-path is bypassed (the index has no signed_at column); brute-force k-NN runs instead so as_of is honoured truthfully.
as_of_signed_atNoBi-temporal transaction-time bound (RFC 3339). Also applied to candidates BEFORE cosine. Same Lance-bypass note as as_of_tslot.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Discloses non-obvious behaviour well beyond the annotations: it materializes and signs a band for the key when absent (reported in materialize_notes), never materializes neighbours, bypasses the ANN fast-path under scope/as_of filters, and explains that an empty result means no attested vector is near rather than no similar place. This is consistent with readOnlyHint=false and 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-loads the operation, then output shape, then mode/band selection, then a 'When to use' block and an example. Dense but every paragraph carries information; the mode exposition is slightly repetitive with the schema enum descriptions.

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 (neighbors, cell, score, lat/lng, band_used, signed receipt) and the edge-case semantics (empty result, materialize_notes). For a 10-parameter tool with nested objects, 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.

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: 'k' bounds (1–1000, default 10), the concrete band names for the 1152-D multi-year fusion, and the relationship between key/inline vectors. It mirrors some schema content rather than always exceeding it, so a 4 rather than 5.

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 ('Find the k nearest cells in the corpus by cell embedding or by an inline vector') and names the exact discriminating concept (k-NN over embeddings) versus the rest of the emem_* family. The agent can tell this apart from emem_recall/emem_locate 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 Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

An explicit 'When to use' section maps natural utterances ('find places like X') to the tool, and it routes between bands (geotessera vs geotessera.multi_year) and modes. It never names a sibling alternative or states when not to use this tool, 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.

emem_guard_verdictCheck whether the citations in a draft actually verifyA
Read-onlyIdempotent
Inspect

Run the emem-guard policy checks on text before you send it. The checks use this responder's corpus. The tool finds every emem: citation, resolves each one, and returns allow or deny with a reason that a machine can read: EMEM-GUARD DENY <CODE> token=<token|-> fix=<fix> leaf=<leaf|->. The codes are: PROV_SIG (the signature did not verify). PROV_BYTES (the citation resolved to different content). PROV_DRIFT (the reading moved past its band threshold). PROV_VALUE (a stated value does not agree with the cited fact). CLAIM_UNGROUNDED (a measurable claim has no citation; turn it on with claim_gating). fix tells you what to do: refresh_token, remove_reference, contact_admin, cite_observation, correct_value. Only a self-hosted guard returns GEO_ZONE and redact_and_retry. This tool is ADVISORY: it blocks nothing. A citation that this responder does not hold is never a denial, because it can be a citation from another responder. Memory algebra: the verify operation (https://emem.dev/docs/model.html).

When to use: Call it on your draft before you assert something, or on a tool result before you reason on it. Then you can fix a citation that does not resolve. With claim_gating: true, it also names measurable claims with no citation, and the band that answers each. For a payload from another framework (CloudEvent, OPA input, OpenAI moderations body, a tool call from another server), send it unchanged and name its shape. The default reader reads only texts, and a check that read nothing answers allow. To ENFORCE the policy, use emem_guard_selfhost. It returns the procedure for your own node.

Example arguments: {"texts":["Lusail ground sits at 2.6 m per emem:fact:defi.zb521.jawI.gOze:f3yr3urkrfwamlemwadulgth2qpw645vi6l6fhtuu4dy5o7onahq"]}

NameRequiredDescriptionDefault
agentNoOptional free-text label for who is asking. Advisory only, never a trust boundary.
shapeNoWhich envelope YOUR payload is in, so you never have to reshape it to ask the question: send the body your own framework produced and name its shape. native reads `texts`; `mcp` reads a JSON-RPC tools/call or tool result; `openai` reads a moderations (`input`) or chat-completions body; `cloudevent` reads a CloudEvents 1.0 structured event; `policy` reads {input}. It matters: a CloudEvent whose citation sits at data.text is invisible to the native reader, and a check that read nothing answers `allow`, so confirm `citations_found` matches what you sent. Unrecognised values fall back to native rather than erroring. This selects how the body is READ only — the verdict always comes back in this tool's declared output shape, because a tool that declares an outputSchema owes conforming structuredContent. To get the ANSWER translated into the same envelope too (an OPA `result:{allow,deny}`, an MCP CallToolResult to substitute on a deny), call POST /v1/guard/verdict?shape=… directly.native
textsNoFree text to check, and the only input this tool needs. Send just the pieces the question is about: a draft answer, a tool result, one turn. Do not send surrounding conversation, because nothing here reads it and a checker should ask for the smallest input that answers the question.
claim_gatingNoAlso flag measurable physical-world claims that carry NO citation (deny code CLAIM_UNGROUNDED, fix cite_observation). Off by default: it reports on the absence of a citation rather than on a failed check. The verdict names the sentence, the magnitude, and the emem band that would answer it.

Output Schema

NameRequiredDescription
fixNoThe actionable half: what to change and retry.
codeNoPresent only on a deny.
claimNoOn CLAIM_UNGROUNDED: the sentence, magnitude, quantity, anchor, and source_band. source_band is a recallable band key, or null when this responder observes no band in that quantity.
actionYesNOT a clearance. `allow` means no rule fired, which on a transcript that cited nothing is silence rather than approval. Branch on citations_found and receipt.fact_cids.
checkedYesHow many were actually resolved, bounded by the verdict budget.
receiptYesed25519 receipt. `fact_cids` lists what actually resolved and is the field that separates a real citation from an invented one.
advisoryYesTrue on the hosted route, where nothing is blocked. Run your own node to enforce.
citationsNoEach citation and what it came to here: verified, signature_failed, byte_mismatch, not_held_here (minted elsewhere or nonexistent: resolve it where it was minted before relying on it), or drifted.
citations_foundYesHow many emem: tokens were found in the text. Compare with receipt.fact_cids: a well-formed token that resolved to nothing counts here and not there.
citations_verified_hereNoHow many of the citations this responder holds and verified.

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, but the description adds substantial behavioral context: this is ADVISORY and blocks nothing, a citation the responder does not hold is never a denial, unrecognised shape values fall back to native rather than erroring, and GEO_ZONE/redact_and_retry appear only on a self-hosted guard. The enumerated deny codes and fix tokens go well beyond what any annotation conveys.

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?

It is front-loaded with what the tool does before the code glossary and usage rules, and most sentences carry operational payload (codes, fix tokens, the empty-read-answers-allow trap). It is nonetheless long, and a few points (the shape fallback, the read-only-texts caveat) echo the schema descriptions rather than adding new 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?

For a complex, multi-mode policy checker with four optional parameters, an output schema, and full annotation coverage, the description is complete: it covers input shape selection, advisory semantics, the full deny-code vocabulary, and the escape hatch to the enforcing tool. An agent has everything needed to invoke it correctly and interpret the result.

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 earns above that by supplying worked example arguments, explaining that claim_gating names the sentence, magnitude, and band, and stressing that texts should carry only the smallest input the question needs. It adds real semantic color rather than repeating 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?

The description gives a specific verb and resource chain — it finds every emem: citation, resolves each one, and returns allow/deny with a machine-readable reason — which is far more than a restatement of the name. It clearly differentiates itself from the enforcing counterpart (emem_guard_selfhost) and from raw API use, but it never distinguishes itself from the verification-flavored siblings actually in the list (emem_echo_verify, emem_verify_receipt), leaving that ambiguity open.

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?

There is an explicit 'When to use' clause (on a draft before you assert something, or on a tool result before you reason on it) plus a clear alternative and its selection condition ('To ENFORCE the policy, use emem_guard_selfhost'). It even supplies the negative guidance an agent needs — send an external payload unchanged and name its shape, and note that a check which read nothing answers allow.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

emem_intentIntent-routed plannerAInspect

State what you want in one typed object and get the answer. You do not choose a primitive. type selects the intent AND the other fields that the tool reads. Send only the fields in its row. The plan runs in the same call: you get results, not a list of calls.

type | needs | optional | answers where_is | description | | cell64 for a named place what_is_here | cell OR place | description | what is attested at a location is_like | a, b | | cosine similarity of two cells did_change | cell, band, window | | delta for one band over [start,end] tslots find_like | key | k, filter | nearest cells by embedding confirm | claim, cell | | verdict and the signed facts behind it ask | description | place/cell/lat+lng | free-text question, packaged answer area_over_time | geometry, bbox OR areas; start_date, end_date | index, max_scenes | index of an area for each overpass, with spread and anomaly

An unknown or missing type returns a needs_intent_type envelope with the valid values. It is not a hard error.

When to use: Call this when the question matches one of the eight rows and you prefer to state the goal. Otherwise call the primitive. A band at a cell is emem_recall. A region is emem_recall_polygon. A free-text question about a place is emem_ask (type:"ask" sends it there). window takes tslots, not dates: get them from emem_trajectory. areas puts up to 6 areas on one chart. You can call a tool that this text names but your list does not show, by name, through tools/call.

Example arguments: {"type":"did_change","cell":"defi.zb64a.cAzU.zfa27","band":"indices.ndvi","window":[20245,20620]}

NameRequiredDescriptionDefault
aNois_like only: cell64 of the first place in the pair.
bNois_like only: cell64 of the second place. The answer is a cosine similarity in [-1,1] over the two cells' embeddings.
kNofind_like only: how many neighbours to return.
keyNofind_like only: cell64 to search from, ranked by embedding cosine.
latNoask only: latitude, paired with `lng`, when you want to pin the location by coordinate rather than by name or cell64.
lngNoask only: longitude, paired with `lat`.
bandNodid_change only: which band to test, e.g. "indices.ndvi". One band per call; the answer is a delta over `window`, not a whole-cell diff.
bboxNo
cellNocell64 address, e.g. "defi.zb64a.cAzU.zfa27". Required by did_change and confirm. Optional for what_is_here and ask: supply it to skip geocoding, omit it and give `place` instead.
typeYesWhich intent; the table in the description gives each row's fields.
areasNoarea_over_time: up to 6 {id,geometry|bbox} on one chart
claimNoconfirm only: the claim to test at `cell`, e.g. {"band":"indices.ndvi","op":"gt","value":0.4}. The answer is a verdict plus the signed facts it rests on.
indexNo
placeNoFree-text place name for what_is_here and ask when you have a name but no cell64, e.g. "Ashok Nagar, Ranchi". The responder geocodes it. Ignored when `cell` is present.
filterNofind_like only: optional claim constraining which cells may be returned. Same object as `claim` below, same ops, same required fields.
windowNodid_change only: exactly two tslots, [start, end], band-tempo-relative integers from the emem epoch (NOT unix seconds or a date string). Get valid tslots for a cell from emem_trajectory.
end_dateNoYYYY-MM-DD
geometryNoarea_over_time: GeoJSON Polygon; or bbox {min_lat,min_lng,max_lat,max_lng}.
max_scenesNo
start_dateNoYYYY-MM-DD
descriptionNowhere_is: the place to resolve, e.g. "Mount Everest". ask: the user's question, forwarded verbatim. what_is_here: optional free text used as the question and, if `place` is absent, as the place. Ignored by the other intents.

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations, the description discloses several behavioral traits: an unknown/missing type returns a needs_intent_type envelope rather than a hard error, the plan executes in the same call (results, not a call list), `window` is tslots not dates and must be sourced from emem_trajectory, and `areas` caps at 6. It does not address the tension that annotations set readOnlyHint=false for what reads as a query/answer tool, nor does it describe latency or limits.

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 a compact table, then when-to-use, then an example. Given 21 parameters and 8 intents this density is justified, though a couple of parenthetical asides ('type:"ask" sends it there') and the repeated window/tslot warning add minor redundancy.

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 21-parameter tagged-union tool with nested objects and no output schema, the definition is complete: the table's 'answers' column conveys the return semantics per intent, the error envelope behavior is stated, cross-tool dependencies (emem_trajectory for tslots) are called out, and an example argument object is provided.

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 already 86%, so the schema carries most per-field meaning. The description still adds real value with the routing table mapping each `type` to its needs/optional fields, the instruction to send only the fields in the row, the note that `window` values are epoch-relative tslots (not unix/date strings), and a worked example. It stops short of documenting every field, so it complements rather than replaces 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?

The description states a specific verb and resource ('State what you want in one typed object and get the answer'), then enumerates the eight intent rows with their required/optional fields and answers. It explicitly distinguishes itself from siblings (emem_recall, emem_recall_polygon, emem_ask), so an agent can route without opening other 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?

There is an explicit 'When to use' block: use this when the question matches one of the eight rows and you prefer to state the goal, otherwise call the primitive. Concrete alternatives are named per case (a band at a cell -> emem_recall, a region -> emem_recall_polygon, free text -> emem_ask), plus the note that named tools can be invoked through tools/call.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

emem_locateResolve place to cell64 + band inventoryA
Read-onlyIdempotent
Inspect

Get the canonical address (cell64) of a real-world place. Every agent resolves a place to the same cell64, so two models refer to the same ground. The answer also lists, by topic, the bands and algorithms that you can recall there. For an OBJECT identity (a bridge, a plot) instead of a cell, use emem_entity. Send lat+lng as numbers, or a free-text place. When both arrive, the coordinates win. q, query and name are other names for place. The answer lists keys that this schema does not declare in _unrecognised_arguments, so a typo is visible.

When to use: Call this when the next step needs the cell64 of a named place, or the bands that exist there. data_at_this_cell lists every band you can recall, by topic (live_bands_by_topic), the recipes that use them (algorithms_for_topic), and the bands with no materializer here. For one packaged answer in one call, use emem_ask.

Example arguments: {"place":"Mount Everest"}

NameRequiredDescriptionDefault
qNoAlias for `place`, accepted because OSM/Mapbox/Google Geocoding all use `q`. Provide either this or `place` (or `lat`+`lng`).
latNoWGS-84 latitude in degrees, paired with `lng`. REQUIRED with `lng` unless `place`/`q` is provided.
lngNoWGS-84 longitude in degrees, paired with `lat`. REQUIRED with `lat` unless `place`/`q` is provided.
nameNoAlias for `place`.
placeNoFree-text place name (e.g. 'Mount Everest', 'Tokyo'). REQUIRED unless `lat`+`lng` is provided. Aliases also accepted: `q`, `query`, `name`.
queryNoAlias for `place`.

Output Schema

NameRequiredDescription
nextYes
cell64NoPass as `cell` to emem_recall.
statusNoneeds_location: no place named.
selectedNo
place_labelNo
data_at_this_cellNo

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/openWorld/idempotent/non-destructive, so the safety profile is covered. The description adds genuinely non-structured behavior: deterministic resolution ('every agent resolves a place to the same cell64'), input precedence ('when both arrive, the coordinates win'), and that unrecognised keys surface in `_unrecognised_arguments` so typos are visible. It stops short of error/rate-limit behavior, so not 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 purpose and an efficient usage block, with a concrete example argument. Slightly verbose: the alias sentence ('q, query and name are other names for place') restates what the 100%-covered schema already documents, which is minor redundancy.

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?

An output schema exists, so return values needn't be enumerated, yet the description still characterizes the answer (bands/recipes by topic). With 6 optional params all documented, annotations covering safety, and precedence plus alias behavior explained, 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 description coverage is 100%, so baseline is 3. The description adds a precedence rule absent from the schema (coordinates win over free text when both arrive) and consolidates the alias set, giving an agent information the schema fields do not encode.

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: 'Get the canonical address (cell64) of a real-world place', plus what else the answer contains (bands/algorithms by topic). It explicitly distinguishes itself from the sibling emem_entity ('For an OBJECT identity ... instead of a cell, use emem_entity'), so an agent can route 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?

A dedicated 'When to use' block names the trigger condition (next step needs a cell64 or the bands there) and names two alternatives with their selecting conditions: emem_entity for object identity, emem_ask for a single packaged answer. When-not and alternatives are both explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

emem_memory_bundleCompose a signed multi-fact memory bundleA
Idempotent
Inspect

Combine N (cell, band, tslot?) triples into ONE signed envelope. Each triple goes through the standard recall path, which materializes on a miss. The tool puts the resulting fact_cids in a content-addressed envelope, and the responder signs the full receipt. The bundle_token is emem:bundle:<bundle_cid>: one string that cites the full set. Memory algebra: the merge operation (https://emem.dev/docs/model.html).

When to use: Call this when you must cite several (place, band, date) facts as one handle. You can verify the bundle offline with /v1/verify_receipt. The receipt covers all the cited fact_cids and cells. Use this instead of N calls to emem_memory_token when the citation is one thing. An example is "the EUDR baseline for these 8 plots at 2020-12-31". The limit is 256 triples for each call. The answer gives members and resolved, so you can see a bundle that resolved only in part.

Example arguments: {"triples":[{"cell":"defi.zb4d9.pefa.zf619","band":"copdem30m.elevation_mean"},{"cell":"defi.zb493.xoso.zcb6a","band":"indices.ndvi"}],"purpose":"audit baseline 2026"}

NameRequiredDescriptionDefault
scopeNoMulti-tenant scope `{user_id, agent_id, run_id, org_id}`, applied to EVERY triple's underlying recall so the whole bundle cites only facts written under that four-tuple.
purposeNoOptional human-readable purpose string. Included in the bundle_cid preimage so the same triples + different purposes produce distinct CIDs.
triplesNoOne to 256 (cell, band, tslot?) triples to bundle. Each entry is recalled through the standard auto-materialize path; the bundle envelope cites every resulting fact_cid. 257 or more is a typed 400: the token is O(1) in size for any N, but covering N facts costs ceil(N/256) calls, so plan round trips rather than meeting the cap mid-run.
fact_cidsNoInstead of triples: the exact facts to bind, by cid. A triple is resolved through recall and can bind a newer fact than the one you showed; a cid binds that fact and no other. Pass triples or fact_cids, not both.

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare idempotentHint=true, destructiveHint=false, and readOnlyHint=false; the description's note that each triple goes through recall and 'materializes on a miss' usefully explains the non-read-only side effect. It also discloses the 256-triple cap and that partial resolution is surfaced via `members`/`resolved`, going beyond the annotations, though it does not spell out permission or authorization requirements.

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 handle format are front-loaded, followed by when-to-use, limits, and an example — a sensible order. It is dense with domain jargon (cell/band/tslot, bundle_cid preimage, memory algebra), which costs a little readability, but no sentence is pure 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?

Despite no output schema, the description covers the return shape ('members' and 'resolved' for partially resolved bundles), the bundle_token format, the 256 cap with a note on round-trip planning, and the offline verification path. For a nested-object, multi-mode tool this is complete enough that an agent can invoke and interpret 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, but the description adds real meaning: it distinguishes that a triple 'is resolved through recall and can bind a newer fact than the one you showed' while a cid 'binds that fact and no other' (triples vs fact_cids), and supplies worked example arguments. The mutually exclusive triples/fact_cids contract is reinforced rather than merely repeated.

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 first sentence gives a specific verb and resource ('Combine N (cell, band, tslot?) triples into ONE signed envelope'), and the later text explicitly differentiates from the sibling emem_memory_token ('Use this instead of N calls to emem_memory_token when the citation is one thing'). An agent can select this tool over its siblings 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 Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

A dedicated 'When to use' block states the trigger condition ('when you must cite several (place, band, date) facts as one handle'), names the alternative it replaces, and gives a concrete example ('the EUDR baseline for these 8 plots at 2020-12-31'). It also points to /v1/verify_receipt for follow-up verification, so the decision path is complete.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

emem_memory_contradictionsScan for multi-attester disagreementA
Read-onlyIdempotent
Inspect

Find where the corpus DISAGREES with itself (algebra: competing evidence). Two or more independent sources can sign different values for the same place, band and time. This tool returns that disagreement with a severity from 0 to 1 and a citation for each disputed fact. It does not pick one value and hide the conflict. It tells you when not to trust a single answer. Read the SCOPE before you quote a zero. By default the tool counts only disagreement between two DIFFERENT attesters. One responder that answers from two upstreams counts only with include_same_attester_sources: true.

When to use: Call this before you rely on a number: 'do the sources agree on X', 'audit this claim'. Use cell_prefix for a region and band for one band family. min_severity removes small differences. Severity depends on the band kind: for a scalar, the spread over the band's range. For a vector, 1 minus the mean cosine. For a category, 1 minus the share of the mode. On a single-responder node, add include_same_attester_sources: true. There, the most likely disagreement is one signer that answers from two providers. Each record names its disagreement_scope. The receipt cites every disputed cid. To measure a pair, use emem_diff. To read the disagrees_with edge, use emem_edges_recall.

Example arguments: {"cell_prefix":"damO","band":"indices.ndvi","min_severity":0.2}

NameRequiredDescriptionDefault
bandNoBand key filter (e.g. `indices.ndvi`). Omit to include all bands.
cellNoAlias for `cell_prefix`, and the spelling the rest of the surface uses for a cell64. Send a cell64 you already hold and the scan narrows to that place instead of running over the corpus.
limitNoMax contradictions to return.
cell64NoAlias for `cell_prefix`.
cell_prefixNoA cell64 to scan, or a bytewise prefix of one (e.g. `defi.zb5f9`). Omit to scan the whole corpus up to the scan cap. A full cell64 is a prefix of itself, so passing one narrows the scan to exactly that place.
min_severityNoSeverity floor in [0, 1]. 0 = report every disagreement, 1 = only flagrant. Severity scoring is per band kind: scalar (max-min over band range), vector (1 - mean cosine), categorical (1 - mode share).
window_unix_sNo[lo, hi] inclusive Unix-seconds filter on attestations' signed_at, all disagreeing attestations must fall in the window.
include_same_attester_sourcesNoAlso report keys where ONE attester answered the same address from two different upstreams. Default false, which scans only for disagreement between two or more DISTINCT attesters — so on a single-responder corpus a zero here means the narrower question was answered, not that nothing disagrees. Set true and a key qualifies when the facts differ in `derivation.fn_key` or in their `sources[].scheme` set; the same provider re-signed is a refresh, not a disagreement, and stays excluded. Each record carries `disagreement_scope` and a `providers[]` list naming what changed.

TDQS

A4.8/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 goes well beyond that: it warns not to pick a value and hide conflict, cautions to read the SCOPE before quoting a zero, explains the default only counts distinct attesters, and defines what qualifies as disagreement versus a mere refresh. This is exactly the extra behavioral context 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 purpose, then usage, then mechanics, then alternatives and an example — a sensible ordering for an 8-parameter tool. It is dense and slightly redundant, restating the band-kind severity formula that also appears in the min_severity schema description, but no sentence is truly wasted.

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 still describes the return shape (severity 0-1, a citation per disputed fact, disagreement_scope on each record, every disputed cid cited in the receipt). Combined with full schema coverage and clear defaults, an agent has everything needed to invoke and interpret the result.

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: it explains the per-band-kind severity formula, the role of cell_prefix/band for narrowing, and the semantics of include_same_attester_sources including the derivation.fn_key and sources[].scheme conditions. The example arguments further clarify how the filters compose.

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 — find where the corpus disagrees with itself — and immediately defines what 'disagreement' means (two or more independent sources signing different values for the same place, band and time). It also distinguishes itself from siblings by naming emem_diff and emem_edges_recall as different operations, so an agent can tell it apart without opening 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 Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit when-to-use trigger ('do the sources agree on X', 'audit this claim') and routes to alternatives for adjacent needs ('To measure a pair, use emem_diff', 'To read the disagrees_with edge, use emem_edges_recall'). It also states the precise condition for the non-default mode: on a single-responder node, add include_same_attester_sources: true.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

emem_memory_tokenCompose a memory_token citation handleA
Read-onlyIdempotent
Inspect

Make a citation handle, emem:fact:<cell64>:<fact_cid> (or :<state_cid>). Any agent or LLM resolves it to the same signed object, byte for byte. Give this one string to another agent instead of a new description of the fact. The tool checks that both parts are not empty and do not contain the : separator. Memory algebra: the cite operation (https://emem.dev/docs/model.html).

When to use: Call this when you need one string that cites a place and an attested fact across messages, agents or tools. Use emem_echo_verify before you publish the value. FOR MANY FACTS, USE emem_memory_bundle. This is a measured result. A token is 83 to 84 characters and 51 LLM tokens. The value it cites is 11 characters and 5.4 tokens on average. Thus N tokens use about 9.5 times the context of the N numbers. A bundle is 38 characters for any N up to 256, and it resolves in one round trip. It costs less than tokens from N=1, and less than the plain values from N=5. Use one token to cite ONE fact that you must verify later.

Example arguments: {"cell":"defi.zb493.xoso.zcb6a","fact_cid":"cxjiu7l54ujzrpnekp24n4534yojpue4mprddbvevnqtti3lh5bq"}

NameRequiredDescriptionDefault
bandNoOptional band key. When set, the minted citation carries the band's tamper-provenance block (class, deterministic, tamper_evidence, trust_rank) so the receiving agent sees the trust class without a resolve round-trip.
cellYescell64, neither component may contain `:`.
fact_cidYes52-char base32-nopad-lowercase content-id of the fact (full 32-byte blake3).
observed_onNoThe fact's source capture date (YYYY-MM-DD) as `/v1/recall` reports it in `sources[].captured_at`. Supplied together with `band` it additionally mints the self-describing `descriptor_token`. A wrong date forges nothing: resolve binds the date to the signed fact and answers 409 on a mismatch.

Output Schema

NameRequiredDescription
cellYes
docsNo
grammarNoThe token grammar, so the form can be parsed rather than pattern-matched.
fact_cidYes
cell_tokenNoThe address alone, when you mean the place rather than an observation of it.
memory_tokenYesThe citation to paste: emem:fact:<cell64>:<fact_cid>. Copy it verbatim; a hand-assembled token that is one character wrong still reads as a citation and resolves to nothing.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover readOnly/idempotent/non-destructive. Description adds valuable context: byte-for-byte resolution, validation of non-empty parts and no `:` separator, and context-cost tradeoffs. Doesn't fully detail the band/observed_on provenance behavior but schema covers much of it.

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?

Format and example are well front-loaded, but the token-cost math (83-84 chars, 51 LLM tokens, 9.5x context) is lengthy and arguably belongs in the sibling bundle's description or docs; it dilutes the core call guidance.

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?

Output schema and full param schema carry the detail burden; description gives enough context to call correctly. Minor gap: doesn't explain when to supply the optional band/observed_on together versus alone.

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 the schema already documents all four parameters in detail (band, observed_on, cell pattern, fact_cid format). Description adds the `:` separator constraint but little else beyond the schema; 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 (Make a citation handle) and gives the exact token format `emem:fact:<cell64>:<fact_cid>`. Clearly distinguishes itself from emem_echo_verify and emem_memory_bundle by naming both.

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 section, names emem_echo_verify before publishing, and routes multi-fact cases to emem_memory_bundle with concrete token-cost reasoning for when each applies.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

emem_memory_token_resolveDereference a memory_token in one round-tripA
Read-onlyIdempotent
Inspect

Read a emem:fact:<cell64>:<fact_cid> citation handle and return the reading that it cites. value, unit, band and kind are at the TOP level of the answer, beside the full signed fact body. You do not split the token or call GET /v1/facts/<cid> yourself. Memory algebra: the resolve operation (https://emem.dev/docs/model.html).

When to use: Call this when you have a memory_token from another agent or an earlier turn and need the value. For a scalar, quote value_verbatim, the exact decimal string that the responder signed. A null value or unit means the fact has none (an absence, or an index with no unit). It does not mean a missing field. A cid that this responder does not hold returns a typed 404. Then try /v1/fetch, or resolve at a mirror.

Example arguments: {"token":"emem:fact:defi.zb493.xoso.zcb6a:cxjiu7l54ujzrpnekp24n4534yojpue4mprddbvevnqtti3lh5bq"}

NameRequiredDescriptionDefault
tokenYesA `emem:fact:<cell64>:<fact_cid>` citation handle to dereference.

Output Schema

NameRequiredDescription
bandYes
cellYes
kindYes
unitNo
valueNoScalars; a vector is in the text's fact.value.
receiptYes
fact_cidYes
fact_urlNo
value_verbatimNo
canonical_tokenYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive/openWorld=false, so the safety profile is covered. The description adds real behavioral context beyond that: null value/unit means an absence rather than a missing field, and a cid not held by this responder yields a typed 404 with a fallback path. It omits auth/permission and rate-limit behavior, so not a full 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?

Purpose and output contract are front-loaded, then usage, then edge cases, then an example — a sensible order with a labeled 'When to use'. It is somewhat long for a one-parameter tool, with mild redundancy between the opening output description and the later null-semantics note, but nearly every sentence carries 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?

Given an output schema and full annotations exist, the description still supplies everything an agent needs: what the token is, the trigger for calling it, the shape of the answer, null semantics, and failure handling with a next step. Nothing material for correct invocation 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% for the single `token` parameter, so the schema already documents it and the baseline is 3. The description reinforces the token's format and supplies a concrete example argument, but adds little semantic meaning 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?

The opening sentence states a specific verb (read/dereference) and a precise resource (an `emem:fact:<cell64>:<fact_cid>` citation handle) and states the return contract. It is clearly distinguishable from siblings like `emem_memory_token` (minting) and `emem_recall`, and the domain reference to memory algebra anchors it.

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 'When to use' clause gives a concrete trigger: you have a memory_token from another agent or earlier turn and need the value. It also names fallback alternatives for the 404 case (/v1/fetch, mirror resolution). It does not explicitly contrast with sibling tools such as emem_memory_token or emem_recall, so it stops short of a full routing guide.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

emem_recallRecall facts at a cell (auto-materializes on miss)A
Idempotent
Inspect

Read the signed facts at a canonical address (cell64). When a band has no fact yet but has a registered materializer, the responder fetches it. A fact_cid names one signed attestation, so you can cite a fact and verify it again. Resolve the cid anywhere and you get the same bytes. A fact_cid is NOT a fingerprint of the observation. The digest includes the responder's key and the time it signed. Thus two responders that measure the same thing make different fact_cids, and a cid resolves only at the responder that signed it. For identity across responders, use emem_entity. Send deterministic:true (or a provenance class list) to keep only facts that you can compute from the cited raw source. In the memory algebra this is ensure(cell, bands), not get: you state what must exist.

When to use: Call this after emem_locate, or with a cell64 or a place name. It returns every Primary fact at that (cell, band, tslot). A band can have no fact but have a materializer. Then the responder fetches the upstream value, signs it, stores it and returns it in the same call. The first call is slow; later calls use the cache. Thus any wired band recalls at any cell on Earth: send bands: [<band>]. materialize_notes lists what the call fetched. Empty notes mean no materializer here.

Example arguments: {"cell":"defi.zb64a.cAzU.zfa27","bands":["weather.temperature_2m","copdem30m.elevation_mean"]}

NameRequiredDescriptionDefault
latNoExplicit latitude, an alternative to `cell`; paired with `lng`.
lngNoExplicit longitude, paired with `lat`.
bandNooptional single band key, convenience alias for bands:[band]. Use when you want exactly one band (e.g. 'geotessera.2020', 'modis.ndvi_mean') and would otherwise have to wrap it in an array. Both `band` and `bands` are accepted; if both are given they are merged.
cellYescell64 string, e.g. 'defi.zb64a.cAzU.zfa27'
bandsNooptional band keys to filter, e.g. ['indices.ndvi','geotessera']
placeNoFree-text place name, an alternative to `cell`.
scopeNoOptional multi-tenant scope {user_id, agent_id, run_id, org_id}. When at least one field is set, the recall is FILTERED to facts written under the same four-tuple (a recall scoped to {user_id:'u1'} sees only u1's facts, never another tenant's and never globally-written facts) AND the signed receipt binds the scope. Omit (or send {}) for the global, pre-v0.0.8 recall.
tslotNooptional time slot (band-tempo-relative integer offset from emem epoch)
cell64NoAlias for `cell`.
includeNoOpt-in response expansion. include:['provenance'] attaches each fact's tamper-provenance class, which is what `deterministic` and the `provenance` filter select ON: without it you can filter by class and never be told which class a returned fact is. include:['freshness'] attaches an advisory per-fact freshness block: a Q(Δt) staleness score from the band's physics decay kernel (the same one /v1/temporal_route ranks bands with), so an agent learns how stale each reading is in the call that returns it. Advisory only; it does NOT enter the receipt. include:['edges'] attaches each fact's typed temporal edges and threads their CIDs into the receipt. Absent leaves the response byte-identical to the pre-v0.0.9 recall.
provenanceNoTamper-provenance filter: return only facts whose band's provenance class is in this list. `attested_execution` is a device reading trusted through its verified OS execution trace and platform attestation (not recomputable). Applied BEFORE the receipt is signed, so the receipt covers exactly the returned facts; `bands_already_attested_at_cell` stays unfiltered so you still see what else exists at the cell.
as_of_tslotNoBi-temporal valid-time bound. Returns the latest fact per (cell,band) whose tslot ≤ as_of_tslot, answers `what did this place look like AS OF date X`. Conflicts with an explicit `tslot` when as_of_tslot < tslot (rejected with code:`invalid_temporal_bound`).
deterministicNoSugar over `provenance`: true keeps only facts any third party can recompute from the cited raw source (direct_sensor + deterministic_index); false keeps the rest (attested_execution + model_output + human_curated + unclassified). Composable with `provenance` (intersection).
as_of_signed_atNoBi-temporal transaction-time bound. RFC 3339 string. Returns only facts whose `signed_at` ≤ as_of_signed_at, answers `what did emem KNOW as of system-date Y`. Malformed strings are rejected with code:`invalid_signed_at_format`.

Output Schema

NameRequiredDescription
factsYesSigned facts at the cell, ordered per fact_order.
receiptYesed25519 receipt over the returned fact_cids. Verify offline; select the rule from its preimage_version. Store and forward it byte-for-byte: preimage_version 2 binds every field it covers, including merkle_proof, so a reshaped receipt reports signature_valid:false on data nobody tampered with.
fact_orderYesThe ordering contract for facts, e.g. tslot_ascending. Stated rather than implied so nothing depends on position by accident.
current_by_bandNoPer band, the fact_cid with the highest tslot: the current reading. Unslotted facts are excluded, since tslot 0 means undated rather than oldest.
materialize_notesNo
bands_already_attested_at_cellNoWhat else is readable here without materialising, so an empty result can be told apart from a wrong band name.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare readOnlyHint=false, idempotentHint=true, openWorldHint=true — and the description supplies the missing 'why': a miss triggers an upstream fetch that is signed and stored, explaining both the write behavior and the first-call latency, while later calls hit cache. It also discloses that materialize_notes reports what was fetched and that empty notes mean no materializer. Remaining gap is modest: it doesn't spell out auth/permission requirements for materialization or failure modes on unfetchable bands.

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 sentence one, followed by a labeled 'When to use:' section and a concrete example call, which is strong structure. It is long and dense, with the fact_cid digression ('A fact_cid is NOT a fingerprint of the observation...') sitting between purpose and usage, but that length is largely justified by a 14-parameter, bi-temporal tools surface.

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 an output schema present, the description needn't explain return values, and it correctly focuses on selection semantics: cell vs. aliases, scope filtering behavior, materialization-on-miss, and the provenance/deterministic interaction. For a 14-parameter tool with nested scope and bi-temporal bounds, the description gives the agent enough to choose inputs and anticipate side effects in a single 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 coverage is 100%, so the schema already carries the parameter burden and the baseline is 3. The description does add cross-parameter meaning the schema states only in fragments — that deterministic is sugar over provenance (direct_sensor + deterministic_index), that the two compose as an intersection, and that a fact_cid is responder-key-bound rather than a fingerprint of the observation — but it does not walk the parameter set or clarify the cell/lat/lng/place/cell64 alias precedence beyond what the schema already says.

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 gives a precise verb+resource: 'Read the signed facts at a canonical address (cell64)', and immediately pins the semantics as 'ensure(cell, bands), not get'. It distinguishes itself from siblings by name — emem_locate as the upstream step and emem_entity for cross-responder identity — so an agent can tell it apart 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?

It has an explicit 'When to use:' block ('Call this after emem_locate, or with a cell64 or a place name'), and it routes the agent away when the intent is different ('For identity across responders, use emem_entity'). It also explains the miss path (materializer fetches, signs, stores, returns in the same call) so the agent knows to expect the slow first call rather than retrying.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

emem_toolsWhat tools exist here, and when to reach for eachA
Read-onlyIdempotent
Inspect

The map of emem's tools, and the one tool that finds all the others. It gives the working loop in order (name, ground, cite, resolve, verify, check for drift). Then it groups every other tool by the question it answers, each with a one-line trigger. Send name for the full schema of one tool and an example that runs. IF YOU SEE A LIST OF 18 TOOLS, IT IS A CURATED SUBSET OF 115, NOT THE FULL SURFACE. Hosts remove _meta, so this text repeats the count. You can call every catalogued tool by name through tools/call at either endpoint.

When to use: Call this FIRST when you do not know which tool answers the question. Also call it when your list does not have a capability. A tool that is not in your list can still be on the server. q searches by topic (ndvi, flood, verify). name returns one exact schema. With no arguments, you get the full map. /mcp/full registers the full catalog. emem_ask answers in one call without a choice of primitive.

Example arguments: {"q":"ndvi"}

NameRequiredDescriptionDefault
qNoFree-text filter over tool names, titles and trigger text, e.g. `ndvi`, `cloud`, `flood`, `verify`, `token`. Plain lowercased substring over name + title + description + trigger text, not fuzzy and not stemmed: `ndvi` hits, `vegetation index` only hits tools that spell that phrase. Combines with `shape`/`bundle`/`category`/`tier` as AND, so an over-narrow combination answers with an empty catalog rather than an error.
nameNoReturn the full descriptor for exactly this tool (input schema, runnable example, annotations), e.g. `emem_ndvi`. Use this when you already know the name and want its schema without loading the whole catalog. It SHORT-CIRCUITS: when `name` is set every other argument here is ignored, so `{name, q}` is not a search within one tool. A name this responder does not carry is not an error status, you get a body with `did_you_mean` holding up to five names that share a substring with what you asked for.
tierNoWhich slice to list. Defaults to `all`, so this tool shows the whole surface even when the endpoint advertises only the core loop, and an `extended` tool you find here is callable by name through tools/call whether or not your host listed it. Pass `core` to see only what a default connection advertises.
shapeNoFilter by what the answer looks like, which is usually the real question. `scalar` is one number at one address; `raster` is a gridded field over an area; `timeseries` is a value per timestep; `vector` is a learned embedding; `identity` is a canonical name for a thing; `token` is a citation handle; `proof` checks one.
bundleNoFilter by the job you are doing. Call with no arguments first to see each bundle and its size.
categoryNoFilter to one category. This is about the shape of the job, NOT about safety: 43 tools outside `write` declare `readOnlyHint: false` because reading a cold address can materialise or mint as a side effect, so `category: "read"` is not a safe-tools filter. Read each result's `annotations.readOnlyHint` for that.

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, closed-world), yet the description adds non-obvious behavior the annotations cannot express: the 18-of-115 curated subset, the warning that hosts strip _meta, that any catalogued tool is callable by name via tools/call at either endpoint, that /mcp/full registers the full catalog, and that an unknown `name` yields a did_you_mean body rather than an error.

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 the 'call this first' trigger are front-loaded, and the all-caps subset warning is deliberately prominent. It is somewhat long and repeats the curated-subset/unlisted-tool point across two paragraphs, which costs a little, but every sentence carries routing 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 still tells the agent what comes back: tools grouped by the question they answer with a one-line trigger each, an example that runs for `name`, and a did_you_mean fallback. For a zero-required-parameter discovery tool, nothing an agent needs before calling 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% and the schema descriptions are themselves unusually detailed (substring semantics, AND-combination, short-circuit on `name`, enum meanings), so the description's parameter notes largely restate structured data. It does add framing ('q searches by topic') and a concrete example argument, but this is the baseline case 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?

It states a specific role in one line: 'The map of emem's tools, and the one tool that finds all the others,' plus the working loop ordering. It also distinguishes itself from the nearest sibling by noting that 'emem_ask answers in one call without a choice of primitive,' so an agent can route between them 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?

Explicit when-to-use is given ('Call this FIRST when you do not know which tool answers the question') along with a second trigger ('when your list does not have a capability') and the named alternative (emem_ask). The unlisted-tool scenario is called out as a positive reason to call, which is exactly the routing decision an agent needs.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

emem_verify_receiptServer-side ed25519 receipt verifierA
Read-onlyIdempotent
Inspect

Verify a signed receipt on the server. The tool builds the canonical preimage again, under the rule that the receipt's preimage_version names. It checks the ed25519 signature with the embedded key. It returns {valid, reason, failure_detail, signature_valid, merkle_proof_valid, signer_pubkey_b32, preimage_blake3_hex}. A receipt verifies BYTE FOR BYTE OR NOT AT ALL. Version 2 binds the inclusion proof, so a change of any kind makes the signature fail: a dropped field, a renamed field, a summary. Use this tool when the browser page /verify is not available. Also use it to audit a receipt from a third party.

When to use: Send the receipt EXACTLY as the read tool returned it, complete and unchanged. Two omissions cause a false forgery, not a 400. Do not drop merkle_proof. Do not drop preimage_version. Without it the value is 0, which selects the v0 rule, and the signature reads as invalid. The signature and the key can be byte arrays, or sig_b32 and responder_pubkey_b32. The tool accepts no other names. When a field changed after signing, the answer is reason: receipt_reshaped_after_signing and names the field. To require a specific signer, set pubkey_b32. A bad signature returns 200 with valid: false, never a 4xx. The example (from emem_tools) is a real receipt over two Trafalgar Square facts. Unchanged, it is valid. Change one byte, and it is not.

Example arguments: 1602 bytes, too long to inline in a listing. Call emem_tools with {"name": "emem_verify_receipt"} for it whole and runnable; it is not shortened here because a truncated example is not one.

NameRequiredDescriptionDefault
factsNoThe fact value(s) you intend to rely on. Each is content-addressed and checked for membership in the receipt's `fact_cids`, so a genuine receipt presented beside a tampered fact answers `valid:false` / `fact_mismatch`. Omit it and only the signature is checked, which a doctored fact survives.
receiptYesThe signed receipt envelope, the object under `receipt` in any read primitive's result. Must carry primitive/served_at/request_id/cells/fact_cids and either `signature` byte[] + `responder_pubkey` byte[] or their b32 string forms. IF ALL YOU HOLD IS AN `emem:fact:` TOKEN, this is not the tool to call first: a token is not a receipt and passing one here is a shape error. Call `emem_memory_token_resolve` on the token, then pass THAT result's `receipt` object here. Resolving proves the token points at the bytes it claims; verifying proves this responder signed them.
pubkey_b32NoOptional explicit responder pubkey (base32). When omitted, uses the receipt's embedded pubkey/responder fields.
current_responder_epochNoThe responder key epoch you currently trust, from `/v1/manifests`. Produces an advisory `key_epoch_advisory` comparison against the receipt's epoch; a mismatch is reported, never rejected.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint/idempotentHint/destructiveHint/openWorldHint, yet the description adds substantial behavior: byte-for-byte verification, false forgery rather than a 400 for omissions, bad signatures returning 200 with valid:false (never 4xx), version-2 binding of the inclusion proof, and advisory-only epoch mismatch. This is rich context well beyond 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?

It is front-loaded with purpose and critical warnings, and every warning about omissions earns its place. It is somewhat long and slightly repetitive (byte-for-byte stated twice) and the closing paragraph about the oversized example meanders, so not 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?

For a complex, nested, multi-param tool with no output schema, the description enumerates the return object fields and semantics ({valid, reason, failure_detail, signature_valid, merkle_proof_valid, ...}), explains failure reasons and edge cases, and covers input shape pitfalls. Nothing critical to correct invocation appears 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 schema already documents all four parameters, setting a 3 baseline. The description nonetheless adds meaning: signature/key may be byte arrays or the b32 fields and 'accepts no other names', dropping merkle_proof/preimage_version causes false forgery, and pubkey_b32 pins a signer — real value on top 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?

States a specific verb and resource — 'Verify a signed receipt on the server' — and the title reinforces it with 'ed25519 receipt verifier'. It distinguishes itself from siblings by naming the browser /verify page, emem_memory_token_resolve, and third-party audit scenarios, 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?

Provides an explicit 'When to use' section: when the browser /verify page is unavailable and to audit a third-party receipt. It names the alternative path (resolve an emem:fact: token via emem_memory_token_resolve first, then pass the resulting receipt), covering both when to use and what to do instead.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

fetchOpen one search result and read the signed recordA
Idempotent
Inspect

Dereference an id from search. You get the reading in one line, then the signed body, the URL that serves those bytes, and metadata: cell, band, signing time and key. The id can be an emem:fact: citation, a bare fact_cid, or an emem:cell: handle for a full cell. The value is the exact decimal string that the responder signed, never a new format. A fact handle writes nothing. A cell handle, like emem_recall, MATERIALIZES a missing band on a cold cell: it fetches, signs and stores it. The flags follow that path: readOnlyHint false.

When to use: Call this on each result that you will cite, before you quote the number. Quote the one-line reading. The body lets a reader check it, and emem_echo_verify grades what you emit against it. When a body is too large, the answer says so and gives the URL that serves it complete.

Example arguments: {"id":"emem:fact:defi.zb493.xoso.zcb6a:cxjiu7l54ujzrpnekp24n4534yojpue4mprddbvevnqtti3lh5bq"}

NameRequiredDescriptionDefault
idYesAn id from `search`: an `emem:fact:` citation, a bare fact_cid, or an `emem:cell:` handle for every fact at one cell.

Output Schema

NameRequiredDescription
idYesEchoed id, in canonical form.
urlYesStable URL serving these bytes.
textYesThe reading in one line, then the signed body it was lifted from. If the body was too large for the wire it says so inline, with the URL that serves it whole.
titleYesWhat this record is.
metadataNocell, band, when it was signed and by which key: the fields a reader needs to judge the citation without re-fetching it.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations are non-obvious (readOnlyHint false on a tool called 'fetch'), and the description explains exactly why: a cell handle MATERIALIZES a missing band, fetching/signing/storing it, while a fact handle writes nothing. It also discloses value fidelity ('exact decimal string that the responder signed, never a new format') and the large-body fallback (returns a URL). This adds substantial context beyond the annotations rather than restating them.

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 lead sentence front-loads what the tool returns, and the usage block is clearly demarcated. It is dense and jargon-heavy with a slightly redundant restatement ('A fact handle writes nothing'), but nearly every sentence carries routing or behavioral 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?

An output schema exists, yet the description still orients the agent on the shape of the result (reading, body, URL, metadata) and on the fallback path when the body is too large. Combined with the flag rationale, 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?

Schema coverage is 100%, so baseline is 3, but the description goes further by attaching distinct semantics to each id form: fact citations are read-only, cell handles trigger materialization. That behavioral split is not in the schema and directly affects how an agent should choose the id to pass.

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 ('Dereference an id from `search`') and immediately enumerates what comes back: the one-line reading, signed body, serving URL, and metadata. It distinguishes itself from siblings `search`, `emem_recall`, and `emem_echo_verify` by name and role, so an agent can route without opening 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 Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'When to use: Call this on each result that you will cite, before you quote the number' gives an explicit trigger and ordering constraint, and it names the downstream tool (`emem_echo_verify` grades what you emit). It also contrasts behavior with `emem_recall` for cell handles, giving the agent a comparison point for the nearest sibling.

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. 15 tool updatesv2.4.4
    • Changedemem_ask5 fields changed
      • changedInput schema / properties / include / description
        Previous value: -"Opt-in heavy response sections. Default response is slim (~5 KB): answer + algorithm key + fact_cids + caveats. Name specific sections to include them. Ignored when verbose=true (which includes everything)."New value: +"Opt-in REST envelope sections. `reasoning` drops `algorithms_for_question`; add `algorithms` to keep it. The MCP projection ignores these."
      • changedInput schema / properties / include / items / enum
        Previous value: -[
        -  "band_observations",
        -  "algorithm_outcomes",
        -  "facts_full",
        -  "temporal_composition",
        -  "foundation_embeddings",
        -  "scene",
        -  "inventory"
        -]New value: +[
        +  "band_observations",
        +  "algorithm_outcomes",
        +  "facts_full",
        +  "temporal_composition",
        +  "scene",
        +  "inventory",
        +  "reasoning",
        +  "algorithms"
        +]
      • changedInput schema / properties / model / description
        Previous value: -"Optional. Compose an EXTRA prose answer with a named model, returned as `model_answer` beside the deterministic `answer`. It does not replace it: `answer` is synthesised from the structured fields and never calls a model, so every number in it traces to a fact_cid, and asking for a model must not turn a checkable answer into an unchecked one. `model_answer` carries provenance.class = model_output. Name it by base_model (`nvidia/Cosmos3-Edge`), by family (`cosmos3_edge`, `gemma`), or by any fragment naming exactly one of them (`cosmos`); a fragment matching several is refused and names them; an unroutable name is refused with the list of routable ones, and a routable model whose service is not answering is refused as busy or down rather than silently substituted. Cosmos deliberates and typically takes 13-22 s."New value: +"Optional. Compose an EXTRA prose answer with a named model, returned as `model_answer` beside the deterministic `answer`. It does not replace it: `answer` is synthesised from the structured fields and never calls a model, so every number in it traces to a fact_cid, and asking for a model must not turn a checkable answer into an unchecked one. `model_answer` carries provenance.class = model_output. Name it by base_model (`nvidia/Cosmos3-Edge`), by family (`cosmos3_edge`, `gemma`), or by any fragment naming exactly one of them (`cosmos`); a fragment matching several is refused and names them; an unroutable name is refused with the list of routable ones, and a routable model whose service is not answering is refused as busy or down rather than silently substituted. Cosmos is refused while its host has no GPU."
      • changedInput schema / properties / verbose / description
        Previous value: -"When true, return the full envelope: per-algorithm formula strings, temporal_recipe blocks, per-fact band_metadata duplicates, and the long _explanation prose. Default (since 2026-05-05) is false so the response fits MCP's 25 KB cap; the signed receipt + fact CIDs + algorithm keys + algorithms_cid are always retained. Pass true to get the full body when debugging."New value: +"REST only: true adds per-algorithm formulas, band metadata and long prose. The MCP projection is small (about 7 KB) either way; the REST envelope is larger."
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "properties": {
        +    "_means": {
        +      "type": "string"
        +    },
        +    "answer": {
        +      "description": "The prose answer. Also in the content block, which carries the MCP projection; POST /v1/ask has the full envelope.",
        +      "type": "string"
        +    },
        +    "cell": {
        +      "description": "The cell64 the question resolved to: emem's address for the place.",
        +      "type": "string"
        +    },
        +    "question": {
        +      "description": "The question as asked.",
        +      "type": "string"
        +    },
        +    "schema": {
        +      "const": "emem.ask_structured.v1",
        +      "type": "string"
        +    },
        +    "spatial_trace": {
        +      "description": "A spatial memory trace: what this responder has measured at this place, as primitives a model can reason over rather than a picture a person looks at.",
        +      "properties": {
        +        "absent": {
        +          "description": "Bands this responder looked for and did not find. Absence is evidence: without it a consumer infers coverage nobody measured.",
        +          "items": {
        +            "properties": {
        +              "band": {
        +                "type": "string"
        +              }
        +            },
        +            "type": "object"
        +          },
        +          "type": "array"
        +        },
        +        "at": {
        +          "description": "[lat, lng] of the cell, so a point has a position without a second call.",
        +          "items": {
        +            "type": "number"
        +          },
        +          "type": "array"
        +        },
        +        "cell": {
        +          "type": "string"
        +        },
        +        "counts": {
        +          "description": "Totals taken BEFORE any cap, so truncation can be seen rather than guessed.",
        +          "properties": {
        +            "absent": {
        +              "type": "integer"
        +            },
        +            "absent_shown": {
        +              "type": "integer"
        +            },
        +            "points_shown": {
        +              "type": "integer"
        +            },
        +            "present": {
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "layers": {
        +          "description": "Points grouped by what kind of evidence they are: surface (what the ground is), built (what stands on it), now (what is happening there), embedding (vectors for similarity). A layer absent from this list means the question never reached that kind of evidence; a band looked for and not found is in `absent` instead.",
        +          "items": {
        +            "properties": {
        +              "layer": {
        +                "enum": [
        +                  "surface",
        +                  "built",
        +                  "now",
        +                  "embedding",
        +                  "other",
        +                  "ground"
        +                ],
        +                "type": "string"
        +              },
        +              "points": {
        +                "description": "One per signed reading.",
        +                "items": {
        +                  "properties": {
        +                    "age_s": {
        +                      "description": "How old the reading was when this answer was written.",
        +                      "type": "integer"
        +                    },
        +                    "band": {
        +                      "type": "string"
        +                    },
        +                    "class": {
        +                      "description": "Provenance class: direct_sensor, deterministic_index, estimator, model_output, attested_execution, human_curated, unclassified. What KIND of claim this is.",
        +                      "type": "string"
        +                    },
        +                    "f": {
        +                      "description": "Index into `receipt.fact_cids` (or the list `_projection.fact_cids_at` names). Dereference it for the signed bytes.",
        +                      "type": "integer"
        +                    },
        +                    "unit": {
        +                      "type": "string"
        +                    },
        +                    "value": {
        +                      "description": "The measured value, in the band's own units. `null` where the band was looked for and not found: an absence is a reading.",
        +                      "type": [
        +                        "number",
        +                        "string",
        +                        "boolean",
        +                        "null"
        +                      ]
        +                    }
        +                  },
        +                  "required": [
        +                    "band",
        +                    "value"
        +                  ],
        +                  "type": "object"
        +                },
        +                "type": "array"
        +              }
        +            },
        +            "required": [
        +              "layer",
        +              "points"
        +            ],
        +            "type": "object"
        +          },
        +          "type": "array"
        +        },
        +        "schema": {
        +          "const": "emem.spatial_trace.v1",
        +          "type": "string"
        +        },
        +        "stage": {
        +          "description": "Which stage of the answer grounded these readings.",
        +          "type": "string"
        +        },
        +        "truncated": {
        +          "type": "boolean"
        +        }
        +      },
        +      "required": [
        +        "schema",
        +        "layers",
        +        "counts"
        +      ],
        +      "type": "object"
        +    }
        +  },
        +  "required": [
        +    "schema",
        +    "spatial_trace"
        +  ],
        +  "type": "object"
        +}
    • Changedemem_echo_verify1 field changed
      • addedInput schema / properties / claimed_value / type
        Added value: +[
        +  "string",
        +  "number"
        +]
    • Changedemem_entity1 field changed
      • addedInput schema / properties / attester
        Added value: +{
        +  "description": "ed25519 binding, verified. Omit it and the refusal's details.how_to_sign gives the digest to sign.",
        +  "properties": {
        +    "pubkey_b32": {
        +      "type": "string"
        +    },
        +    "sig_b32": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "pubkey_b32",
        +    "sig_b32"
        +  ],
        +  "type": "object"
        +}
    • Changedemem_entity_link2 fields changed
      • addedInput schema / properties / attester
        Added value: +{
        +  "description": "ed25519 binding, verified. Omit it and the refusal's details.how_to_sign gives the digest to sign.",
        +  "properties": {
        +    "pubkey_b32": {
        +      "type": "string"
        +    },
        +    "sig_b32": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "pubkey_b32",
        +    "sig_b32"
        +  ],
        +  "type": "object"
        +}
      • addedInput schema / properties / stance
        Added value: +{
        +  "description": "`asserts` (default): this phrasing denotes this object. `disputes`: it does not. Both are attributed to your key and recorded append-only; a dispute is shown beside the binding it answers and deletes nothing.",
        +  "enum": [
        +    "asserts",
        +    "disputes"
        +  ],
        +  "type": "string"
        +}
    • Changedemem_guard_verdict5 fields changed
      • removedInput schema / properties / messages
        Removed value: -{
        -  "description": "A chat-completions-shaped transcript, read for its text. Accepted so the same body works against a self-hosted emem-guard node and against any OpenAI-shaped client. Each item is {role, content} where content is a string or an array of blocks.",
        -  "items": {
        -    "properties": {
        -      "content": {
        -        "description": "A string, or an array of {type,text} blocks."
        -      },
        -      "role": {
        -        "type": "string"
        -      }
        -    },
        -    "type": "object"
        -  },
        -  "type": "array"
        -}
      • changedInput schema / properties / shape / description
        Previous value: -"Which envelope YOUR payload is in, so you never have to reshape it to ask the question: send the body your own framework produced and name its shape. native reads `texts`/`messages`; `mcp` reads a JSON-RPC tools/call or tool result; `openai` reads a moderations (`input`) or chat-completions body; `cloudevent` reads a CloudEvents 1.0 structured event; `policy` reads {input}. It matters: a CloudEvent whose citation sits at data.text is invisible to the native reader, and a check that read nothing answers `allow`, so confirm `citations_found` matches what you sent. Unrecognised values fall back to native rather than erroring. This selects how the body is READ only — the verdict always comes back in this tool's declared output shape, because a tool that declares an outputSchema owes conforming structuredContent. To get the ANSWER translated into the same envelope too (an OPA `result:{allow,deny}`, an MCP CallToolResult to substitute on a deny), call POST /v1/guard/verdict?shape=… directly."New value: +"Which envelope YOUR payload is in, so you never have to reshape it to ask the question: send the body your own framework produced and name its shape. native reads `texts`; `mcp` reads a JSON-RPC tools/call or tool result; `openai` reads a moderations (`input`) or chat-completions body; `cloudevent` reads a CloudEvents 1.0 structured event; `policy` reads {input}. It matters: a CloudEvent whose citation sits at data.text is invisible to the native reader, and a check that read nothing answers `allow`, so confirm `citations_found` matches what you sent. Unrecognised values fall back to native rather than erroring. This selects how the body is READ only — the verdict always comes back in this tool's declared output shape, because a tool that declares an outputSchema owes conforming structuredContent. To get the ANSWER translated into the same envelope too (an OPA `result:{allow,deny}`, an MCP CallToolResult to substitute on a deny), call POST /v1/guard/verdict?shape=… directly."
      • changedInput schema / properties / texts / description
        Previous value: -"Free text to check. Any number of pieces, in any order: a draft answer, a tool result, a whole turn."New value: +"Free text to check, and the only input this tool needs. Send just the pieces the question is about: a draft answer, a tool result, one turn. Do not send surrounding conversation, because nothing here reads it and a checker should ask for the smallest input that answers the question."
      • addedOutput schema / properties / citations
        Added value: +{
        +  "description": "Each citation and what it came to here: verified, signature_failed, byte_mismatch, not_held_here (minted elsewhere or nonexistent: resolve it where it was minted before relying on it), or drifted.",
        +  "items": {
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / citations_verified_here
        Added value: +{
        +  "description": "How many of the citations this responder holds and verified.",
        +  "type": "integer"
        +}
    • Changedemem_intent15 fields changed
      • changedInput schema / description
        Previous value: -"A tagged union: `type` selects the intent and decides which OTHER fields are read. Fields belonging to a different intent are ignored, so send only the ones its row needs."New value: +"A tagged union on `type`; fields of other intents are ignored."
      • addedInput schema / properties / areas
        Added value: +{
        +  "description": "area_over_time: up to 6 {id,geometry|bbox} on one chart",
        +  "maxItems": 6,
        +  "type": "array"
        +}
      • addedInput schema / properties / bbox
        Added value: +{
        +  "type": "object"
        +}
      • changedInput schema / properties / cell / description
        Previous value: -"cell64 address, e.g. \"damO.zb000.xUti.zde78\". Required by did_change and confirm. Optional for what_is_here and ask: supply it to skip geocoding, omit it and give `place` instead."New value: +"cell64 address, e.g. \"defi.zb64a.cAzU.zfa27\". Required by did_change and confirm. Optional for what_is_here and ask: supply it to skip geocoding, omit it and give `place` instead."
      • addedInput schema / properties / claim / properties / value / type
        Added value: +[
        +  "string",
        +  "number",
        +  "boolean",
        +  "array",
        +  "null"
        +]
      • addedInput schema / properties / end_date
        Added value: +{
        +  "description": "YYYY-MM-DD",
        +  "type": "string"
        +}
      • addedInput schema / properties / filter / properties / value / type
        Added value: +[
        +  "string",
        +  "number",
        +  "boolean",
        +  "array",
        +  "null"
        +]
      • addedInput schema / properties / geometry
        Added value: +{
        +  "description": "area_over_time: GeoJSON Polygon; or bbox {min_lat,min_lng,max_lat,max_lng}.",
        +  "type": "object"
        +}
      • addedInput schema / properties / index
        Added value: +{
        +  "enum": [
        +    "ndvi",
        +    "ndwi",
        +    "ndmi",
        +    "lswi",
        +    "evi",
        +    "vv",
        +    "vh",
        +    "vh_vv"
        +  ],
        +  "type": "string"
        +}
      • changedInput schema / properties / k / description
        Previous value: -"find_like only: how many neighbours to return. Defaults to the primitive's own default when omitted."New value: +"find_like only: how many neighbours to return."
      • changedInput schema / properties / key / description
        Previous value: -"find_like only: cell64 to search from. Neighbours are ranked by embedding cosine against this cell."New value: +"find_like only: cell64 to search from, ranked by embedding cosine."
      • addedInput schema / properties / max_scenes
        Added value: +{
        +  "maximum": 24,
        +  "minimum": 3,
        +  "type": "integer"
        +}
      • addedInput schema / properties / start_date
        Added value: +{
        +  "description": "YYYY-MM-DD",
        +  "type": "string"
        +}
      • changedInput schema / properties / type / description
        Previous value: -"Which question you are asking, and therefore which other fields apply. where_is: name a place, get its cell64 (needs `description`). what_is_here: summarise a location (needs `cell`, OR `place`/`description` to resolve it first). is_like: pairwise similarity (needs `a` and `b`). did_change: did one band move over a time window (needs `cell`, `band`, `window`). find_like: nearest neighbours to a known cell (needs `key`; optional `k`, `filter`). confirm: is a claim true at a cell (needs `claim` and `cell`). ask: free-text question about a place, runs locate + topic-route + recall server-side (needs `description`; optional `place`/`cell`/`lat`+`lng` to pin the location)."New value: +"Which intent; the table in the description gives each row's fields."
      • changedInput schema / properties / type / enum
        Previous value: -[
        -  "where_is",
        -  "what_is_here",
        -  "is_like",
        -  "did_change",
        -  "find_like",
        -  "confirm",
        -  "ask"
        -]New value: +[
        +  "where_is",
        +  "what_is_here",
        +  "is_like",
        +  "did_change",
        +  "find_like",
        +  "confirm",
        +  "ask",
        +  "area_over_time"
        +]
    • Changedemem_locate1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "anyOf": [
        +    {
        +      "required": [
        +        "cell64"
        +      ]
        +    },
        +    {
        +      "required": [
        +        "status"
        +      ]
        +    }
        +  ],
        +  "properties": {
        +    "cell64": {
        +      "description": "Pass as `cell` to emem_recall.",
        +      "type": "string"
        +    },
        +    "data_at_this_cell": {
        +      "type": "object"
        +    },
        +    "next": {
        +      "type": "array"
        +    },
        +    "place_label": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "selected": {
        +      "properties": {
        +        "confidence_reason": {
        +          "type": "string"
        +        },
        +        "is_high_confidence": {
        +          "type": "boolean"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "status": {
        +      "description": "needs_location: no place named.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "next"
        +  ],
        +  "type": "object"
        +}
    • Changedemem_memory_bundle2 fields changed
      • addedInput schema / properties / fact_cids
        Added value: +{
        +  "description": "Instead of triples: the exact facts to bind, by cid. A triple is resolved through recall and can bind a newer fact than the one you showed; a cid binds that fact and no other. Pass triples or fact_cids, not both.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "maxItems": 256,
        +  "minItems": 1,
        +  "type": "array"
        +}
      • removedInput schema / required
        Removed value: -[
        -  "triples"
        -]
    • Changedemem_memory_contradictions3 fields changed
      • addedInput schema / properties / cell
        Added value: +{
        +  "description": "Alias for `cell_prefix`, and the spelling the rest of the surface uses for a cell64. Send a cell64 you already hold and the scan narrows to that place instead of running over the corpus.",
        +  "type": "string"
        +}
      • addedInput schema / properties / cell64
        Added value: +{
        +  "description": "Alias for `cell_prefix`.",
        +  "type": "string"
        +}
      • changedInput schema / properties / cell_prefix / description
        Previous value: -"Bytewise prefix on cell64 (e.g. `defi.zb5f9`). Omit to scan the whole corpus up to the scan cap."New value: +"A cell64 to scan, or a bytewise prefix of one (e.g. `defi.zb5f9`). Omit to scan the whole corpus up to the scan cap. A full cell64 is a prefix of itself, so passing one narrows the scan to exactly that place."
    • Changedemem_memory_token_resolve1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "properties": {
        +    "band": {
        +      "type": "string"
        +    },
        +    "canonical_token": {
        +      "type": "string"
        +    },
        +    "cell": {
        +      "type": "string"
        +    },
        +    "fact_cid": {
        +      "type": "string"
        +    },
        +    "fact_url": {
        +      "type": "string"
        +    },
        +    "kind": {
        +      "type": "string"
        +    },
        +    "receipt": {
        +      "type": "object"
        +    },
        +    "unit": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "value": {
        +      "description": "Scalars; a vector is in the text's fact.value.",
        +      "type": [
        +        "number",
        +        "string",
        +        "boolean",
        +        "null"
        +      ]
        +    },
        +    "value_verbatim": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "canonical_token",
        +    "cell",
        +    "fact_cid",
        +    "band",
        +    "kind",
        +    "receipt"
        +  ],
        +  "type": "object"
        +}
    • Changedemem_recall1 field changed
      • changedInput schema / properties / cell / description
        Previous value: -"cell64 string, e.g. 'damO.zb000.xUti.zde78'"New value: +"cell64 string, e.g. 'defi.zb64a.cAzU.zfa27'"
    • Changedemem_tools1 field changed
      • changedInput schema / properties / category / description
        Previous value: -"Filter to one category. This is about the shape of the job, NOT about safety: 13 tools outside `write` declare `readOnlyHint: false` because reading a cold address can materialise or mint as a side effect, so `category: \"read\"` is not a safe-tools filter. Read each result's `annotations.readOnlyHint` for that."New value: +"Filter to one category. This is about the shape of the job, NOT about safety: 43 tools outside `write` declare `readOnlyHint: false` because reading a cold address can materialise or mint as a side effect, so `category: \"read\"` is not a safe-tools filter. Read each result's `annotations.readOnlyHint` for that."
    • Changedemem_verify_receipt1 field changed
      • changedInput schema / properties / receipt / description
        Previous value: -"The signed receipt envelope (as returned by any read primitive). Must carry primitive/served_at/request_id/cells/fact_cids and either `signature` byte[] + `responder_pubkey` byte[] or their b32 string forms."New value: +"The signed receipt envelope, the object under `receipt` in any read primitive's result. Must carry primitive/served_at/request_id/cells/fact_cids and either `signature` byte[] + `responder_pubkey` byte[] or their b32 string forms. IF ALL YOU HOLD IS AN `emem:fact:` TOKEN, this is not the tool to call first: a token is not a receipt and passing one here is a shape error. Call `emem_memory_token_resolve` on the token, then pass THAT result's `receipt` object here. Resolving proves the token points at the bytes it claims; verifying proves this responder signed them."
    • Addedfetch
    • Addedsearch
  2. 2 tool updatesv2.2.1
    • Changedemem_ask1 field changed
      • addedInput schema / properties / model
        Added value: +{
        +  "description": "Optional. Compose an EXTRA prose answer with a named model, returned as `model_answer` beside the deterministic `answer`. It does not replace it: `answer` is synthesised from the structured fields and never calls a model, so every number in it traces to a fact_cid, and asking for a model must not turn a checkable answer into an unchecked one. `model_answer` carries provenance.class = model_output. Name it by base_model (`nvidia/Cosmos3-Edge`), by family (`cosmos3_edge`, `gemma`), or by any fragment naming exactly one of them (`cosmos`); a fragment matching several is refused and names them; an unroutable name is refused with the list of routable ones, and a routable model whose service is not answering is refused as busy or down rather than silently substituted. Cosmos deliberates and typically takes 13-22 s.",
        +  "type": "string"
        +}
    • Changedemem_recall1 field changed
      • changedInput schema / properties / provenance / items / enum
        Previous value: -[
        -  "direct_sensor",
        -  "deterministic_index",
        -  "attested_execution",
        -  "model_output",
        -  "human_curated",
        -  "unclassified"
        -]New value: +[
        +  "direct_sensor",
        +  "deterministic_index",
        +  "estimator",
        +  "attested_execution",
        +  "model_output",
        +  "human_curated",
        +  "unclassified"
        +]
  3. 2 tool updatesv1.3.10
    • Changedemem_memory_contradictions1 field changed
      • addedInput schema / properties / include_same_attester_sources
        Added value: +{
        +  "default": false,
        +  "description": "Also report keys where ONE attester answered the same address from two different upstreams. Default false, which scans only for disagreement between two or more DISTINCT attesters — so on a single-responder corpus a zero here means the narrower question was answered, not that nothing disagrees. Set true and a key qualifies when the facts differ in `derivation.fn_key` or in their `sources[].scheme` set; the same provider re-signed is a refresh, not a disagreement, and stays excluded. Each record carries `disagreement_scope` and a `providers[]` list naming what changed.",
        +  "type": "boolean"
        +}
    • Changedemem_recall1 field changed
      • changedOutput schema / properties / receipt / description
        Previous value: -"ed25519 receipt over the returned fact_cids. Verify offline; select the rule from its preimage_version."New value: +"ed25519 receipt over the returned fact_cids. Verify offline; select the rule from its preimage_version. Store and forward it byte-for-byte: preimage_version 2 binds every field it covers, including merkle_proof, so a reshaped receipt reports signature_valid:false on data nobody tampered with."
  4. 3 tool updatesv1.3.9
    • Addedemem_guard_verdict
    • Addedemem_intent
    • Addedemem_verify_receipt
  5. 11 tool updatesv1.3.8
    • Changedemem_ask2 fields changed
      • addedInput schema / properties / query
        Added value: +{
        +  "description": "Alias for `q`.",
        +  "type": "string"
        +}
      • addedInput schema / properties / question
        Added value: +{
        +  "description": "Alias for `q`.",
        +  "type": "string"
        +}
    • Changedemem_echo_verify3 fields changed
      • changedInput schema / properties / claimed_value / description
        Previous value: -"The value you are about to publish, as a string or a number. A string is compared verbatim first, which is what catches a retype a float comparison would forgive."New value: +"The value you are about to publish, as a string or a number. Send it as a STRING, character for character as you will emit it. A JSON number is stringified before the comparison, so `0.50` arrives as `0.5` and `0.2411000` as `0.2411` (measured against the live responder): the trailing digits this check exists to defend are gone before it runs. Quote `value_verbatim` from resolve as a string and echo the exact characters you will publish."
      • changedInput schema / properties / strict / description
        Previous value: -"Require BYTE-IDENTICAL equality. Default false, which also accepts a numerically equal value spelled differently (0.50 for 0.5)."New value: +"Require BYTE-IDENTICAL equality. Default false, which also accepts a numerically equal value spelled differently (0.50 for 0.5). It changes exactly one outcome: the numerically-equal-but-respelled case, which passes by default and becomes `drift: \"reformatted\"` here. `rounded` and `wrong` already fail either way, so `strict` never turns a pass into a pass. It is also inert when `claimed_value` came in as a JSON number, because the respelling then happened in the JSON parser, before this tool saw it."
      • changedInput schema / properties / token / description
        Previous value: -"The citation you used. Any form resolve accepts, including a bare cid (answers degraded)."New value: +"The citation you used. Any form resolve accepts, including a bare cid, which answers with `degraded: true`: a bare cid asserts no location, so the cell-binding check is skipped and the grade covers the value only. A cid that is not 52 characters is refused as a damaged citation rather than as a missing one, and must not be retried."
    • Changedemem_find_similar4 fields changed
      • addedInput schema / properties / cell
        Added value: +{
        +  "description": "Alias for `key`.",
        +  "type": "string"
        +}
      • addedInput schema / properties / cell64
        Added value: +{
        +  "description": "Alias for `key`.",
        +  "type": "string"
        +}
      • addedInput schema / properties / filter
        Added value: +{
        +  "description": "Claim-algebra predicate evaluated against every candidate before ranking. A cell with no fact for the filter's band is DROPPED rather than treated as false, so 'places like X where NDVI > 0.5' never silently includes cells with no NDVI.",
        +  "type": "object"
        +}
      • addedInput schema / properties / scope
        Added value: +{
        +  "description": "Multi-tenant scope `{user_id, agent_id, run_id, org_id}`. Setting it bypasses the ANN index entirely, because that index carries no scope column, and runs the brute-force scan instead: the tenant filter is honoured truthfully, and the call is slower.",
        +  "type": "object"
        +}
    • Removedemem_guard_verdict
    • Removedemem_intent
    • Changedemem_locate2 fields changed
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Alias for `place`.",
        +  "type": "string"
        +}
      • addedInput schema / properties / query
        Added value: +{
        +  "description": "Alias for `place`.",
        +  "type": "string"
        +}
    • Changedemem_memory_bundle1 field changed
      • addedInput schema / properties / scope
        Added value: +{
        +  "description": "Multi-tenant scope `{user_id, agent_id, run_id, org_id}`, applied to EVERY triple's underlying recall so the whole bundle cites only facts written under that four-tuple.",
        +  "type": "object"
        +}
    • Changedemem_memory_token1 field changed
      • addedInput schema / properties / observed_on
        Added value: +{
        +  "description": "The fact's source capture date (YYYY-MM-DD) as `/v1/recall` reports it in `sources[].captured_at`. Supplied together with `band` it additionally mints the self-describing `descriptor_token`. A wrong date forges nothing: resolve binds the date to the signed fact and answers 409 on a mismatch.",
        +  "type": "string"
        +}
    • Changedemem_recall4 fields changed
      • addedInput schema / properties / cell64
        Added value: +{
        +  "description": "Alias for `cell`.",
        +  "type": "string"
        +}
      • addedInput schema / properties / lat
        Added value: +{
        +  "description": "Explicit latitude, an alternative to `cell`; paired with `lng`.",
        +  "type": "number"
        +}
      • addedInput schema / properties / lng
        Added value: +{
        +  "description": "Explicit longitude, paired with `lat`.",
        +  "type": "number"
        +}
      • addedInput schema / properties / place
        Added value: +{
        +  "description": "Free-text place name, an alternative to `cell`.",
        +  "type": "string"
        +}
    • Changedemem_tools4 fields changed
      • changedInput schema / properties / category / description
        Previous value: -"Filter to one category."New value: +"Filter to one category. This is about the shape of the job, NOT about safety: 13 tools outside `write` declare `readOnlyHint: false` because reading a cold address can materialise or mint as a side effect, so `category: \"read\"` is not a safe-tools filter. Read each result's `annotations.readOnlyHint` for that."
      • changedInput schema / properties / name / description
        Previous value: -"Return the full descriptor for exactly this tool (input schema, runnable example, annotations), e.g. `emem_ndvi`. Use this when you already know the name and want its schema without loading the whole catalog."New value: +"Return the full descriptor for exactly this tool (input schema, runnable example, annotations), e.g. `emem_ndvi`. Use this when you already know the name and want its schema without loading the whole catalog. It SHORT-CIRCUITS: when `name` is set every other argument here is ignored, so `{name, q}` is not a search within one tool. A name this responder does not carry is not an error status, you get a body with `did_you_mean` holding up to five names that share a substring with what you asked for."
      • changedInput schema / properties / q / description
        Previous value: -"Free-text filter over tool names, titles and trigger text, e.g. `ndvi`, `cloud`, `flood`, `verify`, `token`."New value: +"Free-text filter over tool names, titles and trigger text, e.g. `ndvi`, `cloud`, `flood`, `verify`, `token`. Plain lowercased substring over name + title + description + trigger text, not fuzzy and not stemmed: `ndvi` hits, `vegetation index` only hits tools that spell that phrase. Combines with `shape`/`bundle`/`category`/`tier` as AND, so an over-narrow combination answers with an empty catalog rather than an error."
      • changedInput schema / properties / tier / description
        Previous value: -"Which slice to list. Defaults to `all`, so this tool shows the whole surface even when the endpoint advertises only the core loop."New value: +"Which slice to list. Defaults to `all`, so this tool shows the whole surface even when the endpoint advertises only the core loop, and an `extended` tool you find here is callable by name through tools/call whether or not your host listed it. Pass `core` to see only what a default connection advertises."
    • Removedemem_verify_receipt
  6. 1 tool updatev1.3.5
    • Changedemem_echo_verify2 fields changed
      • changedOutput schema / properties / drift / description
        Previous value: -"Present when it does not match: the difference between what you wrote and what emem holds."New value: +"The difference between what you wrote and what emem holds, when they disagree. Explicit null on an exact match: the key is always present, so branch on its value rather than on whether it exists. Declaring this `string` alone was a live schema violation on every matching call, which is how it was found."
      • changedOutput schema / properties / drift / type
        Previous value: -"string"New value: +[
        +  "string",
        +  "null"
        +]
  7. 3 tool updatesv1.3.4
    • Changedemem_echo_verify1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "properties": {
        +    "canonical_token": {
        +      "description": "The token in its canonical spelling, whatever form you passed.",
        +      "type": "string"
        +    },
        +    "claimed_value": {
        +      "description": "Echoed back, so a log line carries both sides of the comparison.",
        +      "type": "string"
        +    },
        +    "degraded": {
        +      "description": "True when a bare cid was passed and the cell binding could not be checked.",
        +      "type": "boolean"
        +    },
        +    "drift": {
        +      "description": "Present when it does not match: the difference between what you wrote and what emem holds.",
        +      "type": "string"
        +    },
        +    "fact_cid": {
        +      "type": "string"
        +    },
        +    "matches": {
        +      "description": "Whether what you were about to publish agrees with the signed fact. Treat false as a gate, not a warning.",
        +      "type": "boolean"
        +    },
        +    "offline_verify_at": {
        +      "description": "Where to re-run this check without trusting this responder.",
        +      "type": "string"
        +    },
        +    "receipt": {
        +      "type": "object"
        +    },
        +    "resolved_value_verbatim": {
        +      "description": "The fact's value as the exact decimal string it was signed as. Quote this rather than reformatting it.",
        +      "type": "string"
        +    },
        +    "token": {
        +      "description": "The citation you passed, echoed back exactly as sent.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "matches",
        +    "token",
        +    "claimed_value"
        +  ],
        +  "type": "object"
        +}
    • Changedemem_guard_verdict1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "properties": {
        +    "action": {
        +      "description": "NOT a clearance. `allow` means no rule fired, which on a transcript that cited nothing is silence rather than approval. Branch on citations_found and receipt.fact_cids.",
        +      "enum": [
        +        "allow",
        +        "deny"
        +      ],
        +      "type": "string"
        +    },
        +    "advisory": {
        +      "description": "True on the hosted route, where nothing is blocked. Run your own node to enforce.",
        +      "type": "boolean"
        +    },
        +    "checked": {
        +      "description": "How many were actually resolved, bounded by the verdict budget.",
        +      "type": "integer"
        +    },
        +    "citations_found": {
        +      "description": "How many emem: tokens were found in the text. Compare with receipt.fact_cids: a well-formed token that resolved to nothing counts here and not there.",
        +      "type": "integer"
        +    },
        +    "claim": {
        +      "description": "On CLAIM_UNGROUNDED: the sentence, magnitude, quantity, anchor, and source_band. source_band is a recallable band key, or null when this responder observes no band in that quantity.",
        +      "type": "object"
        +    },
        +    "code": {
        +      "description": "Present only on a deny.",
        +      "enum": [
        +        "PROV_SIG",
        +        "PROV_BYTES",
        +        "PROV_DRIFT",
        +        "PROV_VALUE",
        +        "GEO_ZONE",
        +        "CLAIM_UNGROUNDED",
        +        "POLICY_MODULE"
        +      ],
        +      "type": "string"
        +    },
        +    "fix": {
        +      "description": "The actionable half: what to change and retry.",
        +      "enum": [
        +        "refresh_token",
        +        "remove_reference",
        +        "contact_admin",
        +        "redact_and_retry",
        +        "cite_observation",
        +        "correct_value"
        +      ],
        +      "type": "string"
        +    },
        +    "receipt": {
        +      "description": "ed25519 receipt. `fact_cids` lists what actually resolved and is the field that separates a real citation from an invented one.",
        +      "type": "object"
        +    }
        +  },
        +  "required": [
        +    "action",
        +    "advisory",
        +    "checked",
        +    "citations_found",
        +    "receipt"
        +  ],
        +  "type": "object"
        +}
    • Changedemem_memory_token1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "properties": {
        +    "cell": {
        +      "type": "string"
        +    },
        +    "cell_token": {
        +      "description": "The address alone, when you mean the place rather than an observation of it.",
        +      "type": "string"
        +    },
        +    "docs": {
        +      "type": "string"
        +    },
        +    "fact_cid": {
        +      "type": "string"
        +    },
        +    "grammar": {
        +      "description": "The token grammar, so the form can be parsed rather than pattern-matched.",
        +      "type": "string"
        +    },
        +    "memory_token": {
        +      "description": "The citation to paste: emem:fact:<cell64>:<fact_cid>. Copy it verbatim; a hand-assembled token that is one character wrong still reads as a citation and resolves to nothing.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "memory_token",
        +    "cell",
        +    "fact_cid"
        +  ],
        +  "type": "object"
        +}
  8. 5 tool updatesv1.3.3
    • Changedemem_entity6 fields changed
      • addedInput schema / properties / lat / description
        Added value: +"Latitude anchoring the object to a place, paired with lng. The identity is hashed from this anchor, so two agents anchoring the same object differently mint different entities."
      • addedInput schema / properties / lat / maximum
        Added value: +90
      • addedInput schema / properties / lat / minimum
        Added value: +-90
      • addedInput schema / properties / lng / description
        Added value: +"Longitude, paired with lat."
      • addedInput schema / properties / lng / maximum
        Added value: +180
      • addedInput schema / properties / lng / minimum
        Added value: +-180
    • Changedemem_find_similar1 field changed
      • addedInput schema / properties / k / description
        Added value: +"How many neighbours to return."
    • Addedemem_guard_verdict
    • Changedemem_intent18 fields changed
      • addedInput schema / description
        Added value: +"A tagged union: `type` selects the intent and decides which OTHER fields are read. Fields belonging to a different intent are ignored, so send only the ones its row needs."
      • addedInput schema / properties / a / description
        Added value: +"is_like only: cell64 of the first place in the pair."
      • addedInput schema / properties / b / description
        Added value: +"is_like only: cell64 of the second place. The answer is a cosine similarity in [-1,1] over the two cells' embeddings."
      • addedInput schema / properties / band / description
        Added value: +"did_change only: which band to test, e.g. \"indices.ndvi\". One band per call; the answer is a delta over `window`, not a whole-cell diff."
      • addedInput schema / properties / cell / description
        Added value: +"cell64 address, e.g. \"damO.zb000.xUti.zde78\". Required by did_change and confirm. Optional for what_is_here and ask: supply it to skip geocoding, omit it and give `place` instead."
      • addedInput schema / properties / claim / description
        Added value: +"confirm only: the claim to test at `cell`, e.g. {\"band\":\"indices.ndvi\",\"op\":\"gt\",\"value\":0.4}. The answer is a verdict plus the signed facts it rests on."
      • addedInput schema / properties / description / description
        Added value: +"where_is: the place to resolve, e.g. \"Mount Everest\". ask: the user's question, forwarded verbatim. what_is_here: optional free text used as the question and, if `place` is absent, as the place. Ignored by the other intents."
      • addedInput schema / properties / filter
        Added value: +{
        +  "description": "find_like only: optional claim constraining which cells may be returned, same shape as `claim`.",
        +  "type": "object"
        +}
      • addedInput schema / properties / k / description
        Added value: +"find_like only: how many neighbours to return. Defaults to the primitive's own default when omitted."
      • addedInput schema / properties / k / minimum
        Added value: +1
      • addedInput schema / properties / key / description
        Added value: +"find_like only: cell64 to search from. Neighbours are ranked by embedding cosine against this cell."
      • addedInput schema / properties / lat
        Added value: +{
        +  "description": "ask only: latitude, paired with `lng`, when you want to pin the location by coordinate rather than by name or cell64.",
        +  "maximum": 90,
        +  "minimum": -90,
        +  "type": "number"
        +}
      • addedInput schema / properties / lng
        Added value: +{
        +  "description": "ask only: longitude, paired with `lat`.",
        +  "maximum": 180,
        +  "minimum": -180,
        +  "type": "number"
        +}
      • addedInput schema / properties / place
        Added value: +{
        +  "description": "Free-text place name for what_is_here and ask when you have a name but no cell64, e.g. \"Ashok Nagar, Ranchi\". The responder geocodes it. Ignored when `cell` is present.",
        +  "type": "string"
        +}
      • addedInput schema / properties / type / description
        Added value: +"Which question you are asking, and therefore which other fields apply. where_is: name a place, get its cell64 (needs `description`). what_is_here: summarise a location (needs `cell`, OR `place`/`description` to resolve it first). is_like: pairwise similarity (needs `a` and `b`). did_change: did one band move over a time window (needs `cell`, `band`, `window`). find_like: nearest neighbours to a known cell (needs `key`; optional `k`, `filter`). confirm: is a claim true at a cell (needs `claim` and `cell`). ask: free-text question about a place, runs locate + topic-route + recall server-side (needs `description`; optional `place`/`cell`/`lat`+`lng` to pin the location)."
      • addedInput schema / properties / window / description
        Added value: +"did_change only: exactly two tslots, [start, end], band-tempo-relative integers from the emem epoch (NOT unix seconds or a date string). Get valid tslots for a cell from emem_trajectory."
      • addedInput schema / properties / window / maxItems
        Added value: +2
      • addedInput schema / properties / window / minItems
        Added value: +2
    • Changedemem_recall3 fields changed
      • changedInput schema / properties / include / description
        Previous value: -"Opt-in response expansion. include:['freshness'] attaches an advisory per-fact freshness block: a Q(Δt) staleness score from the band's physics decay kernel (the same one /v1/temporal_route ranks bands with), so an agent learns how stale each reading is in the call that returns it. Advisory only; it does NOT enter the receipt. include:['edges'] attaches each fact's typed temporal edges and threads their CIDs into the receipt. Absent leaves the response byte-identical to the pre-v0.0.9 recall."New value: +"Opt-in response expansion. include:['provenance'] attaches each fact's tamper-provenance class, which is what `deterministic` and the `provenance` filter select ON: without it you can filter by class and never be told which class a returned fact is. include:['freshness'] attaches an advisory per-fact freshness block: a Q(Δt) staleness score from the band's physics decay kernel (the same one /v1/temporal_route ranks bands with), so an agent learns how stale each reading is in the call that returns it. Advisory only; it does NOT enter the receipt. include:['edges'] attaches each fact's typed temporal edges and threads their CIDs into the receipt. Absent leaves the response byte-identical to the pre-v0.0.9 recall."
      • changedInput schema / properties / include / items / enum
        Previous value: -[
        -  "freshness",
        -  "edges"
        -]New value: +[
        +  "freshness",
        +  "edges",
        +  "provenance"
        +]
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "properties": {
        +    "bands_already_attested_at_cell": {
        +      "description": "What else is readable here without materialising, so an empty result can be told apart from a wrong band name.",
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "current_by_band": {
        +      "description": "Per band, the fact_cid with the highest tslot: the current reading. Unslotted facts are excluded, since tslot 0 means undated rather than oldest.",
        +      "type": "object"
        +    },
        +    "fact_order": {
        +      "description": "The ordering contract for facts, e.g. tslot_ascending. Stated rather than implied so nothing depends on position by accident.",
        +      "type": "string"
        +    },
        +    "facts": {
        +      "description": "Signed facts at the cell, ordered per fact_order.",
        +      "items": {
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "materialize_notes": {
        +      "items": {
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "receipt": {
        +      "description": "ed25519 receipt over the returned fact_cids. Verify offline; select the rule from its preimage_version.",
        +      "type": "object"
        +    }
        +  },
        +  "required": [
        +    "facts",
        +    "receipt",
        +    "fact_order"
        +  ],
        +  "type": "object"
        +}
  9. 6 tool updatesv1.3.1
    • Changedemem_ask1 field changed
      • changedInput schema / properties / cell / description
        Previous value: -"cell64 string (alternative to `place` — use when you have one from a prior emem_locate / emem_recall response). Provide this OR `place` OR `lat`+`lng`."New value: +"cell64 string (alternative to `place`, use when you have one from a prior emem_locate / emem_recall response). Provide this OR `place` OR `lat`+`lng`."
    • Changedemem_find_similar3 fields changed
      • changedInput schema / properties / as_of_tslot / description
        Previous value: -"Bi-temporal valid-time bound. Applied to candidate cells BEFORE cosine scoring — a cell with no fact whose tslot ≤ as_of_tslot under the scoring band is dropped from the candidate pool (undecidable→drop). When set, the Lance ANN fast-path is bypassed (the index has no signed_at column); brute-force k-NN runs instead so as_of is honoured truthfully."New value: +"Bi-temporal valid-time bound. Applied to candidate cells BEFORE cosine scoring, a cell with no fact whose tslot ≤ as_of_tslot under the scoring band is dropped from the candidate pool (undecidable→drop). When set, the Lance ANN fast-path is bypassed (the index has no signed_at column); brute-force k-NN runs instead so as_of is honoured truthfully."
      • changedInput schema / properties / band / description
        Previous value: -"vector band to scan (default: 128-D Tessera foundation embedding). For mode=hamming/hamming_then_rerank you can pass either the cosine band (e.g. 'geotessera') or its binary sibling ('geotessera.bin128') — the responder picks the right one."New value: +"vector band to scan (default: 128-D Tessera foundation embedding). For mode=hamming/hamming_then_rerank you can pass either the cosine band (e.g. 'geotessera') or its binary sibling ('geotessera.bin128'), the responder picks the right one."
      • changedInput schema / properties / mode / description
        Previous value: -"Scoring mode. cosine = fp32 over full vector (precise, ~256 B/cell scan). hamming = sign-bit popcount over the binary sibling band (~16 B/cell, ~1000× faster, ~65% recall@10). hamming_then_rerank = triage with Hamming on 4·k candidates then re-rank by cosine — matches cosine precision at ~16× less work."New value: +"Scoring mode. cosine = fp32 over full vector (precise, ~256 B/cell scan). hamming = sign-bit popcount over the binary sibling band (~16 B/cell, ~1000× faster, ~65% recall@10). hamming_then_rerank = triage with Hamming on 4·k candidates then re-rank by cosine, matches cosine precision at ~16× less work."
    • Changedemem_locate1 field changed
      • changedInput schema / properties / q / description
        Previous value: -"Alias for `place` — accepted because OSM/Mapbox/Google Geocoding all use `q`. Provide either this or `place` (or `lat`+`lng`)."New value: +"Alias for `place`, accepted because OSM/Mapbox/Google Geocoding all use `q`. Provide either this or `place` (or `lat`+`lng`)."
    • Changedemem_memory_contradictions1 field changed
      • changedInput schema / properties / window_unix_s / description
        Previous value: -"[lo, hi] inclusive Unix-seconds filter on attestations' signed_at — all disagreeing attestations must fall in the window."New value: +"[lo, hi] inclusive Unix-seconds filter on attestations' signed_at, all disagreeing attestations must fall in the window."
    • Changedemem_memory_token1 field changed
      • changedInput schema / properties / cell / description
        Previous value: -"cell64 — neither component may contain `:`."New value: +"cell64, neither component may contain `:`."
    • Changedemem_recall6 fields changed
      • changedInput schema / properties / as_of_signed_at / description
        Previous value: -"Bi-temporal transaction-time bound. RFC 3339 string. Returns only facts whose `signed_at` ≤ as_of_signed_at — answers `what did emem KNOW as of system-date Y`. Malformed strings are rejected with code:`invalid_signed_at_format`."New value: +"Bi-temporal transaction-time bound. RFC 3339 string. Returns only facts whose `signed_at` ≤ as_of_signed_at, answers `what did emem KNOW as of system-date Y`. Malformed strings are rejected with code:`invalid_signed_at_format`."
      • changedInput schema / properties / as_of_tslot / description
        Previous value: -"Bi-temporal valid-time bound. Returns the latest fact per (cell,band) whose tslot ≤ as_of_tslot — answers `what did this place look like AS OF date X`. Conflicts with an explicit `tslot` when as_of_tslot < tslot (rejected with code:`invalid_temporal_bound`)."New value: +"Bi-temporal valid-time bound. Returns the latest fact per (cell,band) whose tslot ≤ as_of_tslot, answers `what did this place look like AS OF date X`. Conflicts with an explicit `tslot` when as_of_tslot < tslot (rejected with code:`invalid_temporal_bound`)."
      • changedInput schema / properties / band / description
        Previous value: -"optional single band key — convenience alias for bands:[band]. Use when you want exactly one band (e.g. 'geotessera.2020', 'modis.ndvi_mean') and would otherwise have to wrap it in an array. Both `band` and `bands` are accepted; if both are given they are merged."New value: +"optional single band key, convenience alias for bands:[band]. Use when you want exactly one band (e.g. 'geotessera.2020', 'modis.ndvi_mean') and would otherwise have to wrap it in an array. Both `band` and `bands` are accepted; if both are given they are merged."
      • changedInput schema / properties / deterministic / description
        Previous value: -"Sugar over `provenance`: true keeps only facts any third party can recompute from the cited raw source (direct_sensor + deterministic_index); false keeps the rest (model_output + human_curated + unclassified). Composable with `provenance` (intersection)."New value: +"Sugar over `provenance`: true keeps only facts any third party can recompute from the cited raw source (direct_sensor + deterministic_index); false keeps the rest (attested_execution + model_output + human_curated + unclassified). Composable with `provenance` (intersection)."
      • changedInput schema / properties / provenance / description
        Previous value: -"Tamper-provenance filter: return only facts whose band's provenance class is in this list. Applied BEFORE the receipt is signed, so the receipt covers exactly the returned facts; `bands_already_attested_at_cell` stays unfiltered so you still see what else exists at the cell."New value: +"Tamper-provenance filter: return only facts whose band's provenance class is in this list. `attested_execution` is a device reading trusted through its verified OS execution trace and platform attestation (not recomputable). Applied BEFORE the receipt is signed, so the receipt covers exactly the returned facts; `bands_already_attested_at_cell` stays unfiltered so you still see what else exists at the cell."
      • changedInput schema / properties / provenance / items / enum
        Previous value: -[
        -  "direct_sensor",
        -  "deterministic_index",
        -  "model_output",
        -  "human_curated",
        -  "unclassified"
        -]New value: +[
        +  "direct_sensor",
        +  "deterministic_index",
        +  "attested_execution",
        +  "model_output",
        +  "human_curated",
        +  "unclassified"
        +]
  10. 2 tool updatesv1.3.0
    • Addedemem_echo_verify
    • Changedemem_memory_bundle2 fields changed
      • changedInput schema / properties / triples / description
        Previous value: -"One or more (cell, band, tslot?) triples to bundle. Each entry is recalled through the standard auto-materialize path; the bundle envelope cites every resulting fact_cid."New value: +"One to 256 (cell, band, tslot?) triples to bundle. Each entry is recalled through the standard auto-materialize path; the bundle envelope cites every resulting fact_cid. 257 or more is a typed 400: the token is O(1) in size for any N, but covering N facts costs ceil(N/256) calls, so plan round trips rather than meeting the cap mid-run."
      • addedInput schema / properties / triples / maxItems
        Added value: +256
  11. 14 tool updatesv0.1.0
    • First observedemem_ask
    • First observedemem_entity
    • First observedemem_entity_link
    • First observedemem_entity_resolve
    • First observedemem_find_similar
    • First observedemem_intent
    • First observedemem_locate
    • First observedemem_memory_bundle
    • First observedemem_memory_contradictions
    • First observedemem_memory_token
    • First observedemem_memory_token_resolve
    • First observedemem_recall
    • First observedemem_tools
    • First observedemem_verify_receipt

TDQS

A4.1/5.0

Scored across 18 tools

Disambiguation3/5

The set has several overlapping read paths: emem_ask, emem_intent, search/fetch, emem_recall and emem_locate can all answer place questions, while verify_receipt, echo_verify and guard_verdict form a related verification cluster. The descriptions explicitly distinguish sibling tools, but an agent still has to read carefully to avoid misselection.

Naming Consistency3/5

Most tools use an emem_ prefix, but search and fetch are generic unprefixed names, and the set mixes verb-style names (locate, recall, ask, verify) with noun-style names (memory_token, memory_bundle, entity, intent, tools). The convention is readable but not predictable throughout.

Tool Count3/5

At 18 tools this is in the borderline-heavy range for the rubric, and the broad geospatial/memory domain makes some breadth reasonable. However, multiple tools provide layered alternatives for similar outcomes, so the count feels somewhat heavier than necessary.

Completeness4/5

The core lifecycle is well covered: locate, recall, search/fetch, cite, resolve, verify, guard, contradictions, entities, bundles and similarity search. There are still gaps such as polygon recall, trajectory, diff and edge-recall tools referenced in descriptions, though emem_tools and emem_intent provide partial workarounds.

Maintenance

ActivityActive
ResponsivenessResponsive

Related MCP Connectors

Related MCP Servers