Install
$ agentstack add skill-toolboxmd-karpathy-wiki-karpathy-wiki-ingest ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
karpathy-wiki ingest (for spawned ingester only)
You are a detached claude -p ingester invoked by wiki-spawn-ingester.sh. Your job: process one already-claimed capture into wiki pages and commit. The main agent does NOT read this skill — it's loaded by your spawn prompt.
Deep orientation
Before any wiki write, run this 9-step orientation protocol. The goal: your view of the wiki is shaped by the actual page content, not by titles alone.
Steps 1-3: read the wiki's current state
- Read
/schema.md— current categories, taxonomy, thresholds. - Read
/index.md(or//_index.mdper category) — what pages exist with one-line summaries. - Read the last ~10 entries of
/log.md— recent activity.
Steps 4-7: pick and read 0-7 candidate pages
- Extract candidate signals from the capture. From the body and
frontmatter, gather:
- Words and phrases from the capture title (lowercase, split on
non-alphanumerics).
- Frontmatter
tags:list (if any). - For
chat-onlyandchat-attachedcaptures: meaningful nouns and
proper-noun phrases from the body. Use judgment — you're an LLM, not a regex; pick names, identifiers, technical terms, version numbers.
- For
raw-directcaptures: filename basename + the file's first
200 lines.
- Score candidates against the index. A page is a candidate if ANY
extracted signal:
- Substring-matches its title (case-insensitive), OR
- Matches a tag (exact, case-insensitive), OR
- Appears in its
_index.mdone-line summary.
This is a deterministic substring + tag match — no embeddings, no semantic similarity. See "Why no embeddings / vector search" below for the rationale.
- Pick up to 7 candidates ordered by:
- Signal-match count (descending — more matches = stronger candidate).
- Title length (ascending — shorter titles rank higher for the same
match count; they tend to be more general / canonical).
- Tie-break: alphabetical by title.
- Read all picked candidates in full. Zero is a valid count for a
small or fresh wiki — see "Cold start" below.
Steps 8-9: decide and report observations
- Decide: create new page, augment an existing page, or no-op
(the capture's content is already covered by an existing page). Write your decision rationale into the commit message later.
- Issue reporting (during steps 5-7). While reading the index and
the candidate pages, observe issues. Append each as one JSONL line to /.ingest-issues.jsonl via bash scripts/wiki-issue-log.sh. Do NOT fix issues inline; report only — wiki doctor consumes the log later.
Example invocation:
``bash bash "${CLAUDE_PLUGIN_ROOT}/scripts/wiki-issue-log.sh" \ --wiki "${WIKI_ROOT}" \ --ingester-run "${RUN_ID}" \ --capture "${WIKI_CAPTURE#${WIKI_ROOT}/}" \ --page "concepts/auth.md" \ --type broken-cross-link \ --severity warn \ --detail "Links to /concepts/legacy.md which does not exist." \ --suggested-action "Remove link or create stub" ``
Issue types to watch for (the --type enum in wiki-issue-log.sh):
- broken-cross-link: page links to
/path/foo.mdbut that file
does not exist.
- contradiction: page makes a claim that contradicts another
page you're reading or the capture itself.
- schema-drift: page has
type: concept(singular) but
directory is concepts/; page lacks required frontmatter; page uses retired categories.
- stale-claim: page says "as of 2025-12 library X is at version
Y" and the capture or another source clearly indicates a newer version.
- tag-drift: same concept tagged two different ways across
pages.
- quality-concern: page's
quality.overall /.wiki-configbecomes the PRIMARY lens, not a
backup tripwire:
role: projectorrole: project-pointer: write specifics
about THIS codebase / instance / situation. Document the symptom, the pinpoint, what code path triggered it. Do NOT generalize.
role: main: write general patterns reusable across projects.
Do NOT name specific apps or instances; abstract them.
In the cold-start state the index has insufficient gravity to shape the page; the role hint carries the lens. Defer cross-linking to a future ingester run when more pages exist.
Why no embeddings / vector search
The substring + tag match in step 5 is deterministic, scriptable, testable, and cheap. Embedding-based candidate selection is the "smart" upgrade but explicitly out of scope per CLAUDE.md ("do not add: vector search — defer until genuine scaling pain"). The substring/tag approach degrades gracefully — at large scale it hits more candidates than 7, but the ranking still produces a usable top-7. When that breaks, vector search becomes worth its complexity; not before.
Cost
3-7 extra file reads per ingestion (zero on cold-start wikis). Each page is typically 5-20 KB. The ingester is already reading the capture and the schema; this is the same order of magnitude. No measurable spawn-time impact.
Run record (per ingestion)
At the very start of your work, generate a unique run_id and append a "spawned" record to /.ingest-runs.jsonl:
RUN_ID="in-$(date +%s)-$(openssl rand -hex 4 2>/dev/null || echo $$)"
ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
mkdir -p "${WIKI_ROOT}/.locks"
{
flock 7
printf '{"run_id":"%s","capture":"%s","started_at":"%s","status":"spawned"}\n' \
"${RUN_ID}" "${WIKI_CAPTURE}" "${ts}" >> "${WIKI_ROOT}/.ingest-runs.jsonl"
} 7>"${WIKI_ROOT}/.locks/ingest-runs.lock"
At the END of your work (success or failure), append a closing record:
ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
status="completed" # or "failed" if you exit non-zero
exit_code=0 # or your real exit code
{
flock 7
printf '{"run_id":"%s","ended_at":"%s","status":"%s","exit_code":%d}\n' \
"${RUN_ID}" "${ts}" "${status}" "${exit_code}" >> "${WIKI_ROOT}/.ingest-runs.jsonl"
} 7>"${WIKI_ROOT}/.locks/ingest-runs.lock"
The two records (spawned + closing) tie back via run_id. wiki status reads both files and surfaces asymmetric outcomes in both mode (a fork that has a project record but no main record is flagged).
If the ingester crashes between the two records, the spawned record remains without a closing record. wiki status flags such records as "in-flight or stalled" if they're > 30 minutes old.
On platforms without flock(1) (macOS), use the same noclobber-spin fallback used by scripts/wiki-manifest-lock.sh. The 4 KB-per-line JSONL discipline keeps the append atomic on POSIX even without a lock, but the lock prevents any partial-write contention under high concurrency.
Role guardrail
Read /.wiki-config to determine the wiki's role:
role: projectorrole: project-pointer→ you are writing for a
PROJECT wiki. Document specifics: how this app handles X, where bug Y lived, what we decided for this codebase. Do NOT generalize.
role: main→ you are writing for the MAIN wiki. Extract general
patterns reusable across projects. Do NOT name specific apps or instances.
The role field is the primary lens during cold start (≤ 7 pages in the wiki) and a sanity tripwire in mature wikis (the index pull is the primary lens once enough pages exist). See "Deep orientation — Cold start" above.
If the index pulls strongly toward instance-style or pattern-style writing (you read 5+ existing pages of one shape), trust the pull. The role hint then becomes a tripwire — "if you find yourself generalizing in a project wiki / specifying in a main wiki, stop."
Capture format
See /skills/karpathy-wiki-capture/references/capture-schema.md for the canonical capture frontmatter contract — capture_kind enum, body floors, evidence rules, legacy backward-compat. Do not duplicate that schema here.
Page format
See references/page-conventions.md for the canonical page frontmatter and cross-link conventions.
Body-sufficiency check (first thing — reject if too thin)
Before any other work, measure the capture body size in bytes (content AFTER the closing --- of frontmatter). Apply the per-capture_kind floor:
raw-direct→ no floor (body is auto-generated boilerplate).chat-attached→ 1000 bytes.chat-only→ 1500 bytes.
Legacy captures (no capture_kind): apply backward-compat per /skills/karpathy-wiki-capture/references/capture-schema.md.
If body is BELOW its floor:
- Add
needs_more_detail: trueto the capture's frontmatter. - Add
needs_more_detail_reason: "body is bytes; floor for capture_kind= is bytes". - Rename
.md.processing→.mdso the next session-start drain
re-presents it after the main agent expands.
- Append to
log.md:## [] reject | — body b below b floor. - Exit 0. Do NOT write pages. Do NOT commit.
A thin-capture rejection is a feature, not a failure.
Ingester steps
- The capture is already claimed for you. Read
${WIKI_CAPTURE}(it's a.md.processingfile). If for some reason${WIKI_CAPTURE}is unset or missing, callwiki_capture_claim "${WIKI_ROOT}"to grab any pending capture as fallback.
- Read the orientation files: schema.md, index.md, last 10 entries of log.md (per the Orientation section above).
- Read the capture body.
- Copy evidence with write-staging discipline (v2.4):
Atomic write to raw/ requires the staging dance (skip steps 1–2 and 7 if evidence_type is conversation AND the capture has no real path):
- Copy the evidence file to
/.raw-staging/(NOT directly toraw/). - Compute the new sha256.
- Acquire
/.locks/manifest.lockviabash scripts/wiki-manifest-lock.sh ...for the manifest write + rename block. - Re-read the manifest under the lock. If
raw/already exists with the same sha256, this is a duplicate — skip (apply the sha256 short-circuit below). - Update the manifest entry for
raw/(origin, sha, copiedat, lastingested, referenced_by). - Write the manifest atomically (
.manifest.json.tmp+os.rename) —wiki-manifest.py buildalready does this. - Atomically rename
/.raw-staging/→/raw/(POSIX rename is atomic on the same filesystem). - Release the lock.
- If the source file is in
/inbox/(raw-direct via inbox queue),rmit.
Crash recovery: if the ingester crashes between steps 1 and 7, a file lingers in .raw-staging/. The SessionStart recovery scan SKIPS .raw-staging/ (it's a reserved dot-prefixed directory). Future cleanup is wiki doctor's responsibility.
- In ALL cases (including
chat-only/ legacyconversation): write or update the manifest entry for the raw file in/.manifest.json:
``json { "raw/": { "sha256": "", "origin": "", "copied_at": "", "last_ingested": "", "referenced_by": [""] } } ``
- Always call
python3 scripts/wiki-manifest.py build "${WIKI_ROOT}"at the end of ingest to refresh sha256 andlast_ingested. This is mandatory; the manifest is the drift-detection source of truth. - Iron rule:
originis the capture'sevidencefield value — never the string"file","conversation"(when a real path was available),"mixed", or theevidence_type/capture_kind. Ifcapture_kind == "chat-only"AND the capture has no real path,originis the literal string"conversation". Any other value is a validator failure. - sha256 short-circuit. If
raw/already exists ANDsha256(new) == manifest[raw/].sha256, the evidence content is identical — skip re-ingest of this capture and append## [] skip | — sha match, no-optolog.md. Archive the capture normally (step 10). This prevents re-ingesting the same research file twice when the capture-trigger fires on a near-duplicate. - Title-scope check. Before merging into an existing wiki page in step 6, compare the new evidence's scope to the existing page's slug. Scope is the set of distinct entities (product names, versions, model names, concepts) the evidence covers. If the existing page's slug is NARROWER than the new evidence's scope (example: existing
concepts/gemma4-27b-hardware-requirements.mdvs new evidence covering a 27B+31B comparison), do NOT force-merge the broader content into the narrower-titled page. Instead, either (a) create a sibling concept page with a scope-appropriate slug (e.g.concepts/gemma4-27b-vs-31b-hardware-comparison.md) and cross-link both, or (b) rename the existing page's slug AND frontmatter title to cover the new scope, then merge — only if no other wiki page currently links to the old slug (if any do, use option (a) to avoid broken links). Log which option was taken inlog.md. - Overwrite-detection recovery. If
raw/already exists AND the new sha256 differs from the manifest entry AND the manifest'slast_ingestedis within the last 60 minutes (the evidence file on disk was replaced since the previous ingest), treat this as an overwrite situation: copy the new evidence toraw/AS NORMAL, but also append## [] overwrite | — raw sha changed since , previous referenced_by: []tolog.md. Proceed with the rest of step 4 and the title-scope check in step 6 as above. The overwrite is not an error — it is the exact scenario from the failure-mode transcript (two research agents both wrote to2026-04-24-gemma4-hardware.md), and the title-scope check catches the content-divergence part.
- Decide target pages:
suggested_pagesis a hint; orientation may change it.
- For each target page:
a. Acquire a page lock (wiki_lock_wait_and_acquire). b. Read current page content (read-before-write). c. Merge new material. Do NOT replace existing claims — add dated findings, use contradictions: frontmatter if they disagree. d. Release lock (wiki_lock_release).
6.5. Self-rate every page you just touched. For each page, use the cheap model to score on four dimensions (1-5 each), compute overall as round(mean, 2), and write the following into the page's frontmatter (creating the quality: block if missing, preserving rated_by: human if the page already has it): ``yaml quality: accuracy: completeness: signal: interlinking: overall: rated_at: "" rated_by: ingester `` Rating criteria in one line each:
- accuracy: does every claim map to evidence in
sources:? - completeness: would a future-you searching for this topic find enough to act?
- signal: dense knowledge vs restatement?
- interlinking: does it link to every related page the wiki contains?
Never clobber rated_by: human. If the existing page has quality.rated_by == "human", skip this step for that page entirely. See references/page-conventions.md for the full quality block contract.
- Update indexes via
wiki-build-index.py. Do NOT writeindex.mdor any_index.mddirectly. Instead, for each unique parent directory of a touched page (deduplicated fromtouched_pages), invoke:
``bash for dir in "${TOUCHED_DIRS[@]}"; do python3 "${CLAUDE_PLUGIN_ROOT}/scripts/wiki-build-index.py" \ --wiki-root "${WIKI_ROOT}" "${dir}" done ``
The script regenerates _index.md in that directory and walks UP to ancestors (path-order locks, leaves first). Root MOC (index.md) is rebuilt automatically by the script if a top-level category was added or removed.
If the script exits non-zero (lock timeout, discovery failure), log the failure to log.md and continue. The next ingest catches up because indexes are a function of directory state.
7.5. Missed-cross-link check. Pass the freshly-edited page content AND the relevant _index.md content (the page's parent directory's index, NOT root index.md) to the cheap model with this prompt: "Identify any existing wiki page in _index.md that thi
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: toolboxmd
- Source: toolboxmd/karpathy-wiki
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.