
Llm Wiki
- 198 installs
- 40 repo stars
- Updated August 4, 2026
- akillness/oh-my-skills
Curate and query an LLM-oriented wiki for model capabilities, prompting patterns, tool use, and fast answers during early exploration and architecture decisions.
About
llm-wiki from oh-my-skills exposes a structured LLM knowledge base for agents: terminology, model behaviors, prompting tactics, and implementation notes to accelerate informed decisions during discovery and technical research.
- LLM capability reference
- Prompting pattern lookup
- Tool-use and agent notes
- Model comparison context
- Quick research retrieval
Llm Wiki by the numbers
- 198 all-time installs (skills.sh)
- Ranked #2,901 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/akillness/oh-my-skills --skill llm-wikiAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 198 |
|---|---|
| repo stars | ★ 40 |
| Last updated | August 4, 2026 |
| Repository | akillness/oh-my-skills ↗ |
What it does
Curate and query an LLM-oriented wiki for model capabilities, prompting patterns, tool use, and fast answers during early exploration and architecture decisions.
Files
llm-wiki - Persistent LLM-Maintained Markdown Wiki
Keyword:llm-wiki·obsidian wiki·research vault·knowledge base
>
Use this skill when the user wants knowledge to accumulate as a maintained markdown artifact, not be rediscovered from raw files on every query.
llm-wiki turns Andrej Karpathy's gist into an operational workflow. The core pattern is simple: keep raw sources immutable, let the LLM own the wiki layer, and encode the maintenance contract in AGENTS.md or CLAUDE.md.
When to use this skill
- Bootstrap a new Obsidian or markdown vault for long-lived knowledge work
- Convert raw articles, papers, transcripts, or notes into source summaries plus cross-linked wiki pages
- Maintain
index.mdandlog.mdas navigational primitives before adding heavier search infrastructure - File good answers back into the wiki instead of losing them in chat history
- Run periodic lint passes for broken links, orphan pages, stale claims, and missing synthesis pages
- Add optional helpers such as Scrapling for URL ingestion, qmd for search, or Obsidian CLI for vault automation
Instructions
Step 1: Bootstrap the vault
Create the wiki skeleton first:
bash scripts/bootstrap-vault.sh /path/to/vaultThe bootstrap creates:
raw/sources/for immutable source markdown or copied filesraw/assets/for downloaded images and attachmentswiki/sources/for per-source summarieswiki/entities/andwiki/concepts/for durable synthesis pageswiki/queries/andwiki/reports/for filed answers and higher-value outputsindex.md,log.md, andAGENTS.md
Do not skip the schema file. The schema is what makes the agent act like a disciplined maintainer instead of a generic assistant. See references/architecture.md and references/schema-playbook.md.
Step 2: Treat AGENTS.md or CLAUDE.md as the operating contract
The schema should encode the rules that stay true across sessions:
raw/is source of truth and must stay immutablewiki/plusindex.mdandlog.mdare LLM-owned working artifacts- Every ingest updates the source summary, relevant synthesis pages,
index.md, andlog.md - Every durable query answer gets filed back into
wiki/queries/orwiki/reports/ - Lint passes must look for broken links, orphan pages, stale claims, contradictions, and missing page candidates
Keep the schema short and enforceable. A small contract that the agent actually follows is better than a giant policy file nobody will reread. The starter schema from bootstrap-vault.sh is intentionally minimal; refine it with references/schema-playbook.md.
Step 3: Ingest one source at a time until the workflow is stable
If the source is already local, place it in raw/sources/ and ask the agent to process it. If the source is a URL, use the Scrapling-powered helper:
bash scripts/ingest-url.sh /path/to/vault "https://example.com/article"
bash scripts/ingest-url.sh /path/to/vault "https://app.example.com/post" --mode fetch --wait-selector article
bash scripts/ingest-url.sh /path/to/vault "https://protected.example.com/post" --mode stealth --solve-cloudflareExpected ingest touch points:
1. Save the immutable raw capture under raw/sources/ 2. Create or refresh a source page under wiki/sources/ 3. Update relevant entity or concept pages 4. Update index.md 5. Append a chronological entry to log.md
Prefer one-source-at-a-time ingest when starting. It forces the human to inspect what the wiki changed, surface missing conventions, and refine the schema. Once the workflow is reliable, batching is fine. Use references/ingest-playbook.md for the operating checklist.
Step 4: Query against the wiki, not the raw pile
When answering questions:
1. Read index.md first 2. Open the most relevant wiki pages 3. Drill into raw sources only when the wiki needs grounding or conflict resolution 4. Cite page paths and raw source paths explicitly 5. File durable outputs back into the vault
Create a reusable note stub for high-value answers:
bash scripts/new-query-note.sh /path/to/vault "How does Company A differ from Company B?" --question "How does Company A differ from Company B?"
bash scripts/new-query-note.sh /path/to/vault "Q2 product thesis" --section reports --citation "[[wiki/concepts/product-thesis]]"Use wiki/queries/ for question-shaped outputs and wiki/reports/ for more durable synthesized artifacts such as memos, comparisons, or presentation backbones. More detail lives in references/query-and-filing.md.
Step 5: Lint and repair the wiki periodically
Run the local health check:
python3 scripts/lint-wiki.py /path/to/vault
python3 scripts/lint-wiki.py /path/to/vault --format jsonThis script focuses on structure, not truth. It checks required files and directories, broken wiki links, and orphan pages. Use the lint output as the starting point for a human-guided cleanup pass:
- merge duplicate concepts
- promote heavily referenced ideas into their own page
- retire stale claims superseded by newer sources
- add backlinks or summary pages where the graph is too sparse
See references/maintenance-and-scaling.md for the higher-level lint checklist.
Step 6: Add search and automation only when scale justifies it
index.md plus log.md is enough for small-to-medium vaults. Add heavier tools later:
- Scrapling when URL ingestion becomes common
- qmd when the index is no longer sufficient for wiki search
- Obsidian CLI when you want shell-driven vault automation against a running desktop app
- Dataview when you start relying on frontmatter-driven tables and lists
- Git from day one for version history, branching, and reviewable diffs
Do not force embeddings, MCP, or browser automation on day one. The point of this workflow is that a simple markdown repo already compounds knowledge surprisingly well.
Examples
Example 1: Bootstrap a fresh vault
bash scripts/bootstrap-vault.sh ~/vaults/company-researchExample 2: Capture a static article into raw sources and create a source stub
bash scripts/ingest-url.sh ~/vaults/company-research "https://example.com/article"Example 3: Capture a JavaScript-rendered page
bash scripts/ingest-url.sh ~/vaults/company-research "https://app.example.com/dashboard" --mode fetch --network-idleExample 4: Create a durable query note
bash scripts/new-query-note.sh ~/vaults/company-research "Why this market is consolidating" \
--question "Why is this market consolidating?" \
--citation "[[wiki/concepts/market-structure]]"Example 5: Create a report stub instead of a query note
bash scripts/new-query-note.sh ~/vaults/company-research "Q3 diligence memo" --section reportsExample 6: Run the structure lint
python3 scripts/lint-wiki.py ~/vaults/company-researchBest practices
1. Keep raw/ immutable. Corrections belong in wiki pages or follow-up source notes, not in rewritten raw captures. 2. Update index.md and log.md on every ingest, query filing, and lint pass. If these drift, the whole workflow gets harder to navigate. 3. Prefer a few strong entity and concept pages over hundreds of weak fragments. Compounding happens through synthesis, not page count. 4. Read index.md before doing expensive retrieval work. It is the simplest useful search system for moderate vault sizes. 5. Distinguish facts from synthesis. Source pages should be grounded; concept pages can be more interpretive. 6. File good answers back into the vault. If the answer mattered once, it will probably matter again. 7. Use git commits to separate ingest, query, and lint operations so the wiki stays auditable. 8. Keep the schema alive. Update AGENTS.md when you notice repeated drift or ambiguity.
References
- references/architecture.md
- references/schema-playbook.md
- references/ingest-playbook.md
- references/query-and-filing.md
- references/maintenance-and-scaling.md
- scripts/bootstrap-vault.sh
- scripts/ingest-url.sh
- scripts/new-query-note.sh
- scripts/lint-wiki.py
- Karpathy gist: llm-wiki
interface:
display_name: "LLM Wiki"
short_description: "Build and maintain LLM wiki vaults"
default_prompt: "Use $llm-wiki to design or maintain an Obsidian-based LLM wiki."
{
"skill_name": "llm-wiki",
"evals": [
{
"id": 1,
"prompt": "Obsidian으로 llm-wiki를 시작하고 싶은데 어떤 폴더 구조와 핵심 파일이 필요해?",
"expected_output": "The response bootstraps a vault with raw sources, wiki folders, index.md, log.md, and a schema file.",
"assertions": [
"The response mentions `bash scripts/bootstrap-vault.sh` or an equivalent bootstrap step",
"The response mentions `raw/`, `wiki/`, `index.md`, `log.md`, and `AGENTS.md` or `CLAUDE.md`"
]
},
{
"id": 2,
"prompt": "웹 아티클 URL 하나를 내 wiki에 넣고 싶어. 어떻게 ingest 하지?",
"expected_output": "The response uses the Scrapling-based helper and updates both raw and wiki layers.",
"assertions": [
"The response mentions `bash scripts/ingest-url.sh` or Scrapling-powered URL ingestion",
"The response says ingest updates the raw capture, a source page, `index.md`, and `log.md`"
]
},
{
"id": 3,
"prompt": "SPA 페이지라 JS 렌더링이 필요해. llm-wiki에서도 이걸 처리할 수 있어?",
"expected_output": "The response escalates from static capture to dynamic or stealth fetch modes when needed.",
"assertions": [
"The response mentions `--mode fetch` or a dynamic fetch path",
"The response keeps Scrapling escalation optional instead of making stealth the default"
]
},
{
"id": 4,
"prompt": "질문에 대한 좋은 답변을 chat에서 끝내지 않고 wiki에 남기고 싶어.",
"expected_output": "The response tells the user to read the index first and file durable answers into queries or reports.",
"assertions": [
"The response mentions reading `index.md` first",
"The response mentions `bash scripts/new-query-note.sh` or filing into `wiki/queries/` or `wiki/reports/`"
]
},
{
"id": 5,
"prompt": "위키가 커졌는데 건강검진은 어떻게 해?",
"expected_output": "The response points to the lint script and describes structural plus semantic health checks.",
"assertions": [
"The response mentions `python3 scripts/lint-wiki.py`",
"The response mentions broken links, orphan pages, stale claims, contradictions, or missing pages"
]
},
{
"id": 6,
"prompt": "페이지 수가 많아졌어. 언제 qmd 같은 검색 도구를 붙여야 해?",
"expected_output": "The response keeps index and log as the default navigation layer and introduces qmd later.",
"assertions": [
"The response says `index.md` and `log.md` are enough at small or moderate scale",
"The response mentions qmd as optional later-stage search infrastructure"
]
}
]
}
Architecture
Use this reference when designing the initial vault layout or explaining why the workflow is different from plain RAG.
Three layers
1. Raw sources
Store original source material under raw/.
raw/sources/for markdown captures, transcripts, pasted notes, or copied text filesraw/assets/for downloaded images and attachments
Rules:
- Treat this layer as immutable
- Correct mistakes with follow-up notes, not silent rewrites
- Keep a stable path so wiki pages can cite the exact raw file they relied on
2. The wiki
Store LLM-maintained pages under wiki/.
wiki/sources/for per-source summarieswiki/entities/for people, companies, products, places, or recurring named thingswiki/concepts/for themes, mechanisms, models, or theseswiki/queries/for filed answers to specific questionswiki/reports/for higher-value durable syntheses
The wiki is the compiled knowledge layer. It can change often.
3. The schema
Store the operating contract in AGENTS.md, CLAUDE.md, or the platform-specific equivalent.
The schema should answer:
- What the directories mean
- What gets updated on ingest
- How answers should be cited and filed
- What lint passes should check
- Which files are human-owned versus LLM-owned
Recommended tree
vault/
├── AGENTS.md
├── index.md
├── log.md
├── raw/
│ ├── sources/
│ └── assets/
└── wiki/
├── sources/
├── entities/
├── concepts/
├── queries/
└── reports/Navigation primitives
index.md
index.md is the content-oriented map.
Keep one bullet per durable page with:
- wiki link
- one-line summary
- optional counts or dates when those help
Read it before broad search.
log.md
log.md is chronological.
Use it for:
- ingest entries
- query filings
- lint passes
Stable heading patterns make it grep-friendly:
## [2026-04-08] ingest | Example title
## [2026-04-08] query | Example question
## [2026-04-08] lint | Weekly cleanupPage naming
- Use kebab-case file names
- Keep a single H1 at the top of each page
- Prefer stable paths over human-perfect names
- Use dates for source captures and query notes when chronology matters
Examples:
wiki/sources/2026-04-08-example-article.mdwiki/entities/openai.mdwiki/concepts/long-context-training.mdwiki/queries/2026-04-08-why-market-share-changed.md
Ingest Playbook
Use this reference when turning raw material into wiki updates.
Default ingest flow
1. Save the raw source under raw/sources/ 2. Create or refresh a page in wiki/sources/ 3. Update relevant wiki/entities/ and wiki/concepts/ pages 4. Update index.md 5. Append an entry to log.md
Source-summary checklist
Each page in wiki/sources/ should usually capture:
- what the source is
- the strongest grounded claims
- why it matters to the broader wiki
- what it conflicts with or leaves uncertain
- which concept or entity pages should absorb the information
URL ingest with Scrapling
Use the helper when the source is on the web:
bash scripts/ingest-url.sh /path/to/vault "https://example.com/article"Escalation:
--mode getfor normal static pages--mode fetchfor JS-rendered pages--mode stealthonly when protection blocks ordinary fetching
Pass extra Scrapling flags after -- or directly as trailing arguments:
bash scripts/ingest-url.sh /path/to/vault "https://app.example.com/post" --mode fetch --wait-selector articleLocal-file ingest
If the source already exists locally:
1. Put it in raw/sources/ 2. Create a wiki/sources/ page manually or with your own helper 3. Ask the agent to update affected synthesis pages
This is often better for PDFs, exported chat logs, or meeting transcripts.
One-at-a-time versus batch ingest
Prefer one-at-a-time when:
- the schema is still changing
- the topic is nuanced
- you want to guide emphasis or catch misunderstanding early
Batch ingest is reasonable when:
- page types are stable
- the source set is homogenous
- you mostly want broad coverage first, then cleanup later
Contradictions
Do not silently overwrite disagreement.
When new evidence challenges an older claim:
- update the relevant concept page
- cite both sources
- note which claim is newer, weaker, disputed, or unresolved
- optionally create a dedicated comparison or contradiction note if it matters often
Maintenance and Scaling
Use this reference when the wiki grows beyond a handful of pages and needs regular cleanup.
Structural lint
Start with the local script:
python3 scripts/lint-wiki.py /path/to/vaultThis catches:
- missing required files or directories
- broken wiki links
- orphan pages with no inbound links
Higher-level lint questions
After the structural check, ask the agent:
- Which pages make claims that newer sources might have invalidated?
- Which concepts are mentioned repeatedly but lack their own page?
- Which pages are too broad and should be split?
- Which pages are thin and should probably merge into a larger synthesis page?
- Which questions keep reappearing and should become query or report pages?
Suggested maintenance cadence
- after each ingest: quick index/log update
- weekly: structural lint and orphan cleanup
- monthly: contradiction and stale-claim review
- quarterly: schema review and folder convention cleanup
Git hygiene
Git makes the workflow auditable.
Prefer commits that separate:
- ingest work
- query filing
- lint and cleanup
This makes it easier to review or revert low-quality changes.
When to add search tooling
Stay with index.md first. Add search when:
- the index becomes too long to scan quickly
- concept pages reference too many sources to navigate manually
- you have enough pages that grep alone is noisy
Karpathy's gist mentions qmd as a strong local option for markdown search. It is optional, not foundational.
Useful optional tools
- qmd for local markdown search or MCP access
- Obsidian CLI for terminal-driven vault automation
- Dataview for frontmatter-based lists and tables
- Marp for presentation generation from markdown
- Obsidian graph view for spotting hubs and orphans visually
Scaling principle
Do not optimize early for the hundredth source. Make the first twenty ingests high quality. A small but well-maintained wiki compounds better than a huge pile of weak pages.
Query and Filing
Use this reference when answering questions against the wiki and deciding what should become a durable page.
Query workflow
1. Read index.md 2. Open the most relevant wiki pages 3. Use raw sources only when needed for grounding or conflict resolution 4. Synthesize the answer 5. Decide whether the answer deserves filing
Read order
Prefer this order:
index.md -> wiki/concepts or wiki/entities -> wiki/sources -> raw/sourcesThis keeps the workflow fast and preserves the value of the compiled wiki layer.
What deserves filing
File the answer when it has any of these properties:
- it took real synthesis across multiple pages
- it exposed a new comparison or thesis
- it is likely to be asked again
- it changes how the rest of the wiki should be organized
Queries versus reports
Use wiki/queries/ for:
- one concrete question
- a concise answer with evidence
- reusable follow-up questions
Use wiki/reports/ for:
- a memo
- a diligence note
- a thesis summary
- a deck backbone or presentation outline
Helper script
Create a stub quickly:
bash scripts/new-query-note.sh /path/to/vault "How does X differ from Y?" --question "How does X differ from Y?"For a report-shaped output:
bash scripts/new-query-note.sh /path/to/vault "Q2 strategy memo" --section reportsCitation discipline
Good citations reference:
- wiki pages such as
[[wiki/concepts/example-thesis]] - raw captures such as
[[raw/sources/2026-04-08-example-article]] - source URLs when the raw file is not enough
Do not leave claims floating without a traceable page path or source.
Follow-up loop
After filing a query or report:
- update any affected concept pages
- add missing cross-links
- update
index.md - append to
log.md
The answer should improve the wiki, not just live beside it.
Schema Playbook
Use this reference when writing or refining AGENTS.md or CLAUDE.md for the vault.
What the schema must do
The schema is not prose about the idea. It is the rulebook the agent should follow every session.
Good schema files answer:
1. Which directories are immutable 2. Which files must be updated on every ingest 3. What page types exist and what they are for 4. How answers must cite pages or raw sources 5. What a lint pass should inspect
Minimum contract
At minimum, encode these rules:
1. Never rewrite files under raw/.
2. On ingest update raw capture, one source page, relevant concept/entity pages, index.md, and log.md.
3. Read index.md first for queries.
4. File durable answers back into wiki/queries/ or wiki/reports/.
5. Use wiki links for internal references.
6. During lint passes check broken links, orphan pages, stale claims, contradictions, and missing page candidates.Good additions
Add only rules that will actually change behavior:
- page frontmatter conventions
- page templates per directory
- how to mark uncertainty or contradiction
- how to label stale claims
- when to open raw sources instead of trusting the wiki
- when to create a new concept page instead of bloating an existing one
Bad additions
Avoid schema bloat:
- generic writing advice the agent already knows
- giant lists of optional tools
- vague style rules with no enforcement
- aspirational workflows you will not follow
Suggested schema sections
# Wiki Schema
## Invariants
## Page Types
## Ingest Workflow
## Query Workflow
## Lint Workflow
## Citation Rules
## Naming RulesExample page-type guidance
wiki/sources/: grounded summary tied to one raw sourcewiki/entities/: stable page for a recurring named thingwiki/concepts/: synthesis across many sourceswiki/queries/: filed answer to a reusable questionwiki/reports/: durable memo, comparison, or presentation backbone
Revision strategy
Refine the schema only when you observe repeated drift:
- the agent forgets to update
index.md - query answers stay in chat instead of being filed
- source pages lack enough grounding
- the same ambiguity shows up across multiple sessions
When that happens, add or sharpen one rule at a time.
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'EOF' >&2
Usage: bash scripts/bootstrap-vault.sh <vault_root> [--force]
Create a minimal llm-wiki vault structure with:
raw/sources/
raw/assets/
wiki/sources/
wiki/entities/
wiki/concepts/
wiki/queries/
wiki/reports/
index.md
log.md
AGENTS.md
EOF
}
if (($# < 1)); then
usage
exit 2
fi
FORCE=0
VAULT_ROOT=""
while (($# > 0)); do
case "$1" in
--force)
FORCE=1
shift
;;
-h|--help)
usage
exit 0
;;
*)
if [[ -z "$VAULT_ROOT" ]]; then
VAULT_ROOT="$1"
shift
else
echo "Unknown argument: $1" >&2
usage
exit 2
fi
;;
esac
done
if [[ -z "$VAULT_ROOT" ]]; then
usage
exit 2
fi
VAULT_ROOT="${VAULT_ROOT%/}"
write_file() {
local path="$1"
local rel="${path#$VAULT_ROOT/}"
if [[ -e "$path" && "$FORCE" -ne 1 ]]; then
echo "skip $rel"
return 0
fi
mkdir -p "$(dirname "$path")"
cat >"$path"
echo "write $rel"
}
mkdir -p \
"$VAULT_ROOT/raw/sources" \
"$VAULT_ROOT/raw/assets" \
"$VAULT_ROOT/wiki/sources" \
"$VAULT_ROOT/wiki/entities" \
"$VAULT_ROOT/wiki/concepts" \
"$VAULT_ROOT/wiki/queries" \
"$VAULT_ROOT/wiki/reports"
write_file "$VAULT_ROOT/AGENTS.md" <<'EOF'
# Wiki Schema
This vault is a persistent LLM-maintained wiki.
## Invariants
1. Treat `raw/` as immutable source of truth.
2. Treat `wiki/`, `index.md`, and `log.md` as LLM-maintained working artifacts.
3. On ingest, update the raw source capture, a source summary page, affected synthesis pages, `index.md`, and `log.md`.
4. On query, read `index.md` first, then relevant wiki pages, then raw sources only if grounding is needed.
5. File durable answers back into `wiki/queries/` or `wiki/reports/`.
6. During lint passes, look for broken links, orphan pages, stale claims, contradictions, and missing page candidates.
## Style
- Prefer markdown with wiki links to real pages in the vault.
- Use kebab-case file names and a single H1 matching the page title.
- Distinguish grounded source notes from higher-level synthesis.
- Preserve citations to page paths, raw source paths, or source URLs.
- Keep the schema short and revise it when repeated drift appears.
EOF
write_file "$VAULT_ROOT/index.md" <<'EOF'
# Index
This is the content-oriented map of the wiki. Read this file first before broad search.
## Overview
- Replace this section with a short synthesis once the wiki has a few real pages.
## Sources
<!-- SOURCES:START -->
<!-- SOURCES:END -->
## Entities
<!-- ENTITIES:START -->
<!-- ENTITIES:END -->
## Concepts
<!-- CONCEPTS:START -->
<!-- CONCEPTS:END -->
## Queries
<!-- QUERIES:START -->
<!-- QUERIES:END -->
## Reports
<!-- REPORTS:START -->
<!-- REPORTS:END -->
EOF
write_file "$VAULT_ROOT/log.md" <<'EOF'
# Log
Append-only timeline of meaningful wiki operations.
Use headings in this format:
```md
## [YYYY-MM-DD] ingest | Source title
## [YYYY-MM-DD] query | Question title
## [YYYY-MM-DD] lint | Pass summary
```
Each entry should list the files touched, the reason for the change, and any follow-up work.
EOF
echo "ready $VAULT_ROOT"
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'EOF' >&2
Usage: bash scripts/ingest-url.sh <vault_root> <url> [options] [-- extra scrapling args]
Options:
--mode <get|fetch|stealth> Scrapling mode (default: get)
--slug <slug> File slug override
--title <title> Human-readable title for the source page
--force Overwrite existing raw/source files
-h, --help Show this help
Requires the `scrapling` CLI. The raw capture is saved to raw/sources/ and
the source stub is created under wiki/sources/.
EOF
}
if (($# < 2)); then
usage
exit 2
fi
VAULT_ROOT="$1"
URL="$2"
shift 2
MODE="get"
SLUG=""
TITLE=""
FORCE=0
EXTRA_ARGS=()
while (($# > 0)); do
case "$1" in
--mode)
MODE="$2"
shift 2
;;
--slug)
SLUG="$2"
shift 2
;;
--title)
TITLE="$2"
shift 2
;;
--force)
FORCE=1
shift
;;
-h|--help)
usage
exit 0
;;
--)
shift
EXTRA_ARGS=("$@")
break
;;
*)
EXTRA_ARGS+=("$1")
shift
;;
esac
done
SCRAPLING_BIN="${SCRAPLING_BIN:-scrapling}"
if ! command -v "$SCRAPLING_BIN" >/dev/null 2>&1; then
echo "scrapling CLI not found: $SCRAPLING_BIN" >&2
echo "Install it with the scrapling skill or set SCRAPLING_BIN to a valid binary." >&2
exit 1
fi
slugify() {
printf '%s' "$1" \
| tr '[:upper:]' '[:lower:]' \
| sed -E 's#https?://##g; s#[^a-z0-9]+#-#g; s#^-+##; s#-+$##; s#-+#-#g'
}
titleize() {
printf '%s' "$1" | sed -E 's/-/ /g'
}
insert_marker_line() {
local file="$1"
local marker="$2"
local line="$3"
python3 - "$file" "$marker" "$line" <<'PY'
from pathlib import Path
import sys
path = Path(sys.argv[1])
marker = sys.argv[2]
line = sys.argv[3]
text = path.read_text(encoding="utf-8")
anchor = f"<!-- {marker}:END -->"
if line in text:
raise SystemExit(0)
if anchor not in text:
text = text.rstrip() + "\n\n" + line + "\n"
else:
text = text.replace(anchor, line + "\n" + anchor)
path.write_text(text, encoding="utf-8")
PY
}
append_log() {
local file="$1"
local heading="$2"
local body="$3"
if grep -Fq "$heading" "$file"; then
return 0
fi
{
printf '\n%s\n' "$heading"
printf '%s\n' "$body"
} >>"$file"
}
DATE="$(date +%F)"
STAMP="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
VAULT_ROOT="${VAULT_ROOT%/}"
SLUG="${SLUG:-$(slugify "$URL")}"
TITLE="${TITLE:-$(titleize "$SLUG")}"
mkdir -p "$VAULT_ROOT/raw/sources" "$VAULT_ROOT/wiki/sources"
RAW_REL="raw/sources/${DATE}-${SLUG}.md"
RAW_PATH="$VAULT_ROOT/$RAW_REL"
SOURCE_REL="wiki/sources/${DATE}-${SLUG}.md"
SOURCE_PATH="$VAULT_ROOT/$SOURCE_REL"
if [[ -e "$RAW_PATH" && "$FORCE" -ne 1 ]]; then
echo "raw source already exists: $RAW_PATH" >&2
echo "Use --force to overwrite." >&2
exit 1
fi
if [[ -e "$SOURCE_PATH" && "$FORCE" -ne 1 ]]; then
echo "source page already exists: $SOURCE_PATH" >&2
echo "Use --force to overwrite." >&2
exit 1
fi
case "$MODE" in
get)
CMD=(extract get)
;;
fetch|dynamic)
CMD=(extract fetch)
;;
stealth|protected|stealthy-fetch)
CMD=(extract stealthy-fetch)
;;
*)
echo "Unsupported mode: $MODE" >&2
exit 2
;;
esac
SCRAPLING_CALL=("$SCRAPLING_BIN" "${CMD[@]}" "$URL" "$RAW_PATH")
if ((${#EXTRA_ARGS[@]})); then
SCRAPLING_CALL+=("${EXTRA_ARGS[@]}")
fi
"${SCRAPLING_CALL[@]}"
cat >"$SOURCE_PATH" <<EOF
---
title: "$TITLE"
source_type: "web"
source_url: "$URL"
raw_path: "$RAW_REL"
ingested_at: "$STAMP"
status: "pending-synthesis"
---
# $TITLE
## Summary
- [ ] Replace with an LLM-written summary grounded in \`$RAW_REL\`
## Key Claims
- [ ] Add grounded claims with citations
## Related Pages
- [ ] Link relevant entity and concept pages
## Contradictions or Uncertainty
- [ ] Note anything that conflicts with existing wiki pages
## Open Questions
- [ ] Add follow-up questions worth investigating
EOF
insert_marker_line "$VAULT_ROOT/index.md" "SOURCES" "- [[${SOURCE_REL%.md}]] - Pending synthesis for ${TITLE}"
append_log \
"$VAULT_ROOT/log.md" \
"## [$DATE] ingest | $TITLE" \
"- URL: $URL
- Raw source: [[${RAW_REL%.md}]]
- Source page: [[${SOURCE_REL%.md}]]
- Mode: $MODE"
echo "captured $RAW_PATH"
echo "created $SOURCE_PATH"
#!/usr/bin/env python3
from __future__ import annotations
import argparse
import json
import re
import sys
from collections import defaultdict
from pathlib import Path
WIKILINK_RE = re.compile(r"\[\[([^\]|#]+)(?:[#|][^\]]*)?\]\]")
IGNORE_DIRS = {".git", ".obsidian", ".trash"}
REQUIRED_PATHS = [
"AGENTS.md",
"index.md",
"log.md",
"raw/sources",
"raw/assets",
"wiki/sources",
"wiki/entities",
"wiki/concepts",
"wiki/queries",
"wiki/reports",
]
def collect_pages(vault_root: Path) -> dict[str, Path]:
pages: dict[str, Path] = {}
for path in vault_root.rglob("*.md"):
if any(part in IGNORE_DIRS for part in path.parts):
continue
rel = path.relative_to(vault_root)
if rel.name in {"AGENTS.md", "CLAUDE.md"}:
continue
if rel.parts and rel.parts[0] == "raw":
continue
key = rel.with_suffix("").as_posix()
pages[key] = path
return pages
def build_basename_index(pages: dict[str, Path]) -> dict[str, list[str]]:
index: dict[str, list[str]] = defaultdict(list)
for rel in pages:
index[Path(rel).name].append(rel)
return index
def resolve_target(target: str, basename_index: dict[str, list[str]], pages: dict[str, Path]) -> str | None:
normalized = target.strip().strip("/")
if not normalized:
return None
normalized = normalized.removesuffix(".md")
if normalized in pages:
return normalized
matches = basename_index.get(Path(normalized).name, [])
if len(matches) == 1:
return matches[0]
return None
def lint(vault_root: Path) -> dict[str, object]:
missing = [item for item in REQUIRED_PATHS if not (vault_root / item).exists()]
pages = collect_pages(vault_root)
basename_index = build_basename_index(pages)
inbound: dict[str, int] = {key: 0 for key in pages}
broken_links: list[dict[str, str]] = []
for rel, path in pages.items():
text = path.read_text(encoding="utf-8")
for raw_target in WIKILINK_RE.findall(text):
resolved = resolve_target(raw_target, basename_index, pages)
if resolved is None:
broken_links.append({"page": rel, "target": raw_target})
continue
if resolved != rel:
inbound[resolved] += 1
orphan_pages = sorted(
rel
for rel, count in inbound.items()
if rel not in {"index", "log"} and count == 0
)
return {
"vault_root": str(vault_root),
"missing_paths": missing,
"page_count": len(pages),
"broken_links": broken_links,
"orphan_pages": orphan_pages,
}
def render_text(report: dict[str, object]) -> str:
lines = [
f"Vault: {report['vault_root']}",
f"Pages: {report['page_count']}",
"",
]
missing = report["missing_paths"]
broken = report["broken_links"]
orphan = report["orphan_pages"]
if missing:
lines.append("Missing required paths:")
lines.extend(f"- {item}" for item in missing)
lines.append("")
if broken:
lines.append("Broken wiki links:")
lines.extend(f"- {item['page']} -> [[{item['target']}]]" for item in broken)
lines.append("")
if orphan:
lines.append("Orphan pages:")
lines.extend(f"- {item}" for item in orphan)
lines.append("")
if not missing and not broken and not orphan:
lines.append("No structural issues found.")
return "\n".join(lines).rstrip() + "\n"
def main() -> int:
parser = argparse.ArgumentParser(description="Lint an llm-wiki vault for structural issues.")
parser.add_argument("vault_root", help="Path to the vault root")
parser.add_argument(
"--format",
choices=("text", "json"),
default="text",
help="Output format",
)
args = parser.parse_args()
vault_root = Path(args.vault_root).expanduser().resolve()
if not vault_root.exists():
print(f"Vault root not found: {vault_root}", file=sys.stderr)
return 1
report = lint(vault_root)
if args.format == "json":
print(json.dumps(report, indent=2))
else:
sys.stdout.write(render_text(report))
has_issues = bool(report["missing_paths"] or report["broken_links"] or report["orphan_pages"])
return 1 if has_issues else 0
if __name__ == "__main__":
raise SystemExit(main())
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'EOF' >&2
Usage: bash scripts/new-query-note.sh <vault_root> <title> [options]
Options:
--section <queries|reports> Target directory and index section (default: queries)
--question <text> Original question text
--citation <wikilink> Repeatable citation seed
--force Overwrite an existing note
-h, --help Show this help
EOF
}
if (($# < 2)); then
usage
exit 2
fi
VAULT_ROOT="$1"
TITLE="$2"
shift 2
SECTION="queries"
QUESTION=""
FORCE=0
CITATIONS=()
while (($# > 0)); do
case "$1" in
--section)
SECTION="$2"
shift 2
;;
--question)
QUESTION="$2"
shift 2
;;
--citation)
CITATIONS+=("$2")
shift 2
;;
--force)
FORCE=1
shift
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown argument: $1" >&2
usage
exit 2
;;
esac
done
case "$SECTION" in
queries|reports)
;;
*)
echo "Unsupported section: $SECTION" >&2
exit 2
;;
esac
slugify() {
printf '%s' "$1" \
| tr '[:upper:]' '[:lower:]' \
| sed -E 's#[^a-z0-9]+#-#g; s#^-+##; s#-+$##; s#-+#-#g'
}
insert_marker_line() {
local file="$1"
local marker="$2"
local line="$3"
python3 - "$file" "$marker" "$line" <<'PY'
from pathlib import Path
import sys
path = Path(sys.argv[1])
marker = sys.argv[2]
line = sys.argv[3]
text = path.read_text(encoding="utf-8")
anchor = f"<!-- {marker}:END -->"
if line in text:
raise SystemExit(0)
if anchor not in text:
text = text.rstrip() + "\n\n" + line + "\n"
else:
text = text.replace(anchor, line + "\n" + anchor)
path.write_text(text, encoding="utf-8")
PY
}
append_log() {
local file="$1"
local heading="$2"
local body="$3"
if grep -Fq "$heading" "$file"; then
return 0
fi
{
printf '\n%s\n' "$heading"
printf '%s\n' "$body"
} >>"$file"
}
DATE="$(date +%F)"
STAMP="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
SLUG="$(slugify "$TITLE")"
DIR="$VAULT_ROOT/wiki/$SECTION"
FILE_REL="wiki/$SECTION/${DATE}-${SLUG}.md"
FILE_PATH="$VAULT_ROOT/$FILE_REL"
MARKER="$(printf '%s' "$SECTION" | tr '[:lower:]' '[:upper:]')"
mkdir -p "$DIR"
if [[ -e "$FILE_PATH" && "$FORCE" -ne 1 ]]; then
echo "query note already exists: $FILE_PATH" >&2
echo "Use --force to overwrite." >&2
exit 1
fi
{
cat <<EOF
---
title: "$TITLE"
created_at: "$STAMP"
section: "$SECTION"
status: "draft"
---
# $TITLE
## Question
${QUESTION:-[Fill in the exact question that produced this note.]}
## Answer
- [ ] Replace with the durable answer
## Evidence and Citations
EOF
if ((${#CITATIONS[@]})); then
for citation in "${CITATIONS[@]}"; do
printf -- '- %s\n' "$citation"
done
else
printf -- '- [ ] Add wiki page citations and raw source references\n'
fi
cat <<'EOF'
## Follow-up Questions
- [ ] Add follow-up questions worth reusing later
## Filing Notes
- [ ] Link any concept, entity, or source pages that should be updated after this answer
EOF
} >"$FILE_PATH"
insert_marker_line "$VAULT_ROOT/index.md" "$MARKER" "- [[${FILE_REL%.md}]] - ${TITLE}"
append_log \
"$VAULT_ROOT/log.md" \
"## [$DATE] query | $TITLE" \
"- Filed note: [[${FILE_REL%.md}]]
- Section: $SECTION"
echo "created $FILE_PATH"
Experiment 0 - baseline
Score: 4/6 Change: Initial draft only. Reasoning: Establish the baseline before mutating the skill. Result: The gist pattern was translated correctly at a high level, but the skill still behaved too much like an abstract concept note instead of an executable workflow. Remaining failures: Query filing and lint execution were not concrete enough.
Experiment 1 - keep
Score: 6/6 Change: Added concrete helper scripts, Scrapling escalation commands, query filing stubs, lint tooling, and focused references. Reasoning: The main risk was that a future agent would understand the philosophy but still have to invent the workflow from scratch. Result: All six binary evals passed after the skill gained explicit commands, output paths, and operational references. Remaining failures: None in the current eval suite.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>llm-wiki skill autoresearch</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
:root {
--bg: #f3efe7;
--panel: #fffaf4;
--ink: #1d1b19;
--muted: #655f57;
--line: #d8cec0;
--keep: #166534;
--base: #9a6700;
}
body {
margin: 0;
padding: 32px;
font-family: "Iowan Old Style", "Palatino Linotype", serif;
color: var(--ink);
background:
radial-gradient(circle at top left, rgba(94, 133, 132, 0.16), transparent 28%),
linear-gradient(180deg, #faf6ef, var(--bg));
}
.wrap {
max-width: 980px;
margin: 0 auto;
}
h1, h2 {
margin: 0 0 12px;
}
p {
color: var(--muted);
line-height: 1.5;
}
.grid {
display: grid;
gap: 16px;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
margin: 24px 0;
}
.card {
background: var(--panel);
border: 1px solid var(--line);
border-radius: 18px;
padding: 18px;
box-shadow: 0 12px 24px rgba(40, 35, 29, 0.06);
}
table {
width: 100%;
border-collapse: collapse;
background: var(--panel);
border: 1px solid var(--line);
border-radius: 18px;
overflow: hidden;
}
th, td {
padding: 12px 14px;
border-bottom: 1px solid var(--line);
text-align: left;
vertical-align: top;
font-size: 14px;
}
th {
background: #ece2d4;
}
.status-keep { color: var(--keep); font-weight: 700; }
.status-baseline { color: var(--base); font-weight: 700; }
code {
background: #efe6d9;
padding: 2px 6px;
border-radius: 6px;
}
</style>
</head>
<body>
<div class="wrap">
<h1>llm-wiki skill autoresearch</h1>
<p>Baseline versus improved behavior for the local <code>llm-wiki</code> skill. This run focused on turning the original concept into a concrete Obsidian and markdown workflow.</p>
<div class="grid">
<div class="card">
<h2>Baseline</h2>
<p>Experiment 0 scored 4/6. The architecture was present, but filing answers back into the wiki and running lint as a real command were still too abstract.</p>
</div>
<div class="card">
<h2>Final</h2>
<p>Experiment 1 scored 6/6 after adding concrete scripts for bootstrap, ingest, query filing, and linting plus focused reference documents.</p>
</div>
<div class="card">
<h2>Focus</h2>
<p>Binary evals concentrated on bootstrapping, ingest operations, Scrapling escalation, query filing, lint tooling, and reference hygiene.</p>
</div>
</div>
<table>
<thead>
<tr>
<th>Experiment</th>
<th>Status</th>
<th>Score</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
<tr>
<td>0</td>
<td class="status-baseline">baseline</td>
<td>4 / 6</td>
<td>Initial draft described the vault pattern but did not yet operationalize query filing or lint execution.</td>
</tr>
<tr>
<td>1</td>
<td class="status-keep">keep</td>
<td>6 / 6</td>
<td>Kept mutation added helper scripts, stronger ingest detail, and cleaner separation between the main skill and supporting references.</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
{
"skill_name": "llm-wiki",
"status": "complete",
"updated_at": "2026-04-08T07:50:00Z",
"evals": [
{
"id": "bootstrap-coverage",
"question": "Does the skill operationalize the vault bootstrap with raw and wiki layers, index.md, log.md, and a schema file?"
},
{
"id": "ingest-operations",
"question": "Does the skill describe a concrete ingest flow that updates the raw capture, a source page, index.md, and log.md?"
},
{
"id": "scrapling-escalation",
"question": "Does the skill explain when to use static versus dynamic or stealth Scrapling ingestion?"
},
{
"id": "query-filing",
"question": "Does the skill tell the agent to read index.md first and file durable answers into queries or reports?"
},
{
"id": "lint-tooling",
"question": "Does the skill point to a concrete lint command and the kinds of issues it should surface?"
},
{
"id": "reference-support",
"question": "Does the skill keep the main SKILL.md focused and push detail into scripts and reference files?"
}
],
"experiments": [
{
"experiment": 0,
"score": 4,
"max_score": 6,
"pass_rate": 0.6667,
"status": "baseline",
"description": "Initial draft conveyed the architecture and the ingest/query/lint idea, but it left filing and lint execution under-specified and did not turn Scrapling usage into a concrete command path.",
"kept": true,
"per_eval": {
"bootstrap-coverage": true,
"ingest-operations": true,
"scrapling-escalation": true,
"query-filing": false,
"lint-tooling": false,
"reference-support": true
}
},
{
"experiment": 1,
"score": 6,
"max_score": 6,
"pass_rate": 1.0,
"status": "keep",
"description": "Kept mutation: added bootstrap, ingest, query-note, and lint scripts plus focused reference files for schema, ingest, filing, and scaling decisions.",
"kept": true,
"per_eval": {
"bootstrap-coverage": true,
"ingest-operations": true,
"scrapling-escalation": true,
"query-filing": true,
"lint-tooling": true,
"reference-support": true
}
}
]
}
experiment score max_score pass_rate status description
0 4 6 0.6667 baseline Initial draft captured the three-layer model and ingest idea but did not make query filing or lint execution operational, and only lightly covered the Scrapling escalation path.
1 6 6 1.0000 keep Added concrete bootstrap, URL ingest, query filing, lint scripts, and focused references for schema, ingest, filing, and scaling.
---
name: llm-wiki
description: >
Build a persistent markdown wiki that an LLM maintains on the user's behalf from raw sources,
index files, and a schema document. Use when the user wants an Obsidian or markdown knowledge
base instead of one-shot retrieval from raw files.
allowed-tools: Bash Read Write Edit Glob Grep WebFetch
license: Idea adapted into repository skill implementation
metadata:
tags: llm-wiki, obsidian, knowledge-base, markdown, research, wiki
version: "0.1"
source: https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f
---
# llm-wiki
Use this skill to turn raw sources into a persistent markdown wiki.
## Core workflow
1. Create a vault with `raw/`, `wiki/`, `index.md`, `log.md`, and `AGENTS.md`
2. Save raw sources under `raw/`
3. Create wiki pages under `wiki/`
4. Update `index.md` and `log.md`
## Ingest
For URLs, capture the page and create a source summary page. Use Scrapling if the source is on the web.
## Query
Answer questions from the wiki and cite relevant pages.
## Lint
Check the wiki for contradictions, stale claims, and orphan pages.
## Notes
Add qmd or other search tooling later if the wiki gets too large for simple navigation.
N:llm-wiki
D:[llm-wiki] Build and maintain a persistent markdown wiki that an LLM updates on the user's behalf from immutable raw sources, wiki pages, index/log files, and a schema document.
G:llm-wiki obsidian knowledge-base markdown research synthesis scrapling qmd notes wiki
U[8]:
Bootstrap a git-tracked or Obsidian vault with raw sources wiki pages index log and schema files
Treat AGENTS.md or CLAUDE.md as the operating contract for ingest query and lint workflows
Ingest local files or URLs into raw sources and create source summary pages
Use Scrapling for URL capture and escalate from static to dynamic to stealth fetch only when needed
Read index.md first when answering questions and file durable outputs back into the wiki
Create query or report stubs instead of losing good answers in chat history
Run lint passes for broken links orphan pages stale claims and missing cross references
Add qmd or other search tooling only when index plus log is no longer enough
S[6]{n,action,details}:
1,Bootstrap,run bash scripts/bootstrap-vault.sh /path/to/vault to create raw wiki index log and AGENTS.md
2,Define schema,keep AGENTS.md or CLAUDE.md as the durable workflow contract for ingest query and lint rules
3,Ingest,bash scripts/ingest-url.sh /path/to/vault "https://example.com/article" or place local files under raw/sources then update wiki pages index and log
4,Query,read index.md first open relevant wiki pages cite sources and file durable answers with bash scripts/new-query-note.sh
5,Lint,run python3 scripts/lint-wiki.py /path/to/vault and repair broken links orphan pages and stale claims
6,Scale,add qmd search Obsidian CLI Dataview or other helpers only when the markdown workflow outgrows index plus log
R[8]:
Keep raw sources immutable and do not rewrite captured material in place
Update index.md and log.md every time the wiki changes in a durable way
Prefer one source at a time until the schema and page conventions are stable
Source pages should stay grounded while concept and entity pages can synthesize across many sources
Read index.md before expensive retrieval or broad grep passes
File good answers back into wiki queries or reports instead of leaving them in chat only
Use git commits to separate ingest query and lint operations for reviewability
Keep the schema small and revise it whenever repeated drift shows up
E[6]{type,command}:
Bootstrap,bash scripts/bootstrap-vault.sh ~/vaults/company-research
Static ingest,bash scripts/ingest-url.sh ~/vaults/company-research "https://example.com/article"
Dynamic ingest,bash scripts/ingest-url.sh ~/vaults/company-research "https://app.example.com/post" --mode fetch --network-idle
Query note,bash scripts/new-query-note.sh ~/vaults/company-research "How the market is changing" --question "How is the market changing?"
Report,bash scripts/new-query-note.sh ~/vaults/company-research "Q3 diligence memo" --section reports
Lint,python3 scripts/lint-wiki.py ~/vaults/company-research --format json