Warning Wikification is expensive. It sucks tokens dry. If you're not wealthy, just review conversations. Don't attempt wikification.
This post is a vibe-coding development story for seCall — a CLI tool that collects and searches AI agent conversation sessions. I don't know and don't want to know the detailed code. There's nothing good about knowing it. If you're curious about the code, ask the person who made it(?). (They're faster and make better things than me) I'll only cover the reasoning behind technology choices and the flow.
Series:
Search works, so what?
Through episode 3, search works quite well. It works with Korean, English, and even if you type "비엠25," you get "BM25" conversations.
But if search results just stream out as text in the terminal... honestly, you don't read it. Some conversations have hundreds of turns, and who's going to scroll up and read in the terminal? (Ouch).
Ultimately, conversations need to be extracted into a readable file format. Not just plain text files either, but in a form where conversations are linked to each other and can be filtered by metadata.
I briefly considered connecting to wiki.js, but then I remembered Obsidian, which I'd installed but only written 3 pages in before the new year hit and never touched again. (That method—is it Elastin or Kook Kasten?—doesn't suit lazy people like me. You can only have a second brain if you have a first brain)
Why Obsidian
The reasons for choosing Obsidian are simple:
Markdown-based — Just dump .md files without separate format conversion
Wiki(back)links [[]] — Can connect conversations, projects to each other
Dataview plugin — Query frontmatter metadata like SQL
Local files — No cloud dependency, version control with git
Collapsible callouts — Can neatly hide tool output or thinking processes
Actually, the biggest reason is that I was already using (had only installed but was using) Obsidian. I didn't need to learn new tools (seriously)
Structure: Two layers of Raw and Wiki
At first, I thought I'd just convert conversations to markdown, throw them in a folder, and be done.
But conversation source material is long, repetitive, and structurally inconsistent. A single Claude Code session can exceed 200 turns, and you can't use it as a wiki like that.
So I split it into two layers:
vault/
├── raw/sessions/ ← Conversation source (auto-generated, do not edit)
│ └── 2026-04-05/
│ ├── claude-code_seCall_a1b2c3d.md
│ └── claude-code_myProject_b2c3d4e.md
├── wiki/ ← Organized knowledge (curated by AI)
│ ├── projects/
│ ├── topics/
│ └── decisions/
├── index.md ← Full session list
├── log.md ← Collection log
└── SCHEMA.md ← Rules document
raw/sessions/ is immutable. When you run secall ingest, conversations are converted to markdown and placed here, and are never modified afterward. The goal is to preserve originals.
wiki/ is the result of AI reading and organizing multiple conversations. It organizes things like "what decisions were made about search in the seCall project" by project and by topic.
This distinction is quite important. Raw is record, wiki is knowledge.
Frontmatter: A conversation's resume
Each session markdown comes with frontmatter:
---
type: session
agent: claude-code
model: claude-opus-4-6
project: seCall
session_id: a1b2c3d4-e5f6-7890-abcd-ef1234567890
date: 2026-04-05
start_time: "2026-04-05T14:30:00+09:00"
end_time: "2026-04-05T15:45:00+09:00"
turns: 15
tokens_in: 45000
tokens_out: 12000
tools_used: [Bash, Read, Write]
summary: "Applied RRF algorithm to seCall search feature..."
status: raw
---
With this, Obsidian Dataview can do this:
TABLE agent, turns, date
FROM "raw/sessions"
WHERE project = "seCall" AND turns > 10
SORT date DESC
"Show me only sessions in the seCall project with more than 10 turns, newest first" — not SQL. It reads the frontmatter of markdown files and shows them as a table. This is Obsidian's killer feature.
Obsidian-specific markdown
Plain markdown works in any editor, but using Obsidian-specific syntax makes it much more readable.
Collapsing tool output with callouts
Claude Code sessions have tons of tool calls. Tools like Bash, Read, Write are used dozens of times in a single session, and if you expand all of them, you can't see the conversation flow.
Using Obsidian callouts, you can collapse them:
> [!tool]- Bash
> ```
> git status
> ```
> Output: M src/main.rs, M Cargo.toml...
A single - makes it collapsed by default. You only expand when you want to see it, so conversation flow isn't interrupted.
Thinking blocks work the same way:
> [!thinking]- Thinking
> To combine search results, I need score normalization...
Preventing Dataview conflicts
This was a bit annoying—the Obsidian Dataview plugin recognizes key:: value format as inline fields. But :: appears fairly often in conversations. In Python type hints, URLs, various code snippets.
The solution is surprisingly simple — inserting a zero-width space between :: makes Dataview not recognize it. It's invisible, hardly affects copying, and you can fool Dataview. Within code blocks, we don't escape and leave it as-is. (I'd like to thank github:batmania52 who opened many issue tickets with feedback spanning tens of thousands of lines)
Solving problems with invisible characters is a bit hacky, but it works. 😇
When hundreds of conversations pile up, digging through folders becomes work. That's why there are two auto-generated meta files.
index.md — Full session list. New sessions are added to the top each time one is ingested. Jump directly via wikilinks.
## Sessions
- [[raw/sessions/2026-04-05/claude-code_seCall_a1b2c3d4|Applied RRF algorithm]] — 15 turns, claude-code, 14:30
- [[raw/sessions/2026-04-04/claude-code_seCall_b2c3d4e5|Vector search debugging]] — 8 turns, claude-code, 09:15
log.md — Collection history. Records when, which session, how many turns, how many tokens. Append-only, so it just accumulates.
This too comes alive with wikilinks when opened in Obsidian, so you can jump directly from the log to that session.
Git Sync — Version control as a bonus
Since an Obsidian Vault is ultimately a collection of markdown files, managing it with git means free backup + version history. (And Obsidian even has a git plugin built in!) seCall has a secall sync command that does:
git pull --rebase (fetch remote changes)
Ingest new sessions
git push (push to remote)
One line completes "collect new conversations + update vault + backup to remote." DB files or index files are automatically excluded in .gitignore.
Honestly, this feature overlaps with the Obsidian Git plugin. But being able to do ingest and sync simultaneously with one CLI command is convenient. And it also brings conversations scattered across multiple places together.
So how am I actually using it?
Running secall ingest once triggers:
Auto-detect new conversations from ~/.claude/, ~/.codex/, etc.
Morphological analysis → FTS5 indexing + embedding → vector indexing (covered in #1, #2)
Markdown conversion → create .md files in vault (this episode)
Update index.md, log.md
After that, I review conversations in two ways:
Search is good when you "know what to look for," vault browsing is good when you "don't know what to look for but want to explore." Surprisingly, the latter yields more discoveries. (Wait!? I had that thought!? type discoveries)
Summary
Technology | Role | Selection reason |
|---|
Obsidian Vault | Conversation wikification | Markdown-based, Dataview, already using it |
Frontmatter | Session metadata | Filterable/sortable with Dataview queries |
Collapsible callouts | Hide tool output/thinking | Secure conversation flow readability |
Raw/Wiki separation | Preserve originals + organize knowledge | Distinguish records from knowledge |
Git Sync | Version control + backup | Comes naturally since vault is markdown |
Concluding the series
Over 4 episodes, I've unpacked the key features of seCall.
In #1, built Korean full-text search
In #2, attached semantic vector search
In #3, combined them into hybrid search
In #4, extracted results into a readable form
In retrospect, the core insight was one — AI conversations aren't disposable; they're accumulated knowledge. When you make them searchable, browsable, and organizable, previous conversations become context for the next task. That's probably why Notion and Obsidian became famous.
Learning a lot from a vibe-coding projectfor its kind. I still don't understand code well (at this point, the code and structures that agents write have far exceeded my comprehension limits😇), but SQLite FTS5, BM25, vector embedding, RRF, HNSW... I can explain these concepts now. I think that's what's good about vibe-coding — learning by making.
This post is written in non-vibe mode. (There's no reason to vibe) You can read it with confidence 😁 Agentic development isn't flying blind. It's a chaotic three-legged race between domain knowledge accumulated through diverse experiences with human intelligence and the tireless precise work of artificial intelligence fitted with a sturdy framework.