Trisynapse Memory : Evidence First Memory Layer for AI Agents

A local-first memory engine that stores source-aware evidence, retrieves relevant context, and helps agents answer with traceable citations.

36 min readShanmukha Sainath
HeaderAn illustration of Trisynapse Memory

Why am I building this?

Trisynapse Demo

I have been working on app called Trisynapse. Trisynapse is a local-first, BYOK AI research workspace. It turns scattered papers, PDFs, bookmarks, notes & videos into a private digital brain. The app auto-summarizes, maps concept graphs, and compiles sources into auto-updating wikis. You can work seamlessly with a built-in split-view Browser, local retrieval Chat, AI Assistants, and infinite Canvas whiteboards for note-taking. 100% offline-first (except AI API calls) and private: your vault stays on your machine. I’ve been learning areas like RL, agentic AI, and LLMs. At some point, I couldn’t keep up with the pace of new papers and updates, and I was missing important work. I wanted a simpler way to stay on top of it and that's how Trisynapse started. I tried keeping them in Notion.

The name Trisynapse is inspired from "Trisynaptic Circuit", a neural pathway essential for memory formation in brain.

Trisynaptic CircuitAn illustration of Trisynapse Circuit

The core part for this Trisynapse is Memory Engine that can process, retrieve and remember information across hundreds and thousands of sources efficiently. So, I started doing some research on developing a Memory layer that is more general and also inspired from how Brain process and stores information. I found below papers extremely useful while working on Trisynapse Memory.

Existing Frameworks

While the survey paper mentioned above listed many Agent Memory frameworks (image below), I personally loved the works of SuperMemoryAI, Mem0, AgentMemory and HippoRAG. These are very widely used and also doesn't have a complex workflow.

Open-Source Agent Memory FrameworksOpen-Source Agent Memory Frameworks

While these frameworks are very efficient and shown competitive performance on benchmakrs, I found them to be lagging behind few aspects:

  • Single Retrieval Mechanism : AgentMemory, SuperMemoryAI, Mem0 uses vector similarity during retrieval stage. While vector similarity is known to be great at finding similar chunks of data, it doesn't work in the cases where exact entities, IDs or nubers has to be extracted. Sometimes an exact negation of the query gets high score when we only focus on semantic similarity.
  • Memory Drift : When new information arrives, frameworks like Mem0, AgentMemory prompt an LLM to decide whether to ADD, UPDATE, or DELETE memory entries in place. If the LLM misunderstands context or hallucinates during an update, the original evidence is permanently overwritten or erased.
  • Static Graph : HippoRAG introduces neurobiologically inspired knowledge graphs, but it operates as an offline, static research pipeline. It runs heavy Open Information Extraction (OpenIE) over documents and uses global Personalized PageRank (PPR), which is computationally expensive and cannot handle live real-time conversational streaming, dynamic updates.
  • Memory Lifecycle: In Mem0 or AgentMemory, "forgetting" either means deleting a row in SQLite/Chroma or doing nothing. There is no distinction between updating an erroneous statement, retracting any source.

Core Architecture

Every memory frameworks contaisn mainly 4 stages:

  1. Preprocessing
  2. Extraction
  3. Indexing
  4. Retrieval

The core idea of trisynapse-memory is to make all the four stages independent and flexible. Each stage consists of varitey of options making the framework robust to any types of sources. The codebase is developed in such a way that it is easier to add new branch to any stage. This independent and branching lets us to explore Reinforcement Learning and self-improving memory framework ideas in future.

Vocabulary

There are some terms which I will be using in further sections as part of architectural components. These vocabulary helps understand the algorithm easier

TermMeaning
IngestThe intake process: adding a document, chat, or image, slicing it into chunks, and writing it into the memory log.
Memory logThe permanent master database: everything the system has ever seen or learned.
RecordA single numbered entry in the memory log.
Raw sourceAn exact, unaltered snippet of original input (a PDF page, a chat message, a line of code).
FactA concise statement extracted by an LLM that points directly back to the raw source that supports it.
NoteA direct human instruction, manual correction, or rule.
Record groupA collection of related records from the same file, chat conversation, or event.
Group summaryA quick overview card describing what a record group is about, used to navigate search without reading every page.
ClaimA synthesized assertion that aggregates all facts about a topic and flags any real-world contradictions.
IndexesDisposable, high-speed lookup tables (BM25, embeddings, claims, group summaries) built over the memory log to speed up search.
Embedding indexVector store used for semantic search.
RetrievalThe search process: finding candidate matches in the fast indexes, then pulling the real evidence from the memory log.
Deep summaryAn expanded, multi-hop search stage that activates when a quick search is unsure about retrieved data.
Query RunA report detailing how a search was executed (scores, timings, paths taken)
Headline scores on four memory suites. Blank cells mean the public number was not reported for that protocol. HydraDB is the published BEAM-1M score. Comparisons are only valid within a column.

Preprocessing

We designed a structure and modality aware preprocessing procedure. This helps further steps to extract and index information efficiently which makes retrieval stage easier.

  • Code: Parsed into complete functions and classes using AST.
  • Documents: Preserves exact page numbers, slide numbers, and paragraph locators.
  • Tables: Preserves headers and row structures.
  • Chats: Preserves speaker roles, timestamps, and conversation turns.
  • Images: Uses multimodal vision models to translate diagrams into structured descriptions before ingestion.
  • Structured Data (YAML, JSON, XML...): Parses each JSON object or YAML document into an individual record.
  • Web pages: Strips scripts and styles; converts sections, headings, and tables into structured text.
  • Codebases: Generates a top-level file listing all contents, packages them into a safe bundle, and ingests each file.

Every ingested source is versioned using hashing. If you upload an updated version of a file, the system detects it and cleanly links the new version while archiving the old.

Preprocessing

  1. 01
    Safety and sanitizationGuardrails run before any file is opened.Toggle step details
    • Size caps: Max 25 MiB per file and 250 MiB per ingestion run.
    • SSRF protection: URL fetches block private IPs, localhost, link-local addresses, and embedded credentials.
    • Secret filtering: Ignores .env, credentials.json, *.pem, *.key, and AWS or SSH credentials.
    • Traversal protection: Rejects symlinks and archive path traversal. Respects .gitignore and .trisynapseignore.
  2. 02
    Content hashingSHA-256 decides if this is a new version or a no-op.Toggle step details
    • Hash: SHA-256 of the raw bytes.
    • Same hash: No-op. Returns the existing version for this source key.
    • Changed content: Prepares v2 and keeps v1 active until v2 is fully validated.
  3. 03
    Structure-aware chunkingSlice by modality and keep a locator on every chunk.Toggle step details
    • Code: Complete functions and classes from the AST.
    • Documents: Pages, slides, and paragraphs.
    • Tables: Headers and row structure.
    • Chats: Speaker, timestamp, and turn.
    • Locators: Pointers such as page 2, lines 41-79, or speaker Maya.
  4. 04
    Blob storageThe original file is stored by hash so it can be audited later.Toggle step details
    • Location: store/sources/sha256/{first two hash chars}/{full hash}
    • Permissions: Owner read/write only (600).
    • Purpose: The original can always be audited or re-parsed.
  5. 05
    Common retrieval shapeEvery chunk becomes one searchable shape, not flattened prose.Toggle step details
    • Modality: code, table, document, conversation, or image.
    • Fields: path, symbol, language, page, sheet, or speaker.
    • Why: A code route can boost symbol names without treating everything as generic text.
Click a step to expand.

Extraction

During extraction, LLM parses the raw text to extract structured semantic relationships

Structured Knowledge

  • Subject: The primary entity being discussed (e.g., "Project Atlas").
  • Relation: The relationship or action (e.g., "launched_on", "owned_by", "assigned_as_tech_lead").
  • Object: The target entity, person, or attribute (e.g., "25 April 2026", "Shanmukh", "John Doe").

Temporal Anchors

  • Extracts and Normalizes calendar dates, timestamps, or relative time expressions (e.g., "starting Monday", "Q3 2026", "2026-10-14").

The model's confidence in the extraction (between 0.0 and 1.0) is also being stored.

Indexing

Indexes are specialized, high-speed lookup projections over the Memory Log obtained from Extraction and processing stages. Trisynapse is built five complementary indexing methods, each working complementary to others.

A. Lexical Postings

Lexical search is the exact-match route: names, IDs, error codes, and other tokens that vector similarity often misses. It runs in four stages.

1. Tokenizer (unicode-code-v2)

Text is split into searchable tokens using the tokenizer.

2. Inverted index (retrieval_terms)

SQLite stores a term-frequency posting list plus collection statistics:

SymbolMeaning
NNNumber of documents
avgdl\mathrm{avgdl}Average document length
df(t)\mathrm{df}(t)Document frequency of term tt
tf(t,d)\mathrm{tf}(t, d)Term frequency of tt in document dd
∣d∣\lvert d \rvertLength of document dd
Operational measurements from the same runs. Ingest is per source document, query time per question, context size per answered query. These are within-suite diagnostics, not a speed contest across suites.

3. Okapi BM25 (Lucene-style IDF)

IDF(t)=ln⁡(1+N−df(t)+0.5df(t)+0.5)\mathrm{IDF}(t) = \ln\left(1 + \frac{N - \mathrm{df}(t) + 0.5}{\mathrm{df}(t) + 0.5}\right)
Lucene-style inverse document frequency
BM25(t,d)=IDF(t)⋅tf(t,d)⋅(k1+1)tf(t,d)+k1(1−b+b⋅∣d∣avgdl)\mathrm{BM25}(t, d) = \mathrm{IDF}(t) \cdot \frac{\mathrm{tf}(t, d) \cdot (k_1 + 1)}{\mathrm{tf}(t, d) + k_1\bigl(1 - b + b \cdot \frac{\lvert d \rvert}{\mathrm{avgdl}}\bigr)}
Okapi BM25 score of term tt in document dd

Default parameters:

  • k1=1.5k_1 = 1.5 - term saturation
  • b=0.75b = 0.75 - document length normalization

4. Query match

The document score is the sum over unique query terms T(q)T(q):

score(q,d)=∑t∈T(q)BM25(t,d)\mathrm{score}(q, d) = \sum_{t \in T(q)} \mathrm{BM25}(t, d)
Query score over unique terms

The route returns up to the top 500 candidate records. Lexical Postings are very good at finding Code Functions, Classes, Error codes, Entity names etc.,

B. Vector Embeddings

The Memory logs are transformed into a dense vector in Rp\mathbb{R}^p using local SentenceTransformers (all-MiniLM-L6-v2) or external model providers. This type of semantic information helps in retrieving conceptual search and multilingual paraphrased queries.

C. Knowledge Graph

The knowledge graph is the adjacency index over the same memory log: a directed weighted graph G=(V,E)G=(V,E) whose vertices are citable records (raw chunks and extracted (subject,relation,object)(\mathrm{subject},\mathrm{relation},\mathrm{object}) facts). A query that matches one vertex can walk a few hops to neighbors that never contained the query tokens.

Suppose the store has ingested a Transformer lecture, a LoRA note, and a short fine-tuning chat. The graph around those records looks like this:

Rendering diagram

Three edge types build that picture:

  • followed_by (1.01.0 forward, 0.80.8 backward): order inside one group. Lecture page r1→r2r_1 \to r_2; chat turn c1→c2c_1 \to c_2. Walking the thread is what resolves "it" in the reply.
  • about_same_entity (0.920.92): records that share a normalized subject or object (lora, self-attention, transformer). This is the multi-hop bridge from the LoRA fact to the attention formula.
  • similar_to (≥0.58\ge 0.58, up to 5 neighbors): live cosine links in embedding space, so a paraphrase of the same claim connects even without a shared entity string.

Retrieval seeds from the top BM25 and semantic hits, then spreads score with max-product:

s(v)=max⁡u→v(s(u)⋅w(u,v))s(v) = \max_{u \to v} \bigl(s(u) \cdot w(u, v)\bigr)
Max-product graph walk

For "Does LoRA replace self-attention?", seeds land on c1c_1 and f4f_4. Two hops reach c2c_2 (the anaphor) and r1r_1 (scaled dot-product attention). Default depth is h=2h = 2 (33 in Deep Recall), keeping the top 80 frontier nodes per hop.

D. Compiled Claims

Facts that share a normalized (subject,relation)(\mathrm{subject},\mathrm{relation}) key fold into one claim. BERT pretrained_with Adam and BERT pretrained_with AdamW land in the same bucket; if the objects disagree the claim is CONTESTED and its confidence is multiplied by 0.720.72.

Confidence mixes extraction quality, how many source groups agree, and how old the evidence is:

confidence=0.45 cˉ+0.35 support+0.20 recency\mathrm{confidence} = 0.45\,\bar{c} + 0.35\,\mathrm{support} + 0.20\,\mathrm{recency}
Compiled claim confidence
support=min⁡(1,ln⁡(1+∣E∣)ln⁡5),recency=exp⁡(−ln⁡2⋅Δt90)\mathrm{support} = \min\Bigl(1, \frac{\ln(1 + |E|)}{\ln 5}\Bigr), \qquad \mathrm{recency} = \exp\Bigl(-\frac{\ln 2 \cdot \Delta t}{90}\Bigr)
Support and recency

cˉ\bar{c} is the mean fact confidence in the bucket. ∣E∣|E| is the number of corroborating source groups. Recency uses a 90-day half-life.

This indexing is very helpful when any statement saved in past is being updated in the new sources or when the logs contradict each other. This index gives high confidence for the facts that are being present in multiple sources increasing its credibility.

E. Group Summary

A group summary is an quick or short summary representing a group. Raw chunks and Extracted facts are used to obtain the summary. We also save other metadata like alternate phrasings and it's age which helps during retrieval.

1. Summary card

The compiler reads every raw_source and fact sharing that group_id. With an LLM it uses the versioned group_summary prompt; otherwise it takes the top 4 keywords and the first 4 factual sentences. The card is stored in SQLite recall_cache:

FieldRoleExample
concept_or_topic2–4 word titleLoRA on attention
summary1–2 sentence overviewLoRA injects BABA into Wq,WvW_q, W_v; self-attention is unchanged.
alt_phrasingsUp to 3 query paraphrasesDoes LoRA replace attention?; low-rank adapters for MHA
source_log_idsMemory-log IDs in the groupd_r1, d_f4, d_c1
staleRebuild flagfalse at confidence 0.950.95; true at 0.550.55 after the group grows

2. Indexing

The searchable string is the concatenation of those text fields, then posted to BM25 and the vector index:

index_text=summary∥concept∥alt_phrasings\mathrm{index\_text} = \mathrm{summary} \mathbin{\Vert} \mathrm{concept} \mathbin{\Vert} \mathrm{alt\_phrasings}
Group summary search string

That is how a paraphrase like "Does LoRA replace self-attention?" can hit the lecture group without matching every page.

3. Source Ranking

The engine opens source_log_ids and ranks the raw records.

s(d)=0.72⋅cos⁡(q,d)+0.28⋅∣T(q)∩T(d)∣∣T(q)∣s(d) = 0.72 \cdot \cos(\mathbf{q}, \mathbf{d}) + 0.28 \cdot \frac{\lvert T(q) \cap T(d) \rvert}{\lvert T(q) \rvert}
Ranking inside a group

Rather than comparing a user's question against long individual chunks of raw data, the engine first compares it against Group Summary cards to pinpoint the exact relevant sources.

Retrieval

Trisynapse Memory Retrieval is an adaptive, multi-route pipeline that searches across multiple index structures, fuses their rankings, evaluates retrieval confidence, and strictly grounds the final context in verifiable Memory Log records before final synthesis.

Rendering diagram

Query Classification

Query Planner inspects the query to identify the intent and accordingly modulate routing and context policies.

A. Intent Classification Determined via first-match regex heuristics:

  1. multi_hop: Cues like "because", "relationship between", "lead to", "how did X affect Y".
  2. inference: Cues like "would", "likely", "probably", "might".
  3. temporal: Cues like "when", "what year", "before", "after", "how long ago".
  4. list: Cues like "list", "enumerate", "which", "how many".
  5. fact: Default factual lookup.

Existing Intent classifier contains hardcoded rules but can be easily replaced with a small classifier or even LLM for more accurate classification.

B. Modallity Detection The planner detects active modalities present in the store (code, table, image, document, conversation) and selects a profile:

  • If only one modality is present →\to Modality profile (e.g., code).
  • If multiple modalities are present →\to mixed.
  • Otherwise →\to balanced.

C. Route Weights

Route (bb)Default Weight (wbw_b)Profile Specific Changes
bm251.001.00Boosted in precise profile
semantic1.001.00Boosted in broad profile
code, table, conversation1.001.00Boosted when matching modality detected
document0.950.95Standard document text
image0.900.90Multimodal image descriptions
temporal0.850.85Activated on date cues or temporal kind
graph0.850.85Boosted in broad and multi_hop

Independent routes listed below generates individual candidate rankings for a given Query:

1. Lexical Postings

Queries the SQLite inverted postings table (retrieval_terms) using the unicode-code-v2 tokenizer. Sums BM25 contributions across unique query terms and returns the top 500 documents.

2. Nearest Neighbors

Approximate nearest-neighbor (ANN) search over normalized embeddings. Cosine distance is used to calculate the similarity.

ssem=1−distances_{\mathrm{sem}} = 1 - \mathrm{distance}
Semantic similarity from cosine distance

ANN returns far more neighbors than will fit in the answer. Fusion, reranking, and grounding drop most of them (summaries, duplicates, items that cannot be cited), so the route asks LanceDB for higher number of records.

L=max⁡(200,  8⋅max_context_items)L = \max\bigl(200,\; 8 \cdot \mathrm{max\_context\_items}\bigr)
Semantic candidate window

3. Temporal Matching

Extracts temporal cues (e.g., "October 2026", "before Friday"). Scores records based on calendar proximity, event timestamps, and normalized temporal_anchor metadata. Queries with time words ("when") down-weight records lacking time metadata.

4. Graph Traversal

Graph Traversal uses top 5 BM25 and top 5 Semantic candidate IDs, traversing persisted graph edges (followed_by, about_same_entity, similar_to).

  • Graph Path Scoring Formula: For a path p=(v0,v1,…,vℓ)p = (v_0, v_1, \dots, v_\ell), the path score is the product of edge weights: s(p)=∏i=0ℓ−1w(vi,vi+1)s(p) = \prod_{i=0}^{\ell-1} w(v_i, v_{i+1})
  • Max-Product Selection: s(v)=max⁡p:v0∈S,vℓ=vs(p)s(v) = \max_{p: v_0 \in S, v_\ell = v} s(p)
  • Frontier Cap: Traverses up to hop budget h=2h = 2 (expanded to 33 in Deep Recall). Each hop retains at most the top 80 strongest frontier nodes, preventing combinatorial graph explosions.

5. Modality Aware Routing

Generic BM25 and Vector similarity treats a code snippet like a paragraph. Modality routes re-score with the fields that actually matter for that shape: symbol and path for code, headers and sheet for tables, speaker for chats etc.,

smod(d)=0.56 cos⁡(q,d)+0.30 bounded(BM25)+0.14 fields(d)+0.12⋅1[preferred]\begin{aligned} s_{\mathrm{mod}}(d) = 0.56\,\cos(\mathbf{q}, \mathbf{d}) + 0.30\,\mathrm{bounded}(\mathrm{BM25}) + 0.14\,\mathrm{fields}(d) + 0.12 \cdot \mathbf{1}[\text{preferred}] \end{aligned}
Modality blend

BM25 can land in the tens while cosine lives in [−1,1][-1, 1], so the BM25 term is squashed to [0,1)[0, 1) before mixing:

bounded(x)=x1+max⁡(x,0)\mathrm{bounded}(x) = \frac{x}{1 + \max(x, 0)}
Bounded BM25

fields(d)\mathrm{fields}(d) is the structured-key bonus. 1[preferred]\mathbf{1}[\text{preferred}] is 11 when the planner already selected this modality (code, table, conversation, image).

Weighted Ranking

Different routes produce scores on wildly incompatible scales (BM25 can reach 35.035.0, cosine is bounded [−1,1][-1, 1], and graph path products are in [0,1][0, 1]). Trisynapse uses Weighted Reciprocal Rank Fusion (RRF) with constant k=60k = 60, using candidate rank positions (rb(d)≥1r_b(d) \ge 1) rather than raw scores:

RRF(d)=∑b∈routeswb60+rb(d)\mathrm{RRF}(d) = \sum_{b \in \text{routes}} \frac{w_b}{60 + r_b(d)}
Weighted RRF
  • k=60k = 60? ensures a single best ranking does not completely overpower broad consensus across multiple routes.
  • Unranked candidates in branch bb contribute 00.

Soft Reranker

Reciprocal Rank Fusion (RRF) is great at measuring agreement across routes, but it completely ignores document relevancy scores from each route. Soft Reranker recalculates a multi-factor score over all fused candidates. Soft Reranker ensures stale or low-confidence notes are gently demoted in the ranking.

srerank(d)=0.52 cos⁡(q,d)+0.18 reliability(d)+0.10 recency(d)+0.20 RRF(d)Fmax⁡+0.04⋅1[preferred modality]\begin{aligned} s_{\mathrm{rerank}}(d) &= 0.52\,\cos(\mathbf{q}, \mathbf{d}) + 0.18\,\mathrm{reliability}(d) + 0.10\,\mathrm{recency}(d) + 0.20\,\frac{\mathrm{RRF}(d)}{F_{\max}} + 0.04 \cdot \mathbf{1}[\text{preferred modality}] \end{aligned}
Soft rerank
TermMeaning
Fmax⁡F_{\max}max⁡dRRF(d)\max_d \mathrm{RRF}(d), so the fused rank is scaled to [0,1][0, 1]
reliability(d)\mathrm{reliability}(d)claim confidence, multiplied by 0.550.55 if the card is stale
recency(d)\mathrm{recency}(d)11 if the record has a timestamp or temporal_anchor, else 0.50.5
1[preferred modality]\mathbf{1}[\text{preferred modality}]11 when dd matches the planner's modality profile

The reranked candidates are sorted descending by srerank(d)s_{\mathrm{rerank}}(d), producing the top candidate score s1s_1 and runner-up score s2s_2.

Confidence Gating

Sanity check is performed to top retirved sources before passing them to final Answer Prompt. The gate decides whether the search is good enough, or whether to rewrite the query and try again.

1. Gate

Margin Δ=s1−s2\Delta = s_1 - s_2 (Top 2 candidates), threshold γ=0.018\gamma = 0.018. Search is confident when all of these hold:

confident=(∣H∣>0)∧(s1>0.12)∧(Δ≥γ∨agree(H)≥0.07∨∣H∣=1)∧∀h∈H,  kind(h)≠group_summary\begin{aligned} \mathrm{confident} &= (|H| > 0) \land (s_1 > 0.12) \\ &\quad \land \bigl(\Delta \ge \gamma \lor \mathrm{agree}(H) \ge 0.07 \lor |H| = 1\bigr) \\ &\quad \land \forall h \in H,\; \mathrm{kind}(h) \neq \texttt{group\_summary} \end{aligned}
Confidence gate
CheckMeaning
∣H∣>0\lvert H \rvert > 0at least one hit
s1>0.12s_1 > 0.12the top score is not noise
Δ≥γ\Delta \ge \gamma, or agree(H)≥0.07\mathrm{agree}(H) \ge 0.07, or ∣H∣=1\lvert H \rvert = 1a clear winner, shared vocabulary, or a single hit
no group_summary in HHsummary card cannot count as evidence

agree(H)\mathrm{agree}(H) is the mean token Jaccard between the top hit and hits 2–5:

J(A,B)=∣A∩B∣∣A∪B∣J(A, B) = \frac{\lvert A \cap B \rvert}{\lvert A \cup B \rvert}
Token Jaccard

A tight Δ\Delta still passes if those hits share vocabulary.

2. Query refinement

If the gate fails, the engine takes the four most frequent sequences from the top five hits, appends them (q′=q∥termsq' = q \mathbin{\Vert} \mathrm{terms}), and searches again. At most two rounds.

3. Deep Recall

If it still fails, or the planner tagged multi_hop, Deep Recall widens the search:

  • candidate limit 2×top_k2 \times \mathrm{top\_k} or max_context_items
  • one extra graph hop (h=2→3h = 2 \to 3)
  • query lens: top 8 subject / relation / object tokens from overlapping claims, appended to qq
  • relaxed margin 0.45γ0.45\gamma
  • cold expansion: every record from groups that already have a hit

Memory Log Grounding

All the retrived candidates are now grounded to raw source records.

Rendering diagram

The final grounded source records are scored for the final answer prompt:

sground(d)=0.56 cos⁡(q,d)+0.14 ∣T(q)∩T(d)∣∣T(q)∣+0.12 RRF(d)Fmax⁡+0.10 srerank(d)+0.05 conf(d)+0.03 swalk(d)+0.05⋅1[raw_source]\begin{aligned} s_{\mathrm{ground}}(d) &= 0.56\,\cos(\mathbf{q}, \mathbf{d}) + 0.14\,\frac{\lvert T(q) \cap T(d) \rvert}{\lvert T(q) \rvert} \\ &\quad + 0.12\,\frac{\mathrm{RRF}(d)}{F_{\max}} + 0.10\,s_{\mathrm{rerank}}(d) \\ &\quad + 0.05\,\mathrm{conf}(d) + 0.03\,s_{\mathrm{walk}}(d) \\ &\quad + 0.05 \cdot \mathbf{1}[\texttt{raw\_source}] \end{aligned}
Grounding score
TermWeightMeaning
cos⁡(q,d)\cos(\mathbf{q}, \mathbf{d})0.560.56cosine between the query and the record
∣T(q)∩T(d)∣/∣T(q)∣\lvert T(q) \cap T(d) \rvert / \lvert T(q) \rvert0.140.14fraction of query tokens that also appear in dd
RRF(d)/Fmax⁡\mathrm{RRF}(d) / F_{\max}0.120.12fused multi-route rank, scaled to [0,1][0, 1]
srerank(d)s_{\mathrm{rerank}}(d)0.100.10soft-rerank score from the previous stage
conf(d)\mathrm{conf}(d)0.050.05extraction or claim confidence
swalk(d)s_{\mathrm{walk}}(d)0.030.03max-product graph-walk score
1[raw_source]\mathbf{1}[\texttt{raw\_source}]0.050.0511 if dd is a raw page or chat turn, so a derived fact loses ties

Context Budgeting

To prevent a single long PDF or long conversation from crowding out all other sources, the grounded candidates pass through a diversity filter:

1. Dedup :

Normalized token text is compared. Exact duplicates are dropped.

2. Per-group cap

If more than one record group is in the pool, each group is limited to

cap=max⁡(4,  ⌊context_limit/2⌋)\mathrm{cap} = \max\bigl(4,\; \lfloor \mathrm{context\_limit}/2 \rfloor\bigr)
Per-group cap

A 24-item budget means at most 12 slots from the lecture, so the LoRA note and the fine-tuning chat still fit.

3. Token caps

  • 2,0002{,}000 tokens per source group
  • 6,0006{,}000 tokens for the whole prompt

4. Hit score

Final sources get a presentation score for the answer prompt:

shit(d)=0.65 srerank(d)+0.35(1−ρ∣G∣)+b(d)b(d)={0.06if d is raw_source0.04otherwise\begin{aligned} s_{\mathrm{hit}}(d) &= 0.65\,s_{\mathrm{rerank}}(d) + 0.35\left(1 - \frac{\rho}{\lvert G \rvert}\right) + b(d) \\ b(d) &= \begin{cases} 0.06 & \text{if } d \text{ is } \texttt{raw\_source} \\ 0.04 & \text{otherwise} \end{cases} \end{aligned}
Hit score
TermMeaning
srerank(d)s_{\mathrm{rerank}}(d)soft-rerank score from earlier
ρ\rho00-indexed rank of dd among grounded survivors GG
∣G∣\lvert G \rvertsize of that grounded set
b(d)b(d)0.060.06 for a page or chat turn, 0.040.04 for a derived fact

Answer Synthesis

This is the final stage where the sources left are used to obtain final response for the Query.

1. Abstain

If no source is retrieved or the top shit<0.10s_{\mathrm{hit}} < 0.10, the engine responds with: I don't have enough grounded evidence to answer that.

2. Prompt

LLM sees the question, raw_source and fact records (with IDs and locators), and a policy for the query kind (fact, temporal, multi_hop).

3. Citations

LLM returns answer, abstain, and citation_ids. An answer with no valid citation is dropped and the engine abstains.

{
  "answer": "No. LoRA does not replace self-attention.",
  "abstain": false,
  "citation_ids": ["d_r1", "d_c2"]
}

Putting all together

Rendering diagram

Interactive workflow

Loading

Usage

Trisynapse Memory is designed to fit cleanly into any stage of your AI agent stack. Whether you are embedding long-term memory directly into an autonomous Python agent, managing memory stores from the command line, querying memories from a distributed microservice, building full-stack Node.js/TypeScript applications, or visually debugging retrieval graphs in a browser, Trisynapse provides unified APIs with the exact same guarantees: an immutable evidence log, multi-route consensus search, and strict citation grounding.

Python SDK

The Python SDK is the native, in-process engine ideal for building autonomous agents, backend services, or LangChain/LlamaIndex tools.

Installation

Install the core package, or install with the optional loader dependencies to support PDF parsing, Office documents, code AST parsing (Tree-sitter), and local token counting:

# Core engine & terminal
pip install trisynapse-memory

# Recommended: Core + document loaders (PDF, DOCX, XLSX, PPTX, Tree-sitter)
pip install 'trisynapse-memory[all]'

Requirement: Python 3.11 or higher.

Example

from trisynapse_memory import MemoryEngine, MemoryNamespace, SourceInput

# 1. Initialize the engine with a persistent directory and scoped namespace
namespace = MemoryNamespace(user_id="maya", project_id="atlas-core")
memory = MemoryEngine.open("./memory_store", namespace=namespace)

# 2. Ingest varied sources (PDF document and a chat session)
memory.ingest(
    SourceInput(kind="file", path="q3-brief.pdf", source_key="doc:q3-brief")
)

memory.ingest_messages(
    messages=[
        {"role": "Alex", "content": "Maya, who will serve as the tech lead for Project Atlas?"},
        {"role": "Maya", "content": "Liam Vance is assigned as the tech lead starting Monday."},
    ],
    group_id="chat:sync-9",
)

# 3. Query with verifiable, grounded citations
result = memory.query("Who is the tech lead for Project Atlas and when is the launch?")

print(f"Answer: {result.answer}")
print(f"Abstained: {result.abstain}")

for citation in result.citations:
    print(f"-> Cited Record ID: {citation.record_id}")
    print(f"   Locator: {citation.locator}")
    print(f"   Excerpt: {citation.excerpt}\n")

# 4. Memory Lifecycle: Correct or Forget a memory
# Correct an outdated statement without losing chronological history
memory.correct(
    record_id="d_0191e4a104",
    text="Liam Vance and Sarah Lin are co-tech leads for Project Atlas.",
    reason="Updated staffing announcement",
)

# Logically forget a deprecated preference/rule (keeps audit log, disables ranking)
memory.forget(record_id="d_0191e4a101", reason="Project target superseded")

CLI

Trisynapse Memory CLI DemoTrisynapse Memory CLI Demo

The Command-Line Interface (CLI) provides shell-level memory operations for DevOps, scripting, and an interactive terminal (TUI) for local agent development.

Installation

Install via the automated standalone installer:

# macOS / Linux
curl -LsSf https://github.com/shanmukh05/trisynapse-memory/releases/latest/download/install.sh | sh

# Windows PowerShell
irm https://github.com/shanmukh05/trisynapse-memory/releases/latest/download/install.ps1 | iex

Or install via pip / uv:

pip install 'trisynapse-memory[all]'

Example

# 1. Initialize a new memory store in the default location (~/.trisynapse-memory/store)
trisynapse-memory init

# 2. Ingest files, directories, or public Git repositories
trisynapse-memory ingest ./docs/q3-brief.pdf ./src https://example.com/handbook

# 3. Ask questions directly from the command line
trisynapse-memory query "When is Project Atlas scheduled to launch?"

# 4. Search raw evidence without answer synthesis (returns ranked hits)
trisynapse-memory search "Liam Vance tech lead" --top-k 5

# 5. Run store integrity and consistency validation
# Verifies SQLite health, sequence continuity, and retained file blob hashes
trisynapse-memory validate

# 6. Launch the interactive TUI terminal
trisynapse-memory

REST API

For distributed architectures, microservices, and non-Python environments (Go, Rust, Java, C#), Trisynapse can run as a high-performance REST daemon with OpenAPI specifications.

Installation & Server Launch

Install the server extras and launch the daemon:

pip install 'trisynapse-memory[server]'

# Start the daemon on port 8765
trisynapse-memory serve --port 8765

The OpenAPI documentation and schemas are automatically available at http://127.0.0.1:8765/openapi.json.

Example

1. Ingest Multiple Sources (POST /api/v1/sources/ingest)
curl -X POST http://127.0.0.1:8765/api/v1/sources/ingest \
  -H "Authorization: Bearer $TRISYNAPSE_MEMORY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "namespace": {"project_id": "atlas-core"},
    "sources": [
      {
        "kind": "url",
        "url": "https://company.internal/docs/spec.html"
      },
      {
        "kind": "text",
        "text": "Project Atlas launch date is confirmed for 14 October 2026.",
        "source_key": "launch-memo"
      }
    ]
  }'
2. Execute a Grounded Query (POST /api/v1/query)
curl -X POST http://127.0.0.1:8765/api/v1/query \
  -H "Authorization: Bearer $TRISYNAPSE_MEMORY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "question": "What is the confirmed launch date for Project Atlas?",
    "namespace": {"project_id": "atlas-core"},
    "top_k": 5
  }'

JSON Response:

{
  "query_id": "q_9c82b1",
  "question": "What is the confirmed launch date for Project Atlas?",
  "answer": "Project Atlas is confirmed to launch on 14 October 2026.",
  "abstain": false,
  "citations": [
    {
      "record_id": "d_0191e4a102",
      "locator": {"kind": "source_key", "source_key": "launch-memo"},
      "excerpt": "Project Atlas launch date is confirmed for 14 October 2026."
    }
  ]
}

TypeScript

For Next.js, Node.js backends, Express APIs, or browser frontends, @trisynapse/trisynapse-memory offers a fully typed client library over the REST API.

Installation

npm install @trisynapse/trisynapse-memory
# or
pnpm add @trisynapse/trisynapse-memory
# or
yarn add @trisynapse/trisynapse-memory

Example

import { TrisynapseMemory } from "@trisynapse/trisynapse-memory";

// 1. Initialize the client
const memory = new TrisynapseMemory({
  baseUrl: "http://127.0.0.1:8765",
  apiKey: process.env.TRISYNAPSE_MEMORY_API_KEY,
  namespace: { user_id: "maya", project_id: "atlas-core" },
});

// 2. Ingest web pages, text, or base64 files
const run = await memory.ingest([
  {
    kind: "url",
    url: "https://example.com/handbook",
  },
  {
    kind: "file",
    filename: "meeting-notes.md",
    content_base64: Buffer.from("Maya announced Liam Vance as tech lead.").toString("base64"),
  },
]);

console.log(`Ingestion Run Started: ${run.id}`);

// 3. Ask a grounded question with typed citations
const response = await memory.query({
  question: "Who was announced as tech lead?",
  topK: 5,
});

if (!response.abstain) {
  console.log(`Answer: ${response.answer}`);
  response.citations.forEach((citation) => {
    console.log(`-> Cited: ${citation.record_id} | ${citation.excerpt}`);
  });
} else {
  console.log("Not enough grounded evidence to answer.");
}

// 4. Lifecycle management
await memory.forget("d_0191e4a102", "Outdated requirement");

Memory Studio

Memory Studio is a visual, browser-based observability suite built directly into Trisynapse. It eliminates the "black box" nature of AI agent memory by allowing developers to visually explore, inspect, and debug knowledge representations in real time.

Memory Viewer tab in Memory StudioMemory Viewer: store overview, item counts, and retrieval playground
Queries tab in Memory StudioQueries: grounded answers, retrieval traces, and hybrid routes
Sources tab in Memory StudioSources: ingested documents, types, and active imports

Memory Viewer: store overview, item counts, and retrieval playground

1 / 3

Launching the Studio

Launch the service with the --studio flag:

trisynapse-memory serve --studio --port 8765

Navigate to http://127.0.0.1:8765/studio in your browser.

Key Capabilities

  • Timeline View: A live chronological stream showing the sequence of ingested raw sources, extracted facts, corrections, and logical retractions.
  • Knowledge View: An interactive graph showing high-level concepts, entities, and asserted relationships, including color-coded indicators for ACTIVE vs. CONTESTED claims.
  • Lineage View: A provenance graph that lets you click on any compiled claim or derived fact and trace the exact arrows backward to the originating raw PDF page, chat turn, or code file.
  • Retrieval Playground & Query Inspector: Replay queries to inspect the retrieval engine under the hood:
    • View candidate snapshots from each individual route (BM25, vector, graph walk, temporal).
    • Inspect the Weighted Reciprocal Rank Fusion (RRF) scores and reranking margins.
    • Check confidence thresholds and follow dynamic Deep Recall query escalations.

Benchmark results

I started with a slice of LoCoMo just to check that retrieval was not obviously broken. After that I ran the production path on four public suites that fail in different ways: LoCoMo (long conversational memory), PersonaMem-v2 (implicit preferences and forgetting), HaluMem-Medium (extraction, updates, and hallucinations), and BEAM-1M (million-token conversations). These are not one leaderboard. Answer models, judges, and score definitions differ across columns, so a number is only comparable inside its own suite.

I was asking three things:

  1. Does the engine actually put useful evidence in a bounded context?
  2. When that evidence is there, does the answerer reconcile, order, update, and abstain correctly?
  3. Which misses are write-path / state-management problems rather than missing retrieval?

All stores use MiniLM-L6-v2 embeddings. LoCoMo has 1,540 category 1–4 questions (ingest: Gemini 3.7 Flash). PersonaMem-v2 has 5,000 questions and BEAM-1M has 700 (ingest: GPT-5.6 Luna). HaluMem-Medium has 3,467 questions (ingest: Phi-4). HaluMem and BEAM are judged by Gemini 3.7 Flash against the benchmark reference.

MethodLoCoMoPersonaMem-v2HaluMemBEAM-1M
HydraDB———82.0
Engram———79.7
TrueMemory———76.6
Hindsight82.038.084.073.9
Wontopos———67.5
MemOS88.840.680.9—
EverOS82.835.988.7—
Letta77.135.185.4—
Cognee83.5———
Mem077.736.873.664.1
Supermemory73.539.652.6—
Zep63.832.381.7—
Trisynapse Memory88.129.669.162.2
SuiteScoreIngest (s/doc)Query (s/q)Context tokens
LoCoMo cats 1–488.11.311.34672
PersonaMem-v229.66.2419.32072
HaluMem-Medium69.15.8217.31532
BEAM-1M62.22.4583.24768

The headline scores hide most of the story. The category radars below use each suite's native subcategories on a 0–100 scale. Red is Trisynapse Memory.

Category profiles on LoCoMo, PersonaMem-v2, HaluMem, and BEAM-1MFour radar charts comparing Trisynapse Memory with public systems

LoCoMo

LoCoMo scores 88.1 overall (token F1 10.5). Temporal questions are the strongest category at 93.5. Multi-hop is 89.0, basically tied with MemOS (88.7). Open-domain is the hole: 65.6, with 3.3 F1. That is expected. The memory log only contains ingested dialogue, so questions that need external world knowledge cannot be grounded.

PersonaMem-v2

PersonaMem-v2 scores 29.6 overall, which looks worse than the public rows until you split the categories. Requests to forget score 75.6 because the referenced item is still sitting in the store. Sensitive-information queries score 0.0. Updated-preference rows are 75.6; non-updated rows are 17.4. Token F1 is 9.7. The engine can retrieve a preference that was said out loud. It does not yet have a real forget policy, and it is weak at inferring implicit persona.

HaluMem

HaluMem scores 69.1, with Gemini QA hallucination 23.9 and omission 7.0. Dynamic update is the weakest category at 41.1. Memory-boundary accuracy is 83.7. On the Chen et al. Table 3 Medium protocol, extraction R/WR/F1 is 51.2 / 67.2 / 64.0, FMR is 28.0 (distractors still enter the store), update C/H/O is 50.8 / 13.7 / 35.5, and overlap QA correctness is 34.9. MemOS leads extraction recall (74.1) and GPT-4o QA correctness (67.2). Trisynapse Memory is closer to Mem0 on extraction and sits between Mem0 and MemOS on update correctness. The update gap needs an explicit supersession policy, not more candidate breadth. I did not run the HaluMem Long split.

BEAM-1M

BEAM-1M scores 62.2. Published pass-rates on the same split run from Mem0 (64.1) through Engram (79.7) to HydraDB (82.0). Million-token context does not fix state. Temporal (87.1), knowledge update (95.7), and contradiction resolution (95.7) are strong. Instruction following (17.1), abstention (0.0), and preference (37.7) are not. The radar makes that split obvious.

What this actually says

Three patterns keep showing up:

  • Useful evidence is not enough. Conflict-heavy and ordering-heavy questions still fail even when the right records are nearby.
  • Write-path and lifecycle dominate. Updates, forgetting, and sensitive information are policy problems, not ranking problems.
  • Protocol differences can beat architecture differences. The headline table is a protocol map, not a ranking of memory engines.

I am not claiming state-of-the-art. There are no shared-harness reruns with the same answerer and judge, no route ablations, and no confidence intervals yet. Read the numbers as a diagnosis of this production path.

Future work

Shared-harness evaluation

The numbers above diagnose the current engine. They do not prove that the trisynaptic split, the graph, or grounding caused the score. Next I want a shared answer model and judge against the public baselines, plus ablations (BM25-only, dense-only, graph off, claims off, grounding off) and citation precision.

Improve the Memory Studio

Existing Memory Studio is just designed as placeholder with little to no usability. UI can be improved a lot making it easy to see the mrmory, queries and sources.

Self-improving Memory Engine

The routes, weights, and gates are already separate knobs, so the engine could eventually retune itself from how people actually query it. If multi-hop questions keep missing, lean on the graph. If someone keeps correcting a fact, treat that as a signal. It could even add new branches in different stages making it even more self-improving engine. Reinforcement learning is the obvious way to get there, but that is a long way off.

References

  1. SuperMemory — Memory and context engine for the AI era.
  2. Mem0 — The Memory Layer for AI Agents.
  3. Agent Memory Benchmark (AMB)
  4. AgentMemory — Persistent memory for AI coding agents.
  5. Hu, Y. et al. “Memory in the Age of AI Agents.” arXiv:2512.13564 (2025).
  6. Bering, A. “ZenBrain: A Neuroscience-Inspired 7-Layer Memory Architecture for Autonomous AI Systems.” arXiv:2604.23878 (2026).
  7. Agent Memory Paper List — Companion paper list for “Memory in the Age of AI Agents.”
  8. What is Multi-Hop Reasoning? — Moveworks
  9. Linear Algebra for Machine Learning: Orthogonality and the Gram-Schmidt Process
  10. Maharana, A. et al. “Evaluating Very Long-Term Conversational Memory of LLM Agents.” ACL (2024).
  11. Jiang, B. et al. “PersonaMem-v2: Towards Personalized Intelligence via Learning Implicit User Personas and Agentic Memory.” arXiv:2512.06688 (2025).
  12. Chen, D. et al. “HaluMem: Evaluating Hallucinations in Memory Systems of Agents.” arXiv:2511.03506 (2025).
  13. Tavakoli, M. et al. “Beyond a Million Tokens: Benchmarking and Enhancing Long-Term Memory in LLMs.” arXiv:2510.27246 (2025).
  14. BEAM-1M Leaderboard — HydraDB

Tools

  • Algorithm Development: Codex/Cursor
  • Editor: Cursor
  • Flowchart and Diagrams: Excalidraw

Citation

Cited as:

Shanmukha Sainath. "Trisynapse Memory : Evidence First Memory Layer for AI Agents". TensorWrites (Sep 2026). https://www.tensorwrites.com/posts/trisynapse-memory

BibTeX:
@article{trisynapsememory2026,
  title   = "Trisynapse Memory : Evidence First Memory Layer for AI Agents",
  author  = "Shanmukha Sainath",
  journal = "TensorWrites",
  year    = "2026",
  month   = "Sep",
  url     = "https://www.tensorwrites.com/posts/trisynapse-memory"
}