Overview
Main operating skill for LLM-maintained knowledge bases. Five workflows: compile, query, lint, evolve, reflect. All opus-orchestrated with model-aware subagent dispatch.
First action in every invocation: read kb.yaml from the project root. If missing, tell the user to run kb-init and stop.
Report Preferences
After reading kb.yaml, extract the report_preferences: block. These are free-text prose instructions the user set via kb-init or /kb-preferences, controlling how outputs are written (audience, register, depth, code_handling, diagrams, self_containment, citations, argument_iteration, notes).
Apply to all generated prose:
- Compile: preferences shape how new wiki articles are written — register, self-containment, depth of per-article profiles, diagram choices in article bodies.
- Query: preferences shape the final answer prose and any new wiki articles auto-evolved from the query.
- Lint / Evolve / Reflect: preferences shape the output report prose (lint reports, evolve suggestions), not the mechanical checks themselves.
If report_preferences: is missing: fall back to factory defaults in plugins/kb/references/report-style-guide.md silently. Mention it once in the first output of the session: "No report_preferences set — using factory defaults. Run /kb-preferences init to customize."
Per-task overrides. If the user's current request explicitly contradicts a stored preference, follow the request for this task only. Do NOT modify kb.yaml — reflection handles persistence.
Reflection at end of compile and query
After a compile or query finishes writing its output, run a lightweight reflection step — only propose preference updates for high-confidence signals:
- User explicitly asked you to "remember" something
- User corrected the same style choice twice in the conversation
- User gave clear feedback directly tied to the output just produced
Follow the Reflection Protocol in plugins/kb/skills/kb-preferences/SKILL.md. On approval, write updates to kb.yaml and log to .meta/_preference_history.md with trigger reflection after /kb compile (or /kb query). Skip silently otherwise.
Do NOT run reflection for lint / evolve / reflect workflows — their output is too mechanical to surface meaningful style signals most of the time. The user can run /kb-preferences reflect manually if they want a forced pass.
Obsidian-Native Formatting
All wiki output MUST use Obsidian-native conventions:
- YAML frontmatter delimited by
--- [[wikilinks]]for ALL internal links -- NEVER use markdown-style[text](url)links for internal references[[wikilinks|display text]]when the display name differs from the target article- Tags in frontmatter:
tags: [concept, topic] - Aliases in frontmatter:
aliases: [alternate name] - Image embeds:
![[image-name.png]] - Standard markdown for everything else (headings, lists, bold, code blocks, etc.)
Graph Hygiene
Every .md file in an Obsidian vault becomes a node in the graph. Every internal link — [[wikilink]] or markdown-style [text](file.md) — becomes an edge. Link syntax does not control the graph. Inventory files (_index, _sources, _categories, _evolution, _tags) exist as files that link to every article, so they appear as the highest-degree nodes by construction. The fix is to keep them out of the vault index entirely.
-
Meta/index files live in
.meta/at the vault root, not inwiki/. Obsidian ignores any folder whose name starts with.(the same mechanism that hides.obsidian/itself). Files in.meta/do not appear in the graph, search, quick switcher, backlinks, or file explorer. They remain readable and writable by tooling.Canonical paths:
.meta/_index.md— master article index.meta/_sources.md— raw-source → article mapping.meta/_categories.md— auto-maintained category tree.meta/_evolution.md— append-only change log.meta/_tags.md— canonical tag vocabulary
Any new meta/inventory file goes in
.meta/too, never inwiki/. -
Article-to-article links MUST be
[[wikilinks]]. These carry semantic weight and are the intended graph edges. -
MOC pages MUST use
[[wikilinks]]and live inwiki/. MOCs are curated, narrative conceptual hubs and belong in the graph. -
Verify every
[[wikilink]]target exists before emitting it. Confirm either (a) the target article already exists inwiki/**/*.md(including via itsaliasesfrontmatter), or (b) the agent is creating that target in the same compile pass. If neither, do NOT emit a wikilink — use plain text or italics. Never emit a wikilink as a "TODO placeholder." Why: dangling wikilinks render as ghost/placeholder nodes in the graph and open an empty editor when clicked.
On kb-init and compile
Ensure .meta/ exists in the vault root. If the vault contains legacy meta files at wiki/_index.md, wiki/_sources.md, wiki/_categories.md, wiki/_evolution.md, or wiki/_tags.md, move them to .meta/ with the same filename, and make sure no wiki/**/*.md articles reference them (they shouldn't — meta files reference articles, not the other way around).
.meta/ being a dotfolder is load-bearing. Do NOT rename it to meta/ or _meta/ — Obsidian would then index it.
Past mistakes recorded here so future agents don't repeat them:
- Converting meta-file wikilinks to markdown-style links in the belief that this reduces graph degree — it does not; Obsidian resolves both styles as edges.
- Relying on the graph-view
searchfilter in.obsidian/graph.json— it hides files from the graph only, not from search/backlinks/quick-switcher. - Using
userIgnoreFiltersin.obsidian/app.json— this was partially correct (it does hide files from the index), but leaves the files visible in the file explorer and depends on the user not clearing the filter. The.meta/dotfolder is the structural fix: Obsidian cannot index it regardless of user settings.
Tag Hygiene
Tags are for cross-cutting classification, not restating the title. Without a controlled vocabulary, tags drift (reasoning vs reasoning-models vs cot vs chain-of-thought) and lose their value as navigation.
- Use a namespaced, controlled vocabulary. Every tag MUST fall into one of these namespaces:
domain/*— broad subject area (e.g.,domain/reasoning,domain/rl,domain/alignment,domain/interpretability)method-family/*— class of technique (e.g.,method-family/policy-gradient,method-family/preference-optimization)status/*— mirrors thestatusfrontmatter field (status/seedling,status/budding,status/evergreen)moc— the existing bare tag for Map of Content pages (preserved for continuity)
- Tags must not restate the title. If an article is titled "GRPO," do NOT tag it
grpo. Tag itdomain/rl,method-family/policy-gradient. The title and aliases already handle that lookup dimension. - Reuse before inventing. Before adding a new tag to any article, read
.meta/_tags.md(the canonical tag index — see Index Maintenance) and pick an existing tag if it fits. Invent a new tag only when no existing tag captures the dimension, and when you do, add it to.meta/_tags.mdin the same pass. - Lint must flag tag drift — singletons (tags used on only one article), near-duplicates (different surface forms of the same concept), and any tag that violates the namespace convention. See Workflow 3.
Model Strategy
Always set the model parameter explicitly when dispatching subagents.
| Task | Executor | Verifier |
|---|---|---|
| Index scanning, link checking, file diffing | haiku subagents | none |
| Summarizing individual sources | haiku subagents | opus spot-checks |
| Wiki article writing | sonnet subagents | opus reviews before commit |
| Deep research | sonnet subagents | opus orchestrates + verifies |
| Re |