plugins/knowledge-and-memory/skills/creating-kb/SKILL.md
Builds a portable, embedding-free knowledgebase from a set of files and delivers it as a self-contained `.skill` bundle (BM25 index + bundled searcher + query protocol). Use when a user wants to turn uploaded files, a folder, or a corpus into a searchable knowledgebase they can hand to any agent — phrased as "make a knowledgebase", "build a KB skill", "package these docs for retrieval", "create a searchable bundle", or references to a `.skill` KB. The output runs anywhere with Node or Python — no model, no install, no network. Distinct from `bm25` (ephemeral in-session search) and `building-github-index` (markdown project-knowledge index).
npx skillsauth add oaustegard/claude-skills creating-kbInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Turn a pile of files into a portable, deployable knowledgebase. The output
is a .skill bundle — an ordinary zip — containing a BM25 inverted index, the
chunk text, a pure-Node searcher, and a query protocol. It has no embedding
model and no semantic search: retrieval is lexical, and the consuming agent
supplies the semantic layer by expanding the query at search time. That is what
makes the bundle portable — any agent that can run node can query it with no
npm install, no model download, and no network.
The whole toolchain is JavaScript so one implementation serves both this builder and the in-browser packer. Build with the bundled script; do not hand-roll the index.
SCRIPTS=/mnt/skills/user/creating-kb/scripts
node $SCRIPTS/build_lexkb.js CORPUS_DIR --out /tmp/kb --name my-kb --zip
Collect the files into one directory. In a Claude.ai chat, uploads land in
/mnt/user-data/uploads/ — point the builder there. Otherwise use any path the
user names. Supported extensions default to txt,md,html,htm; pass --ext to
change them.
This MVP interface is bounded by how many files a chat can accept. For a large corpus, stage the files in a directory first, or use the browser packer (built from the same scripts) that runs entirely client-side.
SCRIPTS=/mnt/skills/user/creating-kb/scripts
node $SCRIPTS/build_lexkb.js /mnt/user-data/uploads \
--out /tmp/kb --name my-kb --zip \
--source "human description of the corpus"
The script chunks each file, builds the BM25 index, writes the bundle dir
(SKILL.md + search.js + index.json + chunks.jsonl), and — with --zip —
emits my-kb.skill next to --out.
Move the .skill to the outputs directory and give the user a download link:
cp /tmp/my-kb.skill /mnt/user-data/outputs/
[Download my-kb.skill](computer:///mnt/user-data/outputs/my-kb.skill)
Tell the user how to deploy it: unzip into an agent's skill directory (or upload
it as a skill). The bundle's own SKILL.md then drives querying — the consuming
agent reads it, expands each question into search terms, and runs the bundled
search.js. No further setup.
The retrieval unit and the reasoning unit are decoupled, which makes chunk size a
low-stakes choice. search.py/search.js rank on the whole chunk (best
recall) but return only the query-densest passage of it by default
(--snippet, ~1200 chars), so a big chunk does not flood the consuming agent's
context with surrounding noise. Index for recall; the searcher handles signal.
--target-chars controls chunk size (whole paragraphs are packed up to the
target; --target-chars 0 makes each file one chunk). Lexical BM25 tolerates —
and on a real-corpus sweep slightly preferred — larger chunks than
embedding-based retrieval, because there is no vector to dilute: BM25 scores
individual term presence with length normalization, so a big chunk still ranks on
the exact terms it contains.
--target-chars 0 (whole document). Best recall, fewest chunks;
the snippet return keeps reasoning context focused.1500–4000.500 only if you need very fine-grained chunk ids and accept more chunks.Test before delivering. Run a query against the freshly built bundle and confirm it returns sensible hits:
node /tmp/kb/search.js --query "a representative question" \
--core "key term" --expand "synonym" --k 3
Each hit's text is the query-focused passage by default; add --snippet 0 to
inspect a full chunk.
search.js prints JSON {"hits": [...]}. Confirm the right chunks surface.
| File | Role |
|---|---|
| SKILL.md | the query protocol the consuming agent follows (expand → search → cite) |
| search.js / search.py | equivalent BM25 + RM3 + metadata-filter searchers; return query-focused passages (matched sentences kept in neighbour context, merged); the agent runs whichever runtime it has |
| index.json | precomputed inverted index (postings, df, doc lengths, BM25 params) |
| chunks.jsonl | chunk text + structured metadata |
Both searchers are thin readers of the same neutral JSON index, so the bundle
runs in a Node-only or a Python-only consumer. Metadata stays structured (not
folded into the indexed text), which lets the consuming agent filter on it
(--filter section=blog, --filter date>=2025).
scripts/build_lexkb.js — chunker + BM25 index builder + .skill writer.scripts/search.js — the JS runtime searcher, copied verbatim into every
bundle. It owns the tokenizer; the builder imports it so index and queries
tokenize identically.scripts/search.py — the Python runtime searcher, copied verbatim into every
bundle; a thin reader of the same neutral JSON index, parity-pinned to
search.js (identical results on a shared index).scripts/zipstore.js — pure-JS ZIP-STORED writer (used by the builder; shared
with the in-browser packer).scripts/bundle_SKILL.md — the query-side SKILL.md template written into each
bundle.development
Write effective instructions for Claude: project instructions, standalone prompts, and skill content. Use when users need help writing prompts, setting up project instructions, choosing between instruction formats, or improving how they communicate with Claude. Covers writing principles, model-aware calibration, and format selection. For building and testing complete skills, use skill-creator instead.
data-ai
Discover and load skills on demand from /mnt/skills/user/. Use when you need a capability but don't know which skill provides it, when the boot-emitted skill list is names-only and you need a full description, or when you want to list the catalog. Verbs are list (names only), search (rank by name/description match against a query), and show (emit the full SKILL.md for a named skill).
documentation
Reads the visual content of slides, pages, and images the way a human would, not just their embedded text. Use when a PPTX or PDF has image slides, screenshots, charts, scanned figures, or flattened-to-image layouts that the built-in pptx/pdf skills read as empty; when asked to transcribe, describe, OCR, or extract what is shown in an image, slide deck, or document page; or when embedded-text extraction returned little or nothing from a visually rich file. Triggers on 'read this deck', 'what's on these slides', 'transcribe', 'OCR', 'extract text from image', 'describe this chart/diagram', .pptx/.pdf/.png/.jpg with visual content.
development
Portrait Mode for SVGs — foveated vectorization with 4-zone selective detail. Combines vision annotations, MediaPipe segmentation/landmarks, and optional saliency. Like phone portrait mode, but vectorized. Use when vectorizing a portrait or photo where subject detail should outrank background detail.