MCP server over a markdown vault: recall, load_memory, save_memory, edit_memory, archive_memory and document tools — plus the REST gateway, the quiet hook lanes and the bastra CLI.
Mixed quality across 13 tools. recall and load_memory have exceptional descriptions (200+ chars, detailed guidance on when/how to use, score bands explained). However, 8 of 13 tools (save_memory, edit_memory, archive_memory, find_document, read_document, save_document, move_document, recategorize_document, save_product_doc) have NO visible input schemas in the source, only empty property objects. find_code and find_affected_files have partial schemas. Tool naming is verb-first and clear. The recall tool's description is production-grade (LLM-optimized, actionable); others are minimal. No error handling guidance visible. STDIO transport caps protocol readiness.
Archive a memory by moving it to the archive section of the vault.
Edit an existing memory in place. Carries the revision from load_memory to refuse the edit if the memory moved on meanwhile (#519).
Find files affected by changes to a symbol or file. Returns files that depend on or reference the given symbol.
Search for code symbols and definitions in the repository. Returns matching files, symbols, and their locations.
Search for documents in the vault by title or content.
Load the content (frontmatter + body) of a single memory by id. Step 2 of the recall flow — call this only for the candidates recall() surfaced that you actually need. Returns essential frontmatter + body by default; pass verbosity:'full' for the raw frontmatter (related_via cosines, source, …). The result carries a `revision` — hand it to edit_memory({ expected_revision }) to have your change refused if the memory moved on meanwhile (#519).
8 of 13 tools have NO visible input schemas (save_memory, edit_memory, archive_memory, find_document, read_document, save_document, move_document, recategorize_document, save_product_doc show empty property objects).
8 tools have minimal or missing descriptions (under 50 chars). Examples: 'Search for documents in the vault by title or content.' (find_document), 'Read the full content of a document by id.' (read_document). These lack WHEN to call, WHAT to expect, and dependencies.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 52 | 2026-07-28+ | v2 |
Move a document to a different location in the vault.
Read the full content of a document by id.
Search the memory vault. Returns top-k matching memorys (id, title, type, scope, summary, score). WHEN TO CALL (recall is part of acting, not a separate step): At session start (once): query for active-project + user-preferences to load durable context. Before writing/editing a file: query with a description of what you are about to write (e.g. 'creating React input with focus styles'). This catches lessons before mistakes. Before giving a multi-step plan or recommendation: query for preferences that shape format/scope. When the user's prompt touches a topic that may have a stored lesson, decision, preference, or project-fact. Before save_memory: query to avoid creating a duplicate. WHAT TO DO WITH HITS: READ `score_kind` FIRST — the bands below only exist on the fused scale. `score_kind: "rrf"` (fused rank sum, bounded): score >= ~100 with title/recall_when match: load_memory and apply the lesson before acting. score 30-100: read the summary, load if directly relevant. score < 30: usually noise; skip unless the summary is a perfect topic match. `score_kind: "bm25"` (also flagged `unfused: true`): the vector arm did not run — no embedding model, a cold-start timeout, or an open circuit breaker (`degraded` names which). These are raw MiniSearch scores on an OPEN scale — six figures on a real vault — so 100 means nothing here and every hit would look REQUIRED. Judge those hits by title, summary and recall_when match, and by their ORDER, never by the number. Never ignore a `lesson` hit with strong recall_when match. Two scores are comparable only within the same `score_arms` (and the same `score_version`): the fused scale reaches 163.934 with the two personal arms and 241.803 once the Bastra Commons contribute a third. A batch response whose phrasings disagreed on that reports `merged_by: "query-rank-fusion"` and drops back to `unfused` — its order is meaningful, its numbers are not a band. On the hybrid (BM25 + vector) path the score is a scaled rank sum, not a similarity — a top hit is high by construction. When the response carries top-level `weak_result: true`, no returned hit has a recall_when or title match: the high scores are likely rank-1-of-nothing, so prefer not to load them. recall returns lean CANDIDATES (no bodies). This is step 1 of a two-step flow: call load_memory ONLY for the hits you actually need — do not load every hit.
Change the category of a document.
Save a new document to the vault.
Persist a new memory into the vault as a markdown file with YAML frontmatter. This is YOUR long-term memory — save autonomously when a memory-worthy moment occurs, do not wait to be asked.
Save a product documentation entry.
No error handling guidance visible in any tool description. Agents cannot determine if a failure is retryable, user-fixable, or fatal. No recovery hints (e.g., 'If memory not found, try recall() first').
Output schemas not documented for any tool. Agents cannot plan downstream calls or extract required fields. E.g., recall returns 'id, title, type, scope, summary, score' per description, but no formal schema visible.
STDIO-only transport. Not remotely accessible; cannot be used by hosted MCP clients.