Ingest
A Claude Code plugin for Obsidian — Karpathy's LLM Wiki shipped as a four-layer, hook-enforced agent stack with multi-agent orchestration.
npx -y skills add odere-pro/claude-wiki-pages-plugin --skill ingestAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Ingest one or more sources from vault/raw/ into typed wiki pages under vault/wiki/. Trigger when the user says "ingest this source", "process the file I just dropped in raw/", "add this to the wiki", or invokes /claude-wiki-pages:ingest directly. Prefer the pipeline (/claude-wiki-pages:claude-wiki-pages-ingest-agent) unless the user has asked to skip lint-fix and synthesis.
SKILL.md
15.1 KB, as published. Nobody here has run it
LLM Wiki — Ingest
Process sources under vault/raw/ into the wiki. This skill is the
single-responsibility ingest verb; it is the middle third of what the
claude-wiki-pages-ingest-agent agent does. The agent wraps this skill with a
post-ingest lint-fix pass and an optional synthesis step — invoke the agent
when the user wants the full cycle, invoke this skill when the user wants only
the ingest portion.
Authoring voice
Author every page to the house voice — see skills/voice.
Open each page with a one-line, plain-language definition, then the typed
content in the engineer register: exact terms, no marketing language inside the
vault. Provenance stays factual (sources, derived, confidence are facts,
not adjectives).
When to invoke
- A file exists under
vault/raw/that has no corresponding entry invault/wiki/log.mdunder a## [YYYY-MM-DD] ingest | <title>header. - The user explicitly requests ingest-only (skipping lint and synthesis).
- An agent is chaining ingest as a step.
Reading contract
vault/raw/— the sources themselves. Immutable. Enforced byprotect-raw.sh.vault/CLAUDE.md— the schema. Read first, before touching any source. Its "Linking conventions" section is normative for every link this skill emits.vault/wiki/— to detect existing pages for the entities and concepts the new source mentions. This skill extends existing pages rather than duplicating them.vault/wiki/log.md— to detect already-ingested sources.
Writing contract
Writes are confined to these paths:
| Path | Write intent |
|---|---|
vault/wiki/_sources/<slug>.md | One new summary per never-before-seen source. Body is Metadata, Summary, Key Claims (prose) — NO outbound [[wikilink]] sections; provenance is page → source via each page's sources:. |
vault/wiki/<topic>/*.md | New or updated typed pages (entity or concept). |
vault/wiki/<topic>/<topic>.md (folder note; legacy _index.md if present) | Backfill children: and child_indexes: (quoted "[[wikilink]]" entries) for every folder this skill touches. |
vault/wiki/index.md | Append new top-level pages to the vault MOC. |
vault/wiki/log.md | Append ## [YYYY-MM-DD] ingest | <Source Title> at the bottom. |
This skill MUST NOT:
- Write to
vault/raw/. - Write synthesis notes under
vault/wiki/_synthesis/. - Delete any existing page.
- Renumber, reorder, or rebuild
wiki/index.md(that isindex's role; this skill only appends).
Classification checklist
Every new page extracted during ingest (step 3b below) must be classified before it is written. Work through this checklist for each item.
Enum authority: read the allowed values from ontology-profile-v1 in
vault/CLAUDE.md — that section is the single source of truth for the
type enum and the entity_type enum. Do not restate or copy those lists
here; they live there and only there.
- Assign exactly one
typefrom thetypeenum inontology-profile-v1(vault/CLAUDE.md). The vault's effective enum is the closed core set; it is not owner-extensible (adding a type requires a schema change). - For
type: entitypages, assign exactly oneentity_typefrom theentity_typeenum inontology-profile-v1(vault/CLAUDE.md). The effective legal set is the fixed core union anyentity_type_extensionslist declared in the active vault's ownvault/CLAUDE.md(decision #6); compose the two lists at read time. - Out-of-enum items: if the extracted item does not fit any legal value, direct it to the closest legal type that best captures its nature. If no reasonable mapping exists, flag it as a human decision — never invent an out-of-enum value. Annotate the page with an inline comment explaining the mapping choice so a reviewer can verify or override it.
- Provenance unchanged: a classified page still requires
sourceslinking back to the originatingraw/file. Classification does not replace or weaken thesources,source_quotes,derived, orconfidencefields.
Dedup: two-pass existence check (I2)
Before creating a new page for any extracted entity or concept, run a deterministic two-pass existence check — exact title or alias string match only. Deterministic string comparison only; no probabilistic or approximate matching (§5 non-negotiable).
DRY invariant: one page per concept / entity. A fact lives in exactly one page; the dedup check enforces this alias-aware.
Pass 1 — exact title match
Compare the extracted concept name (case-insensitive) against the title field
of every existing page under vault/wiki/. If an exact title match is found,
extend that page — never create a duplicate.
Pass 2 — alias-aware match
If pass 1 finds no match, compare the extracted concept name (case-insensitive)
against every entry in the aliases list of every existing page under
vault/wiki/. Example: a source about "automobile" must extend the existing
"Car" page that carries aliases: ["automobile", "car"], not create a new page.
If an alias match is found, extend the existing page (add the new source to
sources, increment update_count, advance updated) — never create a
duplicate.
Additive merge: sources are never dropped
When either pass finds a match, perform an additive merge: existing sources
are never dropped, overwritten, or lost. Every merge operation:
- Adds the new source to the page's
sourceslist (append only). - Increments
update_count. - Advances
updatedto today's date. - Recalculates
confidenceper the confidence-discipline rules.
Wikilink emission — piped, basename-targeted, path-qualified
Every [[link]] this skill writes — in body text and in every frontmatter
link field (parent, sources, related, children, child_indexes,
key_pages, members, scope, depends_on) — MUST follow the schema's
"Linking conventions". Obsidian resolves a written [[target]] by exact vault
path or filename basename only — never by a note's aliases: or title:. A
bare [[Title Case]] link does not resolve; it floats as a ghost node and
orphans the target.
Concretely, when emitting any link:
- Target the destination's file basename, with the Title-Case page title as
piped display:
[[entity-name|Entity Name]]. Never emit a bare[[Entity Name]]. Default to this bare-basename form. - Path-qualify ONLY on a genuine vault-wide collision — the basename occurs
in 2+ files anywhere in the vault (including
raw/originals). Awiki/_sources/adr-0001-x.mdsummary and itsraw/docs/adr/ADR-0001-x.mdoriginal share a basename, so a bare-basename link silently routes to the wrong file. Then use the target's actual wiki-relative path (no extension), verified to exist:[[_sources/adr-0001-four-layer-orchestrator|ADR-0001: Four-Layer Orchestrator]]. Never guess the folder — over-qualifying a unique basename with a wrong folder produces a dangling link. parenttargets the containing folder note's basename:parent: "[[<folder>|<Folder Title>]]".sourcesentries target each source summary's basename (path-qualify if it collides with itsraw/original):sources: ["[[<source-slug>|<Source Title>]]"].aliasesstill carry useful display variants for search and autocomplete — they do not make a written link resolve, so never rely on an alias in place of the piped basename form.
When no match is found in either pass, create a new typed page for the concept.
Author it from the body skeleton in vault/_templates/<type>.md: copy that
template's ## Section headings verbatim (concept → ## Definition,
## Key Principles, ## Examples, ## Related Concepts; entity → ## Overview,
## Key Facts, ## Related; and so on per type) and fill each with the
extracted content. Do not invent your own headings — lint-structural.sh
flags any missing template section as a missing-section warning, and verify
alone does not catch it.
Workflow
Follow the 13-step ingest sequence in vault/CLAUDE.md exactly. The short
version:
- Read the schema.
- Identify unprocessed sources (compare
vault/raw/againstvault/wiki/log.md). - For each source:
a. Write the summary to
wiki/_sources/— Metadata, Summary, Key Claims (prose), with NO outbound[[wikilink]]sections. Provenance is one-directional, page → source: the source is reached through thesources:citation on each page it informs (steps e below), so it clusters with its topic instead of bridging every topic it touches. b. Extract entities and concepts. For each extracted item, apply the Classification checklist above before writing the page. c. For each extracted item, run the two-pass existence check (see "Dedup: two-pass existence check" above): pass 1 = exact title match; pass 2 = alias-aware match against existing pages'aliasesfields. If either pass finds a match, extend that page (additive merge — existingsourcesare never dropped). Only create a new typed page when both passes return no match. d. For each extracted item, locate or create its topic folder. e. Add the new source to each touched page'ssources:. f. Incrementupdate_count; advanceupdated. g. Recalculateconfidenceper the confidence-discipline rules. h. Update the per-folder folder note'schildren:/child_indexes:(create new folders' indexes at the folder-note name<folder>/<folder>.md; update a legacy_index.mdin place when one already exists — never create a new_index.md). - Append to
wiki/log.md. - Print a summary table: sources processed, pages created, pages updated, folders touched.
Agent-session sources: ingest like any source (no laundering)
A source_type: agent-session file written by the Stop/SessionEnd hook into
raw/agent-sessions/ is a real raw source (type: source). It enters the
wiki through the same _proposed/ review gate as every other source — never
as an unsourced derived: true page.
Concretely:
- The hook writes
raw/agent-sessions/<session-id>-<timestamp>.mdand commits it. - The next
/claude-wiki-pages:wikior maintenance pass detects it as an unprocessed source (not yet inwiki/log.md). - Ingest creates
wiki/_sources/<slug>.mdwithsource_type: agent-sessionand extracts entities/concepts as drafts under_proposed/. propose approve(or the review gate) promotes drafts towiki/.- Every promoted wiki page lists the agent-session source in its
sourcesfield, keeping provenance structural.
Never write a session learning as derived: true or promote it directly to
wiki/ without going through _proposed/. Provenance is structural (TEAM-BRIEF §5).
PDF sources (I4): source_format: pdf
A PDF file under raw/assets/ is ingested the same way as any other source —
the difference is format-recording in the source note's frontmatter and the
text-extraction step.
How the PDF ingest path works
-
The PDF lives immutably under
raw/assets/. It is append-only raw material. Ingest READS it; it never modifies it.protect-raw.shenforces this invariant (rules/raw-immutable.md). -
The LLM extracts content. Text extraction is the LLM's responsibility — the schema records the format and the attachment reference; it does not prescribe the extraction mechanism. The model reads the PDF and treats the extracted text as the source's content.
-
Create the source note with required fields. The source note at
wiki/_sources/<slug>.mdmust carry:source_format: pdf attachment_path: "raw/assets/<file>.pdf" extracted_at: <YYYY-MM-DD>source_format: pdfsignals that the original is a PDF (not markdown/plain text).attachment_pathpoints to the PDF underraw/assets/so the attachment is traceable.extracted_atrecords when extraction occurred. Bothattachment_pathandextracted_atare required whensource_formatis nottext—validate-frontmatter.shenforces this and blocks the write if either field is absent. -
Extract entities and concepts as usual. Apply the Classification checklist and the two-pass dedup exactly as for any source. The PDF format does not change classification or dedup logic.
-
Provenance via
sourcesis unchanged. Every wiki page extracted from a PDF source lists the source note in itssourcesfield, tracing the claim back toraw/exactly as for text or image sources.
Source note template for a PDF source
---
title: "Document Title"
type: source
source_type: paper # or manual, book, policy, etc.
source_format: pdf
attachment_path: "raw/assets/<file>.pdf"
extracted_at: 2026-06-05
url: ""
author: "Author Name"
publisher: "Publisher"
date_published: 2026-06-01
date_ingested: 2026-06-05
tags: []
aliases: ["Document Title"]
sources: []
created: 2026-06-05
updated: 2026-06-05
status: active
confidence: 1.0
---
Deferred: audio/video formats (
source_format: audio,transcript_path) are Phase 3 (I5). Do not implement until explicitly assigned.
Hook enforcement
Every Write triggers Layer 4 gates:
validate-frontmatter.shrejects missing or malformed frontmatter.check-wikilinks.shrejects markdown links where wikilinks are required (thesources:field, cross-page references).validate-attachments.shrejects source pages referencing missing files underraw/assets/.protect-raw.shrejects any accidental write underraw/.post-wiki-write.shprints a reminder about folder-note (per-folder index) upkeep after every page write.
If any hook returns exit 2, surface the error verbatim. Do not retry the write unchanged — adjust the content to satisfy the hook.
Completion signal
On success, print:
READY: <N> sources ingested, <M> pages written (<C> created, <U> updated).
The claude-wiki-pages-ingest-agent agent looks for this prefix to know it can hand off
to claude-wiki-pages-curator-agent.
Context contract
Machine-readable read/write contract for the engine context verb.
| role | globs |
|---|---|
| inputs (L4) | raw/, raw/wired/ |
| reference (L3) | vault/CLAUDE.md, wiki/_sources/** |
| outputs | wiki/_sources/*, wiki/** |