1. Executive Summary
Huiran-cerebro (赛博大脑, "cyber brain") is a personal and team memory hub and knowledge-base engine — MIT, Python 3.10+, version 1.5.0, 4,582 lines across a handful of modules, one SQLite file with no service dependency. Its stated goal is to settle an AI's memory and knowledge into a local, searchable, conversable private knowledge base, and it ships an MCP server with a written integration guide for Doubao, a web console, and Windows batch launchers.
The engine is four layers in one file: a knowledge base of documents
and chunks, memory fragments, a typed entity graph, and an AI
conversation log, retrieved by FTS5 with trigram tokenisation — the
right choice for Chinese, which has no spaces to tokenise on — fused
with bge-small-zh-v1.5 embeddings by reciprocal rank.
The mechanism worth the visit is the deduplication, and it makes two good decisions in one docstring:
"重复碎片合并:内容 Jaccard >= threshold 的碎片,标记后写者 status='merged'(不删原文)。 保留先创建者(信息源),后写者合并到它。"
Merge duplicate fragments: for fragments whose content Jaccard is at or above the threshold, mark the later writer
status='merged'(do not delete the text). Keep the first creator as the information source; the later writer is merged into it.
It marks rather than deletes, so the duplicate stays
inspectable and the merge is reversible — and because every recall path
selects WHERE status='active', the marked row leaves
retrieval without leaving the store. That is the trust-state mark, and
it is the whole of it: a stored discrete status, set by a real
mechanism, read by the paths that matter.
And it keeps the earlier fragment, on the stated ground that the first writer is the information source. Last-write-wins is the default almost everywhere, and it is the wrong default when the later copy is a restatement of the earlier one rather than a correction of it.
A dry_run flag returns the candidate pairs with their
similarity scores and changes nothing, so the threshold can be tuned
against real data before it is applied to it. Small, and more than many
larger systems here offer.
What to weigh against that. There are no tests — no
test directory, no test file, and the two tools/_*_smoke.py
scripts are smoke checks rather than assertions — under a pass that
rewrites rows in place. The dedup is a full pairwise scan of every
active fragment with a Python Jaccard per pair, so its cost grows with
the square of the store. And because the scan reads only active rows, a
merged fragment is never compared against again: re-adding the same text
creates a fresh active row that the next pass must merge all over again.
The mark records a decision; nothing consults it when the next write
arrives, so it is a retirement rather than a refusal.
namespace exists on fragments and entities with a
default value, and is passed as an optional argument that
emits no predicate when omitted — so it separates nothing unless a
caller asks it to.
Two details for a reader coming from elsewhere. The delete helper is
Windows-only, calling SHFileOperationW with
FOF_ALLOWUNDO so a removed directory lands in the recycle
bin rather than vanishing — a thoughtful default that does not exist on
other platforms. And the README carries a section explicitly addressed
to LLM readers, alongside an llms.txt, which is worth
knowing when an agent summarises this project from its own documentation
rather than from its code.
2. Mental Model
A fragment is a small remembered thing, and it is either active or it has been merged into an earlier one.
Merged means retired from recall, not gone.
The first writer wins, because the first writer is the source.
Diagram source
%% caption: the dedup pass marks the later of two near-identical fragments merged and keeps its text, and every recall path's status='active' predicate is what removes it from results
flowchart TB
W["add a fragment — CLI, web console, or MCP"] --> ROW[("memory_fragments:<br/>type · subject · content · entities ·<br/>tags · status='active' · source_ref ·<br/>importance · namespace")]
DED["dedupe_fragments(threshold, dry_run)"] --> SCAN["read every row WHERE status='active'<br/>AND length(content) >= 8, oldest id first"]
SCAN --> PAIR{"pairwise: identical content,<br/>or Jaccard >= threshold?"}
PAIR -->|"no"| KEEP["both stay active"]
PAIR -->|"yes, dry_run"| CAND["return the pair with its score;<br/>change nothing"]
PAIR -->|"yes"| MARK["UPDATE the LATER row:<br/>status='merged'<br/>— '不删原文', the text is not deleted;<br/>the first creator is kept as the source"]
MARK --> ROW
ROW --> R{"recall · list · summary · relations"}
R -->|"every path"| F["WHERE status='active'"]
F --> OUT["results: FTS5 trigram +<br/>bge-small-zh embeddings, fused by RRF"]
MARK -.->|"merged rows are excluded from the<br/>next scan, so re-adding the same text<br/>makes a new active row the next pass<br/>must merge again"| SCAN
NS["namespace — default 'default',<br/>an optional argument"] -.->|"omitted ⇒ no predicate emitted"| R3. Architecture
| File | Role |
|---|---|
cyber_brain.py |
The schema, the store, search, recall, dedup, summaries |
web_ui.py |
The browser console |
mcp_server.py |
The MCP surface |
session_log.py, summarize.py,
daily_brief.py |
Session capture, rolling summaries, a daily brief |
doctor.py, tools/check_version.py |
Diagnostics, and a version badge kept in sync |
4. Essential Implementation Paths
cyber_brain.py:832-859 — the dedup, its docstring, and
its dry run.
cyber_brain.py:189-206 — the fragment schema and the
status index.
cyber_brain.py:708, :779,
:807, :1173 — the four places the predicate is
repeated.
5. Memory Data Model
Fragments carry a type, a subject, entities, tags, a status, a source
reference, an embedding state, an importance and a namespace. Content
items carry more: a status of draft or done, a version and a parent id
forming a revision chain, a source type, a source tag and an
authorization_ref defaulting to manual —
provenance fields that are recorded and, as far as this reading found,
not yet consulted by a read.
Rolling summaries carry a scope key and a checkpoint version, which is how the system keeps a compacted account of a long stretch without losing the fragments underneath it.
6. Retrieval Mechanics
FTS5 trigram and embeddings fused by reciprocal rank, with the active-status predicate repeated at each site rather than centralised — four copies of one rule, which is the shape that drifts. A retrieval-audit table records what was asked and in what mode.
7. Write Mechanics
Direct inserts; dedup is an explicit pass rather than a write-time check. That ordering is the trade-off: writes stay cheap and unconditional, and duplicates accumulate until someone runs the pass.
8. Agent Integration
An MCP server with a document walking through connecting Doubao, plus
a web console and CLI. add_content takes a status
defaulting to draft, so an agent's write lands as a draft
unless it says otherwise — a small default in the right direction.
9. Reliability, Safety, and Trust
The merge-not-delete rule is the substance. Beyond it: a
doctor command, a version constant with a script that syncs
the README badge to it, and a recycle-bin delete on Windows.
The absence to weigh is testing. A pass that rewrites status in place, over a store whose whole value is that nothing was lost, is the code most in need of a test that a merged fragment is absent from recall and its content still in the table.
10. Tests, Evals, and Benchmarks
None found. Two smoke scripts under tools/ exercise the
frontend and the graph without asserting outcomes. Nothing was installed
or run for this reading.
11. For Your Own Build
Mark, do not delete, and say so in the docstring. A duplicate marked
merged with its text intact can be reviewed, reversed and
counted; a deleted one cannot.
Decide which side of a duplicate survives, and write down why. "Keep the first creator, it is the information source" is a rule a reader can argue with, which is more than a silent last-write-wins offers.
Ship the dry run with the destructive pass, not after it. Returning the candidate pairs and their scores is what makes a threshold tunable.
And put the status predicate in one place. Four copies of
status='active' is four chances for the next read path to
forget it.
12. Open Questions
Whether authorization_ref and source_tag
are consulted anywhere. Both are written with defaults and no reader was
found.
What embedding_state gates. It defaults to
disabled on every fragment, and how the embedding path
treats that was not traced.
Whether a merged fragment can be restored. The row and its text survive; no command to set the status back was found.
Appendix: File Index
| Path | What to read it for |
|---|---|
cyber_brain.py:832-859 |
Mark rather than delete, keep the first writer, and a dry run |
cyber_brain.py:189-206 |
The fragment, and the index the predicate needs |
cyber_brain.py:78-101 |
Provenance fields on a content item, awaiting a reader |
tools/recycle_delete.py |
A delete that lands in the recycle bin, on one platform |
History
2026-09-16 — 08644a7e…
— first reading, at a commit dated 16 September 2026. Screened before
opening, from a shallow clone: two files scanned, no auto-run surfaces,
no build-time execution points, one unpinned surface and one dependency
file inside the seven-day cooldown. Nothing was installed, built or
run.