| name | ak-wiki |
| description | Karpathy's LLM Wiki — persistent, interlinked markdown knowledge base with auto-ingest (raw/ watcher), auto-dreaming (re-promote frozen pages whose relevance returns), three-tier memory aging, custom frontmatter dimensions, external plugin fallback, multi-machine git sync (custom log.md merge driver), and 13 skills from init to sync. |
| version | 1.8.0 |
| author | litianyi |
| license | MIT |
AK LLM Wiki (Standalone Prompt Version)
Build and maintain a persistent, compounding knowledge base as interlinked markdown
files. Based on Andrej Karpathy's LLM Wiki pattern.
Unlike traditional RAG (which rediscovers knowledge from scratch per query), the wiki
is compiled once and kept current. Cross-references are already there.
Contradictions have already been flagged. Synthesis reflects everything ingested.
Obsidian is the IDE. The LLM is the programmer. The wiki is the codebase.
Division of labor: The human curates sources, drops them in raw/, asks good
questions, and edits SCHEMA.md when conventions need to evolve. The human
never (or rarely) writes wiki pages themselves. The LLM does everything else:
reading, summarizing, cross-referencing, filing, maintaining consistency. This is
the whole point — humans abandon wikis because the maintenance burden grows faster
than the value, but LLMs don't get bored.
SCHEMA.md is authoritative
Every convention — page types, frontmatter fields, tag taxonomy, page creation
policy, cross-reference policy, page size limits, log rotation, custom
frontmatter dimensions, and memory-tier thresholds — lives in SCHEMA.md.
That file is user-editable and co-evolves with the wiki. wiki-init writes
a starter based on the user's domain; wiki-lint proposes updates over time.
This skill set reads and enforces SCHEMA.md rather than hardcoding opinions.
This matters because Karpathy's original is intentionally abstract: "Everything
mentioned above is optional and modular — pick what's useful, ignore what isn't."
A reading-a-book wiki and a research wiki need different page types and different
policies. SCHEMA.md is where that per-domain customization lives.
Custom frontmatter dimensions
Beyond standard fields (title, created, updated, type, tags, sources), SCHEMA.md
can declare custom dimensions — extra frontmatter fields specific to the domain.
A software project wiki might declare version: (string, required, prompted on
every ingest). A research wiki might declare venue: or citation_count:.
Each dimension has: name, type (string/date/number/enum/list), description
(prompt text), required, default, refresh_on ([ingest, import, digest, manual]), and optional applies_to (page types). wiki-init sets them up
interactively; wiki-ingest and wiki-import prompt per refresh_on;
wiki-digest surfaces stale values; wiki-lint validates completeness.
Memory tiers (active / archived / frozen)
SCHEMA.md memory_tiers: controls three-tier aging:
- active (default < 365 days) — the hot surface; all query skills default here
- archived (default 365–730 days) — accessible via
--tier=archived|all
- frozen (default > 730 days) — cold storage; future auto-dreaming planned
Tiers are computed on-the-fly from a driving date field (published_at with
ingested_at fallback) — never stored as frontmatter, so threshold adjustments
are instant. A wiki page's tier = most-recent-tier of its cited sources. Manual
tier_override: frontmatter pins are respected. Use wiki-tier to view/adjust.
External fallback plugins
{wiki_path}/.wiki-plugins.yaml registers CLI tools that wiki-query calls when
local search returns insufficient results. Each plugin declares an argv: list
(per-token, no shell — see PLUGINS.md for the v1.4 spec), a trigger condition
(on_empty|on_low_confidence|on_request), and safety settings.
Flow: wiki-query local miss → plugin command → stdout → raw/external/ →
wiki-ingest → wiki pages → future queries hit local first. The external output
becomes a raw source and enters the full ingest pipeline.
Default is auto_run: false — the agent shows the command and waits for user
confirmation. See PLUGINS.md (or the wiki-query skill) for the full spec.
Quick Start
- Run
wiki-init — it asks about your domain and proposes categories that fit
git init in the wiki path (suggested automatically at the end of init)
- Drop a source in
raw/articles/ and run wiki-ingest
- Run
wiki-digest to see your compiled knowledge grow
- Ask questions with
wiki-query; answers file back and compound
| Skill | Argument hint | Description |
|---|
wiki-config | [--show] [--get <path>] [--set <path> <value>] [--explain <path>] [--validate] | Unified read/write for SCHEMA.md config — show all settings in one place, get/set scalar values by… |
wiki-digest | [--since=7d] [--focus=<topic>] [--format=brief|full] [--tier=active|all|archived|frozen] | Generate a digest of the wiki: recent activity summary, key themes by cluster, tier distribution (a… |
wiki-dream | [--since YYYY-MM-DD] [--strategy co-occurrence] [--apply --pages 1,2,3] [--explain <page>] [--out <file>] | Auto-dreaming: re-evaluate frozen and archived pages against recent activity, surface candidates wh… |
wiki-graph | [--query=<expr>] [--neighbors=<page> --depth=N] [--shortest-path=<a>,<b>] [--hubs] [--orphans] [--cluster=<tag>] [--limit=20] [--format=text|json|mermaid] [--tier=active|all|archived|frozen] | Query the wiki as a graph without maintaining a graph DB. Structured frontmatter queries, neighbor… |
wiki-import | <source-path> [--format=folder|obsidian|notion|confluence|markdown] [--map=<mapping-file>] [--dry-run] [--resume] [--priority=recency|links|manual] [--set=key=value,...] [--per-file-prompt] | Import an existing document system (folder tree, Obsidian vault, Notion/Confluence export, etc.) in… |
wiki-ingest | <url|file|text> [--batch] [--no-discuss] [--no-images] [--set=key=value,...] | Ingest a source into the wiki: save raw content and referenced images, prompt the user for any cust… |
wiki-init | [--path=~/wiki] [--domain='AI research'] [--categories='a,b,c'] [--non-interactive] [--set-tags='a,b,c'] [--set-active-days=N] [--set-archived-days=N] [--set-driving-field=published_at|ingested_at] [--set-dimension='name:type:required:refresh_on'] [--enable-dreaming] [--enable-sync] [--refresh-id [--force]] | Interactive bootstrap for a new LLM wiki: ask about domain, propose categories that fit, write a cu… |
wiki-lint | [--fix] [--report-only] [--check=orphans|links|frontmatter|stale|index|tags|size|gaps|schema|tiers|dimensions] | Health-check the wiki: structural checks (orphans, broken links, frontmatter, stale content, tier c… |
wiki-query | <question> [--file] [--format=markdown|table|slides|chart|canvas] [--tier=active|all|archived|frozen] [--external] [--no-external] [--auto-external] | Answer a question using the wiki's compiled knowledge. Searches relevant pages, synthesizes with ci… |
wiki-search | <query> [--tag=<tag>] [--type=entity|concept|comparison|query] [--limit=10] [--tier=active|all|archived|frozen] | Search the wiki by keyword, tag, topic, or type. Returns ranked results with page summaries and mat… |
wiki-sync | [--auto] [--dry-run] | Multi-machine git sync for the wiki: pull, merge with custom drivers (log.md union+sort), push. Loc… |
wiki-tier | [--show] [--set-active=Nd] [--set-archived=Nd] [--set-field=published_at|ingested_at] [--preview] [--pin=<page>:<tier>] [--unpin=<page>] [--list=<tier>] [--disable] [--enable] | Inspect and manage the memory-tier system: view the active/archived/frozen distribution, preview a… |
wiki-watch | [--start [--poll N --debounce N]] [--stop] [--status] [--drain [--pages 1,2,3]] [--remove <id>] | Watch raw/{articles,papers,transcripts,external}/ for new files, queue them, and let the user drain… |
Skills
wiki-init (interactive)
Trigger: "create a wiki", "start my knowledge base", "initialize a wiki for {domain}"
Do not hardcode categories. Ask the user about their domain, propose a
category set that fits, let them edit.
- Resolve path (argument →
WIKI_PATH env → current wiki root →
LLM_WIKI_PROJECT / .llm-wiki.yaml / registry / git root name as
~/.llm-wiki/{repo} →
legacy ~/.ak-wiki/config.yaml → ~/.llm-wiki/common)
- Ask for domain (specific — "transformer ML research", "LoTR trilogy", etc.)
- Propose categories matching the domain:
- Research →
entities/, concepts/, comparisons/, queries/
- Book →
characters/, places/, events/, themes/, timeline/, chapters/
- Personal →
journal/, topics/, patterns/, queries/
- Business →
people/, projects/, customers/, decisions/, meetings/
- Competitive →
competitors/, features/, market/, comparisons/
- Walk through conventions (offer defaults, accept edits):
- Frontmatter fields (default: title/created/updated/type/tags/sources)
- Tag taxonomy (propose 10–20 domain-specific tags)
- Page creation policy (default: "central to source OR mentioned in 2+ sources")
- Cross-reference policy (default: "link wherever genuine; no minimum")
- Page size limit (default: no limit)
- Log rotation threshold (default: no rotation)
- Create directory structure +
raw/articles/, raw/papers/, raw/transcripts/, raw/external/, raw/imported/, raw/assets/
- Write
SCHEMA.md with everything chosen above — mark it "user-editable"
- Write sectioned
index.md (one section per category)
- Write
log.md with init entry
- Suggest
git init — the wiki is a git repo, version history for free
- Report and suggest first ingest
wiki-ingest (with image handling)
Trigger: "ingest this", "add this source", "read this and update the wiki"
Arguments: <url|file|text>, --batch, --no-discuss, --no-images
- Orient: read SCHEMA.md, index.md, recent log.md
- Capture raw source:
- Save text to
raw/articles/ or raw/papers/ — never modify raw files
- Download referenced images to
raw/assets/{source-stem}-{name} and
rewrite the saved raw source to use local paths (URLs rot; local copies persist)
- Process order for multimodal sources — read text first (chunking if long),
identify informative images (diagrams, charts, screenshots — skip decorative),
then view those specific images separately using image tools. LLMs can't
consume markdown + inline images in one pass.
- Discuss takeaways with user (skip if
--no-discuss) — surface 3–5 insights
and ask what to emphasize
- Check existing pages — search index.md and wiki files for every entity/concept
- Write/update pages per SCHEMA.md policy:
- Only create a page if SCHEMA.md's creation policy is met
- Use the frontmatter fields SCHEMA.md requires
- Only use tags from SCHEMA.md's taxonomy — if you want a new one, pause and
propose adding it to SCHEMA.md rather than drifting
- Page type must match an existing category; new kinds → propose schema update
- Cross-reference both ways — a page that exists but is never linked to is invisible
- Update index.md and log.md:
## [YYYY-MM-DD] ingest | Source Title
- Report — list every file, note any schema proposals awaiting approval
A single ingest usually touches 10–15 pages. That's the compounding effect.
wiki-search ⭐ KEY SKILL
Trigger: "find pages about X", "search for Y", "what do we have on Z"
Three-pass scan. No orientation needed — runs cold.
Arguments: <query>, --tag=<tag>, --type=<category>, --limit=10
- Parse query, tag/type filters
- Pass 1: scan
index.md (Karpathy: "reads the index first to find relevant pages")
- Pass 2: scan page frontmatter for tag/title matches
- Pass 3 (if <3 results): full-text search across page bodies (exclude
raw/)
- Rank: title match > hub centrality > content frequency > recency
- Return with excerpt, tags, related pages
Scaling up:
- < 100 pages → built-in 3-pass scan
- 100–500 pages → built-in scan + keep index.md current via
wiki-lint
- 500–2000 pages → install
qmd (hybrid BM25/vector
with LLM re-rank); wiki-search auto-shells-out when qmd is in PATH
- 2000+ pages →
qmd in MCP server mode; agent calls directly, bypassing built-in scan
Karpathy: "You could also build something simpler yourself — the LLM can help you
vibe-code a naive search script as the need arises."
wiki-graph (structured graph queries)
Trigger: "neighbors of X", "shortest path between A and B", "which pages are hubs", "orphans", "Dataview-style filter"
Arguments: [--query=<expr>], [--neighbors=<page> --depth=N], [--shortest-path=<a>,<b>], [--hubs], [--orphans], [--cluster=<tag>], [--limit=20], [--format=text|json|mermaid]
wiki-search handles ranked text relevance. wiki-graph handles structural
queries over frontmatter and the [[wikilink]] graph — with no persistent store.
Every call scans the markdown files fresh, builds an in-memory graph, runs the
query, and exits. The filesystem remains the only source of truth.
Modes:
--query — Dataview-style frontmatter filter. Fields, comparisons on
dates/numbers, AND/OR/NOT, parentheses.
Example: --query "type: entity AND tags contains transformer AND updated > 2025-01"
--neighbors <page> — BFS over [[wikilinks]] up to --depth (cap 4).
Best way to see everything adjacent to a topic.
--shortest-path <a>,<b> — surface bridge concepts between two
entities. Often the highest-signal mode — finds connections the user didn't
realize were there.
--hubs — nodes ranked by |in_edges| + 0.5·|out_edges|. Inbound > outbound.
--orphans — isolated nodes (no links at all) vs. leaves (inbound only).
True orphans are usually ingest bugs; leaves are often intentional stubs.
--cluster=<tag> — members, anchor, intra- vs. external edges, density.
Answers "is this tag a coherent topic or just a shelf?"
Output formats: text (default), json (pipe-friendly), mermaid (paste
into Obsidian or a GitHub README — great for --neighbors, --shortest-path,
--cluster).
Why no persistent graph: a second data store drifts silently out of sync
the moment the agent updates a page and forgets to update the graph. Files-as-
truth is Karpathy's core discipline. Scanning several hundred pages takes
milliseconds — cheaper than keeping an index coherent.
wiki-tier (memory-tier management)
Trigger: "show tier distribution", "push active window to 2 years", "pin this page as active", "which pages just aged out"
Arguments: [--show], [--set-active=Nd], [--set-archived=Nd],
[--set-field=published_at|ingested_at], [--preview],
[--pin=<page>:<tier>], [--unpin=<page>], [--list=<tier>],
[--disable], [--enable]
Manages the three-tier aging system configured in SCHEMA.md memory_tiers:.
--show (default) — print config + distribution table + recently aged-out
pages + pinned overrides
--set-active=Nd / --set-archived=Nd — stage a threshold change, show
the delta ("31 pages move archived→active"), ask before writing SCHEMA.md
--preview — dry-run a threshold change without writing
--pin=<page>:<tier> / --unpin=<page> — write or clear tier_override:
frontmatter on a specific page (for canonical references that shouldn't age out)
--list=<tier> — list every page in a given tier
--disable / --enable — toggle the tier system in SCHEMA.md
Tier changes are safe — they re-interpret existing dates, not mutate content.
Auto-dreaming for frozen content is planned for v2 but not implemented yet.
wiki-digest ⭐ KEY SKILL
Trigger: "what's in the wiki?", "summarize what we know", "give me an overview"
Arguments: --since=7d, --focus=<topic>, --format=brief|full
- Orient (SCHEMA.md + index.md + log.md)
- Activity (from log.md): parse entries in time window, count by action
- Inventory (from index.md): pages by type, most-linked hubs, orphans
- Theme clustering: group by tags, find anchor pages, assess depth
- Coverage gaps: missing synthesis pages, uncompared entities, unfiled queries
- Cross-cutting synthesis: entities spanning clusters, latent contradictions
- Suggested next actions with specific skill invocations
wiki-query (filed answers compound)
Trigger: any question about the wiki's domain
Arguments: <question>, --file, --format=markdown|table|slides|chart|canvas
Like ingestion, substantive query results compound back into the wiki. When an
answer is worth keeping, it's filed as a wiki page and joins the knowledge base
just like sources do.
- Orient; classify question (factual / comparative / synthesis / gap)
- Find pages via
wiki-search
- Read relevant pages (prioritize: comparisons > concepts > entities > queries)
- Synthesize with
[[wikilink]] citations; be explicit about gaps; present
contradictions honestly
- Apply format:
- markdown — prose + headers (default)
- table — comparison table, rows = options, columns = dimensions
- slides — Marp-compatible deck (
marp: true frontmatter, --- slide breaks)
- chart — matplotlib via code execution → save PNG under
queries/
- canvas — Obsidian
.canvas JSON (nodes = pages, edges = connections)
- Decide whether to file back — file to
queries/{name}.md if:
- 4+ pages used (synthesis is valuable)
- It's a comparison that didn't exist
- It reveals an emergent insight
--file flag was passed
- Update
log.md: ## [YYYY-MM-DD] query | Question
wiki-lint (structure + content + evolution)
Trigger: "lint", "audit", "health-check", "clean up"
Two layers of checks. The content layer is where the LLM earns its keep.
Structural checks (the "well-formed?" layer):
| Severity | Check | Description |
|---|
| HIGH | Broken wikilinks | [[links]] pointing to non-existent pages |
| HIGH | Index gaps | Pages on filesystem not in index.md |
| MEDIUM | Orphan pages | Pages with no inbound links |
| MEDIUM | Contradictions | Unresolved contradictions: frontmatter flags |
| MEDIUM | Frontmatter | Missing fields per SCHEMA.md required list |
| LOW | Tag drift | Tags not in SCHEMA.md taxonomy |
| LOW | Stale content | updated older than newer sources mentioning same entities |
| LOW | Oversized pages | Over SCHEMA.md limit (default: no limit) |
| AUTO | Log rotation | Per SCHEMA.md threshold (default: no rotation) |
Content checks (the LLM layer — this is what Karpathy emphasized):
- Content gaps: entities mentioned in 3+ pages with no entity page; open
questions in page text never filed as queries; 5+ co-occurring entities with
no comparison page; clusters of 5+ tagged pages with no synthesis concept page
- Web search suggestions: for each gap, propose a specific web query that
would fill it. Offer to run it and stage results for
wiki-ingest.
- Taxonomy evolution: propose SCHEMA.md updates as diffs — tags to add,
tags to retire, new categories, threshold adjustments. Apply with
--fix
or on user confirmation.
--fix applies safe automated fixes (index gaps, log rotation, approved
schema updates). --report-only is report-only (default).
wiki-import (bulk migration)
Trigger: "import my existing docs", "migrate my vault", "bring in my whole folder"
Arguments: <source-path>, --format=folder|obsidian|notion|confluence,
--map=<file>, --dry-run, --resume, --priority=recency|links|manual
Five-phase import: Discovery → Mapping → Deduplication → Processing
in waves of 20 → Navigation update. Checkpoint to
.wiki-import-checkpoint.json every 20 files; resume on interruption. Handles
Obsidian vaults, Notion/Confluence exports, or plain folders. For large imports
(hundreds of files).
See the full plugin skill for all details.
wiki-watch (raw/ auto-ingest watcher)
Trigger: "watch raw/", "auto-detect new files", "what's pending to ingest", "drain the queue"
Arguments: [--start [--poll N --debounce N]], [--stop], [--status],
[--drain [--pages 1,2,3]], [--remove <id>]
Closes the "I dropped a file in raw/articles/ and forgot to ingest it" gap.
A polling daemon (default 5 s) detects new files in
raw/{articles,papers,transcripts,external}/, debounces against in-progress
writes (default 5 s), and writes them to .wiki-ingest-queue.json with a
pending status. The watcher never auto-runs wiki-ingest — drain is
always explicit, so a misconfigured watcher cannot silently mutate wiki pages.
--start — spawn the daemon for the resolved wiki. PID and log are
per-project (~/.ak-wiki/watcher-{slug}.pid, ….log), so multiple
project wikis (~/.llm-wiki/necall, ~/.llm-wiki/rtc, …) can each run
their own watcher concurrently.
--status (default when no flag passed) — daemon liveness + queue
summary (pending / processed / failed / removed). Works whether or not
the daemon is running.
--drain — for each pending entry in detection order: invoke
wiki-ingest <path>, mark processed on success or failed on error.
After the loop, append a single ## [date] watch | drained N files log
entry. --drain --pages 1,3 processes only the listed indices.
--remove <id|index> — drop an entry from the queue without ingesting.
Use for WIP files you don't want in the wiki yet.
--stop — clean SIGTERM to the daemon (TerminateProcess on Windows).
When NOT to use: for one-off ingestion of a known file → just run
wiki-ingest <path>. The watcher is for the steady-state drip workflow.
For bulk migration of an existing folder use wiki-import.
wiki-dream (auto-dreaming)
Trigger: "what frozen pages just got relevant again", "dream", "re-promote old pages"
Arguments: [--since YYYY-MM-DD], [--strategy co-occurrence],
[--apply --pages 1,2,3], [--explain <page>], [--out <file>]
The only ak-wiki feature that runs without you. While you sleep, the dreamer
re-evaluates which frozen and archived pages have become relevant again
based on this period's ingests. Reads only the wiki filesystem (log.md +
page frontmatter dates ingested_at / updated) — never reads chat
sessions, file mtimes, or any external state. Frontmatter dates are
checked into git, so git clone reproduces dreamer behavior on any
machine; using mtimes would not (mtimes reset on checkout).
How it scores (v1.6 strategy: co-occurrence):
- Entity overlap (weight 0.5 default) — old page shares title / link
targets with new ingests this period
- Tag resurgence (weight 0.2) — tag appears ≥
min_count times in fresh
pages after being dormant for dormancy_window_days
- Citation hit (weight 0.4) — a fresh page directly
[[wikilinks]] to
the old page
Pages above confidence_threshold (default 0.6) become candidates —
surfaced for review, never auto-promoted. --apply --pages 1,2,3 writes
tier_override: active plus a reason and timestamp to selected candidates.
- Default mode — emit candidate JSON + write a dated file at
dreaming/{YYYY-MM-DD}.md for human review next morning. Caps at
max_repromote_per_run (default 10).
--explain <page> — score breakdown for one specific page (entity /
tag / citation components). Useful for "why didn't X get promoted?"
--apply — promotes named candidates and advances the dream |
watermark in log.md.
Schedule weekly via Claude Code: claude /schedule "0 23 * * 0" "/ak-wiki:wiki-dream". Tune via wiki-config --set dreaming.<key> <value>.
wiki-config (unified SCHEMA.md read/write)
Trigger: "show all config", "set dreaming threshold", "what does X mean", "validate SCHEMA.md"
Arguments: [--show], [--get <path>], [--set <path> <value>],
[--explain <path>], [--validate]
Generic path-based interface to SCHEMA.md tunables. Use this when there's no
domain-specific shortcut (e.g. wiki-tier --set-active=540d is better UX
for tier thresholds; wiki-config is for the long tail like dreaming
weights and resurgence params).
--show — all config blocks at a glance (memory_tiers, dreaming,
custom_dimensions, tag_taxonomy_count, categories)
--get memory_tiers.active_days — read one dotted-path value
--set dreaming.confidence_threshold 0.55 — surgical line replacement
that preserves comments, blank lines, and ordering. Validates after every
write; reverts SCHEMA.md if validation fails, surfaces the validation
errors verbatim.
--explain dreaming.weights.entity — read the docstring for any
documented key (kept in sync with TRD additions).
--validate — run the full schema_validate pipeline (structural +
cross-field rules).
v1.6 limitations (deliberate trade for safety):
- Edits existing scalars only — cannot add new keys or new YAML blocks.
- No list-index editing (
custom_dimensions[0].required is unreachable).
- No multi-key transactions — each
--set is independent.
For introducing a dreaming: block to a wiki initialized before v1.6, edit
SCHEMA.md by hand or re-run wiki-init with the dreaming flag.
wiki-sync (multi-machine git sync — v1.8+)
Trigger: "sync the wiki", "pull from origin", "push my changes", "are my machines in sync"
Arguments: [--auto], [--dry-run]
Pull-merge-push your wiki across machines. Custom merge driver
(merge_log.py) auto-merges log.md as a union+sort, deduplicating by
canonical hash and preserving body data on same-triple-different-body
divergence. Per-machine sync reports go to
~/.ak-wiki/sync-reports/{slug}/ — never inside the wiki repo, so
they don't self-conflict on the next sync.
- default (interactive) — acquire local sync lock, stash dirty
tree (with SHA capture), fetch, classify ancestry, merge with
driver, push (bounded retry 3×). Cleanup in three-layer
try/finally so lock always releases.
--auto (cron mode) — any non-clean outcome exits non-zero so a
chained && wiki-dream doesn't run. Recommended cron line:
0 23 * * 0 wiki-sync --auto && wiki-dream
--dry-run — read-only preview; forks BEFORE side effects (no
lock, stash, driver registration, or log mutation). Only git fetch
runs (writes only to .git/refs/remotes/).
Hard stops (exit 1):
- Force-push detected — old origin SHA isn't an ancestor of new origin SHA
- Unrelated histories — first fetch and no merge-base with origin
- Identity mismatch — local
wiki_id ≠ remote wiki_id from
git show origin/main:SCHEMA.md
- Active wiki-import —
.wiki-import-lock fresh OR
.wiki-import-checkpoint.json present (wiki-import was interrupted)
- Local sync lock held by a live PID — same-machine reentrancy guard
- Merge / rebase / cherry-pick already in progress
Conflicts that the driver can't auto-resolve land as standard
unmerged paths (<<<<<<< / >>>>>>>); the conflict report includes
the recovery commands using stash SHA (not stash@{0} which can drift).
v1.8 MVP limitations:
- Only
merge_log.py driver registered. merge_index.py is v1.8-full
per PRD §13 phasing — until then index.md uses git's default 3-way.
- Push-race retry: bounded at 4 total attempts (1s/2s/4s backoff). Each
retry re-fetches, re-classifies, and re-merges with the driver if the
ancestry is still divergent. Out-of-retries →
race-exhausted.
Architecture
{wiki_path}/
├── SCHEMA.md # Conventions, tag taxonomy, policies (USER-EDITABLE)
├── index.md # Sectioned content catalog with one-line summaries
├── log.md # Append-only chronological action log
├── raw/ # IMMUTABLE — source material, never modified
│ ├── articles/
│ ├── papers/
│ ├── transcripts/
│ ├── external/
│ ├── imported/
│ └── assets/ # Downloaded images and attachments
└── {categories}/ # Category directories — defined by SCHEMA.md
# e.g. entities/, concepts/, comparisons/, queries/
# or: characters/, themes/, plot/, timeline/
# or: people/, projects/, decisions/, meetings/
Starter structure ≠ law. Categories match the domain.
Working with Obsidian
The wiki is a drop-in Obsidian vault:
[[wikilinks]] render as clickable
- Graph view — the best way to see the shape of the wiki. When the user asks
"what does my wiki look like?" and they have Obsidian open, point them there.
Otherwise use
wiki-digest for a text equivalent.
- Dataview plugin — runs queries over YAML frontmatter. Add rich frontmatter
(tags, dates, source counts) and Dataview can generate dynamic tables.
- Obsidian Web Clipper — browser extension, converts web articles to markdown
directly into
raw/articles/. Fastest way to get sources in.
- Images — set Obsidian's attachment folder to
raw/assets/; reference as
![[image.png]]
- Marp plugin — renders
--format=slides output inside Obsidian
Git integration
The wiki is a git repo by default. wiki-init suggests git init as the final
step. Every wiki-ingest and wiki-query --file produces clean, reviewable
diffs. Team wikis can use branches for proposed changes before merging. log.md
gives the timeline; git log gives the diffs behind it.
Guards (always enforced)
- Immutability:
raw/ is read-only. Write corrections to wiki pages, not sources.
- Orientation: Read SCHEMA.md + index.md + recent log.md before any
ingest/query/lint/digest. Skipping this causes duplicates and missed cross-references.
- Scope: Confirm before touching 10+ existing pages in one operation.
- Schema: Before adding a tag not in the taxonomy or creating a new page type,
propose a SCHEMA.md update rather than silently drifting.
Pitfalls
- Don't hardcode rules the plugin shouldn't own — all policies live in SCHEMA.md
- Don't create pages for passing mentions — follow SCHEMA.md's creation policy
- Don't force artificial cross-references to hit a link count — link wherever
there's a genuine connection
- Don't silently overwrite contradictions — note both, flag in frontmatter
- Don't skip orientation — it's the main thing preventing duplicates
- Don't forget to handle images — they rot when left as remote URLs
- Don't treat
wiki-lint as a pure formatter — it should suggest content gaps
and schema evolution, not just structural fixes