DEV Community

dengyier
dengyier

Posted on

I Built a Self-Evolving Knowledge Base — Here's the Architecture

I've spent years accumulating notes across a dozen Obsidian vaults — projects, clients, research, half-finished ideas. Like most people, my "second brain" slowly became a second graveyard: searchable, yes, but it never did anything on its own. It certainly never got smarter.

A few weeks ago I decided to fix that. I wanted a knowledge base that:

  1. remembers across sessions (not just a fresh AI agent re-reading everything each time),
  2. pulls in the outside world (news, papers, releases — with real sources, not hallucinated summaries),
  3. distills that into a stable, personalized knowledge core,
  4. runs a daily production loop that's recoverable if it crashes halfway,
  5. and — the hard part — actually evolves when I give it feedback.

This post is the architecture that came out of it. It's built on plain Markdown (Obsidian) plus a handful of open-source tools, and the honest conclusion at the end is probably the most useful part.

The core idea: Markdown is the truth source, everything else is derived

The first rule, and the one that saved me repeatedly: the Markdown files are the only source of truth. The database, the index, the embeddings, the summaries — all of it can be deleted and rebuilt. If every service dies tomorrow, the vault still opens and reads fine.

That single decision made every later step safe. You can rebuild the brain from scratch, you can move directories, you can break a tool — the knowledge survives.

The five layers

I reorganized everything into five top-level layers, each with one job:

Layer Job Rule
00_资源库 (Resources) Raw evidence Read-only. Never edited.
01_主题Wiki (Topic Wiki) Stable knowledge, methods, cases Distilled, cited, confidence-tagged
02_项目库 (Projects) Active projects & decisions Status always explicit
03_输出库 (Outputs) Real, usable deliverables A draft is not an output
04_系统维护 (System) Rules, profiles, state, feedback, logs The nervous system

The root directory keeps only three things: AGENTS.md, the home page, and an inbox. Everything else has a home.

Layer 1: Long-term memory (cross-session retrieval)

The goal: a brand-new AI session should be able to answer a question by querying memory first, then verifying against the original file — not by re-reading 700 files.

I used GBrain — Garry Tan's open-source agent brain. It runs on PGLite (Postgres-in-WASM), so there's no server and no Docker. The whole thing is a single local file.

# install (Bun is required)
bun install -g github:garrytan/gbrain
gbrain init                 # PGLite, zero config
gbrain import ~/vault/ --no-embed
gbrain search "who pays for this and how fast"
Enter fullscreen mode Exit fullscreen mode

The import was honest about what it did and didn't index: it skipped dot-directories (nested .git, .venv) and README/index files, and I verified the exact count reconciliation rather than trusting it. Idempotency was tested by re-running the import — 0 new pages, 0 errors.

Key insight: I run it keyless. Keyword search + agent-written memory costs $0 and sends nothing to a third party. Semantic search (embeddings) is a paid upgrade you can add later, but the core loop works without it.

Layer 2: The outside world (a personal knowledge radar)

A knowledge base that never gets new input rots. I added Horizon — an AI-powered news radar that fetches RSS/Hacker News/GitHub, deduplicates, scores with an LLM, and generates bilingual daily briefings.

# Python + uv
git clone https://github.com/Thysrael/Horizon.git
uv sync
uv run horizon --hours 24
Enter fullscreen mode Exit fullscreen mode

I started with six sources (official RSS + one high-signal personal blog), and configured it to output to the Resources layer with per-item metadata: unique ID, title, author, publish time, source URL, source type, fetch time — with the AI summary stored separately from the original, never mixed.

Two honesty tests mattered more than the happy path:

  • A failing source must report "fetch failed", not "nothing new". One of my feeds returned HTTP 403 — the system logged it as a failure, I swapped it out. Silence would have been a lie.
  • An AI-provider failure must not lose the raw material. With no API key set, it fetched everything first and then failed loudly at the scoring step. Raw data was preserved either way.

The distillation: from notes to knowledge cards

This is where most systems stop — they store, but they don't think. I built templates for eight card types (resource / knowledge / project / decision / output / feedback / evolution-proposal / case-closure), each with mandatory fields:

title, type, status, created, updated, source, confidence, sensitivity
Enter fullscreen mode Exit fullscreen mode

And every card's body separates facts from judgments from opportunities from risks — with a source link back to the original note, a confidence level, and an explicit invalidation condition ("what would make this wrong?").

Then I distilled a core sample of my vault into real cards. The discipline that made it work: nothing without a source gets promoted to fact — it gets demoted to "hypothesis". Contradictions are stored side by side, not merged. The original files are never moved or overwritten.

The personalized layer: a career pack built from your evidence, not stereotypes

Instead of assuming what "a consultant" or "a creator" should do, the system generates a career pack from your own history: your stated role, your real deliverables, your rejected work, your explicit preferences.

Each rule in the pack carries its evidence and an invalidation condition. For example, one of my confirmed rules:

"First ask: who pays, what do they buy, how fast do they pay, what does delivery cost — before discussing market size or vision."

That's not a generic platitude — it's extracted from my own project records where I repeatedly watched "local artifacts complete" vs "customer accepted and paid" be two entirely different gates.

The important safeguard: without real historical material, the pack stays a candidate, never active. No invented persona.

The production loop + a recoverable state machine

The daily loop is: precheck → ingest → distill → link → route → produce → feedback → close. Every round must end in exactly one of three closures: a real output, stable knowledge, or an explicit drop.

I then wrapped it in a state machine that makes it crash-safe:

  • single-instance lock (two agents can't run the same round),
  • a run_id, target date, and input-list hash written at start,
  • every phase idempotent,
  • resume from a recovery point after interruption (no duplicate artifacts),
  • "missed a day" is recorded as pending catch-up, not system failure,
  • skip if already closed within 24h.

Then I ran fault injection: a source failing, the brain failing, a mid-run kill, two simultaneous instances, an interruption between state-write and output-write, and a missed schedule. All six recovered correctly. That's the difference between "automation that runs when nothing goes wrong" and "automation you can actually trust."

Quality gates that fail loudly

Finally, a set of gates that run against the vault and fail loudly on violations:

  • resource layer never overwritten,
  • secret scan (no API keys in the repo),
  • every card has a source + valid dates,
  • facts separated from judgments,
  • no duplicate outputs,
  • exactly one closure per round,
  • brain index consistency,
  • a draft must never be marked "published".

I tested these against both clean samples (8/8 pass) and deliberately broken samples (missing source, missing sections, a draft masquerading as delivered) — the gates caught all of them.

The honest part

Here's the thing nobody tells you: you cannot automate self-evolution into existence.

The system's evolution loop — feedback → proposal → approval → rule upgrade → measurable behavior change — only activates on real feedback. A single opinion doesn't change global rules; a repeated signal or real outcome data does. I built the entire mechanism, but it sits idle until I actually use the outputs and say "this worked / this didn't."

The tutorial I followed was explicit about this, and it's the most valuable lesson of the whole build:

Without 30 days of real running, without real feedback on outputs, without an activated personal pack, you should describe the system as "same-tier architecture and loop, but your own instance" — not a finished product.

That's exactly where mine is: the architecture, the loop, and the gates are all built and tested. The evolving part starts the day I start giving it honest feedback.

Takeaways

  1. Make Markdown the truth source — everything else becomes safely disposable.
  2. Separate memory, ingestion, distillation, and production into layers with one job each.
  3. Test the failure paths, not just the happy path — a tool that fakes "nothing new" is worse than one that crashes loudly.
  4. Distill with sources and confidence, never with vibes — and demote unsourced claims to hypotheses.
  5. Self-evolution is a feedback problem, not an engineering problem. You can build the loop, but only you can feed it.

The stack is all open source: Obsidian, GBrain, Horizon, PGLite, and a couple of small Python scripts for the state machine and quality gates. None of the interesting parts are proprietary — the interesting part is the discipline.

What's your knowledge base doing for you that you're not doing for it?

Top comments (0)