Developer Documentation
Overview
MentisDB is a standalone Rust crate available on crates.io. Add it to your project:
mentisdb = "0.9.1"The crate provides the full memory engine, skill registry, storage adapter interface, agent registry, and optional HTTP server stack (MCP + REST + dashboard) behind the server feature flag.
Full API Reference
The complete, generated API documentation is hosted on docs.rs:
docs.rs/mentisdb
Full rustdoc for all public types, traits, functions, and modules. Includes MentisDb, Thought, ThoughtInput, ThoughtQuery, StorageAdapter, SkillRegistry, BinaryStorageAdapter, and the HTTP server.
MCP Server
MentisDB ships a built-in MCP (Model Context Protocol) HTTP server. Enable it with the server feature. All MentisDB operations are exposed as MCP tools over JSON-RPC 2.0 via HTTP, making it compatible with any MCP-capable AI tool. The canonical onboarding path is not a separate URL: it happens during the MCP initialize call via startup instructions plus the embedded resource mentisdb://skill/core exposed through resources/list and resources/read.
Default HTTP endpoint: http://127.0.0.1:9471 — HTTPS endpoint: https://127.0.0.1:9473.
All 37 MCP Tools
| Tool | Description | Key Parameters |
|---|---|---|
mentisdb_bootstrap | Create a chain if needed and write one bootstrap checkpoint when it is empty | chain_key,content,concepts,importance |
mentisdb_append | Append a durable semantic thought with optional tags, concepts, refs, scope, and signature metadata | chain_key,thought_type,content,agent_id,tags,concepts,scope,importance,confidence |
mentisdb_append_retrospective | Append a guided retrospective memory to prevent future agents from repeating a hard failure | chain_key,content,concepts,refs,importance |
mentisdb_search | Search thoughts by semantic filters, identity filters, time bounds, and scoring thresholds | chain_key,text,thought_types,roles,agent_ids,since,until,min_importance,min_confidence |
mentisdb_lexical_search | Return flat ranked lexical matches with explainable term and field provenance | chain_key,text,thought_types,limit,offset |
mentisdb_ranked_search | Return flat ranked results with lexical, graph-aware, or heuristic score breakdowns. Supports point-in-time queries and memory scope filtering | chain_key,text,as_of,scope,enable_reranking,rerank_k,concepts_any,roles,limit |
mentisdb_context_bundles | Return seed-anchored grouped support context beneath the best lexical seeds | chain_key,text,as_of,scope,graph,limit |
mentisdb_list_chains | List known chains with version, storage adapter, counts, and storage location | chain_key |
mentisdb_merge_chains | Merge all thoughts from a source chain into a target chain, then permanently delete the source | source_chain_key,target_chain_key |
mentisdb_branch_from | Create a new chain diverging from a thought on an existing chain. Searches on the branch transparently include ancestor results | source_chain_key,branch_chain_key,branch_thought_id |
mentisdb_list_agents | List the distinct agent identities participating in one chain | chain_key |
mentisdb_get_agent | Return one full agent registry record including status, aliases, description, keys, and per-chain activity metadata | agent_id,chain_key |
mentisdb_list_agent_registry | Return the full per-chain agent registry | chain_key |
mentisdb_upsert_agent | Create or update a registry record before or after an agent writes thoughts | agent_id,display_name,agent_owner,description,status,chain_key |
mentisdb_set_agent_description | Set or clear the description stored for one registered agent | agent_id,description,chain_key |
mentisdb_add_agent_alias | Add a historical or alternate alias to a registered agent | agent_id,alias,chain_key |
mentisdb_add_agent_key | Add or replace one public verification key on a registered agent | agent_id,key_id,algorithm,public_key_bytes,chain_key |
mentisdb_revoke_agent_key | Revoke one previously registered public key | agent_id,key_id,chain_key |
mentisdb_disable_agent | Disable one agent by marking its registry status as revoked | agent_id,chain_key |
mentisdb_recent_context | Render recent thoughts into a prompt snippet for session resumption | chain_key,last_n |
mentisdb_memory_markdown | Export a MEMORY.md-style Markdown view of the full chain or a filtered subset | chain_key,agent_ids,thought_types,roles,since,until,limit |
mentisdb_import_memory_markdown | Import a MEMORY.md-formatted Markdown document into a target chain | markdown,default_agent_id,chain_key |
mentisdb_get_thought | Return one stored thought by stable id, chain index, or content hash | thought_id,thought_index,thought_hash,chain_key |
mentisdb_get_genesis_thought | Return the first thought ever recorded in the chain, if any | chain_key |
mentisdb_traverse_thoughts | Traverse the chain forward or backward in append order from a chosen anchor, in chunks, with optional filters | chain_key,anchor_id,anchor_index,anchor_hash,direction,chunk_size,thought_types,roles,since,until |
mentisdb_skill_md | Return the official embedded MENTISDB_SKILL.md Markdown file | (none) |
mentisdb_list_skills | List versioned skill summaries from the skill registry | chain_key |
mentisdb_skill_manifest | Return the versioned skill-registry manifest including searchable fields and supported formats | (none) |
mentisdb_upload_skill | Upload a new immutable skill version from Markdown or JSON | agent_id,skill_id,content,format,signing_key_id,skill_signature,chain_key |
mentisdb_search_skill | Search skills by indexed metadata such as ids, names, tags, triggers, uploader identity, status, format, schema version, and time window | chain_key,text,skill_ids,names,statuses,since,until,limit |
mentisdb_read_skill | Read one stored skill as Markdown or JSON. Responses include trust warnings for untrusted or malicious skill content | skill_id,version_id,format,chain_key |
mentisdb_skill_versions | List immutable uploaded versions for one skill | skill_id,chain_key |
mentisdb_deprecate_skill | Mark a skill as deprecated while preserving all prior versions | skill_id,reason,chain_key |
mentisdb_revoke_skill | Mark a skill as revoked while preserving audit history | skill_id,reason,chain_key |
mentisdb_head | Return head metadata, the latest thought at the current chain tip, and integrity state | chain_key |
mentisdb_register_webhook | Register a webhook to receive HTTP POST notifications when thoughts are appended. Delivery is fire-and-forget with exponential backoff retries (up to 5 attempts) | chain_key,url,event_types |
mentisdb_list_webhooks | List all registered webhooks | chain_key |
mentisdb_delete_webhook | Remove a webhook registration by its UUID | webhook_id,chain_key |
JSON-RPC Request/Response Example
MCP uses JSON-RPC 2.0 over HTTP. Send a POST to the MCP endpoint:
POST / HTTP/1.1
Host: 127.0.0.1:9471
Content-Type: application/json
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "mentisdb_append",
"arguments": {
"chain_key": "default",
"agent_id": "assistant",
"thought_type": "Insight",
"content": "Memory deduplication triggers when Jaccard similarity exceeds threshold",
"importance": 0.7,
"confidence": 0.9,
"tags": ["feature:dedup"],
"concepts": ["memory-dedup", "jaccard-similarity"]
}
}
}
// Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "Thought appended: a1b2c3... (index 42)"
}
]
}
}MCP HTTP Ports
The MCP server listens on two ports:
http://127.0.0.1:9471— HTTP (unencrypted), suitable for local developmenthttps://127.0.0.1:9473— HTTPS (TLS), recommended for production
The daemon binary (mentisdb) starts the MCP server automatically. For embedding in your own Axum app, see the docs.rs API reference for server module details.
REST API
The same daemon also serves a REST API alongside MCP. Key endpoints:
| Method | Path | Description |
|---|---|---|
POST | /v1/thoughts | Append a new thought to a chain. Supports scope parameter for memory scope tagging |
POST | /v1/search | Search/query thoughts. Supports as_of for point-in-time queries and scope for scope filtering |
POST | /v1/lexical-search | Ranked lexical search with scores and matched-term diagnostics |
POST | /v1/ranked-search | Canonical flat ranked retrieval with lexical + vector + graph-aware score breakdowns (hybrid when managed sidecars are available). Supports as_of, scope, enable_reranking, and rerank_k parameters |
POST | /v1/context-bundles | Seed-anchored grouped support context for agent reasoning and dashboard inspection. Supports as_of and scope parameters |
GET | /v1/chains | List available chain keys |
POST | /v1/chains/branch | Create a branch chain diverging from a thought on an existing chain |
POST | /v1/agents | List agents in a chain or inspect the registry |
GET | /mentisdb_skill_md | Compatibility fallback for clients that cannot use MCP resources; MCP-native clients should read mentisdb://skill/core after initialize |
POST | /v1/skills/upload | Upload a skill version |
POST | /v1/skills/read | Read a skill (latest or specific version) |
POST | /v1/recent-context | Render a compact resumption prompt for recent, important context |
POST | /v1/memory-markdown | Export a chain as MentisDB-flavored MEMORY.md markdown |
POST | /v1/head | Return current chain head metadata and the latest thought |
GET | /health | Liveness health check |
POST | /v1/bootstrap | Bootstrap a chain with an initial memory |
POST | /v1/retrospectives | Append a guided retrospective thought |
POST | /v1/thought | Retrieve a single thought by ID, hash, or index |
POST | /v1/thoughts/genesis | Retrieve the first thought in a chain |
POST | /v1/thoughts/traverse | Traverse thoughts in append order with filtering and pagination |
POST | /v1/import-markdown | Import MEMORY.md-formatted markdown into a chain |
GET | /v1/skills | List uploaded skill summaries |
GET | /v1/skills/manifest | Return the skill registry manifest with searchable fields |
POST | /v1/skills/search | Search the versioned skill registry by indexed fields |
POST | /v1/skills/versions | List immutable versions for a stored skill |
POST | /v1/skills/deprecate | Mark a stored skill as deprecated |
POST | /v1/skills/revoke | Mark a stored skill as revoked |
POST | /v1/agent | Get a single agent record by ID |
POST | /v1/agent-registry | List the full agent registry for a chain |
POST | /v1/agents/upsert | Create or update an agent record |
POST | /v1/agents/description | Set or clear an agent's description |
POST | /v1/agents/aliases | Add an alias to an agent |
POST | /v1/agents/keys | Add a verification key to an agent |
POST | /v1/agents/keys/revoke | Revoke a verification key from an agent |
POST | /v1/agents/disable | Disable (revoke) an agent |
POST | /v1/vectors/rebuild | Rebuild vector sidecar indexes for a chain |
POST | /v1/chains/merge | Merge all thoughts from a source chain into a target, then delete the source |
For MCP-native agents, prefer the streamable HTTP root at POST / and let the agent bootstrap itself from the initialize instructions and resource catalog.
For direct crate users, 0.8.0 keeps vector sidecars additive and rebuildable, but ranked search now blends lexical, graph, and managed-sidecar vector signals automatically when sidecars are enabled. The append-only chain remains canonical; sidecars are derived acceleration state.
The daemon now applies persisted managed-vector settings whenever it opens a chain. By default each chain gets the built-in local-text provider (local-text-v1), and ranked search across REST, MCP, and dashboard surfaces upgrades to hybrid scoring when that sidecar is available.
REST Example: POST /v1/thoughts (Append Thought)
POST /v1/thoughts HTTP/1.1
Host: 127.0.0.1:9471
Content-Type: application/json
{
"chain_key": "default",
"agent_id": "assistant",
"thought_type": "Insight",
"content": "Memory deduplication triggers when Jaccard similarity exceeds threshold",
"importance": 0.7,
"confidence": 0.9,
"tags": ["feature:dedup"],
"concepts": ["memory-dedup", "jaccard-similarity"],
"scope": "user",
"relations": [
{ "kind": "ContinuesFrom", "target_id": "<uuid-of-prior-turn>" }
]
}
// Response:
{
"thought": {
"id": "a1b2c3d4-...",
"index": 42,
"hash": "9f14...",
"thought_type": "Insight",
"content": "Memory deduplication triggers when Jaccard similarity exceeds threshold",
"agent_id": "assistant",
"importance": 0.7,
"confidence": 0.9,
"tags": ["feature:dedup"],
"concepts": ["memory-dedup", "jaccard-similarity"],
"created_at": "2026-04-14T12:00:00Z"
}
}REST Example: POST /v1/ranked-search
POST /v1/ranked-search HTTP/1.1
Host: 127.0.0.1:9471
Content-Type: application/json
{
"chain_key": "default",
"text": "how does memory deduplication work",
"scope": "user",
"limit": 10,
"enable_reranking": true,
"rerank_k": 50
}
// Response:
{
"results": [
{
"thought": {
"id": "a1b2c3d4-...",
"thought_type": "Insight",
"content": "Memory deduplication triggers when Jaccard similarity exceeds threshold",
"importance": 0.7
},
"score": 4.82,
"lexical_score": 1.2,
"vector_score": 3.1,
"session_cohesion": 0.4,
"rank": 1
}
],
"total": 1,
"query_time_ms": 12
}REST Example: POST /v1/context-bundles
POST /v1/context-bundles HTTP/1.1
Host: 127.0.0.1:9471
Content-Type: application/json
{
"chain_key": "default",
"text": "memory deduplication decision",
"scope": "user",
"limit": 5
}
// Response:
{
"bundles": [
{
"seed": {
"id": "a1b2c3d4-...",
"thought_type": "Decision",
"content": "Enable dedup at 0.85 Jaccard threshold",
"score": 5.1
},
"supporting": [
{
"id": "b2c3d4e5-...",
"thought_type": "LessonLearned",
"content": "Previous attempts at 0.95 threshold produced too many false negatives",
"chain_key": "default"
}
],
"children": []
}
]
}REST Example: POST /v1/webhooks/register
POST /v1/webhooks/register HTTP/1.1
Host: 127.0.0.1:9471
Content-Type: application/json
{
"chain_key": "default",
"url": "https://myapp.example.com/mentisdb-webhook",
"event_types": ["thought.append", "thought.relation.added"]
}
// Response:
{
"webhook": {
"id": "wh_abc123",
"chain_key": "default",
"url": "https://myapp.example.com/mentisdb-webhook",
"event_types": ["thought.append", "thought.relation.added"],
"created_at": "2026-04-14T12:00:00Z",
"status": "active"
}
}0.8.0 Search & Storage Improvements
MentisDB 0.8.0 introduces five major improvements to the search and storage pipeline: Porter stemming, tiered vector-lexical fusion, importance weighting, bincode hashing, and managed sidecar entries with auto_sync.
Porter Stemming (Normalizer v2)
The lexical tokenizer now applies English Porter stemming. Words like preferences → prefer and running → run now match in lexical search. Existing chains auto-reindex on first open — no manual migration step required.
Tiered Vector-Lexical Fusion
Ranked search scoring replaces the flat addition model with a tiered boost that respects the relationship between lexical and vector signals:
- Lexical = 0 and vector > 0:
vector × 60— full boost for semantic-only hits - 0 < lexical < 1.0 and vector > 0:
vector × (1 + 20 × fraction)— partial boost proportional to lexical overlap - Lexical ≥ 1.0: vector as-is — no boost, lexical dominates
This ensures that pure semantic matches surface prominently, while thoughts already matched lexically are not artificially inflated by an additional vector boost.
Importance Weight 3.0×
User-originated thoughts carry higher importance. At the default 3.0× weight multiplier, a user thought (importance 0.8) contributes +2.4 to the final score versus an assistant thought (importance 0.2) at +0.6. This makes user-stated preferences and decisions rank above routine assistant summaries in retrieval results.
Bincode Hashing
compute_thought_hash() now uses bincode instead of serde_json for thought serialization, eliminating full JSON serialization per append. This reduces hash computation overhead and produces smaller, deterministic binary encodings. Existing chains auto-reindex on first open.
ManagedSidecarEntry with auto_sync
Vector sidecar management uses ManagedSidecarEntry with an auto_sync flag that controls whether the sidecar rebuilds on startup. The new register_vector_sidecar_for_search() method registers a sidecar for search-only without triggering a rebuild, allowing faster daemon startup while keeping the sidecar available for ranked search fusion.
0.8.1 Search Improvements
MentisDB 0.8.1 refines the scoring pipeline with session cohesion, smooth exponential fusion, and a tighter BM25 document-frequency cutoff. LongMemEval R@5 climbs from 65.0% to 67.6%; LoCoMo 2-persona R@10 reaches 88.7%.
Session Cohesion Scoring
Thoughts within ±8 positions of a high-scoring lexical seed (score ≥ 3.0) receive a proximity boost up to 0.8, decaying linearly with distance. This surfaces evidence turns adjacent to the matching turn but sharing no lexical terms. The session_cohesion field is now included in ranked search score responses.
Smooth Exponential Vector-Lexical Fusion
Replaces the 0.8.0 step-function tiers with a continuous decay: vector × (1 + 35 × exp(-lexical / 3.0)). Pure-semantic matches get ~36× amplification; by lexical = 3.0 the boost has decayed to ~12×; at lexical = 6.0 it is purely additive. This eliminates discontinuities between tiers.
BM25 DF Cutoff 30%
Terms appearing in >30% of documents (corpus ≥ 20 docs) are skipped during scoring. This filters non-discriminative entity names without blanket stopword removal.
NaN/Infinity Guard
with_confidence() and with_importance() now reject non-finite floats. f32::NAN.clamp(0.0, 1.0) returns NaN in Rust, which previously crashed serde_json serialization when the dashboard tried to render affected thoughts.
0.8.2 Features
MentisDB 0.8.2 introduces four major features: temporal edge validity, memory deduplication, multi-level memory scopes, and CLI subcommands.
Temporal Edge Validity
ThoughtRelation now carries optional valid_at: Option<DateTime<Utc>> and invalid_at: Option<DateTime<Utc>> fields. A relation is considered active when the current time falls between these bounds. If neither is set the relation is always active (backward compatible with V2 chains). Schema V3 migration adds these fields transparently on first open.
The as_of query parameter (RFC 3339 timestamp) is supported on ranked search, context bundles, and traversal endpoints. When provided, only thoughts appended at or before the timestamp are included in results. This enables point-in-time auditing and decision reproduction.
When a relation's invalid_at has passed, the target thought is added to invalidated_thought_ids in the search response, allowing clients to filter or highlight stale edges.
Memory Dedup
Automatic deduplication on append, controlled by two environment variables:
MENTISDB_DEDUP_THRESHOLD— Jaccard similarity threshold (0.0–1.0). When set, each append compares the new thought's content against the last N thoughts. If similarity exceeds the threshold, the new thought receives an auto-Supersedesrelation pointing at the most similar existing thought instead of being appended as a duplicate. Disabled when unset.MENTISDB_DEDUP_SCAN_WINDOW— how many recent thoughts to scan (default: 64). Only used when MENTISDB_DEDUP_THRESHOLD is set.
The builder API exposes .with_dedup_threshold(f64) and .with_dedup_scan_window(usize) for programmatic control. When dedup fires, the append still succeeds but the resulting thought carries a Supersedes relation and the content is not duplicated in search results.
Multi-Level Memory Scopes
The MemoryScope enum introduces three scope levels for thoughts within a single chain:
MemoryScope::User— globally visible across sessions (default, backward compatible)MemoryScope::Session— ephemeral working memory scoped to a single conversationMemoryScope::Agent— private to the authoring agent, not visible to other fleet members
Scopes are stored as tags (scope:user, scope:session, scope:agent) on each thought. Set scope via .with_scope(MemoryScope::Session) on the builder, or pass scope in MCP/REST append calls. Filter in search with the scope parameter.
CLI Subcommands
The mentisdb binary now supports inline subcommands for quick operations without an MCP client:
mentisdb add "content"— append a thought directly from the command line (usesureqto POST to the local daemon)mentisdb search "query" --limit 5— ranked search from the terminalmentisdb agents— list registered agents across all chains
These subcommands communicate with the running daemon over HTTP (via ureq), so the daemon must already be started. They are convenience shortcuts — all functionality remains available via MCP, REST, and the dashboard.
Schema Version
MentisDB 0.8.2 uses schema version 3 (MENTISDB_SCHEMA_V3 = 3). V3 adds valid_at and invalid_at fields to ThoughtRelation for temporal edge validity. All new chains are created at V3 automatically. Legacy V2 chains (created before 0.8.2) are migrated transparently on first open — no manual migration step and no data loss.
Bulk Import API
Import an existing MEMORY.md (or any MentisDB-style Markdown export) into a chain in one call:
let count = db
.import_from_memory_markdown(markdown_str, "orion")
.await?;
println!("Imported {} thoughts", count);The method parses the Markdown document, creates one thought per heading/section, and appends them all to the chain under default_agent_id. Returns the count of thoughts imported.
The same operation is also available via REST and MCP:
- REST:
POST /v1/import-markdown— body:{ "markdown": "...", "default_agent_id": "orion", "chain_key": "..." } - Dashboard:
POST /dashboard/api/chains/{chain_key}/import-markdown - MCP:
mentisdb_import_memory_markdown(markdown, default_agent_id, chain_key)
Thought Taxonomy
The canonical enum names below are accepted by the crate API, MCP tools, REST filters, and MEMORY.md import/export. ThoughtType carries semantic meaning; ThoughtRole carries operational meaning.
ThoughtType (30): PreferenceUpdate, UserTrait, RelationshipUpdate, Finding, Insight, FactLearned, PatternDetected, Hypothesis, Mistake, Correction, LessonLearned, AssumptionInvalidated, Constraint, Goal, Plan, Subgoal, Decision, StrategyShift, Wonder, Question, Idea, Experiment, ActionTaken, TaskComplete, Checkpoint, StateSnapshot, Handoff, Summary, Surprise, and Reframe.
ThoughtRole (8): Memory, WorkingMemory, Summary, Compression, Checkpoint, Handoff, Audit, and Retrospective.
The Agent Guide contains the human-facing explanation of when to use each ThoughtType and ThoughtRole; docs.rs is the authoritative source for the Rust enum definitions and builder APIs.
MemoryScope
0.8.2 introduces MemoryScope — a visibility partition within a single chain. Scopes are stored as tags on each thought:
MemoryScope::User— globally visible (default). Tag:scope:userMemoryScope::Session— ephemeral, scoped to one conversation. Tag:scope:sessionMemoryScope::Agent— private to the authoring agent. Tag:scope:agent
Set scope on the builder with .with_scope(MemoryScope::Session) or pass scope in MCP/REST append calls. Filter in search with the scope parameter. Existing thoughts without a scope tag are treated as User-scoped — no migration required.
Thought Relations & Cross-chain References
A ThoughtRelation is a typed semantic edge between two thoughts. Attach relations to a ThoughtInput using the builder API:
// Intra-chain relation:
let input = ThoughtInput::new(ThoughtType::Reframe, "We now frame this as Y.")
.with_relation(ThoughtRelation {
kind: ThoughtRelationKind::Supersedes,
target_id: old_thought_uuid,
chain_key: None,
valid_at: None,
invalid_at: None,
});
// Relation with temporal bounds:
let input = ThoughtInput::new(ThoughtType::Decision, "Adopted the caching strategy.")
.with_relation(ThoughtRelation {
kind: ThoughtRelationKind::Supersedes,
target_id: old_thought_uuid,
chain_key: None,
valid_at: Some("2025-12-01T00:00:00Z".parse().unwrap()),
invalid_at: None,
});
// Cross-chain relation — use the convenience builder:
let input = ThoughtInput::new(ThoughtType::Decision, "Adopted the shared convention.")
.with_cross_chain_relation(
ThoughtRelationKind::Supersedes,
old_thought_uuid,
"platform-conventions",
);The chain_key: Option<String> field on ThoughtRelation makes cross-chain references first-class. Intra-chain relations (chain_key: None) remain fully backward-compatible with all existing code.
ThoughtRelationKind::Supersedes
Use Supersedes to declare that a new thought replaces an older one that was correct but is now outdated or reframed. It is the canonical replacement edge — distinct from a Correction (which signals a factual error). Pair it with the Reframe ThoughtType for perspective or framing shifts.
All relation kinds
ThoughtRelationKind variants accepted by both the Rust API and POST /v1/thoughts:
References— generic pointer to another thoughtSummarizes— this thought condenses the targetCorrects— fixes a factual error in the targetInvalidates— target is no longer applicableCausedBy— this thought resulted from the targetSupports— this thought provides evidence for the targetContradicts— this thought conflicts with the targetDerivedFrom— this thought is derived from the targetContinuesFrom— sequential continuation; used to chain consecutive session turnsRelatedTo— weak associative linkSupersedes— replaces the target's framing or approach
REST — relations in POST /v1/thoughts
Pass relations as a JSON array in the request body. Each element has a kind string, a target_id (UUID), and an optional chain_key for cross-chain edges:
POST /v1/thoughts
{
"agent_id": "planner",
"thought_type": "Observation",
"content": "Retry logic resolved the timeout — root cause was DNS.",
"refs": [41],
"relations": [
{ "kind": "ContinuesFrom", "target_id": "<uuid-of-prior-turn>" },
{ "kind": "CausedBy", "target_id": "<uuid>", "chain_key": "infra-ops" }
]
}Storage Adapters
MentisDB separates the memory model from the storage backend via the StorageAdapter trait:
- BinaryStorageAdapter — Default (and only supported adapter for new chains). Compact binary format with write buffering. Best for production.
Implement the StorageAdapter trait to plug in your own backend (S3, SQLite, etc.). See docs.rs for the trait definition.
0.8.6 Features
MentisDB 0.8.6 adds three retrieval features and a chain branching primitive:
RRF Reranking
Reciprocal Rank Fusion (RRF) is an opt-in reranking pass on ranked search. When enable_reranking is set, the engine produces separate lexical-only, vector-only, and graph-only rankings over the top rerank_k candidates (default 50), merges them via 1/(k + rank) with k=60, and replaces the additive total with the RRF total. Non-rankable signals (importance, confidence, recency, session cohesion) are added back as small adjustments. Use RRF when lexical and vector signals disagree on top candidates.
Irregular Verb Lemma Expansion
The query tokenizer now expands irregular English verbs to their base form (e.g. "went" → "go", "gave" → "give", "ran" → "run"). About 170 mappings are included. Indexed content is not modified — expansion is query-time only.
Memory Chain Branching
New ThoughtRelationKind::BranchesFrom enables cross-chain divergence. MentisDb::branch_from() creates a new chain with a genesis thought pointing back to the branch-point on the source chain. When searching a branch chain, the server transparently searches ancestor chains and merges results, annotated with chain_key. REST: POST /v1/chains/branch. MCP: mentisdb_branch_from.
Per-Field BM25 DF Cutoffs
The Bm25DfCutoffs struct on LexicalQuery allows configuring separate document-frequency cutoff ratios per field (content, tags, concepts, agent_id, agent_registry). Terms whose global DF exceeds the cutoff for a given field are skipped for that field only. Default cutoffs: content=0.30, tags=0.30, concepts=0.30, agent_id=0.70, agent_registry=0.60.
0.9.x Features
MentisDB 0.9.x adds four major features: LLM extraction, federated cross-chain search, an official Python client, and an improved setup experience.
Opt-in LLM Extraction (0.9.1)
The extract_memories_from_text function uses GPT-4o (or any OpenAI-compatible endpoint) to convert raw agent text, conversation logs, or reasoning traces into structured ThoughtInput records. Extraction is opt-in behind the llm-extraction feature (enabled by default). Uses openai-rust2 with 3x retry on 429/5xx, 60s timeout, temperature 0.1. Configure via OPENAI_API_KEY, LLM_BASE_URL, and LLM_MODEL env vars. The pipeline returns raw ExtractionResult — callers must review and validate thoughts before appending to protect the hash chain from untrusted LLM output.
Federated Cross-Chain Search (0.9.1)
The BranchesFrom primitive enables fleet memory hierarchies. A project chain branches from a company-wide knowledge chain at a checkpoint. Ranked search on the branch transparently queries both the local chain and ancestor chains, annotated with chain_key so you know where each result originated. REST: POST /v1/chains/branch. MCP: mentisdb_branch_from.
Python Client — pymentisdb (0.9.1)
pymentisdb is on PyPI. Full MentisDbClient with typed enums, LangChain MentisDbMemory, webhook management, skill registry, and memory import/export. Install:
pip install pymentisdbOr with LangChain:
pip install pymentisdb[langchain]Webhook Callbacks (0.9.1)
Register HTTP POST callbacks that fire when thoughts are appended. Useful for reactive agents, cross-system sync, or audit logging. REST: POST /v1/webhooks. MCP: mentisdb_register_webhook, mentisdb_list_webhooks, mentisdb_delete_webhook. Delivery is fire-and-forget with exponential backoff retries.
Smart Stdio Mode — Auto-Detect Daemon (0.9.2)
The stdio MCP mode now detects if a daemon is already running on the configured MCP port via the health endpoint. If running, the stdio process acts as a lightweight proxy forwarding requests to the daemon's HTTP MCP endpoints. If not running, it launches the daemon in the background (nohup on Unix, start /B on Windows) in headless HTTP mode and proxies. This means Claude Desktop users get shared live state with zero configuration — just set the command to mentisdb with args --mode stdio.
Dashboard Skill Editing (0.9.7)
The web dashboard can now edit skills from both the Skills table and a skill detail page. Saving creates a new immutable skill version through the existing upload path, preserving audit history instead of mutating prior content.
Wizard Brew-First Setup (0.9.1)
The interactive setup wizard mentisdb setup now tries brew install mcp-remote before npm. It detects Homebrew-installed mcp-remote (which has a proper shebang pointing to the correct Node version) and writes the minimal Claude Desktop config automatically.
Custom Ontology — entity_type (0.8.7)
Thoughts can carry an optional entity_type label (e.g. "bug_report", "architecture_decision"). The ThoughtQuery accepts entity_type as a filter. Entity types are auto-observed per chain and persisted in a chain_key-entity-types.json sidecar.
Episode Provenance — source_episode (0.8.8)
Thoughts can carry a source_episode field pointing to the original thought, with a new DerivedFrom relation kind. The dashboard shows full provenance graphs.
LLM-Based Reranking (0.8.8)
In addition to arithmetic RRF, RankedSearchQuery accepts an optional llm_rerank block that delegates the final rerank of the top-rerank_k candidates to an OpenAI-compatible model. The server sends the candidate thoughts and the original query, parses the model's ranked IDs, and blends the returned ordinal score (under the llm_score field on each hit) with the arithmetic signals as an additive tie-breaker. LLM reranking is strictly opt-in and disabled by default; the core pipeline remains LLM-free.
Operations & Admin
For the full list of environment variables that tune storage, behaviour, networking, TLS, the dashboard, updates, and audio cues, see the Environment Variables Reference in the user manual — every MENTISDB_* knob is documented there with defaults, purpose, and a concrete example.
POST /v1/admin/flush
REST endpoint that walks every open chain and calls flush() on its storage adapter. Useful in buffered-write mode (MENTISDB_AUTO_FLUSH=false) where up to FLUSH_THRESHOLD − 1 records can sit in the background-writer queue. The backup CLI calls this automatically when it detects a running daemon; consistent on-disk state is a precondition for a reliable .mentis archive.
Backup & Restore (.mentis archive)
mentisdb backup produces a .mentis ZIP archive covering every chain data file (*.tcbin, *.agents.json, *.entity-types.json, *.vectors.*.json), the global chain registry, the skill registry, and optionally TLS certificates. When a daemon is running the CLI first POSTs to /v1/admin/flush so pending writes are on disk before the archive is assembled.
mentisdb restore reverses the operation. Path traversal is rejected server-side — manifest entries containing ../ or absolute paths fail with InvalidData before any file is written outside the target directory. Existing files are preserved by default; pass --overwrite to replace them, or answer yes to the interactive confirmation.
Dashboard PIN
Set MENTISDB_DASHBOARD_PIN to require a shared PIN before the web dashboard accepts any request. An empty string is treated as absent. Failed logins are rate-limited per-IP to prevent brute-force enumeration; the dashboard is always served over TLS so the PIN is never transmitted in the clear on a local network.
Benchmarking
MentisDB ships with two benchmark styles:
- Criterion microbenchmarks for in-process append, query, traversal, import, and skill-registry hot paths
- HTTP concurrency benchmarks for live
mentisdbwrite/read waves under concurrent client load
Run the full benchmark suite with:
make benchThis currently runs cargo bench and saves stdout to /tmp/mentisdb_bench_results.txt.
Durable vs Buffered Write Mode
Benchmark write-heavy changes in both persistence modes. They now behave differently enough that one run is not representative of the other:
MENTISDB_BENCH_AUTO_FLUSH=true— durable mode. Appends are queued to the bounded background writer and the request only returns after the writer flushes them. Concurrent appends may share a short group-commit window.MENTISDB_BENCH_AUTO_FLUSH=false— buffered mode. Appends are queued and acknowledged before the worker flushes them, trading durability for higher write throughput.
MENTISDB_BENCH_AUTO_FLUSH=true cargo bench --bench http_concurrency
MENTISDB_BENCH_AUTO_FLUSH=false cargo bench --bench http_concurrencyCriterion Baselines
Criterion benchmarks such as thought_chain and skill_registry automatically compare the current run against the saved baseline in target/criterion/. That is why the output includes messages like Performance has improved, Performance has regressed, or No change in performance detected.
time: [low mid high]— lower is betterthrpt: [low mid high]— higher is betterchange— percentage delta versus the saved baselinep < 0.05— the change is statistically meaningful
If you have changed the benchmark harness itself or want a fresh comparison, clear the old Criterion baseline before trusting the regression/improvement messages.
HTTP Concurrency Baselines
The custom http_concurrency benchmark now persists its own baselines under target/http_concurrency/ and prints delta tables on later runs. This means you no longer need to manually compare the Markdown output tables by eye.
MENTISDB_BENCH_AUTO_FLUSH=true MENTISDB_BENCH_BASELINE=durable cargo bench --bench http_concurrency
MENTISDB_BENCH_AUTO_FLUSH=false MENTISDB_BENCH_BASELINE=buffered cargo bench --bench http_concurrencyUseful environment variables:
MENTISDB_BENCH_CONCURRENCY— comma-separated client counts such as100,1000,10000MENTISDB_BENCH_AUTO_FLUSH—truefor durable group commit,falsefor buffered throughput modeMENTISDB_BENCH_BASELINE— names the saved baseline file so you can keep separate durable, buffered, nightly, or branch-specific histories
How to Read the HTTP Table
wall_ms— total time for the whole wavereq/s— throughputp50_ms,p95_ms,p99_ms— median and tail latencyerrors— non-2xx responses or transport failures
For write-path work, focus on the Write — POST /v1/thoughts table at high concurrency. Read-path changes should primarily move the Read — POST /v1/head table and the query/traversal Criterion benches.
What to Benchmark After Storage Changes
cargo bench --bench thought_chain append_single -- --noplot— strict append latencycargo bench --bench thought_chain query_by_tag -- --noplot— indexed query pathcargo bench --bench thought_chain traverse_filtered_miss_10 -- --noplot— full-scan traversal miss pathcargo bench --bench http_concurrency— live daemon concurrency behavior
A useful workflow is to measure a clean baseline on master, apply the storage change, rerun the same focused benches, and only then trust the wider make bench output.
Contributing
MentisDB is open source under the MIT license.
git clone https://github.com/cloudllm-ai/mentisdbRun the test suite:
cargo testRun benchmarks:
make bench