Skip to main content
Glama

k-NN over the corpus by embedding

emem_find_similar
Idempotent

Find similar places or vectors by cell ID or inline embedding, returning nearest neighbours ranked by similarity. Uses cosine or fast Hamming scoring to match what the corpus already holds.

Instructions

k-NN over the corpus by cell embedding or inline vector. Returns neighbours ordered nearest-first, each with cell64, score and the band scanned, plus a signed receipt over the vectors read. Scoring is mode: cosine is exact fp32; hamming is a sign-bit popcount that scans far more cells for the same budget; hamming_then_rerank does both. k is 1..1000, default 10. It ranks what the corpus already holds and materialises nothing, so an empty result means nobody has attested a vector nearby, not that nowhere resembles the key.

When to use: Call when the user asks 'find places like X', 'where else looks like this', or hands an embedding to find neighbours. key is either a cell64 or inline:[x,y,...]. Default band is geotessera (128-D Tessera foundation embedding); pass band: "geotessera.multi_year" for the 1152-D 9-vintage (2017–2025) fusion.

Example arguments: {"key":"damO.zb000.xUti.zde78","k":10}

Input Schema

TableJSON Schema
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.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed4 schema fields changedv1.3.8
    • 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"
      +}
  2. Changed1 schema field changedv1.3.3
    • addedInput schema / properties / k / description
      Added value: +"How many neighbours to return."
  3. Changed3 schema fields changedv1.3.1
    • 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."
  4. First observedv0.1.0

TDQS

A4.6/5.0
Behavior5/5

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

The description discloses far more than annotations alone: mode tradeoffs (~1000× faster, ~65% recall@10), the open-world empty-result meaning ("empty result means nobody has attested a vector nearby"), and the ANN fast-path bypass for scope/as_of with the honest-cost tradeoff ("brute-force scan instead... the call is slower"). Filter semantics ("DROPPED rather than treated as false") and bi-temporal candidate-dropping are also candidly stated. No contradiction with annotations; there is only a soft tension between readOnlyHint=false and "materialises nothing", but the receipt is returned to the caller rather than persisted.

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 mechanism and return shape, then a labeled "When to use" block, then an example. It is on the longer side and the mode paragraph partly duplicates the schema's mode description, but every sentence carries either selection or invocation information rather than filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 10-parameter tool with nested objects and no output schema, the description covers the entire invocation surface: return contract (neighbours with cell64/score/band plus signed receipt), empty-result semantics, k bounds, key forms, band choices, mode tradeoffs, and the scope/filter/as_of behaviors. An agent can select and invoke this tool correctly from the text alone.

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% and the schema's own parameter descriptions are already rich (mode byte-costs, filter drop rule, scope bypass). The description still adds non-redundant value: key formats (cell64 vs inline:[x,y,...]), band dimensionality (128-D foundation vs 1152-D 9-vintage 2017–2025 fusion) with the exact band name to pass, and a concrete example. That lifts it above the baseline-3 for fully covered schemas.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening line names a specific operation – k-NN over the corpus – with explicit input forms ("by cell embedding or inline vector") and a concrete return contract ("neighbours ordered nearest-first, each with cell64, score and the band scanned"). The trigger phrases "find places like X" / "where else looks like this" clearly separate it from siblings like emem_recall and emem_locate. It adds method and output detail well beyond the title.

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?

There is an explicit "When to use" block with concrete user-phrasing triggers and the embedding-input case, plus a worked example argument {"key":"damO.zb000.xUti.zde78","k":10}. What is missing is explicit when-not-to-use guidance or named sibling alternatives, so exclusion routing is left to inference.

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