The Problem Technical books are dense PDFs or EPUBs that are hard to query programmatically. Users either search the raw file (which returns page numbers) or ask a LLM, which either hallucinates or refuses because the content isn’t indexed. The result is lost knowledge and wasted time when a developer needs a specific snippet from a book they’ve read once.
What This Does book-to-skill converts a supported source (PDF, EPUB, DOCX, MD, HTML, RTF, MOBI) into a Claude Code “skill” – a collection of markdown chapters plus a manifest that agents can load on demand. The conversion lives in book_to_skill/:
cli.pydefines themainentry point (python -m book_to_skillorbook-to-skillafter install).parsers/holds format‑specific extractors (pdf.py,epub.py, …) that normalise raw text into a uniform structure.utils.pysupplies token‑counting, chapter detection and numeral conversion that many modules depend on (13 importers, 11 imports).sanitize.pycleans extracted text of bidi controls and other artefacts before it is written to the skill output.
The generated skill can be consumed by Claude Code, GitHub Copilot CLI, or any agent that understands the “Agent Skills” open standard.
How It Is Wired Execution starts in book_to_skill/cli.py at line 4 (def main). main parses CLI arguments, prints a banner, and calls run_dependency_check → prepare_dependencies → offer_dependency_install (in dependencies.py). After ensuring external tools (e.g., pdftotext, ebook-convert) are present, main invokes extract_single_file (in __main__.py).
extract_single_file selects the appropriate parser via resolve_input_files and then calls one of the format‑specific functions such as clean_pdftotext (PDF), extract_with_ebook_convert (EPUB/ MOBI), or extract_docx_with_python_docx (DOCX). These parsers rely heavily on book_to_skill/utils.py – functions like estimate_tokens, _structural_chapter_count, and _cn_numeral_to_int are called 81, 22 and 19 times respectively across the code base, making utils.py the central hub.
After raw text is obtained, sanitize.py runs sanitize_extracted_text to strip bidi controls and other problematic Unicode. The cleaned chapters are written to the output directory (file I/O occurs in ~60 functions, e.g., book_to_skill/parsers/text.py’s read_text_file). No network calls are made; the only external interaction is the execution of helper binaries (e.g., pdftotext) from book_to_skill/parsers/pdf.py.
The call graph shows no circular imports and a modest depth (max indentation 7). The most blast‑radius functions are detect_structure (81 callers) and strip_rtf_fallback (23 callers), indicating that changes there will ripple widely.
How To Use It
# Clone the repo
git clone https://github.com/moses-y/book-to-skill
cd book-to-skill
# Install the package and its Python dependencies
pip install . # pyproject.toml drives the install
# Verify the CLI is available
book-to-skill --help
# Convert a PDF (example)
book-to-skill ./my‑book.pdf --output ./my‑skill
The CLI options are defined in book_to_skill/cli.py; --output selects the target directory for the generated skill. No additional configuration files are required.
Real‑World Use A development team stores internal design guides as PDFs. By running the above command, each guide becomes a skill under ./skills/guide-name. When a developer asks Claude Code “/guide‑name how do I configure X?”, the agent loads the relevant markdown chapter and returns the exact wording from the original document, eliminating hallucination and manual searching.
Code Health & Issues
- High – Missing lockfile (
pyproject.tomlonly). Fix: Run the chosen package manager (e.g.,pip install -r requirements.txtoruv pip compile) and commit the generated lockfile. - Medium – GitHub Actions checkout persists credentials (
.github/workflows/deploy-docs.yml). Fix: Addwith: persist-credentials: falseand pass an explicit token only to the push step. - Low – No timeout on CI jobs (
.github/workflows/ci.yml). Fix: Addtimeout-minuteswith a realistic bound to each job.
Additional observations from the static analysis:
- Broad
except:blocks appear inutils.py,parsers/pdf.py, andparsers/epub.py– replace with specific exception handling. - Deep nesting (up to 7 levels) in
utils.pyand several parsers – refactor with guard clauses or strategy dispatch. utils.pyis a hub (13 dependents, 11 imports) – keep its API stable; consider moving volatile logic to dedicated modules.- Repeated test helper code across multiple test files – extract shared fixtures to reduce duplication.
The Bottom Line book-to-skill provides a focused, CLI‑driven pipeline that reliably turns supported document formats into structured agent skills. The codebase is functional but concentrated around a few large modules (utils.py, parsers) that would benefit from refactoring and tighter exception handling. With a lockfile and the CI tweaks noted, the project is ready for production use in environments that need deterministic, searchable knowledge from technical books.