Skip to main content
Glama

Holographic Memory

Local memory for agents and apps: full-text and vector search, a memory API and a vector-symbolic fact store in one embeddable Rust engine that makes no network calls.

CI crates.io docs.rs PyPI MSRV 1.89 OpenSSF Scorecard OpenSSF Best Practices License: Apache-2.0

Bemula forgetting score, DeepSeek backbone LongMemEval dev, gpt-4o reader and judge VIBE llama-128-ip max recall@100, one thread SIFT-1M QPS at recall@10 0.95, one query thread, unpinned

Website · Docs · Get started · Results · Why "holographic"? · Capabilities · Limits · Contribute

What it is

Holographic Memory (HMS for short) is a Rust library that stores text, vectors and facts in a directory on your machine and finds them again. It ships with Node.js bindings, C, WASM and UniFFI bindings, an HTTP server with a Python client, and an MCP server. There are no service calls, no telemetry and no model downloads unless you turn on a feature that asks for one.

Capability

What you get

Document search

Chunking, stemmed BM25 over blocked postings, Boolean and phrase queries, hybrid fusion with embeddings you supply, metadata filters, byte offsets

Vector index

Graph index with a memory-mapped vertex file, an updatable delta for inserts and deletes, optional query-aware routing trained on sample queries

Memory API

remember, recall, forget and explain with time validity and supersession; conversation memory with source provenance

Storage

Atomic replace and delete, crash-safe journal and checkpoints, verified compaction, one writer per store

Security

Optional AES-256-GCM encryption at rest, signed audit log, COSE/SCITT provenance

Vector-symbolic layer

Sparse hypervectors with bind, bundle and permute, triples with multi-hop queries, Hopfield cleanup

Related MCP server: mnemo-mcp

Who it's for

You are building

What you get

An agent or assistant that needs memory

A memory API with forgetting that removes facts from the store, and an MCP server for editors and agent hosts

A local-first or offline app

Embedded search and storage in one directory, with no server process and optional encryption

A service that needs vector or text search

hms-server over HTTP with tenants and scoped keys, or the library in-process

Research on vector-symbolic memory

The bind/bundle algebra, meaning memory and capacity experiments with their result files

Headline results

Every row links to the committed file it comes from. These are single machines and stated protocols, not a substitute for testing your own data.

Result

Conditions

Source file

Bemula forgetting score 0.322; best published row 0.310 (LangMem)

Full split: 50 dialogues, 135 forget requests. Agent and judge both deepseek-v4-flash-0731 through OpenRouter pinned to DeepSeek, temperature 0; the judge snapshot is inferred from the authors' run metadata. Recall k=5 hybrid with text-embedding-3-small. Compared with the paper's published DeepSeek rows; a same-day rerun of the suite's naive RAG baseline scored 0.075. One run.

bemula_v1.json

LongMemEval dev 89.75 of 100 correct (mean of 4 runs, range 87 to 93)

Official generation and judge prompts, gpt-4o-2024-08-06 as reader and judge, top 10 context. Retrieval is the reference turn ranking over cached Qwen3 scores, not native conversation-memory recall. k was chosen on dev; there is no held-out result.

longmemeval_official_dev_summary.json

VIBE llama-128-ip strict recall@100 up to 0.99687 at 1,457 QPS

Official test queries, one thread, query-aware graph (ef=512). Neither frozen RoarGraph configuration reached 0.99. Behind at 0.95 and 0.99 QPS (see below).

query_aware_graph_v1/README.md

VIBE yi-128-ip at recall 0.95: 3,214 QPS against 1,953 (MLANN RF80)

Same protocol; compared only with the frozen RoarGraph and MLANN configurations measured there. Recall 0.99 was not reached.

query_aware_graph_v1/README.md

SIFT-1M QPS at recall@10 0.95: 17,481 against hnswlib 7,630 (2.29x, interval 1.95 to 2.39)

Core Ultra 9 185H, queries issued one at a time from one client thread, process not pinned to a core, index built with 8 threads. Timed through the Rust API, hnswlib through its Python binding.

heavy-ann-sift-...-185h-22c-27g.json

SciFact nDCG@10 hybrid 0.729, above its own BM25 (0.688) and dense (0.645)

5,183 documents, 300 queries, MiniLM embeddings supplied by the harness. NFCorpus: 0.355 against 0.323 and 0.317.

public_scifact.json, public_nfcorpus.json

Where it's behind

Result

Conditions

Source file

ann-benchmarks at recall 0.95: sift 2,819 QPS against faiss-ivfpqfs 3,788 (0.74x); glove 1,019 against ScaNN 1,535 (0.66x)

Official ann-benchmarks runner, each run pinned to one CPU, AVX2 host

ann_benchmarks_harness_wl02_v1.json

VIBE llama-128-ip QPS: 24.6% behind RoarGraph at recall 0.95, 54.8% behind MLANN RF80 at 0.99

One thread, official test queries

query_aware_graph_v1/README.md

SIFT-1M build time 0.58x and serving RSS 0.46x of hnswlib

Same run as the QPS row above

docs/benchmarks/GAPS.md

Text search ingest time, serving RSS and cold start behind SQLite FTS5 and tantivy on most corpora

BEIR and memory corpora, two hosts

docs/benchmarks/GAPS.md

glove-100-angular with the sparse vector path: recall@10 0.252 at 33.7 QPS against FAISS HNSW 0.832 at 4,111 QPS

One thread, Apple M4; the sparse path is experimental

public_glove-100-angular.json

Method, intervals and every loss: docs/benchmarks and the benchmarks pages.

Generated from benchmarks/results/competitive/ by hms-bench table; method and caveats in docs/benchmarks/COMPARISON.md. W = HMS ahead (95% interval excludes parity), T = tie, L = a comparator is ahead.

Dataset

Metric

HMS

Best other

Advantage

sift-128-euclidean

QPS @ recall@10 >= 0.95 (QPS)

17,481

hnswlib 7,630

2.29x

W

sift-128-euclidean

p99 latency @ 0.95 (us)

105

hnswlib 220

2.10x

W

sift-128-euclidean

Build time (s)

312.60

hnswlib 182.49

0.58x

L

sift-128-euclidean

RSS, serving (MiB)

2,204

hnswlib 1,019

0.46x

L

sift-128-euclidean

Index size (MiB)

446.3

hnswlib 873.8

1.96x

-

beir:fiqa

nDCG@10

0.2654

SQLite FTS5 0.2678

0.99x

T

beir:fiqa

QPS (single thread) (QPS)

3,576

tantivy 1,617

2.21x

W

beir:fiqa

p99 latency (us)

501

tantivy 1,269

2.53x

W

beir:fiqa

Ingest/build time (s)

2.16

SQLite FTS5 1.18

0.55x

L

beir:fiqa

Peak RSS, serving (MiB)

2,480

SQLite FTS5 2,480

1.00x

T

beir:fiqa

On-disk size (MiB)

20.6

Apache Lucene 9.12.3 (JVM) 12.2

0.59x

L

memory

nDCG@10

0.4561

Apache Lucene 9.12.3 (JVM) 0.4627

0.99x

T

memory

QPS (single thread) (QPS)

2,225

tantivy 2,399

0.93x

T

memory

p99 latency (us)

786

tantivy 733

0.93x

T

memory

Ingest/build time (s)

2.52

SQLite FTS5 2.06

0.82x

L

memory

Peak RSS, serving (MiB)

66

SQLite FTS5 26

0.39x

L

memory

On-disk size (MiB)

9.8

Apache Lucene 9.12.3 (JVM) 10.3

1.05x

W

memory

nDCG@10

0.4561

Apache Lucene 9.12.3 (JVM) 0.4627

0.99x

T

memory

QPS (single thread) (QPS)

11,857

tantivy 4,591

2.58x

W

memory

p99 latency (us)

145

tantivy 412

2.85x

W

memory

Ingest/build time (s)

1.21

SQLite FTS5 0.88

0.73x

L

memory

Peak RSS, serving (MiB)

2,480

SQLite FTS5 2,480

1.00x

T

memory

On-disk size (MiB)

9.8

Apache Lucene 9.12.3 (JVM) 10.3

1.05x

W

beir:nfcorpus

nDCG@10

0.2916

SQLite FTS5 0.2914

1.00x

T

beir:nfcorpus

QPS (single thread) (QPS)

38,963

tantivy 14,705

2.65x

W

beir:nfcorpus

p99 latency (us)

57

tantivy 150

2.62x

W

beir:nfcorpus

Ingest/build time (s)

0.23

SQLite FTS5 0.14

0.59x

L

beir:nfcorpus

Peak RSS, serving (MiB)

748

SQLite FTS5 748

1.00x

T

beir:nfcorpus

On-disk size (MiB)

2.1

Apache Lucene 9.12.3 (JVM) 1.5

0.72x

L

beir:nfcorpus

nDCG@10

0.2916

SQLite FTS5 0.2914

1.00x

T

beir:nfcorpus

QPS (single thread) (QPS)

9,532

tantivy 7,105

1.34x

T

beir:nfcorpus

p99 latency (us)

298

tantivy 300

1.01x

T

beir:nfcorpus

Ingest/build time (s)

0.59

SQLite FTS5 0.29

0.48x

L

beir:nfcorpus

Peak RSS, serving (MiB)

57

SQLite FTS5 30

0.53x

L

beir:nfcorpus

On-disk size (MiB)

2.1

Apache Lucene 9.12.3 (JVM) 1.5

0.72x

L

beir:scifact

nDCG@10

0.7027

Apache Lucene 9.12.3 (JVM) 0.7022

1.00x

T

beir:scifact

QPS (single thread) (QPS)

17,782

tantivy 6,450

2.76x

W

beir:scifact

p99 latency (us)

95

tantivy 292

3.09x

W

beir:scifact

Ingest/build time (s)

0.31

SQLite FTS5 0.20

0.63x

L

beir:scifact

Peak RSS, serving (MiB)

196

tantivy 174

0.89x

T

beir:scifact

On-disk size (MiB)

2.9

Apache Lucene 9.12.3 (JVM) 2.0

0.68x

L

beir:scifact

nDCG@10

0.7027

Apache Lucene 9.12.3 (JVM) 0.7022

1.00x

T

beir:scifact

QPS (single thread) (QPS)

2,711

tantivy 2,879

0.94x

L

beir:scifact

p99 latency (us)

526

tantivy 520

0.99x

T

beir:scifact

Ingest/build time (s)

1.42

SQLite FTS5 0.43

0.30x

L

beir:scifact

Peak RSS, serving (MiB)

160

SQLite FTS5 54

0.34x

L

beir:scifact

On-disk size (MiB)

2.9

Apache Lucene 9.12.3 (JVM) 2.0

0.68x

L

Get started

Clone once: git clone https://github.com/writerslogic/holographic-memory && cd holographic-memory. Run the offline agent-memory demo with cargo run --release --example demo-offline-agent.

From your own Rust project, add the current Apache-2.0 source:

cargo add holographic-memory --git https://github.com/writerslogic/holographic-memory

The published crate 0.6.1 remains AGPL-3.0-or-later.

use holographic_memory::{DocumentInput, HmsCore, SearchOptions};

let dir = tempfile::tempdir()?;
let hms = HmsCore::new(4096, Some(dir.path().display().to_string()), None)?;
hms.memorize_document(DocumentInput {
    id: "backups".into(),
    text: "Restore deleted documents from verified backups.".into(),
    source_uri: Some("operations.md".into()),
    version: Some("1".into()),
    metadata: Some(serde_json::json!({ "project": "alpha" })),
    chunk_words: None, overlap_words: None, store_text: None, embeddings: None, title_weight: None,
})?;
let hits = hms.search_documents("restore backups", &SearchOptions::default())?;
println!("{} {:?}", hits[0].document_id, hits[0].source_uri);

The npm registry carries only the deprecated 0.3.0; build the native module from source (Rust required):

npm ci --omit=optional && npm run build
const { HolographicMemorySystem } = require('./index.js')
const { DocumentMemory } = require('./semantic.js')

async function main() {
  const dir = require('node:fs').mkdtempSync(require('node:path').join(require('node:os').tmpdir(), 'hms-readme-'))
  const memory = new DocumentMemory(new HolographicMemorySystem(4096, dir))
  await memory.memorize({
    id: 'backups', text: 'Restore deleted documents from verified backups.',
    sourceUri: 'operations.md', version: '1', metadata: { project: 'alpha' },
  })
  const [hit] = await memory.search('restore backups', { filter: { project: 'alpha' } })
  console.log(hit.documentId, hit.sourceUri, hit.text)
  await memory.flush()
}
main().catch(error => { console.error(error); process.exit(1) })

The Python package holographic-memory-sdk is an HTTP client for hms-server, which stores vectors you supply. (holographic-memory-py provides native vector search and phase vectors, but no document search.)

cargo build --release --features server --bin hms-server
HMS_API_KEY=change-me target/release/hms-server --input-dim 384 &
uv pip install holographic-memory-sdk
from holographic_sdk import HolographicClient

client = HolographicClient(url="http://127.0.0.1:8080", api_key="change-me", tenant_id="demo")
client.add_documents([{"id": "a", "vector": [0.1] * 384, "text": "hello", "metadata": {}}])
print(client.query([0.1] * 384, top_k=1)["matches"][0]["id"])

Endpoints, flags, tenants and limits are in the server docs. A runnable Python quickstart with a toy embedder is in examples/quickstart/python.

hms-mcp serves a store to any Model Context Protocol client over stdio or HTTP:

cargo build --release --features mcp,security --bin hms-mcp   # add local-models for semantic recall
./target/release/hms-mcp                                       # stdio
./target/release/hms-mcp --transport http                      # http://127.0.0.1:8765/mcp

Client setup, data directory and the one-writer rule: MCP integration.

The five-minute quickstart walks through ingest, search, a SQLite FTS5 comparison and encryption in Rust, Python and Node, and CI runs that code on every pull request. For a whole agent memory with no embeddings and no network, run cargo run --example demo-offline-agent.

Why is it called "holographic"?

In a hologram, every fragment of the plate carries a blurry copy of the whole picture. Cut it in half and you get the whole picture at lower resolution, not half a picture. Holographic Reduced Representations and Vector Symbolic Architectures (VSA) give memory that property:

  • Bind two vectors (here, XOR of sparse bit sets) to tie a role to a filler: capital ⊗ paris. Binding again with the role recovers a noisy copy of the filler.

  • Bundle many bound pairs into one vector of fixed size. The result stays similar to every part, so one vector can hold a whole record, with no single bit holding any one fact.

  • Recall by resonance. Present a noisy cue and the nearest stored pattern wins (similarity search, Hopfield cleanup). Damaging the vector degrades every item a little instead of deleting a few, so recall falls off gradually under noise.

You can watch it happen in a few lines (a union bundle of 100 items, damaged step by step): cargo run --release --manifest-path examples/quickstart/rust/Cargo.toml --bin holographic.

What is literally that here: the sparse hypervector type and its bind, bundle and permute operations; the relational "meaning memory" (triples stored as bound composites, multi-hop queries, Hopfield cleanup); the union-bundle membership test and the resonator network (both behind the experimental feature).

What is conventional engineering: document search (stemmed BM25 plus exact cosine; it does not read the hypervectors), the graph and inverted-file vector indexes, the memory API, the journaled storage and the servers. No holographic behavior is claimed for these. The longer version, with the tested numbers, is in Concepts.

What ships today

Capability

Status

Documented limit

Hybrid document search (BM25 + exact cosine, filters, byte offsets)

Ships

Exact scan of eligible chunks; benchmark your corpus before assuming capacity (guide)

Boolean lexical search (+required, -excluded, quoted phrases)

Ships

Flat queries only, no nesting; an empty or only-excluded query matches nothing (design)

Atomic replace/delete, crash-safe journal, verified compaction, process lock

Ships

One writer per store; compaction is not secure erasure

Vector index (qgraph vertex graph, memory-mapped)

Ships

Build time and serving RSS behind hnswlib on SIFT-1M (gaps)

Updatable vector index (durable delta for inserts and deletes)

Ships

Single writer; format in VECTOR-UPDATES.md

Query-aware graph routing (trained on sample queries)

Ships (opt-in)

Needs representative training queries; tested on VIBE llama and yi (report)

Memory API: remember, recall, forget, explain

Ships

Forgetting removes a fact from the store; it does not cover what a model inferred (docs)

Conversation memory (conversation-memory)

Ships

Bounded context with exact source provenance; native recall not yet benchmarked on LongMemEval end to end

Meaning memory: triples, multi-hop, Hopfield cleanup

Ships (runtime opt-in)

Tested on synthetic and 2,120-fact sets (research_bench_16384_256.json)

Union-bundle membership (experimental)

Research

At D = 16,384: positive gap to N = 500 (4% false positives), tested to 2,500 (benchmark_scaling_results.json)

Sparse vector index (memorize_vector)

Experimental

Not competitive with HNSW (results)

Encrypted stores (security)

Ships

AES-256-GCM, Argon2id; covers the log, index caches and the text segment. Metadata, file names and sizes are not encrypted

Signed audit log, credential-gated access, COSE/SCITT/C2PA (provenance)

Ships

Host must authenticate DIDs; PoSME, RATS, did:web not implemented

On-device models (local-models: Qwen3 embed/rerank/LLM)

Ships

Local weights only; never downloads

hms-server HTTP API, multi-tenant (server)

Ships

Single node; TLS, per-tenant scoped keys (guide)

MCP server (mcp: hms-mcp, stdio and HTTP)

Ships

Encryption needs security; semantic recall needs local-models

Node.js bindings

Ships (build from source)

npm package not yet republished

C, WASM and UniFFI bindings

Ships (build from source)

See bindings/

Python

Client + phase substrate

No in-process document search

Query-private search (private-search)

Experimental

For searching an index someone else holds; hides the query vector from the scorer only (notes)

Every capability above except document search and the vector index is behind a Cargo feature or runtime option that is off by default; Cargo features lists them all.

Architecture

flowchart TB
  subgraph bindings["Bindings and servers"]
    rust["Rust crate"]
    node["Node.js (napi)"]
    ffi["C, WASM, UniFFI"]
    python["Python: holographic-memory-sdk"]
    server["hms-server (HTTP)"]
    mcp["hms-mcp (stdio, HTTP)"]
  end
  subgraph engine["Engine API"]
    core["HmsCore: documents, vectors, facts, mutation gate"]
    prov["Security and provenance: signed audit log, COSE/SCITT"]
  end
  subgraph indexes["Indexes and memory"]
    text["Text index: blocked postings, BM25, Boolean and phrase"]
    vector["Vector index (qgraph): vertex file, updatable delta, query-aware projection"]
    memory["Memory API: remember, recall, forget, conversation memory"]
    vsa["Vector-symbolic layer: bind, bundle, Hopfield cleanup"]
  end
  subgraph storage["Storage"]
    journal["Journal and checkpoints"]
    segments["Append-only segments (CRC32, LZ4)"]
    mapped["Memory-mapped files"]
    crypto["AES-256-GCM encryption (optional)"]
  end
  python --> server
  rust --> core
  node --> core
  ffi --> core
  server --> core
  mcp --> core
  core --> text
  core --> vector
  core --> memory
  core --> vsa
  core --> prov
  memory --> text
  text --> journal
  vector --> journal
  memory --> journal
  journal --> segments
  segments --> mapped
  segments --> crypto

Module map: docs/ARCHITECTURE.md.

Limits

  • Not anonymous. Hypervector sketches and term counts are not encryption; anyone with a store can encode candidate text and compare. storeText: false keeps term counts, IDs and embeddings, so it is not a privacy control.

  • Document search is conventional. It does not use the hypervectors; the holographic parts are the algebra and the meaning memory.

  • One writer per store. A second writing process fails at open with a lock error.

  • Capacity numbers are points, not guarantees, and are stated only over the tested range (capacity).

  • Benchmark results are single machines. Conditions are in each results file; the single-core ann-benchmarks run and the VIBE high-recall points are losses (see Where it's behind).

  • Masking is obfuscation. Client-side vector masking preserves every pairwise similarity.

  • A store is a directory and HmsCore::new(.., None, ..) uses the current directory.

Full statement: docs/PRIVACY.md. Report vulnerabilities privately via SECURITY.md.

Contributing

CONTRIBUTING.md: setup, the checks CI runs, DCO sign-off (git commit -s, no CLA). Start with a good first issue or Discussions. See the Code of Conduct. Benchmark changes regenerate the results file they touch; the README cites files, not remembered figures.

License

Apache-2.0. See LICENSE. Use, modify and embed it in open-source or proprietary software, including network services, with no copyleft obligation. Releases up to and including crate 0.6.1 were published under AGPL-3.0-or-later and stay available under those terms.

Available Tools

8 tools
exportExport memory contentsA
Read-onlyIdempotent

Read a portable snapshot of memory contents as JSON, JSONL or Markdown; use list for short previews instead. Read-only. The payload is returned as text and capped by the server's export byte limit; pass next_cursor as cursor to continue.

NameRequiredDescriptionDefault
tagNoInclude only memories carrying this tag.
limitNoMaximum memories in this export segment, also bounded by the server's byte limit.
cursorNo`next_cursor` from the previous export segment.
formatNoSerialization of the returned text payload.json
prefixNoInclude only memory ids starting with this prefix.

Output Schema

NameRequiredDescription
bytesYesSize of the returned text payload in bytes.
countYesNumber of exported memories in this segment.
formatYesSerialization used for the text payload.
next_cursorYesPass a string value as `cursor` for the next segment; null ends the export.

TDQS

A4.3/5.0
Behavior5/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true and destructiveHint=false, so the safety profile is covered. The description adds genuinely new behavior: the payload comes back as text, it is capped by a server-side export byte limit, and segments are chained via cursor — exactly the truncation semantics an agent must know. No contradiction with 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?

Front-loaded with the verb, resource, and formats, followed by the sibling alternative and the pagination note, with no filler. It is dense — three distinct points packed into two sentences — but each sentence earns its 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?

An output schema exists, so return-value details need not be explained, and annotations handle the safety profile. Between the description and schema, formats, byte cap, and cursor continuation are all covered; only snapshot consistency across segments is left implicit.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so every parameter (tag, limit, cursor, format, prefix) is already documented in the schema, and the description mostly restates the format enum and the cursor/next_cursor relationship. Baseline 3 applies when the schema does the heavy lifting; the description adds little syntax or edge-case meaning beyond it.

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 ("Read a portable snapshot of memory contents") plus the three serializations produced. It explicitly differentiates from the `list` sibling by naming it as the short-preview alternative, 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 Guidelines4/5

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

Gives one explicit exclusion with a condition: use `list` for short previews instead. It also explains the continuation path ("pass `next_cursor` as `cursor` to continue"). It does not address when to prefer export over `get`, `recall`, or `search`, so it stops short of full when/when-not coverage.

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

forgetDelete memoriesA
DestructiveIdempotent

Delete memories from the active store by id, ids or id prefix; use remember to update content instead. Inspect prefix matches with list first: prefix deletion requires confirm: true. Returns the deletion count and ids that were absent.

NameRequiredDescriptionDefault
idNoOne exact memory id to delete; cannot combine with `prefix`.
idsNoExact memory ids to delete in one call; cannot combine with `prefix`.
prefixNoDelete every id starting with this prefix; use `list` with the same prefix first.
confirmNoSet true to authorize prefix deletion; exact ids do not need it.

Output Schema

NameRequiredDescription
deletedYesNumber of memories deleted.
missingYesRequested ids that were not present.

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already declare destructiveHint and idempotentHint, so the description's added value is the confirm gate for prefix deletion and the note that the tool reports deletion count plus absent ids. That is genuine behavioral context the annotations do not carry; it stops short of stating irreversibility or how partial failures are handled across a 1000-id batch.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

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

A single dense sentence front-loads the action and selection modes, then the alternative, the pre-check, and the return contract follow in order. Every clause carries information; nothing is 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?

With a destructive, no-required-param tool and an output schema, the description covers the destructive scope of prefix deletion, the confirmation requirement, the recommended inspection step, and the sibling to use instead. An agent can call this correctly without further reading.

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 already documents the id/ids/prefix mutual exclusion and the confirm flag, so the description is largely restating it. It does tie `confirm` to the prefix mode operationally, but adds no new syntax or edge-case semantics (e.g. calling with no selector at all, where all params are optional).

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 ("Delete") plus resource ("memories from the active store") and names the three selection modes (id, ids, prefix). It also routes away from a sibling by naming `remember` for the update case, so the tool is distinguishable without inspecting the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

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

Explicitly names the alternative for the adjacent use case ("use `remember` to update content instead") and gives a precondition/ordering rule ("Inspect prefix matches with `list` first"). It also states the gate condition for the risky path (prefix deletion requires `confirm: true`), leaving nothing to inference.

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

getGet memoryA
Read-onlyIdempotent

Read one known memory id in full, including tags, metadata and version. Use an id from list or search; use recall when only a natural-language question is known. Read-only; an unknown id returns an error.

NameRequiredDescriptionDefault
idYesExact id of the memory to read, as returned by `remember`, `list` or `search`.

Output Schema

NameRequiredDescription
memoryYes

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already declare read-only, idempotent, non-destructive, and closed-world behavior. The description adds useful behavioral context by stating that an unknown id returns an error, though it repeats the read-only trait already covered by annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

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

The description is three compact sentences with no wasted text. The core operation is front-loaded, followed by sourcing and alternative guidance.

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 simple one-parameter read tool with rich annotations and an output schema, the description is complete. It covers the operation, id source, alternative tool, and error behavior for unknown ids.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, and the `id` parameter is fully documented in the schema as the exact id returned by `remember`, `list`, or `search`. The description reinforces the id provenance but adds little parameter-level detail beyond 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: reading one known memory id in full. It also names included fields and explicitly differentiates this from `recall`, `list`, and `search`, so an agent can distinguish it from siblings without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

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

It gives explicit sourcing guidance: use an id from `list` or `search`, and use `recall` when only a natural-language question is known. This directly covers when to use this tool versus a key alternative.

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

listList memoriesA
Read-onlyIdempotent

Browse memories in id order, optionally limited by id prefix or tag; use search for relevance ranking. Read-only. Returns text previews unless full is true; pass next_cursor as cursor to continue.

NameRequiredDescriptionDefault
tagNoInclude only memories carrying this tag.
fullNoReturn full text instead of a 240-character preview.
limitNoMaximum memories in this page.
cursorNo`next_cursor` of the previous page.
prefixNoInclude only memory ids starting with this prefix.

Output Schema

NameRequiredDescription
countYesNumber of memories in this page.
memoriesYesMemories in id order, with full text or previews.
next_cursorYesPass a string value as `cursor` to continue; null ends the listing.

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already declare read-only, idempotent, non-destructive behavior, so the safety profile is covered. The description adds useful behavioral detail beyond that: results are in id order, previews are returned unless `full` is true, and pagination continues by passing `next_cursor` as `cursor`.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

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

It is a single dense sentence with zero filler, front-loading the core operation and ordering before alternatives and return behavior. Every clause carries operational 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?

The tool is simple, has full schema coverage, has output schema support, and has clear annotations. The description still covers ordering, filtering, preview-vs-full behavior, pagination, and the sibling alternative, so nothing important is missing for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and the schema already documents tag, full, limit, cursor, and prefix in detail. The description reinforces the important filter and pagination semantics but largely restates what the schema provides, so baseline 3 is appropriate.

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

Purpose5/5

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

The description states a specific verb and resource ('Browse memories') plus the ordering ('id order') and filtering options ('id prefix or tag'), and explicitly contrasts this with `search` for relevance ranking. An agent can distinguish it from siblings without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

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

It gives explicit routing: use this tool for browsing in id order, and use `search` when relevance ranking is needed. That is the key alternative among the listed sibling tools, and the condition for choosing it is stated directly.

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

recallRecall matching memoriesA
Read-onlyIdempotent

Retrieve full memories ranked for a natural-language question. Use this for ordinary recall; use search when you need metadata filters, ranking controls or score details. Read-only; default builds rank lexically, and a configured model adds semantic ranking.

NameRequiredDescriptionDefault
kNoMaximum number of ranked memories to return.
tagsNoLabels; filters match memories carrying every listed tag.
queryYesNatural-language question or phrase to match against stored memories; nonblank, at most 4,096 UTF-8 bytes.
min_scoreNoDrop hits below this relative rank score (0 to 1); this is not a probability.

Output Schema

NameRequiredDescription
countYesNumber of returned hits.
resultsYesRanked hits with full memory text.

TDQS

A4.2/5.0
Behavior4/5

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

Annotations already cover read-only, idempotent, closed-world, non-destructive, so the safety bar is met elsewhere. The description still adds genuine value by disclosing that ranking is lexical by default and becomes semantic when a model is configured, which explains why identical queries may order results differently across deployments.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

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

Three short sentences, zero waste, with the core purpose front-loaded before the sibling routing and the behavioral note. Nothing is repeated from the title or schema.

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?

Rich annotations, a full-coverage schema and an output schema mean the description need not explain return values. It covers purpose, routing and ranking behavior, but the mismatch between 'use `search` for metadata filters' and this tool's own `tags`/`min_score` params leaves a small ambiguity an agent must resolve.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so `k`, `tags`, `query` and `min_score` are already fully documented with bounds and defaults. The description adds no per-parameter meaning beyond a general mention of ranking, so the baseline 3 applies.

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

Purpose5/5

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

States a specific verb and resource ('retrieve full memories') plus the ranking model ('ranked for a natural-language question'), which precisely distinguishes it from `search`. An agent can tell the two 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 Guidelines4/5

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

Explicitly routes the agent: 'use this for ordinary recall; use `search` when you need metadata filters, ranking controls or score details.' However, the boundary is muddied because this tool's own schema exposes `tags` (a metadata filter) and `min_score` (a ranking control), so the stated exclusion is not fully consistent with what it accepts.

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

rememberStore memoryA
Destructive

Store a durable fact, decision or preference; use recall to find one instead. A supplied id replaces that memory, while an omitted id creates a new one. Use if_version to reject concurrent changes or create_only to reject overwrites.

NameRequiredDescriptionDefault
idNoStable id; replaces an existing memory with this id.
tagsNoLabels; filters match memories carrying every listed tag.
textYesUTF-8 memory content; must be nonblank unless `allow_empty` is true. The server also enforces a byte limit and a 4,096-word limit.
titleNoOptional display title; does not change the id.
metadataNoArbitrary JSON object; keys starting with "hms." are reserved.
if_versionNoVersion from `remember` or `get`; write only if the stored version still matches. Cannot combine with `create_only`.
allow_emptyNoPermit blank text for file-like use; otherwise blank text is rejected.
create_onlyNoReject the write if the chosen id already exists; cannot combine with `if_version`.

Output Schema

NameRequiredDescription
idYesId of the stored memory.
bytesYesStored text size in UTF-8 bytes.
createdYesTrue when this call created an id.
versionYesNew version for a later conditional update.
namespaceYesStore namespace used for the write.

TDQS

A4.7/5.0
Behavior4/5

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

Annotations flag destructiveHint=true, and the description supplies the reason an agent needs: supplying an `id` overwrites that memory, omitting it creates a new one. It also discloses the two opt-in guards against clobbering. It stops short of saying what happens to fields not supplied on replace, but that is the only meaningful gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

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

Two sentences, both load-bearing: the first establishes scope and the sibling routing, the second covers id semantics and the two guard parameters. The most decision-critical fact (replace vs create) is front-loaded after the routing hint.

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 need no explanation, and the schema documents all eight parameters including tags, title, metadata and limits. The description fills the remaining conceptual gap – overwrite behavior and concurrency guards – so an agent has everything needed to call this 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; the description earns above baseline by explaining the interaction between `if_version` and `create_only` as a pair of mutually exclusive conflict strategies, rather than just restating the per-field definitions. It adds intent, not syntax, which the schema already handles.

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 (store) plus the resources it stores (durable fact, decision or preference), and explicitly routes the agent away from the sibling `recall`. The create-vs-replace distinction makes the operation unambiguous even before opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

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

Names the alternative tool explicitly ('use `recall` to find one instead') and gives the conditions that select the two conflict-control modes: `if_version` for concurrent-change rejection, `create_only` for overwrite rejection. Nothing about when-to-use 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.

statsStore statisticsA
Read-onlyIdempotent

Inspect store counts, recall mode, encryption status, storage size and active limits without reading memory contents. Read-only; use list to inspect stored memories.

NameRequiredDescriptionDefault

No parameters

Output Schema

NameRequiredDescription
limitsYesActive text, metadata, tag, result and export caps.
recallYesActive lexical or hybrid recall mode.
memoriesYesNumber of stored memories.
namespaceYesStore namespace being inspected.
dimensionsYesConfigured vector dimensions.
store_pathYesLocal filesystem path of the store.
storage_bytesYesApproximate local store size in bytes.
server_versionYesVersion of the core server binary.
embedded_memoriesYesMemories with a semantic embedding.
encryption_at_restYesWhether the store is encrypted at rest.

TDQS

A4.7/5.0
Behavior4/5

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

Annotations already declare readOnly, idempotent, non-destructive and closed-world, so the safety profile is covered. The description adds genuinely new context — that no memory contents are exposed — which matters for a stats endpoint. It stops short of noting cost or latency, but nothing essential is missing.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

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

Two short sentences, both earning their place: the first defines scope, the second defines the read-only nature and the alternative. Front-loaded with the resource list before the routing hint.

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 spelled out; combined with annotations covering safety and a zero-parameter schema, the description supplies everything an agent needs to select and invoke it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so there is nothing for the description to disambiguate; baseline 4 applies. The listed fields describe the output rather than inputs, which is harmless.

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 ('Inspect') plus an enumerated set of resources (counts, recall mode, encryption status, storage size, active limits). It also distinguishes itself from the sibling `list` by clarifying it does not read memory contents.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

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

Explicitly routes the agent: use `list` to inspect stored memories, implying this tool is for store-level metadata only. The when-not-to-use condition ('without reading memory contents') is stated up front.

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. 8 tool updatesv0.1.2
    • First observedexport
    • First observedforget
    • First observedget
    • First observedlist
    • First observedrecall
    • First observedremember
    • First observedsearch
    • First observedstats

TDQS

A4.4/5.0

Scored across 8 tools

Disambiguation4/5

Each tool targets a distinct operation, but `recall` and `search` both perform retrieval and rely on the descriptions to separate natural-language lookup from filtered/ranked lookup; `list` also overlaps with `search` for browsing. The descriptions do a good job of redirecting between them, so an agent is unlikely to misselect in practice.

Naming Consistency4/5

All names are short, single-word imperative/lowercase tokens (remember, recall, search, get, forget, list, export) with `stats` as the only noun form. The convention is consistent and readable, just not a strict verb_noun pattern.

Tool Count5/5

Eight tools is a well-scoped surface for a memory store: write, several read modes, delete, and two introspection utilities. No tool looks redundant enough to remove, and nothing feels missing at the count level.

Completeness4/5

Covers the full lifecycle: create/overwrite (remember with id/if_version/create_only), read (get, recall, search, list), delete (forget), diagnostics (stats) and snapshot export. The notable gap is an `import`/restore counterpart to `export`, plus explicit tag/metadata-only mutation, which agents must work around by rewriting content.

Maintenance

ActivityNo data
ResponsivenessSlow

Related MCP Connectors

Related MCP Servers