by drpwchen
Turn your own PDF textbooks into an AI-searchable knowledge base and structured, fully-cited notes — figures included. Local-first, token-frugal.
# Add to your Claude Code skills
git clone https://github.com/drpwchen/textbook-to-noteGuides for using ai agents skills like textbook-to-note.
Last scanned: 7/21/2026
{
"issues": [],
"status": "PASSED",
"scannedAt": "2026-07-21T06:28:04.293Z",
"npmAuditRan": true,
"pipAuditRan": false,
"promptInjectionRan": true
}textbook-to-note is an open-source ai agents skill for AI coding assistants such as Claude Code, Codex CLI, and ChatGPT, built by drpwchen. Turn your own PDF textbooks into an AI-searchable knowledge base and structured, fully-cited notes — figures included. Local-first, token-frugal. It has 93 GitHub stars.
Yes. textbook-to-note passed SkillsLLM's automated security scan — a dependency vulnerability audit plus prompt-injection heuristics — with no high-severity issues. You can read the full report in the Security Report section on this page.
Clone the repository with "git clone https://github.com/drpwchen/textbook-to-note" and add it to your Claude Code skills directory (see the Installation section above).
textbook-to-note is primarily written in Python. It is open-source under drpwchen on GitHub, so you can review or fork the full source.
Yes. SkillsLLM lists many other AI Agents skills you can browse and compare side by side. Open the AI Agents category from the badge at the top of this page, or use the Related Skills and comparison links further down to weigh textbook-to-note against similar tools.
No comments yet. Be the first to share your thoughts!
Turn your own PDF textbooks into an AI-searchable knowledge base and structured, fully-cited notes — figures included. A local-first pipeline that spends (almost) zero LLM tokens on the heavy lifting and reserves the frontier model for the one thing it's uniquely good at: synthesizing a note you can actually learn from.
I've loved taking notes since med school, and over the years I've built up thousands of them — but I can no longer keep every one at the same quality by hand. In an age of information overload, trustworthy high-quality sources become the precious thing, and textbooks are among the best; yet my specialty alone has 40+ designated reference books, with a single concept scattered across chapters in many of them. Reading them all cover to cover just isn't realistic. LLMs are great at long context, but you can't dump hundreds of books on one at once — so the real unlock is pairing good search and a database with teaching the AI my own note-making process, so it produces grounded, structured notes I only have to absorb.

Left: one of the templates in templates/. Right: a real note in my vault, written against it — every claim traceable, every section where I expect it.
Not everyone wants the whole pipeline, and the parts stack in one direction — each profile below is the one above it plus one more thing. Pick the smallest one that solves your problem; you can move up later without redoing anything.
| Profile | What you get | What you set up |
|---|---|---|
| A · Converter only | Your PDFs/EPUBs as clean, greppable markdown with page markers, tables, and figure-reference markers. Search with grep. |
pip install -r requirements.txt, then converter/convert.py. Nothing else — no GPU, no ollama, no index. |
| B · A + the note workflow | An AI writes structured, per-claim-cited notes from that corpus, with figures extracted through a QC gate. | A, plus the two skills in skills/ and workflows/note-writing.md. |
| C · B + semantic search | Cross-book retrieval by meaning rather than keyword — worth it once "which book was that in?" stops being obvious. | B, plus an indexer: the companion repo vault-search, a local embedding model, and INDEXER_SCRIPT. |
This repo ships no indexer. Profile C's semantic search comes from vault-search (or any
indexer exposing the same --incremental / --book <name> CLI); post_convert.py --index
is only the hook that calls it. Profile A is a fully supported end state, not a degraded one —
for a few dozen books, grep over the converted markdown is genuinely enough.
If you're having an AI set this up, tell it which profile you want; AGENTS.md
asks this first and then skips the steps your profile doesn't need.
Feeding a raw PDF to a frontier model seems simple until you hit the real problems:
This pipeline treats each of those as a distinct engineering problem with a deliberate solution, organized as five stages.
PyMuPDF text extraction at ~130 ms/page. Two non-obvious pieces:
T2N_COLUMN_SORT=0 to disable.)pdfplumber's table detection is the slowest part of conversion. We gate it behind a cheap fitz pre-check (ruling-line signature incl. three-line tables, plus multilingual "Table"/表 keywords), so table-sparse books convert ~3.4× faster without missing tables. (T2N_TABLE_GATE=0 to disable.)T2N_TABLE_MERGE=1 to stitch a table that ends near a page bottom to a geometrically-matching table at the top of the next page (same column count / x-edges, no intervening heading), deduping a repeated header row and leaving a <!-- table continues from page N --> trace comment. Same exact-fallback discipline: default OFF ⇒ byte-identical output.pdfplumber enough intersecting edges to "find" a table covering the whole page body, with 1 column and every word on the page dumped into a single cell. That output is worse than a missing table: a real multi-column table arrives with its columns interleaved line by line, carrying its caption and every value, so it reads as clean citable data while the row↔column binding is destroyed. Candidates of one column whose largest cell exceeds 500 characters, or whose bbox alone covers half the page, are dropped and replaced by a <!-- ⚠️ page-frame pseudo-table rejected on page N --> comment — the page's own prose already carries the text. Measured at 9.9% of extracted tables across 128 books; on a hand-read sample of 34 pages from 10 books, 28 were genuine defects and the 6 legitimate boxed lists lost nothing (100% of their tokens are present in the page prose). Default ON — this corrects wrong output; T2N_TABLE_FRAME_REJECT=0 restores the old behaviour.mg, mL, mg/kg, IU, dose ranges — a wrong value here is the worst output the tool can produce). Each gets a <!-- ⚠️ table needs out-of-band review … verify against PDF page N --> marker and a queue entry; the second opinion is a bring-your-own-model pass (fast text model first, vision as escalation). In testing, ~1 in 6 continuation×dose tables carried a high-severity misbinding versus ~0 in a random table sample — the danger concentrates exactly where both triggers meet. Opt in with T2N_REVIEW_QUEUE=1 (default OFF; recommended ON for clinical corpora). Details, the failure mode, and a hazard-primed verifier prompt: docs/table-review.md.T2N_TABLE_HEADER_COLLAPSE=0 restores byte-identical output.pdfplumber parses 0 pages while fitz opens the file, or a book yields 0 tables despite ≥10 table captions, the conversion report and the markdown itself get a loud warning instead of nothing at all. Detection only — extraction is unchanged. Fires on 22 of 34 zero-table books in our corpus and on none of the 226 that extract tables. Partial loss is caught too: a book that recovers some tables but fewer than BOOK_PARTIAL_TABLE_RATIO (0.20) per caption is warned ab