Wiki Warehouse
The vault is the index; a separate private GitHub repo (knowledge-warehouse) is the
warehouse. Originals and full extracted text live in the warehouse. The vault gets
only a lean Source note — summary, key excerpts, and a content-hash pointer — so it
stays fast and its git history stays small. The two are joined by a doc_id (a sha256
content hash), never a path, so warehouse files can be reorganized without breaking the
vault.
This skill owns the intake pathway. It does not replace wiki-synthesizer — the
synthesizer still compiles the resulting Source note into Knowledge/ concepts. Think of
it as: warehouse ingests the artifact → synthesizer distills its meaning.
Prerequisites
- The
obsidian-vault MCP server connected (same as wiki-operator). Verify with /mcp.
- The
knowledge-warehouse repo cloned locally, with push access. The intake tool is
bin/intake.py in that repo; the vault side is this skill.
- For born-digital PDFs (the common case), one extractor available to
intake.py:
pip install pymupdf is enough. Scanned documents additionally need an OCR tool
(apt install ocrmypdf) — intake.py detects and reports this per document.
If the MCP server or the warehouse clone is unavailable, stop and tell the user — do not
simulate ingestion or write a Source note with a pointer to a file that wasn't stored.
Principles
- The binary never enters the vault. Originals and full text live only in the
warehouse. The vault holds a summary + excerpts + pointer. If you catch yourself about
to paste full document text into a note, stop.
- Content hash is the identity. The
doc_id (sha256) is the join key. Never key the
vault note to a file path — paths change, hashes don't.
- Ingest is idempotent.
intake.py dedupes by content hash. Re-ingesting the same
file is a no-op that reports the existing location; never create a second Source note
for a doc_id that already has one (search the vault first).
- Distill, don't dump. The Source note's summary and excerpts are curated — a few key
quotes and a paragraph, not the first N pages. The full text is one click away in the
warehouse for when it's actually needed.
- Confirm before committing to the warehouse. Pushing to the private warehouse is an
external, durable action — show what will be stored and get confirmation before the
push, unless the user said to just do it.
/ingest [file] [title]
Store a raw document in the warehouse and index it in the vault.
- Locate the file the user provided (a path, or a file they attached). Confirm it
exists.
- Run the warehouse intake tool from the warehouse repo:
python bin/intake.py <file> --title "<title>"
This hashes the file, dedupes, copies the original into raw/<year>/, extracts text
into text/<year>/, updates manifest.json, and prints a frontmatter block plus a
short excerpt. Capture that output — the doc_id, paths, extraction_method, and
excerpt are what the vault note needs.
- If intake reports "already ingested," search the vault for a Source note carrying
that
doc_id. If one exists, stop and point the user to it. If not (warehoused but
never indexed), continue from step 4 using the existing paths.
- If intake reports little/no text (a scan with no OCR tool), tell the user: the
original is safely stored, but there's no searchable text yet. Offer to proceed with
a metadata-only note now, or pause until they install
ocrmypdf and re-run intake to
backfill the text.
- Commit + push the warehouse. Confirm with the user, then commit the new
raw/,
text/, and manifest.json (or run intake with --commit and push). The original must
be safely in the remote before the vault points at it.
- Read the extracted text from the warehouse's
text/<year>/…txt to write the note
from the actual content (not just the excerpt) — but keep only a short summary + a few
key excerpts in the note.
- Search the vault (
search_notes) for an existing page on this topic before
creating anything — one canonical Source note per document.
- Write the Source note to
Sources/<subfolder>/<title>.md via the MCP write_note,
using the warehouse frontmatter contract (see references/warehouse-schema.md):type: source
status: draft
confidence: medium
updated: <today>
warehouse_repo: Hefrock/knowledge-warehouse
doc_id: sha256:<hash>
warehouse_path: raw/<year>/<slug>-<shortid>.<ext>
text_path: text/<year>/<slug>-<shortid>.txt
extraction_method: <method>
Body: a ## Summary (a paragraph you distilled), ## Key excerpts (a few verbatim
quotes with rough locators), and ## Connections linking to relevant Knowledge/
pages — creating status: draft stubs for concepts that don't exist yet, exactly as
the synthesizer does.
- Confirm in one line what happened: what was warehoused (doc_id + path), and which
vault note now points to it.
/warehouse-audit
Reconcile the two sides. This runs in two halves — the warehouse-side integrity check is
a script; the vault-side pointer check uses MCP.
Half 1 — warehouse integrity (run the tool). From the warehouse repo:
python bin/audit.py --json
audit.py re-hashes every stored original against its doc_id (catching silent swaps or
bit-rot), confirms every manifest path resolves, and reports corrupt, missing,
orphan, and drift. Surface any CORRUPT finding prominently — it means a stored
original no longer matches its own hash, which is the one failure the whole content-hash
design exists to detect. Do not "fix" corruption automatically; report it and let the
user restore the file.
Half 2 — vault pointers (use MCP). The script can't see the vault, so check the other
direction here:
- Query the vault for all notes carrying a
doc_id (query_frontmatter).
- Load the warehouse
manifest.json (or reuse the audit output).
- For each vault
doc_id: confirm it exists in the manifest, and that the note's
warehouse_path / text_path match the manifest's current paths (the manifest is the
source of truth — if they drifted, the note is stale, not the manifest).
- Report four buckets: dangling (doc_id not in manifest — original may have been
removed), drifted (paths in the note no longer match the manifest — offer to patch
the note's frontmatter to the manifest's current paths), orphaned-in-warehouse
(manifest docs with no vault note — offer to write a metadata Source note straight from
the existing
raw_path/text_path; no intake step needed, the doc is already indexed),
and unindexed (files in audit.py's orphan list — on disk under raw/ but not
even in the manifest yet, typically from a manual git push straight to the warehouse
repo). For unindexed files, do NOT re-run /ingest's normal copy path — the file is
already in place, and intake.py would copy it a second time under a new name, leaving
the original behind as a permanent second orphan. Instead run, from the warehouse repo:python bin/intake.py --reindex <path>
to backfill the manifest entry and extracted text in place, then continue as a normal
/ingest from step 4 using its printed output (doc_id, paths, extraction_method,
excerpt).
- Propose fixes; apply only with confirmation (drifted-path patches are low-risk;
anything involving deletion is not).
What belongs where
|
Warehouse (private repo) |
Vault (Obsidian) |
| Original file (PDF/scan/…) |
✅ |
❌ never |
| Full extracted text |
✅ |
❌ never |
| Summary + key excerpts |
❌ |
✅ |
| Concept links, curation |
❌ |
✅ |
doc_id pointer |
(manifest) |
✅ (frontmatter) |
Pairing
- wiki-synthesizer — after
/ingest, run /synthesize sources to promote the new
Source note's ideas into Knowledge/ concept pages.
- wiki-librarian — its structural audit plus this skill's
/warehouse-audit together
cover both intra-vault links and vault→warehouse pointers.
- wiki-governor — Phase 1 runs
/warehouse-audit automatically whenever the vault has
any doc_id-carrying notes, and folds its corrupt/missing/dangling/drifted counts into
the health score as the Warehouse integrity sub-metric (Phase 3).
Reference files
references/warehouse-schema.md — the vault↔warehouse join contract: the Source-note
frontmatter fields, the doc_id semantics, and how pointer integrity is checked. Read
before changing the frontmatter shape or the audit logic.
1---2name: wiki-warehouse3description: Ingests raw research documents (PDFs, ebooks, scans, articles) into a separate private "cold storage" GitHub repo, then writes a lean pointer note into the Obsidian vault — keeping originals and full extracted text out of the vault so it stays fast and git-diffable. Use when the user wants to file, archive, warehouse, or "add a document/paper/PDF to my knowledge base," or to keep large source files outside the vault. Triggers on "warehouse this," "ingest this document," "add this PDF to cold storage," "file this paper," and the commands /ingest and /warehouse-audit. Requires the obsidian-vault MCP server connected and the knowledge-warehouse repo cloned locally. Pairs with wiki-synthesizer (which compiles the resulting Source note into concepts) and wiki-librarian (structural audits).4---56# Wiki Warehouse78The vault is the **index**; a separate private GitHub repo (`knowledge-warehouse`) is the9**warehouse**. Originals and full extracted text live in the warehouse. The vault gets10only a lean **Source note** — summary, key excerpts, and a content-hash pointer — so it11stays fast and its git history stays small. The two are joined by a `doc_id` (a sha25612content hash), never a path, so warehouse files can be reorganized without breaking the13vault.1415This skill owns the intake pathway. It does **not** replace `wiki-synthesizer` — the16synthesizer still compiles the resulting Source note into `Knowledge/` concepts. Think of17it as: **warehouse ingests the artifact → synthesizer distills its meaning.**1819## Prerequisites20211. The `obsidian-vault` MCP server connected (same as wiki-operator). Verify with `/mcp`.222. The `knowledge-warehouse` repo cloned locally, with push access. The intake tool is23 `bin/intake.py` in that repo; the vault side is this skill.243. For born-digital PDFs (the common case), one extractor available to `intake.py`:25 `pip install pymupdf` is enough. Scanned documents additionally need an OCR tool26 (`apt install ocrmypdf`) — `intake.py` detects and reports this per document.2728If the MCP server or the warehouse clone is unavailable, stop and tell the user — do not29simulate ingestion or write a Source note with a pointer to a file that wasn't stored.3031## Principles32331. **The binary never enters the vault.** Originals and full text live only in the34 warehouse. The vault holds a summary + excerpts + pointer. If you catch yourself about35 to paste full document text into a note, stop.362. **Content hash is the identity.** The `doc_id` (sha256) is the join key. Never key the37 vault note to a file path — paths change, hashes don't.383. **Ingest is idempotent.** `intake.py` dedupes by content hash. Re-ingesting the same39 file is a no-op that reports the existing location; never create a second Source note40 for a doc_id that already has one (search the vault first).414. **Distill, don't dump.** The Source note's summary and excerpts are curated — a few key42 quotes and a paragraph, not the first N pages. The full text is one click away in the43 warehouse for when it's actually needed.445. **Confirm before committing to the warehouse.** Pushing to the private warehouse is an45 external, durable action — show what will be stored and get confirmation before the46 push, unless the user said to just do it.4748## /ingest [file] [title]4950Store a raw document in the warehouse and index it in the vault.51521. **Locate the file** the user provided (a path, or a file they attached). Confirm it53 exists.542. **Run the warehouse intake tool** from the warehouse repo:55 ```bash56 python bin/intake.py <file> --title "<title>"57 ```58 This hashes the file, dedupes, copies the original into `raw/<year>/`, extracts text59 into `text/<year>/`, updates `manifest.json`, and prints a **frontmatter block** plus a60 short excerpt. Capture that output — the `doc_id`, paths, `extraction_method`, and61 excerpt are what the vault note needs.62 - If intake reports **"already ingested,"** search the vault for a Source note carrying63 that `doc_id`. If one exists, stop and point the user to it. If not (warehoused but64 never indexed), continue from step 4 using the existing paths.65 - If intake reports **little/no text (a scan with no OCR tool)**, tell the user: the66 original is safely stored, but there's no searchable text yet. Offer to proceed with67 a metadata-only note now, or pause until they install `ocrmypdf` and re-run intake to68 backfill the text.693. **Commit + push the warehouse.** Confirm with the user, then commit the new `raw/`,70 `text/`, and `manifest.json` (or run intake with `--commit` and push). The original must71 be safely in the remote before the vault points at it.724. **Read the extracted text** from the warehouse's `text/<year>/…txt` to write the note73 from the actual content (not just the excerpt) — but keep only a short summary + a few74 key excerpts in the note.755. **Search the vault** (`search_notes`) for an existing page on this topic before76 creating anything — one canonical Source note per document.776. **Write the Source note** to `Sources/<subfolder>/<title>.md` via the MCP `write_note`,78 using the warehouse frontmatter contract (see `references/warehouse-schema.md`):79 ```yaml80 type: source81 status: draft82 confidence: medium83 updated: <today>84 warehouse_repo: Hefrock/knowledge-warehouse85 doc_id: sha256:<hash>86 warehouse_path: raw/<year>/<slug>-<shortid>.<ext>87 text_path: text/<year>/<slug>-<shortid>.txt88 extraction_method: <method>89 ```90 Body: a `## Summary` (a paragraph you distilled), `## Key excerpts` (a few verbatim91 quotes with rough locators), and `## Connections` linking to relevant `Knowledge/`92 pages — creating `status: draft` stubs for concepts that don't exist yet, exactly as93 the synthesizer does.947. **Confirm** in one line what happened: what was warehoused (doc_id + path), and which95 vault note now points to it.9697## /warehouse-audit9899Reconcile the two sides. This runs in two halves — the warehouse-side integrity check is100a script; the vault-side pointer check uses MCP.101102**Half 1 — warehouse integrity (run the tool).** From the warehouse repo:103```bash104python bin/audit.py --json105```106`audit.py` re-hashes every stored original against its `doc_id` (catching silent swaps or107bit-rot), confirms every manifest path resolves, and reports `corrupt`, `missing`,108`orphan`, and `drift`. Surface any **CORRUPT** finding prominently — it means a stored109original no longer matches its own hash, which is the one failure the whole content-hash110design exists to detect. Do not "fix" corruption automatically; report it and let the111user restore the file.112113**Half 2 — vault pointers (use MCP).** The script can't see the vault, so check the other114direction here:1151. Query the vault for all notes carrying a `doc_id` (`query_frontmatter`).1162. Load the warehouse `manifest.json` (or reuse the audit output).1173. For each vault `doc_id`: confirm it exists in the manifest, and that the note's118 `warehouse_path` / `text_path` match the manifest's current paths (the manifest is the119 source of truth — if they drifted, the note is stale, not the manifest).1204. Report four buckets: **dangling** (doc_id not in manifest — original may have been121 removed), **drifted** (paths in the note no longer match the manifest — offer to patch122 the note's frontmatter to the manifest's current paths), **orphaned-in-warehouse**123 (manifest docs with no vault note — offer to write a metadata Source note straight from124 the existing `raw_path`/`text_path`; no intake step needed, the doc is already indexed),125 and **unindexed** (files in `audit.py`'s `orphan` list — on disk under `raw/` but not126 even in the manifest yet, typically from a manual `git push` straight to the warehouse127 repo). For **unindexed** files, do NOT re-run `/ingest`'s normal copy path — the file is128 already in place, and `intake.py` would copy it a second time under a new name, leaving129 the original behind as a permanent second orphan. Instead run, from the warehouse repo:130 ```bash131 python bin/intake.py --reindex <path>132 ```133 to backfill the manifest entry and extracted text in place, then continue as a normal134 `/ingest` from step 4 using its printed output (doc_id, paths, extraction_method,135 excerpt).1365. Propose fixes; apply only with confirmation (drifted-path patches are low-risk;137 anything involving deletion is not).138139## What belongs where140141| | Warehouse (private repo) | Vault (Obsidian) |142|---|---|---|143| Original file (PDF/scan/…) | ✅ | ❌ never |144| Full extracted text | ✅ | ❌ never |145| Summary + key excerpts | ❌ | ✅ |146| Concept links, curation | ❌ | ✅ |147| `doc_id` pointer | (manifest) | ✅ (frontmatter) |148149## Pairing150151- **wiki-synthesizer** — after `/ingest`, run `/synthesize sources` to promote the new152 Source note's ideas into `Knowledge/` concept pages.153- **wiki-librarian** — its structural audit plus this skill's `/warehouse-audit` together154 cover both intra-vault links and vault→warehouse pointers.155- **wiki-governor** — Phase 1 runs `/warehouse-audit` automatically whenever the vault has156 any `doc_id`-carrying notes, and folds its corrupt/missing/dangling/drifted counts into157 the health score as the Warehouse integrity sub-metric (Phase 3).158159## Reference files160161- `references/warehouse-schema.md` — the vault↔warehouse join contract: the Source-note162 frontmatter fields, the `doc_id` semantics, and how pointer integrity is checked. Read163 before changing the frontmatter shape or the audit logic.