[Development Log] You Need to Extract Searched Conversations as Markdown to Read Them — Obsidian Vault Wikification Edition

27.255.***.***
8

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:

  • #1: SQLite FTS5 + Korean morphological analysis

  • #2: Local vector search

  • #3: Hybrid search + RRF

  • #4: Obsidian Vault wikification ← This post (final)


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. 😇


index.md and log.md

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:

  1. git pull --rebase (fetch remote changes)

  2. Ingest new sessions

  3. 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:

  1. Auto-detect new conversations from ~/.claude/, ~/.codex/, etc.

  2. Morphological analysis → FTS5 indexing + embedding → vector indexing (covered in #1, #2)

  3. Markdown conversion → create .md files in vault (this episode)

  4. Update index.md, log.md

After that, I review conversations in two ways:

  • When search is needed: secall recall "search term" — quickly find from the terminal

  • When I want to review: Open Obsidian and browse the vault — slowly read while filtering with Dataview

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.

로그인한 회원만 댓글 등록이 가능합니다.

개발한당

KR | ID | EN
  • IDR
  • KOR
8.36 0.01

2026.07.10 KEB 하나은행 고시회차 970회

다가오는 한인 행사일정

  • 등록 된 일정이 없어요!