LLM Wiki nad Obsidianem v QubesOS

Jak jsem rozšířil svůj osobní knowledge management Obsidian vault na perzistentní znalostní bázi pomáhající LLM AI — s qmd, Claude Code a specifiky QubesOS.

> Upozornění: Následující text není všepopisný návod po jednotlivých krocích. Spíš je záznamem na co můžete narazit při implementaci a jak to lze řešit.

💡 Co je LLM Wiki

Andrej Karpathy publikoval v dubnu 2026 jednoduchý nápad: místo toho aby pokaždé znovu vysvětloval AI co ví, nechá ji jednou přeložit zdrojové materiály do strukturované wiki a pak AI z těhle dat odpovídá.

Rozdíl oproti běžnému RAG je zásadní:

Přístup Znalost Stav
RAG Odvozuje pokaždé znovu Bezstavový
LLM Wiki Jednou zkompiluje, tu část, kterou zrovna potřebuje a tu pak čte Stavový, kumulativní

RAG je jako vzít knihovnu a pokaždé ji celou přečíst. LLM Wiki je jako mít knihovníka, který si udělal vlastní poznámky a index — a odpovídá z nich.

Základní myšlenka:

code
zdrojové materiály (raw/) → LLM kompiluje → wiki/ → LLM odpovídá
  • raw/ je source of truth, který píšeš ty.
  • wiki/ je synthesis layer, který píše výhradně LLM. Nikdy to nezaměňuješ.

👻 (Víceméně) zbytečné obavy

  • “AI mi udělá zmatek v léta opečovávaných poznámkách v mém knowledge management řešení Obsidian.” → Neudělá. Součástí Karpathyho konceptu LLM Wiki je vstupní adredář raw/ jako zdroj, ve kterém nic nemění a výstupní (pro LLM AI pomocný) adresář wiki/.
  • “Jakmile začnu měnit strukturu dat něco se rozbije”. → Vyloučit to nelze, ale proto si při úpravách počínáme obezřetně a kontrolujeme si zda zamýšlené změny jsou v souladu s tím jak to funguje. Na co je třeba si dát pozor, např. v nastavení Obsidian, je zmíněné dále v textu.

🤔 Výchozí situace: velký existující Obsidian vault

Standardní Karpathy pattern předpokládá, že začínáš od nuly — vytvoříš raw/ a vedle něj wiki/. Pokud ale máš existující Obsidian vault s léty poznámek, narazíš hned na první otázku: kam co patří?

Můj vault (~/Obsidian.SyncThing/) měl přibližně 500 MB obsahu, 1 078 markdown souborů ve 42 složkách a přílohy (obrázky, PDF) přímo v kořeni. Obsah je primárně zaměřen na bezpečnost a IT (Security, IT, pentest, hacking tvoří ~43 % poznámek), dále finance, soukromí, QubesOS, GrapheneOS a různé další poznámky.

Obsidian Vault je synchronizovaný přes Syncthing — stejný obsah je dostupný ve dvou QubesOS VM:

  • notes (Ubuntu 22.04 LTS, kde běží Obsidian) a
  • ai-anthropic (Debian 13 Trixie, kde běží Claude Code).

Syncthing zajišťuje že obě VM vidí vždy stejný stav vaultu, včetně nově přidaných zdrojů a wiki stránek zapsaných agentem. Z toho vyplývá pojmenování složky vaultu: ~/Obsidian.SyncThing/ — název reflektuje způsob synchronizace.

Proč nemít wiki/ přímo v kořeni vaultu

Technicky by šlo mít wiki/ jako podsložku kořene vaultu, kde je i zbytek obsahu. Ale vznikají tím problémy:

  • Při promptu “projdi všechny soubory” musíš vždy explicitně vyloučit wiki/ aby se LLM nemátl vlastním výstupem
  • Totéž platí pro .obsidian/, .claude/, .stfolder a další skryté složky
  • Vyjímky je snadné opomenout zmínit → agent čte co sám napsal → chyby se kumulují

Čistší řešení: přesunout veškerý obsah do raw/ a mít jasnou strukturu:

code
~/Obsidian.SyncThing/
├── raw/                  ← tvůj obsah (vstupy jako source of truth)
├── wiki/                 ← LLM synthesis výstupy (nikdy needituješ ručně)
├── .obsidian/            ← nastavení Obsidianu
├── .claude/              ← instrukce pro Claude Code
├── .agents/              ← instrukce pro Codex a jiné agenty
├── .stfolder             ← Syncthing marker
└── CLAUDE.md             ← instrukce pro agenta platné pro celý vault

Přesun obsahu do raw/

Obsidian má ve výchozím nastavení “New link format: Shortest path possible” — wikilinky jako [název souboru](nazev-souboru.html) se resolvují vyhledáním jména po celém vaultu bez ohledu na cestu. Přesun souborů do podsložky tedy wikilinky nerozbije.

Před přesunem si ověř nastavení: Settings → Files & Links → New link format.

Přesun z příkazové řádky:

bash
cd ~/Obsidian.SyncThing

# Vytvoř cílovou složku
mkdir raw

# Přesuň vše kromě skrytých složek a raw samotného
find . -maxdepth 1 \
  ! -name '.' \
  ! -name 'raw' \
  ! -path './.obsidian' \
  ! -path './.claude' \
  ! -path './.agents' \
  ! -path './.stfolder' \
  ! -path './.trash' \
  -exec mv {} raw/ \;

Pozor: find bez správného vylučování skrytých složek je přesune taky. Vzor výše vylučuje explicitně každou skrytou složku která patří na vault root. Pokud máš jiné skryté složky v kořeni, které nechceš přesouvat, zmiň je ve vyjímkách stejným způsobem. Děláš to jen jednou. Pak už to bude správně.

Po přesunu zkontroluj v Obsidianu: Settings → Files & Links → Default location for new attachments — pokud ukazoval na konkrétní složku, aktualizuj na raw/attachments.

Sjednocení příloh

Přílohy (obrázky, PDF) ze starších importů mohou být roztroušené přímo v raw/ místo v raw/attachments/. Přesun je bezpečný díky Shortest path:

bash
mkdir -p ~/Obsidian.SyncThing/raw/attachments

find ~/Obsidian.SyncThing/raw/ -maxdepth 1 -type f ! -name "*.md" \
  -exec mv {} ~/Obsidian.SyncThing/raw/attachments/ \;

Pak nastav výchozí umístění příloh: Settings → Files & Links → Default location for new attachments → “In the folder specified below”raw/attachments.

Kontrola broken linků

bash
cd ~/Obsidian.SyncThing

# Reference v .md souborech
grep -roh '!\[\[^\](.html)*\]\]' raw/ \
  | sed 's/.*!\[\[//;s/\]\].*//' \
  | sort -u > /tmp/referenced.txt

# Skutečné soubory příloh
find raw/ -type f ! -name "*.md" \
  | xargs -I{} basename {} \
  | sort -u > /tmp/existing.txt

# Rozdíl = rozbité linky
comm -23 /tmp/referenced.txt /tmp/existing.txt

Prázdný výstup = vše v pořádku.


💪 Obsidian Skills

Ve vaultu jsou nainstalované obsidian-skills od Steph Anga. Každý skill je markdown soubor v

  • .claude/skills/<skill-name>/SKILL.md (pro Claude Code) a
  • .agents/skills/<skill-name>/SKILL.md (pro Codex CLI).

Obsah je identický, liší se jen discovery path.

Instalace:

bash
git clone https://github.com/kepano/obsidian-skills.git /tmp/obsidian-skills

mkdir -p ~/Obsidian.SyncThing/.claude/skills
cp -r /tmp/obsidian-skills/skills/* ~/Obsidian.SyncThing/.claude/skills/

mkdir -p ~/Obsidian.SyncThing/.agents/skills
cp -r /tmp/obsidian-skills/skills/* ~/Obsidian.SyncThing/.agents/skills/

rm -rf /tmp/obsidian-skills

Nainstalované skills:

Skill Účel
obsidian-markdown Správný Obsidian-flavored markdown: wikilinky, frontmatter, callouts
obsidian-cli Otevírání souborů v Obsidianu z agenta
obsidian-bases Databázové pohledy (Obsidian Bases)
json-canvas Vizuální mapy znalostí v Canvas formátu
defuddle Čištění web obsahu při ingestu (odstraní navigaci, boilerplate)

Skills cestují s vaultem — při kopírování do jiného VM přes qvm-copy jsou automaticky dostupné bez jakékoliv globální instalace.


CLAUDE.md: instrukce pro agenta

CLAUDE.md v kořeni vaultu čte Claude Code automaticky při každém spuštění session. Definuje strukturu, pravidla a workflow.

Klíčové části:

markdown
## Struktura vaultu

~/Obsidian.SyncThing/          ← vault root
├── raw/                       ← zdrojový obsah, POUZE čteš
├── wiki/                      ← synthesis layer, POUZE ty píšeš
│   ├── synthesis/             ← shrnutí témat
│   ├── query/                 ← odpovědi na konkrétní dotazy
│   └── index.md               ← přehled co je ve wiki
├── .claude/skills/            ← skills pro Claude Code
└── .obsidian/                 ← NIKDY nesahej

## Pravidla

- raw/ nikdy neupravuj, nepřejmenovávej, nesmazávej
- wiki/ píšeš výhradně ty, uživatel ji ručně neupravuje
- Při procházení raw/ vždy vyluč wiki/ aby ses nespletl s vlastním výstupem

Důležitá je sekce kontextu domény, aby agent nepotřeboval vault pokaždé znovu analyzovat:

markdown
## Kontext vaultu

Primární témata (pro prioritizaci synthesis):
- Bezpečnost, IT, pentest, hacking (~43 % obsahu)
- Finance, soukromí
- QubesOS, GrapheneOS
- Osobní poznámky, recepty a ostatní

Při technických tématech preferuj přesnost před zjednodušením.

Struktura wiki/

code
wiki/
├── synthesis/     ← zkompilovaná témata z raw/
├── query/         ← odpovědi na konkrétní dotazy (archiv)
├── index.md       ← přehled obsahu wiki
└── log.md         ← audit trail co agent dělal a kdy

wiki/synthesis/ obsahuje trvalé stránky kompilované z raw/ obsahu. wiki/query/ je archiv odpovědí na jednorázové dotazy — agent ho přidává ale nemaže.


qmd: lokální search engine

Při 1 078 souborech nestačí procházet soubory jeden po druhém. qmd je lokální search engine pro markdown soubory s hybridním BM25/vektorovým vyhledáváním, které běží plně on-device. Má MCP server, takže ho Claude Code může volat jako nativní nástroj.

Instalace na Fedora / Debian v QubesOS

Ve výchozí instalaci nemusí být dostupný ani bun ani go. qmd je npm balíček, ale jeho wrapper script vyžaduje bun jako runtime:

bash
# 1. Instalace qmd přes npm
npm install -g @tobilu/qmd

# 2. Instalace bun (potřebný runtime)
curl -fsSL https://bun.sh/install | bash

Instalátor bunu automaticky přidá do ~/.bashrc:

bash
export BUN_INSTALL="$HOME/.bun"
export PATH="$BUN_INSTALL/bin:$PATH"

Pro fish shell je potřeba přidat ručně do ~/.config/fish/config.fish:

fish
fish_add_path "$HOME/.bun/bin"

Ověření:

bash
export PATH="$HOME/.bun/bin:$PATH"
qmd --version
# qmd 0.9.0

Vytvoření kolekcí

Gotcha: Syntaxe qmd collection add je odlišná od dokumentace. Správně: první argument je cesta, název je --name.

bash
qmd collection add /home/user/Obsidian.SyncThing/raw \
  --name my-vault --mask "**/*.md"

qmd collection add /home/user/Obsidian.SyncThing/wiki \
  --name wiki --mask "**/*.md"

Gotcha: Nepřidávej kolekce spojené přes && pokud první selže — zůstane prázdný záznam v databázi. Přidávej každou zvlášť.

Přidání kontextu (pomáhá při query s re-rankingem):

bash
qmd context add qmd://my-vault/ "Obsidian vault raw obsah - bezpecnost/IT/pentest"
qmd context add qmd://wiki/ "LLM wiki synthesis stranky"

Indexace

bash
# BM25 full-text index (~30 sekund pro 1000 souborů)
qmd update

# Vektorové embeddingy — stáhne ~300 MB modely z HuggingFace
# Spusť na pozadí, zabere 10-20 minut
nohup qmd embed > /tmp/qmd-embed.log 2>&1 &
tail -f /tmp/qmd-embed.log

Po qmd update funguje qmd search (BM25 full-text). Po qmd embed fungují i qmd vsearch (sémantické vyhledávání) a qmd query (BM25 + vektory + LLM re-ranking).

Použití

bash
qmd search "pentest"                          # BM25 keywords
qmd vsearch "privilege escalation techniky"   # sémantické vyhledávání
qmd query "jak detekovat lateral movement"    # hybrid + reranking

MCP server pro Claude Code

Gotcha: mcpServers nepatří do ~/.claude/settings.json — validace schématu to odmítne. Správné místo je ~/.claude/mcp.json.

json
{
  "mcpServers": {
    "qmd": {
      "command": "/home/user/.local/bin/qmd",
      "args": ["mcp"],
      "env": {
        "PATH": "/home/user/.bun/bin:/usr/local/bin:/usr/bin:/bin"
      }
    }
  }
}

Gotcha: PATH v env musí explicitně obsahovat ~/.bun/bin — MCP server se spouští s čistým prostředím a bun jinak nenajde.

Ověření bez restartu Claude Code (přímý JSON-RPC):

bash
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"qmd_search","arguments":{"query":"pentest"}}}' \
  | PATH="/home/user/.bun/bin:$PATH" /home/user/.local/bin/qmd mcp

Po restartu Claude Code session jsou dostupné nástroje: qmd_search, qmd_vsearch, qmd_query, qmd_get, qmd_multi_get.


🚀 Workflow

💼 Ingest

Přidáš soubor do raw/ (ručně, přes Obsidian Web Clipper nebo jinak) a řekneš agentovi:

code
Ingestuj raw/[soubor nebo složka]

Agent přečte zdroj, vytvoří nebo aktualizuje wiki/synthesis/[téma].md, aktualizuje wiki/index.md a zapíše do wiki/log.md.

🔍 Query

code
Odpověz na: [otázka]

Agent prohledá wiki/synthesis/ přes qmd. Pokud téma nenajde, prohledá raw/ a vytvoří wiki/query/[slug].md se syntézou a wikilinky na zdrojové soubory.

🧹 Lint

code
Lint wiki

Agent zkontroluje synthesis stránky bez zdrojových odkazů, zastaralé stránky a chybějící témata. Výsledek zapíše do wiki/query/lint-[datum].md.


📦 Specifika QubesOS

Aktualizace Obsidian na QubesOS

Systémový .deb balíček se neaktualizuje přes standardní apt, protože na QubesOS je rootfs v AppVM neperzistentní přes restarty (záleží na typu VM).

App verze 1.12.7 se aktualizovala sama, protože: - Zápis do ~/.config/ v home adresáři je povolen (home je persistentní i na QubesOS AppVM) - Obsidian auto-updater fungoval v user-space, bez potřeby root

Praktický dopad

  • Dokud Electron shell v /opt/ funguje a je kompatibilní, nemusíš .deb aktualizovat
  • Pokud by Obsidian vyžadoval novější Electron (např. kvůli novým API), pak by installer version zaostala a mohly by být problémy — ale to se u 1.7.5 → 1.12.7 zatím nestalo

Dvě verze = dvě různé věci

Co Verze Kde
Installer version 1.7.5 /opt/Obsidian/obsidian — systémový .deb balíček
App version 1.12.7 ~/.config/obsidian/ — auto-aktualizovaný app bundle

Jak to funguje

code
/opt/Obsidian/obsidian
       │
       │  (Electron shell / launcher)
       ▼
~/.config/obsidian/obsidian-1.12.7.asar   ← skutečná aplikace
  1. .deb balíček nainstaloval Electron runtime (shell) do /opt/Obsidian/
  2. Při prvním spuštění si Obsidian stáhl aktuální verzi aplikace jako .asar bundle do home adresáře uživatele
  3. Electron launcher vždy načte nejnovější .asar z ~/.config/obsidian/

Lze ověřit:

bash
ls -la ~/.config/obsidian/
# nebo
find ~/.config/obsidian -name "*.asar" 2>/dev/null

Proč to tak dělají

Electron shell se mění zřídka (nová verze Chromia/Node.js), zatímco samotná aplikace se aktualizuje často. Tím pádem nepotřebují root práva pro každou aktualizaci — .asar se aktualizuje pouze v home adresáři.

Vault synchronizace

  • Obsidian vault primárně žije v notes VM (Ubuntu 22.04 LTS) kde běží Obsidian.
  • Claude Code běží v oddělené ai-anthropic VM (Debian 13 Trixie).

Synchronizaci mezi VM zajišťuje Syncthing — obě VM sledují stejnou složku vaultu.

Když přidáš zdroj do raw/ v notes VM nebo AI zapíše synthesis stránku do wiki/ v ai-anthropic VM, Syncthing změny automaticky propaguje na opačnou stranu. Není potřeba nic kopírovat ručně.

Syncthing běží v obou VM jako systemd user unit:

bash
systemctl --user status syncthing.service
systemctl --user enable syncthing.service  # spuštění při startu VM

Skills v .claude/skills/ a .agents/skills/ jsou součástí vaultu a tedy taky synchronizované — nejsou potřeba žádné globální instalace v agent VM.

qmd a bun jsou nainstalované v ai-anthropic VM. Databáze qmd kolekcí zůstává lokálně v ai-anthropic VM (není součástí vaultu a nesynchronizuje se).

.stfolder je Syncthing marker — musí zůstat na kořeni sledované složky (~/Obsidian.SyncThing/), ne v raw/. Při přesunu obsahu do raw/ ho vynech.


✔️ Výsledný stav

code
~/Obsidian.SyncThing/
├── raw/                    ← 1 078 .md souborů, 42 složek, ~500 MB
│   └── attachments/        ← obrázky a PDF
├── wiki/
│   ├── synthesis/          ← LLM-kompilovaná témata
│   ├── query/              ← archiv dotazů a odpovědí
│   ├── index.md
│   └── log.md
├── .claude/
│   ├── mcp.json            ← qmd MCP server config
│   └── skills/             ← obsidian-markdown, obsidian-cli, ...
├── .agents/
│   └── skills/             ← totéž pro Codex
├── .obsidian/
├── .stfolder
└── CLAUDE.md

qmd kolekce: my-vault (1 078 souborů) a wiki. BM25 index aktivní, vektorové embeddingy se doindexovávají (~300 MB modely).


😬 Gotchas shrnutí

  1. find bez vylučování přesune i skryté složky jako .stfolder, .claude — vyluč je explicitně
  2. qmd collection add — první argument je cesta, název je --name (ne pozicionální)
  3. Kolekce s && — pokud první selže, zanechá prázdný záznam; přidávej každou zvlášť
  4. bun v PATH — qmd wrapper ho vyžaduje; v MCP env ho nastav explicitně
  5. MCP config patří do .claude/mcp.json, ne do settings.json
  6. qmd embed je separátní krok od qmd update; bez něj funguje jen BM25 search
  7. wiki/ jako podsložka raw/ je funkční alternativa bez přesunu obsahu, ale vyžaduje výjimky v každém promptu — raw/ jako explicitní složka je čistší