Skip to content
Consultation

Stealing OpenViking's L0 Pattern for My Research Knowledge Base

Adityo Guni Waluyo

Queries returned just a path and a score. So I stole OpenViking's L0 summary pattern: one line per dossier, no new infrastructure.

TL;DR

Search results in my knowledge base showed only scores, so I kept opening dossiers just to judge relevance. Rather than install OpenViking, I stole its L0 tier pattern and added a mandatory one-line summary field to each dossier in about 40 lines of Python. Making summaries a hard requirement keeps them consistent, no new dependency needed.

Query my research knowledge base, and this is what shows up on screen: a dossier path plus a score of 0.42. That's it. What does 0.42 mean? What's in the file? One answer: open the dossiers one by one. Sometimes I'd open two or three files just to find the one relevant hit.

This happened enough times that I got sick of it. The knowledge base itself runs fine, 14 research dossiers with local embeddings, a score threshold of 0.30, results always relevant. The problem was the output: I couldn't judge relevance without opening the full file.

My First Wrong Guess

When I first looked at OpenViking, the open-source repo from volcengine that positions itself as a "context database for AI agents" [1] (35,390 stars on GitHub [3]), my assumption was: this is the answer, just install it. I figured there'd be an installation, some configuration, maybe a data migration.

Turns out I hadn't read the details first. OpenViking is a full virtual filesystem for agents, memory-resources-skills in one place, and agents can run ls/tree/find against their own context. That's infrastructure. All I needed was one idea from it.

After reading the official docs, I found what I was looking for: three context tiers. L0 abstract, roughly 100 tokens, for a quick relevance check. L1 overview for planning. L2 full content, read only when actually needed [1]. The docs are more precise: L0 is a .abstract.md file per directory, default cap of 256 characters, meant for "vector retrieval, quick filtering". L1 is .overview.md, 4000 characters, for "rerank, content navigation" [2].

One summary line per archive. That's all I wanted.

What I Ended Up Writing

No OpenViking installation at all. What I "stole" was the pattern, then I implemented it myself in about 40 lines of Python inside the existing tools/research-knowledge.py. New infrastructure? Not needed. The JSON index plus local Ollama bge-m3 embeddings already running from yesterday's article were enough.

Concretely, here's what changed:

Every research dossier now has a ringkasan: field in its frontmatter. One sentence, max 240 chars. This field shows up in query output, so search results now include a one-line summary I can read immediately to decide whether to open the file or not.

The contract is spelled out in _TEMPLATE.md and research/README.md: new dossiers must have a summary from the moment they're created. The cron job that archives pages demands that field too. Backfilling the 14 old dossiers? Once, then done.

The catalog of 14 dossiers is lightweight. extract_l0(text) grabs the first bullet under the "## Temuan" section, strips markdown, cuts at a sentence boundary, max 240 chars. Zero LLM. Just a fallback.

In cmd_build, existing files only get their summary metadata and mtime synced, no re-embedding. New files get embedded from the first 8000 chars of the file. The build stays cheap.

There's one deliberate deviation from OpenViking's design: there, L0/L1 are sidecars per directory, not per file. Summaries of individual files aggregate into the directory's L1 [2]. I went per-dossier because my scale is 14 files, not a full filesystem. A good pattern from a big project doesn't have to be adopted wholesale.

Why This Makes Sense

The core idea is tiered loading: don't read the full file before you're sure it's relevant. My brain works the same way when digging through a folder. Title first, then open what looks promising.

My opinion on this is firm: a summary is a contract, not a toll. What kills the L0 pattern for most people isn't the technique, it's summaries written later, written carelessly, or never updated. If the summary is a requirement for the archive to exist, consistency is enforced by structure, not good intentions. That's why I did the backfill once, then made the field mandatory.

One more thing I like about rolling it myself: extract_l0() with no LLM. If the summary isn't filled in, it takes the core sentence from the first bullet under the Temuan section. Zero cost, accurate enough for a fallback. I did briefly consider an LLM to generate summaries, but why? I wrote the dossier contents myself, and the Temuan section was already designed so the first sentence is dense.

As for OpenViking's benchmark claiming 80-83% memory accuracy vs 24-57% native, with input tokens down as much as 91% [1]: that's a vendor claim, tested on their own model (Doubao). I cite it as a claim, not as proof the L0 pattern works in my KB. What I can confirm from my own experience: queries now come back with a summary per hit, and I've stopped opening dossiers just to read what's inside.

Will I move to full OpenViking someday? Maybe, if the KB grows to hundreds of files and the directory structure gets deeper. For now, 40 lines in an existing file beats one new dependency. And that's a decision I won't second-guess.

Sources

  1. volcengine/OpenViking README (GitHub)
  2. OpenViking docs: Context Layers (L0/L1/L2)
  3. GitHub API: repos volcengine/OpenViking

Related articles