Synapse¶
Synapse connects what angelo knows to what it can prove. It is a capability inside the zettelkasten MCP server—not a fifth server—with two complementary jobs:
- Grounded navigation assembles a bounded neighborhood from memory, zettelkasten, code, and data/experiments; lets an LLM navigate and propose a cited reasoning graph; then lets deterministic code decide whether an answer is supported.
- Practice ↔ canon overlay searches, connects, and compares the episodic memory tree with the citation-backed zettelkasten.
Most Synapse actions are read-only. build is the deliberate exception: it
writes only the committed typed-link overlay under .synapse/links/. Navigation
may update derived caches under .angelo/, but it does not mutate source
knowledge.

Four evidence systems feed one bounded turn. The LLM proposes a cited ReasoningDAG; deterministic epistemics and grounding checks decide what may reach the answer surface.
- Tool reference: MCP tools → zettelkasten
- Behavioral contract:
.cursor/rules/zettelkasten.mdc - How grounded navigation works: Grounded navigation
- Internal protocol: MemDSL v1
Two capabilities, one connective layer¶
1. Grounded navigation¶
Call synapse(action="navigate", question="…") when the answer should be
derived from the repository's evidence rather than recalled from model memory.
The loop is intentionally asymmetric: the LLM chooses useful moves and writes
claims, while the engine owns addresses, provenance, epistemic status, budgets,
verification, and the final answer-or-abstain decision.
The four source families keep their own meaning:
- Memory (blue) — decisions, experiments, checkpoints, and plans from actual project work.
- Zettelkasten (rose) — extracted claims, findings, methods, and verified quotations.
- Codebase (teal) — addressable files and symbols pinned to exact git objects.
- Data and experiments (amber) — measured runs with immutable data and environment provenance.
One turn follows a fixed trust loop:
- Adapters resolve the requested scope and assemble a bounded neighborhood.
- The engine derives each node's status and renders the neighborhood as MemDSL, with explicit gaps and navigation affordances.
- A model may
expand,join,ground, orprune, then returns exactly one terminal:@answerwith a cited ReasoningDAG or@abstain. - The grounding router re-derives status, verifies citations, checks verbatim restatements and numeric coverage, and rejects unsupported prose.
- A deterministic projector emits the versioned
answer_surface; any inconsistency fails closed to an abstention.
An accepted answer carries verified text, status, premise claim IDs, canonical
citation addresses, and any inseparable outdated disclosure. An abstention
instead names the reason—such as missing-hop, stale, false-premise, or
low-coverage—and carries answer_surface: null. This is not a model confidence
score: it is the result of deterministic checks over the material available to
that turn.
Bounded, read-only, and fail-closed
Navigation runs in an isolated subprocess so a timeout or native indexing failure cannot take down the MCP server. Public node, hop, token, and body budgets bound the turn. Source stores are read-only; only derived caches may warm. See Grounded navigation for the full pipeline, status calculus, budgets, public JSON, and validation stack.
2. Practice ↔ canon overlay¶
The memory tree and the zettelkasten are built on the same embedding model and the same KGLite index machinery. That shared vector space is what makes a bridge cheap: a memory entry and a zettelkasten note are directly comparable without any translation layer. Synapse leans on that to do three things — search across both, connect across both, and compare across both — while keeping each store the sole author of its own contents.
.synapse/links/, never back into either source store.Every hit synapse returns is tagged by store (memory vs zk) and
tier (practice vs canon), so a reader can weigh what was actually
done here against what the field says — and, most usefully, notice where they
disagree.
The practice ↔ canon pieces¶
Intersection config¶
A memory graph rarely relates to every zettelkasten project — only a few are
relevant. .synapse/config.yaml names the intersecting ZK projects, and that
set scopes every synapse operation by default. Any tool call can override it by
passing an explicit project list, or pass an empty list to work over memory
alone.
Unified retrieval¶
Synapse presents the memory tree to the zettelkasten's own framing machinery as
just another source (a MemorySourceGraph adapter). On top of that it offers
two read operations over the combined scope: a search that runs each store's
keyword + semantic channels and fuses the ranked lists with Reciprocal Rank
Fusion, and a frame that decomposes a research question into facets and
characterizes each as established, contested, or thin across both stores.
Typed cross-store connections¶
Synapse can propose candidate memory↔zettelkasten pairs from two hands-off
signals — semantic nearest-neighbours in the shared embedding space, and shared
provenance (a memory entry pinned to a file that a note cites). A tool-free LLM
pass then types each surviving pair into a relation — applies,
corroborates, contradicts, motivated-by, instantiates, or related —
with a confidence and a one-line rationale. The surviving edges are persisted to
a committed overlay under .synapse/links/, which is signature-stamped so it
can detect when either store has drifted and needs a rebuild.
The matrix lens¶
Because the overlay is a bipartite set of edges, it projects cleanly into a practice × canon matrix: memory (practice) nodes as rows, zettelkasten (canon) nodes as columns, and each typed edge as a cell. Optionally, an LLM rolls each row and column up into a summary and folds those into an apex synthesis — turning the raw link set into a readable comparison surface. The matrix is a read-only lens; nothing is materialized back into either store.
Claim-aligned overlay and grounded synthesis¶
The generic overlay above links notes of any register — a useful, broad
substrate. On top of it synapse builds a second, claim-aligned overlay
(kind claim, persisted separately to .synapse/links/claim_links.json) that
narrows both endpoints to the registers where a practice↔canon comparison is
meaningful: the canon endpoint is restricted to claim/finding notes
(preferring multi-source _cross synthesis claims over single-source
findings), and the practice endpoint to substantive memory entries
(decision/experiment/checkpoint, not the noise of annotations/notes).
Because matching a terse memory decision against a formal claim is a recall
risk, the claim path leans on the register-independent shared-provenance channel
and overfetches nearest-neighbours before applying the type filter.
Each surviving claim-aligned edge is annotated with the canon claim's
claim_strength and a blended priority = typer_confidence ×
f(claim_strength). The typer confidence stays the sole gate (min_confidence);
claim_strength only weights the synthesis order — a weak claim keeps a
positive priority floor, so it is never silently dropped.
For the highest-value cells — a strong claim met by a high-confidence relation, or any contradiction — synapse can then produce a grounded per-cell brief: one to three sentences stating what the practice did, what the canon claim asserts, and the agreement or tension between them. The brief cites the memory entry id and quotes only the claim's retrieved verbatim quotes (quotes are retrieved, never generated), and an optional deterministic verifier flags any brief whose content does not trace back to that provided material.
That verifier reports a traceability signal, not a semantic-entailment
guarantee. verified=True means only that every numeric token and quoted span
in the brief traces to the provided material — a fabricated statistic is caught
in digits (400bps) and, when it carries a magnitude word or a statistic unit,
spelled out (four hundred basis points, twenty percent) — and that the
memory id is cited (the id itself is checked as a literal string, so a real
hex-id hash never lends its digits to a fabricated number). A standalone bare
cardinal used as ordinary prose ("one of our decisions", "the first
experiment") is intentionally not treated as a figure, so grounded prose is not
over-flagged. It does not judge whether the brief's meaning is correct.
Three error classes are deliberately out of scope and will pass the check:
lexical meaning-inversion (asserting the opposite using in-vocabulary words —
"momentum decreases returns" when the material says it increases them),
unit-variant restatements (2.5% where the material says 250bps), and
spelled multiplier / fraction / ordinal magnitudes — the spelled-number check
covers cardinals plus a magnitude/unit but not multipliers ("double", "tenfold"),
fractions ("a quarter", "half") or ordinals used as magnitudes ("a fourth"). In
every case the brief is flagged, never rewritten — the verifier surfaces an
unfaithful brief for review rather than silently dropping or editing it.
Finally, a practice node that contradicts a strong canon claim is real-world counter-evidence, so those cross-store contradictions are folded into the same WS3 debate map as literature counter-evidence — a claim's contested status can then reflect practice, not just the published record.
Evaluation¶
A small CLI harness (python -m zettelkasten.synapse.eval) measures synapse's
effect on retrieval — comparing results with and without connection expansion —
and helps spot-check the precision of the typed edges.
The interface: one dispatcher tool¶
All of the above is exposed through a single MCP tool, synapse(action=…),
mirroring the zettelkasten server's other dispatchers (note, source,
citation):
| Action | What it does |
|---|---|
search |
Hybrid, RRF-fused search across both stores (optionally 1-hop connection expansion). |
frame |
Frame a research question into facets across both stores. |
navigate |
Navigate a bounded heterogeneous substrate and return a deterministic answer or labeled abstention with a versioned answer_surface. |
get |
Read the full body of a memory entry (ground before quoting). |
connections |
List the typed cross-store edges touching a node (pass kind="claim" for the claim overlay). |
matrix |
Project the overlay as a practice × canon matrix (optional LLM synthesis; kind="claim" uses the claim overlay). |
synthesize |
Grounded per-cell briefs over the claim overlay's high-value cells (cites the memory id + retrieved verbatim quotes). |
debate |
Fold the claim overlay's practice→canon contradictions into the WS3 debate map as cross-store counter-evidence. |
build |
(Re)build a connection overlay — the only synapse write, and only to .synapse/links/. Pass kind="claim" for the claim-aligned overlay. |
Every action except build is source-read-only. build is the sole authored
write, touches only Synapse's own overlay, and is refused when the server runs
write-free (for example, the dashboard chat agent). navigate can warm derived
indexes and caches under .angelo/, but cannot write memory, zettelkasten, code,
datasets, or experiments. The dashboard renders a grounded-answer card only
from the trusted navigate tool-completion event—not from model-authored JSON.
Enabling it¶
Synapse ships with the zettelkasten bundle — there is nothing extra to install:
pip install "angelo[zettelkasten] @ git+https://github.com/natashahirt/angelo"
angelo init --with-zettelkasten
Point it at the relevant projects by listing them in .synapse/config.yaml.
The typed-connection overlay lives under .synapse/links/ and is committed to
git, so the cross-store links travel with the repo; only the embedding and
fulltext caches under .angelo/ are ignored.
Commands¶
Natural-language phrasings that trigger synapse — say the thing, the agent runs it. See the full command cheatsheet.
| Say this | What runs |
|---|---|
| "answer this from the project evidence", "navigate what we know about X", "give me a grounded answer" | synapse(action="navigate") |
| "synthesize", "connect practice to canon", "build the synapse links", "cross-link memory and the zettelkasten" | synapse(action="build") |
| "show the matrix", "practice vs canon", "where do we disagree with the literature" | synapse(action="matrix") |
| "build the claim links", "align practice to claims" | synapse(action="build", kind="claim") |
| "synthesize the cells", "ground the practice–claim briefs" | synapse(action="synthesize") |
| "does practice contradict the literature", "debate map with practice" | synapse(action="debate") |
| "search everything", "look across both stores", "what do we know about X" | synapse(action="search") |
| "frame this across both", "map the landscape (practice + canon)" | synapse(action="frame") |
| "what connects to this", "show the cross-store links" | synapse(action="connections") |
| "find cross-connections", "what links across graphs" | suggest(kind="cross-connections") |
Design notes¶
The decisions behind this, drawn as a slice of the memory tree.
- P Synapse: read-only cross-store layer linking memory tree and zettelkastenactive
Confirmed plan (in implementation). - C Synapse v0 implemented + tools consolidated to one synapse(action=...) dispatcher
Built the read-only cross-store Synapse layer under zettelkasten/ and consolidated its MCP surface. - P Phase: MemDSL grounded navigation capabilityactive
Build the v1 read engine: a callable, domain-agnostic angelo capability that navigates an n-type substrate and answers with calibrated honesty (grounded where covered, hedged where extrapolated, abstaining where coverage… - P Grounded Navigation Productizationactive
Implement six gated milestones without weakening epistemic honesty: (1) deterministic versioned answer surface, (2) MCP/CLI/dashboard exposure plus model provenance and max_nodes=0 semantics, (3) deterministic and live C… - C Grounded Navigation Productization complete
Completed all six milestones without changing the plan file or canonical corpus_v1 oracle: deterministic answer_surface v1; trusted MCP/CLI/dashboard exposure with transport-authenticated tool provenance, honest model me… - P Synapse documentation expansionactive
Publish the native-resolution Synapse animation, reframe the Synapse explanation as a product hub, add dedicated grounded-navigation and MemDSL v1 pages, wire navigation/cross-links, and verify the strict docs build.
- R Angelo
- P synapse — cross-store grounded reasoning layeractive
- P Synapse: read-only cross-store layer linking memory tree and zettelkastenactive
- C Synapse v0 implemented + tools consolidated to one synapse(action=...) dispatcher
- N Added Synapse docs page (own section after Zettelkasten)
- N Grouped Stream + Synapse under a new docs 'Extensions' section
- N Docs ang-arch SVG diagrams rendered ~300px left-aligned; root cause = Material figure{width:fit-content}
- P Phase: MemDSL grounded navigation capabilityactive
- A Anti-fabrication gotcha: restatement licensing must use verifier-matched SOURCE span, never caller-supplied payload text
- E Live navigate reaches GROUNDED tier end-to-end; bottleneck is pin-drift staleness starving coverageactive
- E Live navigate after outdated reframe + git-resolver hardening: grounded+outdated tier solid; the two remaining barriers to a GROUNDED ANSWER are token-budget and MemDSL OUTPUT parse-failactive
- N Fixed test-pollution: epistemics leaked ZETTEL_SKIP_EMBEDDINGS, starving federated_ann (6 fails -> 0)
- P Grounded Navigation Productizationactive
- C Grounded Navigation Productization complete
- P Synapse documentation expansionactive
- C Synapse documentation expansion complete
- P Synapse: read-only cross-store layer linking memory tree and zettelkastenactive
- P synapse — cross-store grounded reasoning layeractive
Related¶
Semantically related entries from the memory graph.