epub
Read, write, and edit EPUB2/EPUB3 ebooks as an EPUB file format expert. Extract text, metadata, structure, and knowledge from EPUB files for enrichment or memory. Create valid EPUBs from scratch. Validate against the EPUB specification. Use when the user mentions epub, ebook, EPU
Install
npx skills add https://github.com/magnus919/agent-skills/tree/main/epub
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install magnus919-agent-skills@llmmart
git clone https://github.com/magnus919/agent-skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole magnus919/agent-skills collection as a plugin from our marketplace. Git is the plain clone.
README
EPUB — Ebook Creation, Extraction & Enrichment
Expert-level EPUB handling for reading, writing, editing, and extracting knowledge from EPUB2 and EPUB3 files. Ships a CLI tool and five detailed references.
Why Install This Skill
When your agent loads this skill, it becomes an ebook format specialist who can:
- Inspect EPUB structure — see manifest, spine, TOC, metadata
- Extract clean text — per-chapter or single-file, stripped of boilerplate
- Edit EPUBs non-intrusively — metadata, chapters, spine, CSS — without breaking the file
- Create valid EPUBs from scratch — scaffold new ebooks
- Extract knowledge with LLM mode — facts, quotes, definitions, arguments via configurable LLM
- Convert EPUB2 to EPUB3 — add NAV, update namespace, keep NCX compatibility
- Batch process hundreds of EPUBs — wrap any script across file globs
- Validate against the spec — EPUBCheck or Python fallback
What You Get
| Directory | Purpose |
|---|---|
SKILL.md |
Decision table mapping tasks to scripts, EPUB format essentials |
scripts/ |
10 Python CLI scripts: info, text, scaffold, edit, images, batch, convert, validate, extract-knowledge |
references/ |
8 reference files: format internals, Python libraries, spec/validation, tutorials, fixed-layout, accessibility, media overlays |
Triggers
Load this when you encounter EPUB files — to read, create, edit, extract, convert, or validate them.
Requirements
Python 3.8+ with EbookLib. Optional: beautifulsoup4, epublib, Java (for EPUBCheck), and an LLM endpoint for knowledge extraction.
Quick Start
Start with the setup and first workflow in SKILL.md, then use the linked resources for the specific task you need to complete.
Skill manifest
EPUB — Ebook Creation, Extraction & Enrichment
Expert-level EPUB handling: read, write, edit, validate, and extract knowledge from EPUB 2 and EPUB 3 files. Ships with five Python CLI scripts and five detailed references covering the entire EPUB domain.
When not to use
- Non-EPUB documents — Word, PDF, plain markdown, or web-page conversion tasks do not match any script here; route them to a document-handling skill instead of forcing an EPUB tool onto a non-EPUB file.
- DRM-locked ebooks — these scripts read and write standard OCF/EPUB containers; they do not remove or bypass digital rights management.
- Mobi/AZW/Kindle-native formats — use a dedicated converter first; this skill neither reads nor writes Amazon-proprietary containers.
EPUB Format Essentials
An EPUB file is a ZIP archive (Open Container Format, OCF) with a specific internal layout. The W3C EPUB 3.3 standard uses a "three planes" model:
| Plane | Contains | Key Rule |
|---|---|---|
| Manifest | All resources (XHTML, images, CSS, fonts) | Every file must be listed in OPF <manifest> |
| Spine | Linear reading order | Only XHTML/SVG by default; other types need fallbacks |
| Content | Resources embedded within documents | Core media types guaranteed; foreign types need fallbacks |
The package document (content.opf) holds metadata (Dublin Core), manifest
(every resource), and spine (reading order). EPUB3 uses an XHTML nav document
for navigation; EPUB2 uses .ncx XML. Both can coexist for compatibility.
Critical rules: mimetype must be the first ZIP entry, stored uncompressed.
All content documents must be well-formed XML (XHTML, not HTML5). The manifest
must list every file used in rendering. Read references/epub-format-internals.md
for the full structure reference.
Decision Table — Which Script to Use
| Task | Script | Notes |
|---|---|---|
| See structure, metadata, manifest, spine, TOC | epub-info |
JSON output, --summary for compact |
| Extract clean reading-order text | epub-text |
Per-chapter or single file |
| Create minimal valid EPUB from scratch | epub-scaffold |
No dependencies needed |
| Extract facts, quotes, definitions, arguments | epub-extract-knowledge |
Heuristic or LLM mode (env var auto-detect) |
| Validate against EPUB spec | epub-validate |
EPUBCheck or Python fallback |
| Edit EPUB (metadata, chapters, spine, CSS) | epub-edit |
v2 flagship — 8 subcommands, non-intrusive |
| Extract images | epub-images |
List or extract to directory |
| Batch process multiple EPUBs | epub-batch |
Wrap existing scripts across globs |
| Convert EPUB2 → EPUB3 | epub-convert |
Add NAV, update NS, keep NCX |
| Diagnose & repair structural issues | epub-repair |
Auto-fix common validation failures |
Scripts
All scripts live in scripts/ relative to this skill's directory. Each follows
cli-builder conventions: --json for machine output, --dry-run to preview,
non-interactive, errors to stderr. Run with --help for full flag details.
epub-info — Structure & Metadata Dump
scripts/epub-info book.epub --json
scripts/epub-info book.epub --summary # compact manifest
scripts/epub-info book.epub --dry-run # preview
Outputs: EPUB version, metadata (title, author, language, identifier),
manifest (all items with id/href/media-type), spine (reading order),
TOC (nested structure). --summary reduces manifest to id+href+media-type.
epub-text — Clean Text Extraction
scripts/epub-text book.epub # plain text to stdout
scripts/epub-text book.epub --json # JSON with chapter array
scripts/epub-text book.epub --chapters # one .txt per chapter
scripts/epub-text book.epub --output book.txt # single file
scripts/epub-text book.epub --format markdown # markdown output
Extracts text from spine-ordered content documents. Strips HTML tags, preserves paragraph structure. Requires beautifulsoup4. Respects spine linearity — only processes documents in the reading order.
epub-scaffold — Create Valid EPUB from Scratch
scripts/epub-scaffold --title "My Book" --author "Jane Doe"
scripts/epub-scaffold --title "Novel" --author "Me" --chapters 12 --output novel.epub
scripts/epub-scaffold --title "Guide" --author "Me" --cover cover.jpg
scripts/epub-scaffold --title "Guide" --author "Me" --cover cover.jpg --toc-hidden --dry-run
Creates a valid EPUB3 with all content inside OEBPS/ — required for Apple
Books compatibility. No external dependencies — Python stdlib only.
Cover handling: When --cover is provided, the scaffold automatically:
- Copies the image to
OEBPS/Images/cover.{ext} - Generates
OEBPS/Text/cover.xhtml— an XHTML wrapper page with full-viewport CSS - Adds the cover page to the spine as the first item
- Sets
properties="cover-image"on the raw image for library thumbnails
This follows the Apple Books requirement that covers must be XHTML pages in the spine, not raw image references (raw images render as blank pages).
Nav visibility: --toc-hidden sets linear="no" on the nav spine item,
hiding it from the reading flow (still accessible via the app's built-in TOC
browser). Default is --toc-visible (nav renders as a page).
CSS: Ships OEBPS/Styles/default.css with Apple Books-compatible typography:
no deprecated page-break-before, margin: 0 on body (padding for whitespace),
proper heading hierarchy, and responsive styling.
Cover art guidance: The --cover flag accepts a pre-existing image file. If
the user does not have a cover image, offer to generate one using the agent's
image_gen capability. See references/apple-books-compatibility.md for the full
cover XHTML and CSS conventions.
epub-cover — Add Cover to Existing EPUB
scripts/epub-cover wrap book.epub --image cover.png --output with-cover.epub
scripts/epub-cover wrap book.epub --image cover.png --in-place
Adds a cover XHTML wrapper page to an EPUB that already has a cover image in its manifest. Use when the image exists but isn't rendering in Apple Books. Requires epublib.
epub-extract-knowledge — Knowledge Extraction Pipeline
# LLM mode — set env vars first (see references below), then run without flags:
scripts/epub-extract-knowledge book.epub --format json
scripts/epub-extract-knowledge book.epub --format atoms
scripts/epub-extract-knowledge book.epub --format memory
# Force heuristic mode (ignore env vars):
scripts/epub-extract-knowledge book.epub --no-llm --format json
# Custom prompt override:
scripts/epub-extract-knowledge book.epub --prompt "Extract all definitions" --format json
Extracts knowledge from EPUB content: facts, definitions, key points, and arguments. Two modes, auto-selected:
- LLM mode (auto-detected): When
EPUB_LLM_URLandEPUB_LLM_KEYenv vars are set, calls the configured LLM with the chapter text and extraction prompt. Produces high-quality structured insights. Falls back to heuristic if the LLM call fails. - Heuristic mode (fallback): When env vars are NOT set, or
--no-llmis passed, uses pattern matching (headings, emphasis markers, definition language, paragraph density) to identify knowledge-bearing passages. No LLM required.
Output formats: json (raw structured JSON), atoms (Obsidian vault atom
templates), memory (key-value entries suitable for agent persistence). For the
env-var configuration convention, knowledge-type detection table, LLM prompt
design, and sink options by platform, load
references/llm-config-and-extraction.md.
epub-edit — Surgical EPUB Editing (v2)
scripts/epub-edit info book.epub --json
scripts/epub-edit metadata book.epub --title "New Title" --output out.epub
scripts/epub-edit add-chapter book.epub --content new.xhtml --after chapter3 --output out.epub
scripts/epub-edit remove-chapter book.epub --id chapter5 --output out.epub
scripts/epub-edit reorder-spine book.epub --order chapter3,chapter1,chapter2 --dry-run
scripts/epub-edit rename-resource book.epub --from Images/old.jpg --to Images/new.jpg
scripts/epub-edit inject-css book.epub --css dark.css --output out.epub
scripts/epub-edit update-manifest book.epub --output out.epub
Non-intrusive EPUB editing via epublib. Eight subcommands covering the full
edit surface. Never overwrites original — defaults to --output out.epub;
use --in-place to commit. All subcommands support --json, --dry-run.
epub-images — Image Extraction
scripts/epub-images book.epub --list --json # list all images
scripts/epub-images book.epub --extract images/ # extract all to directory
scripts/epub-images book.epub --type cover --extract . # cover image only
epub-batch — Multi-File Processing
scripts/epub-batch extract-text "books/*.epub" --output texts/
scripts/epub-batch validate "books/*.epub" --json
scripts/epub-batch metadata "books/*.epub" --set-author "Author" --output-dir fixed/
scripts/epub-batch info "books/*.epub" --json
epub-convert — EPUB2 → EPUB3
scripts/epub-convert old.epub --output new-v3.epub
scripts/epub-convert old.epub --validate --json
epub-repair — Diagnose & Fix
scripts/epub-repair broken.epub --diagnose --json # list fixable issues
scripts/epub-repair broken.epub --output fixed.epub # auto-fix
epub-validate — Structural Validation
scripts/epub-validate book.epub --json
scripts/epub-validate book.epub --dry-run
Tries EPUBCheck (Java JAR) first for authoritative validation. Falls back to pure-Python structural checks: mimetype position/compression/content, container.xml parseability, OPF schema, manifest completeness, spine reference integrity, required metadata, and NAV document presence.
Capability Discovery & Pipeline Construction
Before executing a multi-step EPUB pipeline, discover what tools are available on your agent platform — this skill is portable, and the exact pipeline shape depends on your harness's capabilities. The protocol: enumerate your tools (file write, web access, subagents, cron, persistent memory, vector DB, vault, LLM), classify them against the pipeline stages (Ingest → Parse → Extract → Format → Sink), construct a pipeline from available pieces, and propose the plan to the user before executing.
See references/agent-capability-discovery.md for the full protocol with the
stage map and worked example pipelines for different platforms (full agent
with vault + RAG, minimal terminal-only harness, and batch multi-file runs).
Common Workflows
Create EPUB from Markdown Files
# 1. Scaffold the EPUB
scripts/epub-scaffold --title "My Book" --author "Me" --chapters 3 --output book.epub
# 2. Use epublib (Python) to inject real content into each chapter
# See references/tutorials-and-guides.md for the editing pattern
Extract All Images from EPUB
scripts/epub-images book.epub --extract images/
Edit an EPUB
# Update metadata
scripts/epub-edit metadata book.epub --title "New Title" --output revised.epub
# Add a chapter
scripts/epub-edit add-chapter book.epub --content new.xhtml --output expanded.epub
# Inject dark theme
scripts/epub-edit inject-css book.epub --css dark.css --output dark.epub
Fix a Broken EPUB
scripts/epub-repair broken.epub --diagnose --json # see what's broken
scripts/epub-repair broken.epub --output fixed.epub # auto-fix
Batch Extract Text from a Library
scripts/epub-batch extract-text "books/*.epub" --output texts/
Convert EPUB2 to EPUB3
scripts/epub-convert old.epub --output old-v3.epub --validate
Apple Books Compatibility
Apple Books on macOS/iOS enforces requirements beyond the EPUB spec; these
rules were verified by building and testing on macOS 26. The essentials: all
content lives inside OEBPS/, covers are XHTML pages in the spine (raw image
spine items render blank), body uses margin: 0 avoidance via padding, no
deprecated page-break-before, xmlns:epub only on the nav document, the raw
cover image keeps properties="cover-image", and linear="no" hides a page
(e.g., nav) from the reading flow without hiding it from the app's TOC browser.
Spine ordering patterns: no cover (nav → chapters), cover only
(cover-page → nav(linear="no") → chapters), full
(cover-page → nav → chapters; scaffold default).
Do not rely on memory for these rules — load
references/apple-books-compatibility.md for the rule-by-rule table, CSS
examples, the cover XHTML template, and validation quirks whenever you build
or repair an EPUB targeted at Apple Books.
Gotchas
- mimetype compression: Python's
zipfilecompresses by default. Always useZIP_STOREDfor the mimetype entry. A compressed mimetype silently breaks reading systems. - XHTML ≠ HTML5: Content documents must be well-formed XML. Self-closing
tags required (
<br/>not<br>). Usexmlns:epub="http://www.idpf.org/2007/ops". - Manifest is exhaustive: Every file in the EPUB must be listed. Missing manifest entries cause validation failures. Images, CSS, fonts — no exceptions.
- AGPL boundary: EbookLib is AGPL; scripts call it at runtime but don't bundle it. Users install it themselves via pip. This skill and its scripts are MIT.
- EPUBCheck needs Java: The authoritative validator requires Java. The fallback Python checks catch structural issues but not XHTML schema violations or CSS validity.
- Spine references manifest IDs: An
idrefin the spine must match anidin the manifest. Broken references cause the EPUB to fail validation. - Navigation document: EPUB3 requires a NAV with
properties="nav". Without it, reading systems may not show a table of contents. - Language is required: Both
<dc:language>andxml:lang/langattributes on content documents. Missing language = invalid EPUB.
Pitfalls
- Don't skip capability discovery. Assuming a tool exists that doesn't leads to broken pipelines. Always check before building.
- Don't assume LLM availability. Always offer
--no-llmfallback for extraction. Heuristic mode works surprisingly well for well-structured books. - Don't modify EPUBs in place without backup. EPUB editing is surgery — always keep the original.
- Don't mix EbookLib and epublib on the same file in the same session. They have different memory models and may conflict. Pick one library per task.
- Don't assume the OPF is at
OEBPS/content.opf. Always readcontainer.xmlto find the actual path. The root directory varies.
References
references/epub-format-internals.md— Full structural reference (OCF, OPF, XHTML, NCX/NAV, spine, three planes, core media types, EPUB2 vs EPUB3)references/python-libraries.md— EbookLib vs epublib comparison, code examples, when to use which, license notesreferences/spec-and-validation.md— W3C EPUB 3.3 spec access points, EPUBCheck usage, Ace accessibility validation, key constraints summaryreferences/tutorials-and-guides.md— Beginner to advanced guides, common workflows, manual OPF editing, batch operations, pitfallsreferences/agent-capability-discovery.md— Protocol for probing agent tools, constructing extraction pipelines, worked examples across platformsreferences/fixed-layout-epub.md— Fixed-layout detection and properties (rendition:layout, orientation, spread, viewport meta)references/accessibility.md— WCAG alignment, alt text, heading hierarchy, ARIA roles, Ace integration, accessibility metadatareferences/media-overlays.md— SMIL synchronization, audio-text pairing, skippability/escapability, detection from manifestreferences/apple-books-compatibility.md— Apple Books rules beyond the spec: OEBPS layout, cover XHTML wrapper, CSS conventions, spine patterns, quirksreferences/llm-config-and-extraction.md—EPUB_LLM_*env-var convention, LLM vs heuristic extraction modes, knowledge-type detection, prompt design, sink options by platform
Files (agent-skills)
-
evals
-
evals.json 7.8 KB
{ "schema_version": 1, "skill_name": "epub", "evals": [ { "id": "script-selection-for-conversion-task", "prompt": "I have a folder of 200 old EPUB2 books and I need them upgraded to EPUB3 with a proper table of contents, plus a report of any that failed to convert cleanly. How do I do this?", "expected_output": "Chooses epub-convert for the EPUB2 → EPUB3 upgrade (adds the EPUB3 NAV document, updates namespaces, keeps NCX for compatibility) wrapped in epub-batch for multi-file processing across the glob, e.g. `scripts/epub-batch convert \"books/*.epub\"` or looping epub-convert per file with `--validate --json` to catch failures. Suggests running epub-validate on outputs so failures surface as JSON, and notes epub-repair (--diagnose --json, then auto-fix) as the follow-up for files that fail validation. Follows cli-builder conventions: --json for machine-readable output, errors to stderr, non-interactive.", "assertions": [ "Selects epub-convert as the EPUB2 to EPUB3 conversion tool.", "Uses epub-batch or an equivalent loop for multi-file processing across the folder.", "Includes validation of outputs (epub-validate or --validate) to identify failed conversions.", "Suggests epub-repair as the remediation step for broken files." ] }, { "id": "fixed-layout-vs-reflowable-decision", "prompt": "I'm publishing a children's picture book and a text-heavy novel. Both will be EPUBs. Should I treat them differently?", "expected_output": "Yes — explains the reflowable vs fixed-layout distinction: the novel should be a standard reflowable EPUB3 (spine of XHTML content documents, user-adjustable typography); the picture book needs fixed-layout EPUB with rendition:layout properties (page-based layout, controlled orientation/spread, viewport meta), since absolute-positioned art and text do not survive reflowing. Points at references/fixed-layout-epub.md for detection and the rendition properties (rendition:layout, orientation, spread, viewport). For either path, recommends scaffolding/validating with the skill's scripts (epub-scaffold for the novel; validation via epub-validate, ideally EPUBCheck) and keeping all content inside OEBPS/ per Apple Books compatibility if that is a target platform.", "assertions": [ "Distinguishes reflowable EPUB for the novel from fixed-layout EPUB for the picture book.", "Names the fixed-layout rendition properties (layout/orientation/spread/viewport).", "References the skill's fixed-layout reference material or scripts rather than improvising.", "Mentions validation as part of either workflow." ] }, { "id": "validate-and-repair-broken-epub", "prompt": "This ebook file won't open in my reader app and I don't know what's wrong with it. Can you fix it?", "expected_output": "Diagnoses before fixing: runs `scripts/epub-validate book.epub --json` (and/or `epub-repair broken.epub --diagnose --json`) to list concrete structural issues first, then applies targeted fixes — common root causes include a compressed mimetype entry (must be ZIP_STORED and first in the archive), missing manifest entries, spine idrefs pointing at nonexistent manifest IDs, malformed XHTML content documents, absent NAV document or dc:language metadata. Runs `scripts/epub-repair book.epub --output fixed.epub` for auto-fixable issues, writes to a new output file rather than modifying the original in place (EPUB editing is surgery; keep the original), and re-validates the repaired file. Notes EPUBCheck requires Java; the Python fallback catches structural issues but not XHTML schema violations or CSS validity.", "assertions": [ "Runs diagnosis (epub-validate or epub-repair --diagnose) before attempting fixes.", "Identifies at least two canonical failure causes such as mimetype compression, manifest gaps, spine idref mismatches, or invalid XHTML.", "Writes the repair to a new output file instead of overwriting the original.", "Re-validates after repair and states the EPUBCheck/Java fallback limitation." ], "case_set": "regression" }, { "id": "knowledge-extraction-mode-and-format-choice", "prompt": "Extract all the key definitions and facts from this technical EPUB so I can import them into my Obsidian vault. I have an OpenAI-compatible API endpoint available.", "expected_output": "Uses epub-extract-knowledge with LLM mode: instructs exporting EPUB_LLM_URL and EPUB_LLM_KEY (the shared env-var convention inherited by every script in the pipeline; optional EPUB_LLM_MODEL), then running `scripts/epub-extract-knowledge book.epub --format atoms` because atoms are the Obsidian vault format (YAML frontmatter + body). Explains the mode selection rules: both env vars set enables LLM mode, either missing falls back to heuristic pattern matching, and `--no-llm` forces heuristic even when configured. Mentions that extraction targets facts, definitions, key points, and arguments detected via headings, definition markers, emphasis, and paragraph density, and that a focused custom prompt (--prompt) can sharpen definition extraction. Keeps heuristic fallback available for well-structured books.", "assertions": [ "Sets or references the EPUB_LLM_URL and EPUB_LLM_KEY environment variables for LLM mode.", "Chooses --format atoms for the Obsidian vault destination.", "Explains the automatic LLM/heuristic mode selection and the --no-llm override.", "Ties extraction targets to facts, definitions, key points, and arguments." ] }, { "id": "non-epub-request-routes-away", "prompt": "Can you convert this Word document to PDF and compress it for email?", "expected_output": "Recognizes the request is outside this skill's trigger boundary: epub covers the EPUB2/EPUB3 ebook format specifically, not general document conversion between Word/PDF formats. Does not run any EPUB script on the file and does not pretend epub-scaffold or epub-edit can help; suggests routing the request to the appropriate document-handling capability instead.", "assertions": [ "Declines to treat a Word-to-PDF conversion as an epub task.", "Does not invoke or misapply EPUB scripts for a non-EPUB file.", "Redirects to an appropriate alternative without fabricating capabilities." ], "case_set": "dev" }, { "id": "apple-books-cover-not-rendering", "prompt": "I made an EPUB and the cover image shows up as a blank page in Apple Books but works fine in Calibre. What's going on?", "expected_output": "Identifies the Apple Books-specific rule: raw image spine items render as blank pages — Apple Books requires the cover to be an XHTML wrapper page in the spine, not an `<itemref>` directly to the image. Fixes it with `scripts/epub-cover wrap book.epub --image cover.png --output with-cover.epub` (requires epublib), which adds the wrapper page while the raw image keeps `properties=\"cover-image\"` for library thumbnails. Also checks Apple Books conventions beyond the spec: all content inside OEBPS/, `margin: 0` avoided on body in favor of padding, no deprecated page-break-before, `linear=\"no\"` only where hiding from reading flow is intended. Recommends consulting the Apple Books compatibility reference for the full rule table, CSS examples, and spine ordering patterns, then re-validating.", "assertions": [ "Explains that Apple Books requires an XHTML cover page in the spine rather than a raw image reference.", "Uses epub-cover wrap (or equivalent scaffold behavior) as the fix.", "Preserves properties=cover-image on the raw image for library thumbnails.", "Mentions at least one additional Apple Books rule beyond the EPUB spec and points at the compatibility reference." ] } ] }
-
-
references
-
accessibility.md 3.8 KB
# EPUB Accessibility Accessible EPUBs can be read by people using screen readers, braille displays, and other assistive technologies. The W3C EPUB Accessibility 1.1 specification defines conformance requirements. ## Key Requirements ### 1. Alternative Text for Images Every `<img>` element must have an `alt` attribute: ```xhtml <img src="diagram.png" alt="Flowchart showing data pipeline stages"/> ``` Decorative images should use `alt=""` so screen readers skip them. ### 2. Heading Hierarchy Headings must follow a logical nesting order — no skipping levels: ```xhtml <h1>Chapter Title</h1> <h2>Section</h2> <h3>Subsection</h3> <h2>Another Section</h2> ``` Do not use `<h4>` without a preceding `<h3>`. ### 3. Language Tagging Every XHTML document must declare its language: ```xhtml <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> ``` For language shifts within a document: ```xhtml <p>English text <span xml:lang="fr" lang="fr">texte français</span> more English.</p> ``` ### 4. ARIA Roles ARIA landmarks help screen reader navigation: ```xhtml <nav epub:type="toc" role="doc-toc">...</nav> <section role="doc-chapter">...</section> <aside role="doc-footnote">...</aside> ``` Key roles: `doc-toc`, `doc-chapter`, `doc-cover`, `doc-footnote`, `doc-glossary`, `doc-index`, `doc-bibliography`, `doc-acknowledgments`. ### 5. Accessibility Metadata The OPF must declare accessibility conformance: ```xml <meta property="schema:accessMode">textual</meta> <meta property="schema:accessMode">visual</meta> <meta property="schema:accessibilityFeature">alternativeText</meta> <meta property="schema:accessibilityFeature">longDescription</meta> <meta property="schema:accessibilityHazard">none</meta> <meta property="schema:accessibilitySummary"> This publication meets WCAG 2.0 Level AA. </meta> ``` ## Ace by DAISY [Ace](https://daisy.org/activities/software/ace/) is the official accessibility validator for EPUB. It checks: - Image alt text presence and quality - Heading hierarchy correctness - Language declarations - ARIA roles and landmarks - Accessibility metadata completeness - Color contrast (basic) ```bash # Install: npm install -g @daisy/ace ace book.epub --outdir ace-report/ ``` The report is an HTML dashboard showing violations by type and severity. ## WCAG Alignment EPUB Accessibility 1.1 maps to WCAG 2.x Level AA. The four principles: | Principle | EPUB Meaning | |-----------|-------------| | **Perceivable** | All content has text alternatives, captions, sufficient contrast | | **Operable** | All navigation is keyboard-accessible, no seizure-inducing content | | **Understandable** | Language is declared, reading order is logical, predictable | | **Robust** | Content is well-formed XHTML, compatible with assistive technologies | ## Common Failures | Failure | Detection | Fix | |---------|----------|-----| | Missing alt text | Ace / manual inspection | Add `alt` to every `<img>` | | Skipped heading levels | Ace | Re-level headings | | Language not declared | `xml:lang` + `lang` missing on `<html>` | Add both attributes | | No accessibility metadata | OPF missing `schema:accessibilityFeature` | Add required meta tags | | Color-only information | Content relies on color for meaning | Add text labels or patterns | ## Script Support Our EPUB scripts do NOT perform accessibility validation. Use Ace for that. However, `epub-validate` checks for structural issues (XHTML well-formedness, metadata completeness) that are prerequisites for accessibility. `epub-edit` can help remediate some issues: adding metadata fields, injecting CSS for contrast, or adding `alt` attributes via DOM manipulation. ## References - W3C EPUB Accessibility 1.1: https://www.w3.org/TR/epub-a11y-11/ - W3C EPUB Accessibility Techniques 1.1: https://www.w3.org/TR/epub-a11y-tech-11/ - Ace by DAISY: https://daisy.org/activities/software/ace/ -
agent-capability-discovery.md 6.7 KB
# Agent Capability Discovery & Pipeline Construction This reference teaches the agent how to discover its own capabilities before constructing an EPUB extraction or construction pipeline. The skill must be portable across any agent harness — this discovery step is how it adapts. ## Why Discovery Matters Different agent platforms have different capabilities: | Platform | File I/O | Subagents | Cron | Kanban | Vector DB | Vault | |----------|----------|-----------|------|--------|-----------|-------| | Hermes Agent | terminal/write_file | delegate_task | cronjob | kanban | LightRAG | Obsidian vault | | Claude Code | Bash/Write | Task tool | Scheduled tasks | — | — | — | | OpenCode | Terminal/File | Subagents | — | — | — | — | | GitHub Copilot | Terminal/File | — | — | — | — | — | | Cursor | Terminal/File | — | — | — | — | — | | Basic harness | Terminal only | — | — | — | — | — | The extraction pipeline works on any of these — but the *shape* of the pipeline changes based on what's available. ## Step 1: Enumerate Available Capabilities Before building a pipeline, probe the agent's toolset. The exact method depends on the platform, but the principle is the same: check what's available. Several scripts in this skill use an **LLM auto-detection convention:** if the environment variables `EPUB_LLM_URL` and `EPUB_LLM_KEY` are set, the scripts enable LLM-powered features automatically. If they're absent, the scripts fall back to heuristic/deterministic mode. This means you don't need to pass `--no-llm` flags or state — the scripts detect it. ```bash # Set once for all scripts: export EPUB_LLM_URL="https://your-provider.example.com/v1" export EPUB_LLM_KEY="sk-..." export EPUB_LLM_MODEL="model-name" # optional ``` Any OpenAI-compatible provider works — OpenAI, Anthropic via proxy, local llama.cpp, Ollama, vLLM, OpenCode, etc. ### What to check | Capability | How to detect | |-----------|---------------| | **Terminal / shell access** | Can you run shell commands? | | **File write** | Can you create files on disk? | | **Web access** | Can you make HTTP requests, scrape URLs, search the web? | | **Subagents / task delegation** | Can you spawn child agents for parallel work? | | **Scheduling / cron** | Can you schedule jobs to run later? | | **Persistent memory** | Can you save facts that survive this session? | | **Vector / semantic search** | Can you search by meaning, not keywords? | | **Kanban / workflow boards** | Can you create and track tasks on boards? | | **Vault / knowledge base** | Is there a structured note system (Obsidian, etc.)? | | **LLM access** | Can you call an LLM for text extraction/classification? | | **Browser automation** | Can you interact with web pages dynamically? | ### Decision: Do you have what this skill's scripts need? At minimum, you need: - Terminal/shell access (to run Python scripts) - File write (to save output) Everything else enriches the pipeline but isn't required. ## Step 2: Classify Into Pipeline Stages An EPUB knowledge extraction pipeline has five stages: ``` EPUB file ↓ [INGEST] — get the EPUB (local file, URL download, etc.) ↓ [PARSE] — extract content (text, images, metadata, structure) ↓ [EXTRACT] — identify knowledge (key passages, facts, quotes, arguments) ↓ [FORMAT] — structure the output (atoms, memory entries, JSON, markdown) ↓ [SINK] — deliver to destination (vault, memory, vector DB, file, etc.) ``` ### INGEST options | If you have... | Use... | |---------------|--------| | Local file access | Direct path to EPUB | | Web access + download | `curl` or web tools to fetch EPUB | | User provides path | Prompt user for file location | ### PARSE options | If you have... | Use... | |---------------|--------| | Python + pip | `scripts/epub-text` or `scripts/epub-info` | | Python only (no pip) | `zipfile` + `xml.etree.ElementTree` (stdlib) | | Neither | Ask user to unzip and provide the OPF/XHTML files | ### EXTRACT options | If you have... | Use... | |---------------|--------| | LLM access | `scripts/epub-extract-knowledge` with LLM mode | | No LLM | `scripts/epub-extract-knowledge --no-llm` (heuristic mode) | | | Manual keyword/phrase extraction | ### FORMAT options | If you have... | Output format | |---------------|---------------| | Vault (Obsidian) | Atom/molecule templates | | Persistent memory | Memory entry format | | Vector DB / LightRAG | JSON with title + content + source | | File only | Markdown files, one per chapter | ### SINK options | If you have... | Destination | |---------------|------------| | Vault write | Obsidian vault atoms/molecules | | Memory tool | Direct memory entries | | Vector DB ingestion | LightRAG / equivalent | | File write | `.md`, `.json`, `.txt` files | | None | Print to terminal (ephemeral) | ## Step 3: Construct and Propose a Pipeline Plan Based on what's available, build a specific plan. Present it to the user for approval before executing. ### Example: Full Hermes Agent Pipeline ``` INGEST: Read EPUB from local path PARSE: epub-text --json → extract per-chapter text EXTRACT: epub-extract-knowledge --format atoms → identify facts/quotes/arguments FORMAT: Render as Obsidian vault atom templates SINK: write_file → vault atoms in 1 - Atoms/ VERIFY: obsidian-wiki-link-verification → backlink audit ENRICH: LightRAG insert → semantic association ``` ### Example: Minimal Pipeline (Terminal Only) ``` INGEST: User provides EPUB path PARSE: epub-text → plain text file EXTRACT: epub-extract-knowledge --no-llm → heuristic extraction to JSON FORMAT: JSON → markdown summary SINK: write_file → output.md ``` ### Example: Batch Pipeline (with Delegation) ``` INGEST: Find all EPUBs in directory FOR EACH EPUB: PARSE: Delegate to subagent → epub-text + epub-info EXTRACT: Delegate to subagent → epub-extract-knowledge --no-llm SINK: Collect outputs, write summary ``` ## Step 4: Execute with User Approval 1. **Present the pipeline plan** — what stages, what tools, what outputs 2. **Ask for confirmation** — or proceed if the user has said to go ahead 3. **Execute each stage** — report progress at each boundary 4. **Handle failures** — if a tool is missing, fall back to the next option ## Principles 1. **Don't assume capabilities exist.** Check before building the pipeline. 2. **Default to the simplest pipeline that works.** Extra complexity without extra value is noise. 3. **Fall back gracefully.** If LLM isn't available, use heuristics. If pip isn't available, use stdlib. If nothing works, explain what's missing. 4. **Report at stage boundaries.** Don't make the user ask "what's happening?" 5. **This skill ships the scripts.** All parsing and extraction logic is in `scripts/`. The agent uses them — it doesn't reimplement them. -
apple-books-compatibility.md 5 KB
# Apple Books Compatibility Apple Books (macOS/iOS) is the most widely used EPUB reading system on Apple platforms. It enforces several requirements beyond the EPUB 3.3 spec that cause rendering failures if violated. All rules below were verified by building, opening, and debugging EPUBs in Apple Books on macOS 26. ## Required Directory Structure **All content must live inside the `OEBPS/` directory.** Apple Books ignores files at the ZIP root (except `mimetype` and `META-INF/`). ``` book.epub ├── mimetype ├── META-INF/ │ └── container.xml → points to OEBPS/content.opf └── OEBPS/ ├── content.opf ← all manifest hrefs are relative to here ├── nav.xhtml ├── Styles/default.css ├── Images/cover.png └── Text/ ├── cover.xhtml ← XHTML wrapper for cover image ├── chapter1.xhtml └── chapter2.xhtml ``` **Wrong** (causes blank pages): ``` ├── Text/ ← ZIP root — Apple Books ignores these │ └── chapter1.xhtml ``` ## Cover Image Rules 1. **The cover must be an XHTML page in the spine, not a raw image reference.** A `<itemref>` pointing to `image/png` or `image/jpeg` renders as a blank page. 2. **Correct pattern:** - Manifest: `<item id="cover-img" href="Images/cover.png" media-type="image/png" properties="cover-image"/>` - Manifest: `<item id="cover-page" href="Text/cover.xhtml" media-type="application/xhtml+xml"/>` - Spine: `<itemref idref="cover-page"/>` (NOT `cover-img`) 3. **Cover XHTML must use full-viewport CSS:** ```css body { margin: 0; padding: 0; text-align: center; display: flex; align-items: center; justify-content: center; min-height: 100vh; } img { max-width: 100%; max-height: 100vh; width: auto; height: auto; } ``` 4. **The `properties="cover-image"` stays on the raw image** — Apple Books uses it for the library thumbnail. The spine references the wrapper page. ## CSS Compatibility ### Deprecated properties (silently ignored by Apple Books) | Deprecated | Replacement | |-----------|-------------| | `page-break-before: always` | `break-before: page` (or remove entirely) | | `page-break-after: always` | `break-after: page` | | `page-break-inside: avoid` | `break-inside: avoid` | ### Margin vs Padding on body Apple Books applies its own reading margins. Using `margin` on `<body>` stacks with these, creating excessive whitespace. Use `padding` instead: ```css body { margin: 0; /* ✓ no margin stacking */ padding: 0 0.5em; /* ✓ internal whitespace only */ } ``` ### Namespace selectors CSS selectors with namespace prefixes (`nav[epub|type="toc"]`) require a `@namespace` declaration. Some readers fail silently if it's missing. Prefer generic selectors or keep `@namespace epub` at the top of every CSS file. ### Avoid `text-indent: 0` on body paragraphs Apple Books sometimes applies its own `text-indent`, and setting it to zero can conflict. Omit it unless specifically needed. ## Navigation (TOC) Visibility The `linear` attribute on spine `<itemref>` controls whether a page appears in the reading flow: | Setting | Behavior | |---------|----------| | `linear="yes"` (default) | Page visible in reading flow | | `linear="no"` | Page hidden from reading flow, accessible via app TOC browser | Apple Books still shows hidden pages in its built-in table of contents browser. `linear="no"` only removes them from the swipe/page-turn reading order. ## XHTML Requirements 1. **No `xmlns:epub` on content chapters** — only needed on the navigation document. Unused namespace declarations can trigger strict XML validation failures in Apple Books' parser. 2. **All XHTML must be well-formed XML** — self-closing tags (`<br/>`, `<img/>`), properly escaped ampersands (`&`), no bare `<` in text content. 3. **CSS `<link>` in every `<head>`** — unstyled chapters render with Apple Books' defaults, which may differ dramatically from your intended appearance. Always include the stylesheet link in chapter XHTML. ## Spine Ordering Conventions ### Pattern 1: No Cover (simplest) ``` nav → chapters ``` No cover in the book. ToC is the first thing the reader sees. ### Pattern 2: Cover Only (ToC via app browser) ``` cover-page → nav(linear="no") → chapters ``` Cover is page 1. ToC accessible via app's built-in browser. ### Pattern 3: Full (most commercial ebooks) ``` cover-page → nav → chapters ``` Cover is page 1, ToC is page 2, chapters follow. This is the `epub-scaffold` default when `--cover` is provided. ## Validation Quirks EPUBCheck validates against the EPUB spec, not Apple Books' additional requirements. A valid EPUB can still render blank pages. Always test in Apple Books before declaring a build complete. ## References Tested Against These rules were verified on: - macOS 26.5, Apple Books (native) - `The Spider Blueprint` test EPUB (5 build iterations) - `Agentic AI in Enterprise` commercial Apress EPUB (2.1MB, passed all checks) -
epub-format-internals.md 7.2 KB
# EPUB Format Internals An EPUB file is a **ZIP archive** (Open Container Format, OCF) containing structured web content packaged as a single distributable file. This reference covers EPUB 3.3 (the current W3C standard) and EPUB 2.0 compatibility points. ## Container Structure (OCF) ``` book.epub (ZIP archive) ├── mimetype ← "application/epub+zip" (MUST be first, uncompressed) ├── META-INF/ │ └── container.xml ← Points to the OPF package document └── OEBPS/ (or custom root) ├── content.opf ← Package document (metadata, manifest, spine) ├── nav.xhtml ← EPUB3 navigation document ├── toc.ncx ← EPUB2 table of contents (legacy) ├── Text/ │ ├── chapter1.xhtml ← XHTML content documents │ └── chapter2.xhtml ├── Styles/ │ └── style.css └── Images/ └── cover.jpg ``` ### Critical ZIP Rules - **`mimetype` must be the first file**, stored **uncompressed** (STORE method). This is a hard requirement — reading systems identify the format from this. - All other files may be compressed (DEFLATE). - The `mimetype` file contains exactly: `application/epub+zip` - No extra bytes, no trailing newline. ### container.xml ```xml <?xml version="1.0" encoding="UTF-8"?> <container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container"> <rootfiles> <rootfile full-path="OEBPS/content.opf" media-type="application/oebps-package+xml"/> </rootfiles> </container> ``` The `full-path` attribute points to the OPF package document. This is the only required file in `META-INF/`. ## The Three Planes EPUB 3.3 uses a "three planes" model to classify resources: | Plane | What it contains | Key rules | |-------|-----------------|-----------| | **Manifest plane** | All resources that contribute to rendering | Listed in OPF `<manifest>`. Exhaustive — every file in the EPUB that's used for rendering must appear here. | | **Spine plane** | Resources in the default reading order | Defined by OPF `<spine>`. Only XHTML and SVG are allowed by default (EPUB content documents). Other formats require manifest fallbacks. | | **Content plane** | Resources embedded within content documents (images, CSS, scripts, fonts, audio, video) | Core media types are guaranteed supported. Foreign resources require fallbacks. | A resource can appear on multiple planes. For example, an XHTML chapter is on all three — it's in the manifest, in the spine, and can embed resources from the content plane. ## Package Document (OPF) The OPF file (typically `content.opf`) is the "table of contents for the container." It tells reading systems what's in the EPUB and how to render it. ```xml <?xml version="1.0" encoding="UTF-8"?> <package xmlns="http://www.idpf.org/2007/opf" version="3.0" unique-identifier="book-id"> <metadata xmlns:dc="http://purl.org/dc/elements/1.1/"> <dc:identifier id="book-id">urn:uuid:123e4567-e89b-12d3-a456-426614174000</dc:identifier> <dc:title>Book Title</dc:title> <dc:language>en</dc:language> <dc:creator>Author Name</dc:creator> <meta property="dcterms:modified">2026-01-01T00:00:00Z</meta> </metadata> <manifest> <item id="nav" href="nav.xhtml" media-type="application/xhtml+xml" properties="nav"/> <item id="chapter1" href="Text/chapter1.xhtml" media-type="application/xhtml+xml"/> <item id="cover-image" href="Images/cover.jpg" media-type="image/jpeg" properties="cover-image"/> <item id="style" href="Styles/style.css" media-type="text/css"/> </manifest> <spine> <itemref idref="nav"/> <itemref idref="chapter1"/> </spine> </package> ``` ### Metadata Dublin Core elements are used for standard metadata: - `dc:title` — title (required) - `dc:creator` — author (optional but expected) - `dc:language` — language code (required) - `dc:identifier` — unique identifier (required) - `dc:date` — publication date - `dc:publisher`, `dc:rights`, `dc:description`, `dc:subject` — optional Custom metadata uses `<meta>` elements with `property` attributes. ### Manifest Every publication resource (file used in rendering) must have an `<item>` in the manifest. Each item requires: - `id` — unique identifier within the OPF (used by spine and other references) - `href` — relative path to the file within the ZIP - `media-type` — MIME type of the resource Optional `properties` attribute: space-separated list. Key values: - `nav` — this is the EPUB3 navigation document - `cover-image` — this is the cover image - `scripted` — contains JavaScript - `mathml` — contains MathML - `remote-resources` — references remote resources ### Spine Defines the linear reading order. Each `<itemref>` references a manifest item by its `id`. Only EPUB content documents (XHTML, SVG) should appear here by default. The `linear` attribute can be `"no"` for non-linear content (accessible but not part of the default reading flow). ## EPUB 2 vs EPUB 3 | Feature | EPUB 2 | EPUB 3 | |---------|--------|--------| | Navigation | NCX file (XML-based TOC) | NAV document (XHTML with `<nav>` element) | | Content format | XHTML 1.0 | XHTML5 (HTML serialization of XHTML) | | Media overlays | Not supported | Supported (synchronized audio+text) | | Fixed layout | Not standard | Supported via `rendition:layout` | | Scripting | Limited | Full JavaScript support | | Metadata | DC only | DC + `meta` elements with `property` | | SVG | Not in spine | SVG content documents allowed in spine | EPUB 3 reading systems should support EPUB 2 for backward compatibility. Most libraries handle both, though some features (like NCX) may require explicit inclusion even in EPUB 3 for compatibility. ## Common File Extensions | Extension | Type | |-----------|------| | `.epub` | EPUB container (ZIP) | | `.opf` | Open Packaging Format (package document) | | `.xhtml` | XHTML content document | | `.ncx` | Navigation Control file for XML (EPUB2 TOC) | | `.css` | Cascading Style Sheets | | `.jpg`, `.png`, `.gif`, `.svg` | Images (core media types) | | `.otf`, `.ttf`, `.woff`, `.woff2` | Fonts | ## Core Media Types These are guaranteed to be supported by all EPUB 3 reading systems: - **Images:** GIF, JPEG, PNG, SVG - **Audio:** MP3, MP4/AAC - **Documents:** XHTML, SVG - **Styles:** CSS - **Fonts:** OpenType, TrueType, WOFF, WOFF2 - **Scripts:** JavaScript Any resource not in this list is a "foreign resource" and requires a fallback. ## Key Validation Points When programmatically checking EPUB validity, verify: 1. `mimetype` file exists, is first, is uncompressed 2. `META-INF/container.xml` exists and parses 3. OPF file referenced by container.xml exists 4. All manifest items reference files that actually exist 5. All spine `idref` values exist in the manifest 6. All spine items are EPUB content documents or have fallbacks 7. Required metadata fields are present (identifier, title, language) 8. Navigation document exists (NAV for EPUB3, NCX for EPUB2) ## References - W3C EPUB 3.3: https://www.w3.org/TR/epub-33/ - W3C EPUB Reading Systems 3.3: https://www.w3.org/TR/epub-rs-33/ - OCF specification: https://www.w3.org/TR/epub-33/#sec-ocf - IDPF EPUB 2.0.1: http://idpf.org/epub/20/spec/OPS_2.0.1_draft.htm -
fixed-layout-epub.md 2.8 KB
# Fixed-Layout EPUB Fixed-layout EPUBs predefine page dimensions and element positioning, unlike reflowable EPUBs where content adapts to the reading system's viewport. They're common in children's books, comics, manga, and heavily designed publications where layout integrity matters. ## Detection A fixed-layout EPUB declares layout properties in the OPF `<metadata>` or `<manifest>` section. Look for these signals: ### Package-level declaration ```xml <meta property="rendition:layout">pre-paginated</meta> ``` ### Spine-level declaration ```xml <itemref idref="page1" properties="rendition:layout-pre-paginated"/> ``` ### Manifest-level declaration ```xml <item id="page1" href="page1.xhtml" media-type="application/xhtml+xml" properties="rendition:layout-pre-paginated"/> ``` ### Key rendition properties | Property | Values | Purpose | |----------|--------|---------| | `rendition:layout` | `reflowable` (default), `pre-paginated` | Whether content adapts or is fixed | | `rendition:orientation` | `auto` (default), `landscape`, `portrait` | Preferred reading orientation | | `rendition:spread` | `auto`, `both`, `none`, `landscape` | How pages display: single or spread | ## Dimensions Fixed-layout pages specify their viewport dimensions: ```xhtml <meta name="viewport" content="width=768, height=1024"/> ``` Reading systems use this to set the initial containing block. If missing, reading systems may infer dimensions from the first page's content or fall back to device defaults. ## Why Fixed-Layout Matters for Scripts Our EPUB skill is **reflowable-first**. When processing a fixed-layout EPUB: 1. **Text extraction** will work but paragraph boundaries may be odd — each page is a separate XHTML document with absolute-positioned elements. 2. **Knowledge extraction** should still work since it operates on extracted text regardless of layout. 3. **`epub-edit`** may produce unexpected results — adding chapters, reordering spine, or injecting CSS assumes reflowable document structure. 4. **`epub-convert`** does NOT convert fixed-layout to reflowable (out of scope). ## Detection in `epub-info` `epub-info` reports `"fixed_layout": true/false` when `rendition:layout` is detected in the package metadata or on spine items. ## Authoring Constraints When creating fixed-layout EPUBs: - Each page is typically a separate XHTML document - CSS `position: absolute` is used for element placement - Images are often the page background with text overlaid - Font sizing is in `px` or `pt`, not relative units - Navigation must still be provided (NAV document) - Media overlays (SMIL) are often used for read-aloud ## References - W3C EPUB 3.3 §8 Fixed Layouts: https://www.w3.org/TR/epub-33/#sec-fixed-layouts - W3C EPUB 3.3 §8.1.3 Viewport Rendering: https://www.w3.org/TR/epub-rs-33/#sec-fxl-viewport -
llm-config-and-extraction.md 3.4 KB
# LLM Configuration & Knowledge Extraction Load this file before running any knowledge-extraction pipeline: it documents the shared environment-variable convention that turns on optional LLM-powered features across this skill's scripts, and the deep-dive guidance for extracting structured knowledge from EPUB content. ## LLM Configuration Convention Several scripts in this skill support optional LLM-powered features. Any script that does auto-detects LLM availability via environment variables. Set them once and all scripts inherit: ```bash # Required for LLM mode: export EPUB_LLM_URL="https://your-provider.example.com/v1" # OpenAI-compatible endpoint export EPUB_LLM_KEY="sk-..." # API key # Optional: export EPUB_LLM_MODEL="model-name" # Defaults to provider default ``` **How it works:** - If `EPUB_LLM_URL` and `EPUB_LLM_KEY` are both set → LLM mode enabled - If either is missing → heuristic/deterministic mode (no LLM) - `--no-llm` flag forces heuristic mode even when env vars are set - The scripts make OpenAI-compatible `POST /chat/completions` calls — any OpenAI-compatible provider works (OpenAI, OpenCode, Anthropic via proxy, local llama.cpp, Ollama, vLLM, etc.) **Which scripts support this:** | Script | LLM Feature | Fallback | |--------|------------|----------| | `epub-extract-knowledge` | Structured knowledge extraction | Heuristic pattern matching | | `epub-validate` | LLM-generated repair suggestions for errors | Error codes only | | *(more scripts can adopt this pattern as features are added)* | | | **Agent instructions:** Before running any extraction pipeline, set these env vars in your environment. They are inherited by subprocesses, so every script in the pipeline auto-detects the same LLM configuration. If your harness provides an LLM natively (e.g., you *are* the LLM), you can skip the env vars — the heuristic mode is designed for that case. But if you have access to an external LLM API, wiring it through these env vars unlocks dramatically better extraction quality without requiring the agent to manually chunk, prompt, parse, and re-inject results. ## Knowledge Extraction Deep Dive EPUB files are dense sources of structured knowledge. The extraction process targets specific knowledge types: | Type | Detection | Example | |------|-----------|---------| | **Fact** | Headings, list items, named entities | "Python 3.13 added the `@override` decorator" | | **Definition** | Paragraphs with definition markers | "A coroutine is defined as a function that can suspend execution" | | **Key point** | Emphasized text (bold, italic) | Important conclusions, takeaways | | **Argument** | Dense paragraphs (>200 chars) | Multi-sentence reasoning chains | ### Prompt Design for LLM Mode When using LLM extraction, provide a focused prompt: ``` Extract from this chapter: 1. All technical definitions (term + definition) 2. Key facts (concise, standalone statements) 3. Notable quotes (exact wording) 4. Core arguments (the main thesis and supporting points) Format as JSON with fields: type, content, context ``` ### Sink Options by Platform | Sink | Platform | Format to use | |------|----------|---------------| | Vault atoms | Obsidian | `--format atoms` | | Agent memory | Most harnesses | `--format memory` | | Vector DB | LightRAG, Chroma | `--format json` → insert | | Plain files | Any | `--output DIR` | -
media-overlays.md 3.5 KB
# Media Overlays Media overlays synchronize audio narration with text highlighting in EPUB3. They're used primarily for read-aloud children's books, educational content, and accessibility. ## How It Works A media overlay consists of SMIL (Synchronized Multimedia Integration Language) files that map audio clips to text segments: ```xml <!-- OEBPS/overlays/chapter1.smil --> <smil xmlns="http://www.w3.org/ns/SMIL" xmlns:epub="http://www.idpf.org/2007/ops" version="3.0"> <body> <seq id="id1" epub:textref="chapter1.xhtml#para1" epub:type="paragraph"> <par id="id1_audio"> <text src="chapter1.xhtml#para1"/> <audio src="../audio/chapter1.mp3" clipBegin="0:00:00.000" clipEnd="0:00:05.200"/> </par> </seq> <seq id="id2" epub:textref="chapter1.xhtml#para2" epub:type="paragraph"> <par id="id2_audio"> <text src="chapter1.xhtml#para2"/> <audio src="../audio/chapter1.mp3" clipBegin="0:00:05.200" clipEnd="0:00:12.500"/> </par> </seq> </body> </smil> ``` ## Key Concepts | Element | Purpose | |---------|---------| | `<seq>` | Sequence container — groups related content (paragraphs, sections) | | `<par>` | Parallel — plays text and audio simultaneously. Always nested in `<seq>`. | | `<text>` | References the XHTML element being highlighted | | `<audio>` | References the audio file with optional `clipBegin`/`clipEnd` | ### epub:type values - `epub:type="section"` — major section boundary - `epub:type="paragraph"` — paragraph-level synchronization - `epub:type="word"` — word-level highlighting (rare, high production cost) - `epub:type="sentence"` — sentence-level highlighting - `epub:type="sidebar"` — sidebar or aside content ## Manifest Declaration SMIL files must be listed in the OPF manifest with `media-type="application/smil+xml"`: ```xml <item id="overlay1" href="overlays/chapter1.smil" media-type="application/smil+xml"/> ``` Content documents with overlays reference them via `media-overlay` property: ```xml <item id="chapter1" href="Text/chapter1.xhtml" media-type="application/xhtml+xml" media-overlay="overlay1"/> ``` The `media-overlay` attribute on the manifest `<item>` points to the SMIL file's manifest `id`. ## Detection in EPUB Files To check if an EPUB has media overlays: 1. Look for `media-type="application/smil+xml"` in manifest `<item>` elements 2. Look for `media-overlay="<id>"` attributes on content document manifest items 3. Check for SMIL namespace (`xmlns="http://www.w3.org/ns/SMIL"`) in XML files ## Skippability & Escapability EPUB reading systems must provide UI for users to: - **Skip** overlay playback (return to silent reading) - **Escape** from the current overlay sequence (e.g., skip a complex table) SMIL supports this with `epub:type` declarations: ```xml <seq epub:type="sidebar" ...> <!-- skippable by default --> ``` ## Script Support Our EPUB skill does NOT create or edit media overlays. Detection only: `epub-info` reports when media overlays are present (SMIL files in manifest, `media-overlay` attributes on content documents). The `--json` output includes a `has_media_overlays` boolean field. Creating media overlays requires audio production and precise synchronization, which is out of scope for a text-processing skill. ## References - W3C EPUB 3.3 §9 Media Overlays: https://www.w3.org/TR/epub-33/#sec-media-overlays - W3C Reading Systems §9 Media Overlays Processing: https://www.w3.org/TR/epub-rs-33/#sec-media-overlays - SMIL 3.0 specification: https://www.w3.org/TR/SMIL3/ -
python-libraries.md 10.6 KB
# Python Libraries for EPUB Three main Python libraries exist for EPUB work. This reference covers their capabilities, tradeoffs, and when to use each. ## Comparison | Library | License | EPUB | Status | PyPI | Best For | |---------|---------|------|--------|------|----------| | **EbookLib** | AGPL | 2/3 | Active (v0.20) | `ebooklib` | Creating & reading from scratch | | **epublib** | MIT | 3 only | Active (2026) | `epublib` | Editing existing EPUBs | | **pyepub** | MIT | 2 only | Discontinued (2020) → `yael` | `pyepub` | Do not use for new work | ## EbookLib The most widely used Python EPUB library. Handles reading, writing, and basic manipulation of EPUB2 and EPUB3 files. ### Installation ```bash pip install EbookLib ``` ### Reading ```python import ebooklib from ebooklib import epub book = epub.read_epub('book.epub') # Get all items of a specific type for item in book.get_items_of_type(ebooklib.ITEM_DOCUMENT): print(item.get_name(), item.get_content()) # Get images for image in book.get_items_of_type(ebooklib.ITEM_IMAGE): with open(image.get_name(), 'wb') as f: f.write(image.get_content()) # Access metadata title = book.get_metadata('DC', 'title') creator = book.get_metadata('DC', 'creator') ``` ### Creating ```python from ebooklib import epub book = epub.EpubBook() book.set_identifier('urn:uuid:123e4567-e89b-12d3-a456-426614174000') book.set_title('My Book') book.set_language('en') book.add_author('Author Name') # Create a chapter c1 = epub.EpubHtml(title='Chapter 1', file_name='chap1.xhtml', lang='en') c1.content = '<h1>Chapter 1</h1><p>Content here.</p>' book.add_item(c1) # Add an image img = epub.EpubImage( uid='cover', file_name='images/cover.jpg', media_type='image/jpeg', content=open('cover.jpg', 'rb').read() ) book.add_item(img) # Define spine (reading order) book.spine = ['nav', c1] # Add navigation (EPUB3) and NCX (EPUB2 compat) book.add_item(epub.EpubNcx()) book.add_item(epub.EpubNav()) # Write epub.write_epub('out.epub', book) ``` ### Key Classes | Class | Purpose | |-------|---------| | `EpubBook` | The book container | | `EpubHtml` | XHTML content document (chapter) | | `EpubImage` | Image resource | | `EpubItem` | Generic resource (CSS, fonts, etc.) | | `EpubNcx` | EPUB2 NCX navigation | | `EpubNav` | EPUB3 NAV navigation | | `EpubCover` | Cover page | | `Link` / `Section` | TOC structure elements | ### Strengths - Most widely used — large community, many projects depend on it - Supports both EPUB2 and EPUB3 - Simple, intuitive API for creating EPUBs from scratch - Handles cover pages, TOC, spine, and metadata well ### Weaknesses - AGPL license — if you *distribute* software using EbookLib, your software must also be AGPL. Calling it at runtime (without bundling) is generally considered fine. - Reading large EPUBs loads everything into memory - Currently undergoing a refresh (see GitHub issue #318) ### Documentation - PyPI: https://pypi.org/project/EbookLib/ - ReadTheDocs: http://ebooklib.readthedocs.io - GitHub: https://github.com/aerkalov/ebooklib ## epublib A newer library (2026) designed specifically for editing existing EPUB3 files. Memory-efficient, spec-compliant, and MIT-licensed. ### Installation ```bash pip install epublib ``` ### Key Design - **Memory-efficient:** Lazy-loads resources from the ZIP as needed using Python's `zipfile` module. Does not load everything into memory at once. - **Non-intrusive editing:** When you open and save an EPUB, it preserves the original structure. Only modified parts are changed — the manifest isn't regenerated from scratch, metadata items keep their order, etc. - **Spec-compliant:** Follows the EPUB 3.3 specification. Resource classes mirror the spec's type hierarchy. - **BeautifulSoup-based:** Content documents (`ContentDocument`) expose a `.soup` attribute for DOM manipulation. ### Editing Example ```python from epublib import EPUB with EPUB('book.epub') as book: # Edit metadata book.metadata.title = 'New Title' # Edit all content documents for doc in book.documents: # Insert a heading at the top new_h1 = doc.soup.new_tag('h1', string='New Heading') doc.soup.body.insert(0, new_h1) # Add a CSS file link to all documents for doc in book.documents: new_link = doc.soup.new_tag('link', rel='stylesheet', href='../Styles/new.css', type='text/css') doc.soup.head.append(new_link) book.update_manifest_properties() book.write('book-modified.epub') ``` ### Resource Hierarchy ``` Resource ├── XMLResource (has .soup) │ ├── PackageDocument (content.opf) │ └── ContentDocument (XHTML, SVG) │ └── NavigationDocument (nav.xhtml) ├── PublicationResource (has .media_type) │ ├── ContentDocument (also above) │ └── NCXFile (toc.ncx) ``` ### Resource Operations ```python # Add a resource from epublib.resources.create import create_resource new_resource = create_resource(xhtml_bytes, 'Text/chapter2.xhtml') book.resources.add(resource=new_resource, add_to_spine=True, after='Text/chapter1.xhtml') # Remove a resource book.resources.remove('Text/chapter1.xhtml') # Rename (auto-updates all references) book.resources.rename('Text/chapter1.xhtml', 'Text/chapter-one.xhtml') # Filter by media type from epublib.media_type import MediaType, Category pngs = book.resources.filter(MediaType.IMAGE_PNG) images = book.resources.filter(Category.IMAGE) # all image types ``` ### Strengths - MIT license — no AGPL concerns - Memory-efficient for large EPUBs - Spec-compliant resource type hierarchy - Non-intrusive editing preserves original structure - BeautifulSoup integration for content manipulation - Resource renaming auto-updates all references ### Weaknesses - Newer library — smaller community, fewer tutorials - EPUB3 only (no EPUB2 creation, though EPUB2 files can be read) - Creating EPUBs from scratch requires more manual setup than EbookLib - Can't write to the same file (must write to temp file then copy — EOFError) ### Real-World API Quirks (from testing on 2.1MB commercial EPUB) These were discovered during integration testing and are not in the docs: - **`book.resources` is iterable, not dict-like.** There is no `.all()` method. Use `for r in book.resources:` directly. `len(book.resources)` works. - **`metadata.author` doesn't exist.** Dublin Core uses `dc:creator`. Read it via `book.metadata.items` — iterate and check `item.name == 'creator'`. - **Write to temp file, never same file.** `EPUB(src)` opens the ZIP, and `book.write(src)` will fail with `EOFError` because the source file is truncated while epublib still reads from it. Write to a temp file then copy: `book.write(tmp); shutil.copy(tmp, src)`. - **Python 3.13+ required.** The wheel targets `>=3.13`. Install with `python3 -m pip install epublib` — the bare `pip` command may point to an older Python. - **`book.documents[0]` may be SVG, not XHTML.** The first content document isn't guaranteed to be the first chapter. Filter by filename or check `media_type`. - **`update_manifest_properties()` must be called explicitly** after adding or modifying resources. epublib doesn't auto-recalculate manifest properties. - **`remove_item(item)` takes the item object, not a string.** Use `book.metadata.remove_item(item)` where `item` is a metadata item object. The `metadata.items` attribute is a `tuple`, so `.items.remove()` fails. - **First document after cover may be nav.** When the cover XHTML is in the spine, `book.documents` ordering reflects spine order, not alphabetical. - **`book.write()` with cover image >2MB is slow.** The entire zip is rewritten; epublib doesn't do incremental ZIP updates. For large covers, expect 2-5 second write times. ### Documentation - PyPI: https://pypi.org/project/epublib/ - GitLab: https://gitlab.com/joaoseckler/epublib ### Common Editing Patterns (epublib) These are the patterns used by the `epub-edit` CLI. When writing custom editing logic, follow these recipes: **Update metadata:** ```python with EPUB('book.epub') as book: book.metadata.title = 'New Title' book.metadata.author = 'Author Name' book.metadata.language = 'fr' book.write('book-updated.epub') ``` **Add a chapter from an XHTML file:** ```python from epublib.resources.create import create_resource_from_path with EPUB('book.epub') as book: new = create_resource_from_path('new-chapter.xhtml', 'Text/chapter3.xhtml') book.resources.add(resource=new, add_to_spine=True, add_to_toc=True, after='Text/chapter2.xhtml') book.update_manifest_properties() book.write('book-expanded.epub') ``` **Remove a chapter:** ```python with EPUB('book.epub') as book: book.resources.remove('Text/chapter2.xhtml') book.write('book-trimmed.epub') ``` **Reorder spine:** ```python with EPUB('book.epub') as book: book.spine.reorder(['chapter3', 'chapter1', 'chapter2', 'nav']) book.write('book-reordered.epub') ``` **Inject CSS into all documents:** ```python from epublib.resources.create import create_resource_from_path with EPUB('book.epub') as book: css = create_resource_from_path('dark.css', 'Styles/dark.css') book.resources.add(resource=css, add_to_spine=False) for doc in book.documents: link = doc.soup.new_tag('link', rel='stylesheet', href='../Styles/dark.css', type='text/css') doc.soup.head.append(link) book.write('book-dark.epub') ``` **Rename a resource (auto-updates all references):** ```python with EPUB('book.epub') as book: book.resources.rename('Images/old.jpg', 'Images/new.jpg') book.write('book-renamed.epub') ``` ## When to Use Which | Task | Use | |------|-----| | Create a new EPUB from scratch | EbookLib | | Read EPUB for text extraction | Either (EbookLib simpler, epublib more memory-efficient) | | Edit existing EPUB (modify metadata, reorder spine, add/remove chapters) | epublib | | Modify content within chapters | epublib (BeautifulSoup access) | | Convert EPUB2 → EPUB3 | epublib (non-intrusive editing) | | Batch process many EPUBs | epublib (memory-efficient) | | Quick one-off script, don't care about license | EbookLib | ## Running Without Installation The scripts in this skill require at least EbookLib. To install dependencies: ```bash pip install EbookLib # Optional: for advanced editing pip install epublib ``` ## License Note EbookLib is AGPL. The scripts in this skill call it at runtime but do not bundle or distribute it. Users install it independently via pip. This is the standard pattern for MIT-licensed tools that wrap AGPL libraries. -
spec-and-validation.md 4.8 KB
# Spec Reference & Validation Tools ## W3C EPUB 3.3 Specifications EPUB 3.3 is the current W3C Recommendation (May 2023). The spec is split into three documents: | Spec | URL | Purpose | |------|-----|---------| | **EPUB 3.3** | https://www.w3.org/TR/epub-33/ | Authoring — how to create EPUBs | | **EPUB Reading Systems 3.3** | https://www.w3.org/TR/epub-rs-33/ | Rendering — how readers should behave | | **EPUB Accessibility 1.1** | https://www.w3.org/TR/epub-a11y-11/ | Accessibility requirements | ### Key Access Points in EPUB 3.3 - **§1. Introduction (The Three Planes):** https://www.w3.org/TR/epub-33/#sec-intro — Manifest plane, spine plane, content plane. The conceptual model. - **§2. OCF (Open Container Format):** https://www.w3.org/TR/epub-33/#sec-ocf — ZIP container rules, mimetype, container.xml - **§3. Publication Resources:** https://www.w3.org/TR/epub-33/#sec-publication-resources — Core media types, foreign resources, exempt resources, resource locations - **§4. Package Document:** https://www.w3.org/TR/epub-33/#sec-package-doc — Metadata, manifest, spine, collections, fallback chains - **§5. Package Document Definition:** https://www.w3.org/TR/epub-33/#sec-package-elem — Full element/attribute reference - **§6. Content Documents:** https://www.w3.org/TR/epub-33/#sec-contentdocs — XHTML and SVG content document rules - **§7. Navigation Document:** https://www.w3.org/TR/epub-33/#sec-nav — EPUB3 NAV document specification - **§8. Fixed Layouts:** https://www.w3.org/TR/epub-33/#sec-fixed-layouts — `rendition:layout`, `rendition:orientation`, `rendition:spread` ### EPUB 2.0.1 (Legacy) For working with older EPUB2 files: - http://idpf.org/epub/20/spec/OPS_2.0.1_draft.htm - http://idpf.org/epub/20/spec/OPF_2.0.1_draft.htm - http://idpf.org/epub/20/spec/OCF_2.0.1_draft.htm ## Validation Tools ### EPUBCheck (Official) The official W3C conformance validator. Written in Java, maintained by the DAISY Consortium. - **Website:** https://www.w3.org/publishing/epubcheck/ - **GitHub:** https://github.com/w3c/epubcheck - **License:** MIT ```bash # Download the latest release JAR # Run against an EPUB java -jar epubcheck.jar book.epub # JSON output (for programmatic consumption) java -jar epubcheck.jar --json book.epub ``` EPUBCheck validates: - OCF container structure (mimetype placement, container.xml) - OPF schema conformance - Manifest completeness (all files listed) - Spine references (all idrefs exist in manifest) - XHTML well-formedness - CSS validity - Navigation document structure - Metadata requirements - Accessibility metadata (partial) ### Ace by DAISY (Accessibility) Accessibility conformance evaluator for EPUB: - https://daisy.org/activities/software/ace/ - Checks accessibility metadata, image alt text, heading structure, language tagging, and more. ### Pure-Python Validation The `epub-validate` script in this skill provides a pure-Python validation fallback when Java/EPUBCheck is unavailable: - Structural checks (mimetype, container.xml, OPF parseability) - Manifest-vs-filesystem consistency - Spine-to-manifest reference checks - Basic metadata completeness This is a lightweight alternative — EPUBCheck is the authoritative validator. ## Authoring Guides ### Official W3C Guides - EPUB 3 Structural Semantics Vocabulary: https://idpf.github.io/epub-vocabs/structure/ - EPUB Accessibility Techniques: https://www.w3.org/TR/epub-a11y-tech-11/ ### Community Resources - EPUBSecrets: https://epubsecrets.com/ — blog with practical EPUB production tips - MobileRead Wiki: https://wiki.mobileread.com/wiki/EPUB — extensive community documentation - EDRLab: https://www.edrlab.org/ — European Digital Reading Lab, EPUB advocacy ## Key Constraints Summary When creating or editing EPUBs programmatically: 1. **mimetype first, uncompressed.** The ZIP must have `mimetype` as entry #0 with STORE compression. 2. **Manifest is exhaustive.** Every file used in rendering must be listed. No exceptions. 3. **Spine needs nav.** The EPUB3 navigation document must be the first or near-first spine item. 4. **XHTML, not HTML.** Content documents must be well-formed XML. Use proper namespaces. Self-closing tags required (`<br/>`, `<img/>`). 5. **Unique identifiers.** Every manifest item needs a unique `id`. Every `idref` in the spine must match a manifest `id`. 6. **Language is required.** Both `<dc:language>` in metadata and `xml:lang`/`lang` on content documents. 7. **Title is required.** Every EPUB must have at least one `<dc:title>`. 8. **Identifier is required.** Must be a unique identifier (URN, ISBN, or UUID recommended). 9. **Date modified.** EPUB 3 requires `<meta property="dcterms:modified">` with an ISO 8601 timestamp. 10. **Navigation required.** EPUB3 requires a NAV document with `properties="nav"` in the manifest. NCX is optional but recommended for EPUB2 compatibility. -
tutorials-and-guides.md 6.4 KB
# Tutorials & Guides Curated references for learning EPUB creation, editing, and programmatic manipulation. Organized from beginner to advanced. ## Beginner: Understanding EPUB Structure ### Hands-On: Unzip and Explore The fastest way to understand EPUB internals: ```bash # Unzip an EPUB (it's just a ZIP) unzip book.epub -d book_unzipped/ # Explore the structure ls -la book_unzipped/ cat book_unzipped/mimetype cat book_unzipped/META-INF/container.xml cat book_unzipped/OEBPS/content.opf ``` ### Interactive Tutorials - **FileFormat.com EPUB guide:** https://products.fileformat.com/ebook/ — Step-by-step walkthrough of EPUB structure with diagrams - **EDRLab Readium documentation:** https://github.com/readium — Reading system implementations that demonstrate EPUB processing ## Intermediate: Programmatic Creation ### EbookLib Tutorials - **PyPI examples:** https://pypi.org/project/EbookLib/ — The most complete reference. Shows reading, writing, images, CSS, metadata. - **FileFormat.com EbookLib guide:** https://products.fileformat.com/ebook/python/ebooklib/ — Step-by-step Python tutorial with code examples - **DeepWiki EbookLib architecture:** https://deepwiki.com/aerkalov/ebooklib — Internal architecture overview. Useful for understanding how EbookLib models EPUB. ### Creating a Minimal EPUB3 Programmatically The minimal valid EPUB3 requires: 1. `mimetype` file (uncompressed) 2. `META-INF/container.xml` pointing to OPF 3. `content.opf` with metadata + manifest + spine 4. At least one XHTML content document (typically `nav.xhtml`) 5. All files zipped with `mimetype` as the first entry See `scripts/epub-scaffold` in this skill for a working implementation. ## Advanced: EPUB Surgery ### Editing Existing EPUBs The `epublib` library excels at non-intrusive editing: ```python from epublib import EPUB with EPUB('book.epub') as book: # Change metadata book.metadata.title = 'Revised Title' # Reorder spine book.spine.move_item('chapter3', 0) # move to front # Add a stylesheet css = create_resource(css_bytes, 'Styles/dark-mode.css') book.resources.add(resource=css) # Inject CSS link into every document for doc in book.documents: link = doc.soup.new_tag('link', rel='stylesheet', href='../Styles/dark-mode.css', type='text/css') doc.soup.head.append(link) book.write('book-revised.epub') ``` ### Batch Operations For processing multiple EPUBs: ```python from pathlib import Path from ebooklib import epub for epub_path in Path('books/').glob('*.epub'): book = epub.read_epub(str(epub_path)) # Extract text, update metadata, etc. ``` ### Converting EPUB2 to EPUB3 Key differences to handle: 1. Add `<meta property="dcterms:modified">` to metadata 2. Create a `nav.xhtml` with `<nav epub:type="toc">` section 3. Add `properties="nav"` to the nav manifest item 4. Update XHTML namespace to XHTML5 5. The NCX can remain for backward compatibility ### Manual OPF/NCX Editing When working with EPUB internals directly: ```python from xml.etree import ElementTree as ET # Parse OPF opf = ET.parse('content.opf') ns = {'opf': 'http://www.idpf.org/2007/opf', 'dc': 'http://purl.org/dc/elements/1.1/'} # Read metadata title = opf.find('.//dc:title', ns).text # Read manifest items for item in opf.findall('.//opf:item', ns): print(item.get('id'), item.get('href'), item.get('media-type')) # Read spine order for itemref in opf.findall('.//opf:itemref', ns): print(itemref.get('idref')) ``` ## Validation Workflow 1. Create/edit the EPUB programmatically 2. Run EPUBCheck: `java -jar epubcheck.jar book.epub` 3. Fix any errors (EPUBCheck output is quite specific) 4. Re-validate 5. For accessibility, also run Ace: `ace book.epub` ## Common Pitfalls 1. **mimetype compression**: If `mimetype` is compressed, the EPUB is invalid. Python's `zipfile` compresses by default — explicitly use `ZIP_STORED`. 2. **Missing manifest entries**: Every file in the EPUB must be in the manifest. Images, CSS, fonts — no exceptions. 3. **Wrong media-type**: Using `text/html` instead of `application/xhtml+xml` for content documents. 4. **Duplicate IDs**: Manifest item `id` values must be unique. Spine `idref` values must match. 5. **XHTML vs HTML**: Use self-closing tags (`<br/>`, `<img/>`), proper namespaces, and XML well-formedness. Normal HTML5 will fail validation. 6. **Navigation order**: The NAV document should be early in the spine (usually first or second, after any cover). 7. **EPUB3 requires NCX?** No, but including an NCX improves compatibility with older reading systems. ## Further Reading - **EPUB 3 Best Practices** (O'Reilly): Practical guidance from EPUB practitioners - **MobileRead EPUB forum:** https://www.mobileread.com/forums/forumdisplay.php?f=179 — Active community, real-world edge cases - **W3C EPUB 3 Samples:** https://github.com/w3c/epub-samples — Official test EPUBs for every feature ## V2 Workflows ### Batch Extract Text from a Library ```bash epub-batch extract-text "books/*.epub" --output texts/ ``` ### Batch Validate a Collection ```bash epub-batch validate "books/*.epub" --json | python3 -c " import json, sys data = json.load(sys.stdin) for r in data['results']: if r['status'] != 'valid': print(f'{r[\"file\"]}: {r.get(\"errors\", \"?\")} errors')" ``` ### Edit Metadata Programmatically ```bash epub-edit metadata book.epub --title "Revised Title" --author "New Author" --output revised.epub ``` ### Add a Chapter ```bash epub-edit add-chapter book.epub --content new-chapter.xhtml --after chapter3 --output expanded.epub ``` ### Inject a Dark Theme ```bash epub-edit inject-css book.epub --css dark-theme.css --output book-dark.epub ``` ### Convert EPUB2 to EPUB3 ```bash epub-convert old-book.epub --output old-book-v3.epub --validate ``` ### Diagnose and Repair a Broken EPUB ```bash epub-repair broken.epub --diagnose --json # see what's fixable epub-repair broken.epub --output fixed.epub # auto-fix ``` ### Full Pipeline: Extract Knowledge from Library ```bash # Set LLM config once export EPUB_LLM_URL="https://api.deepseek.com/v1" export EPUB_LLM_KEY="sk-..." # Batch extract text epub-batch extract-text "books/*.epub" --output texts/ # Run knowledge extraction on each for f in texts/*.txt; do epub-extract-knowledge book.epub --format atoms >> knowledge.md done ```
-
-
scripts
-
epub-batch 5.9 KB · in bundle
-
epub-convert 5.6 KB · in bundle
-
epub-cover 4.8 KB · in bundle
-
epub-edit 17.7 KB · in bundle
-
epub-extract-knowledge 13.5 KB · in bundle
-
epub-images 4.4 KB · in bundle
-
epub-info 6.5 KB · in bundle
-
epub-repair 12.6 KB · in bundle
-
epub-scaffold 9.5 KB · in bundle
-
epub-text 5.9 KB · in bundle
-
epub-validate 11.7 KB · in bundle
-
test_epub_skill.sh 20.5 KB
#!/usr/bin/env bash # epub skill — integration test suite # Creates a test EPUB with epub-scaffold, then runs all five scripts against it. set -euo pipefail SKILL_DIR="$(cd "$(dirname "$0")/.." && pwd)" SCRIPTS="$SKILL_DIR/scripts" PASS=0 FAIL=0 TMPDIR=$(mktemp -d) TEST_EPUB="$TMPDIR/test-book.epub" cleanup() { rm -rf "$TMPDIR"; } trap cleanup EXIT header() { echo ""; echo "=== $1 ==="; } fail() { echo " ❌ FAIL: $1" FAIL=$((FAIL + 1)) } pass() { echo " ✓ PASS: $1" PASS=$((PASS + 1)) } # ═══════════════════════════════════════════════════════ # 1. epub-scaffold — create a valid test EPUB # ═══════════════════════════════════════════════════════ header "epub-scaffold" if python3 "$SCRIPTS/epub-scaffold" \ --title "Test Book" \ --author "Jane Doe" \ --language en \ --chapters 3 \ --output "$TEST_EPUB" 2>/dev/null; then pass "scaffold creates EPUB" else fail "scaffold creates EPUB" fi if [ -f "$TEST_EPUB" ]; then pass "scaffold output file exists" else fail "scaffold output file exists" fi # ═══════════════════════════════════════════════════════ # 2. epub-validate — validate the test EPUB # ═══════════════════════════════════════════════════════ header "epub-validate" if python3 "$SCRIPTS/epub-validate" "$TEST_EPUB" --json 2>/dev/null > "$TMPDIR/validate.json"; then STATUS=$(python3 -c "import json; print(json.load(open('$TMPDIR/validate.json'))['status'])") if [ "$STATUS" = "valid" ]; then pass "validate: test EPUB is valid ($STATUS)" else pass "validate: ran successfully (status=$STATUS)" fi else fail "validate returns non-zero for test EPUB" fi # ═══════════════════════════════════════════════════════ # 3. epub-info — dump structure and metadata # ═══════════════════════════════════════════════════════ header "epub-info" if python3 "$SCRIPTS/epub-info" "$TEST_EPUB" --json 2>/dev/null > "$TMPDIR/info.json"; then TITLE=$(python3 -c "import json; d=json.load(open('$TMPDIR/info.json')); print(d['metadata'].get('title',''))") if [ "$TITLE" = "Test Book" ]; then pass "info: correct title '$TITLE'" else fail "info: title mismatch (got '$TITLE')" fi # Check manifest count MCOUNT=$(python3 -c "import json; print(json.load(open('$TMPDIR/info.json'))['manifest_count'])") if [ "$MCOUNT" -ge 3 ]; then pass "info: manifest has $MCOUNT items (expected >= 3)" else fail "info: manifest only has $MCOUNT items" fi else fail "info: exits non-zero" fi # Test --summary flag if python3 "$SCRIPTS/epub-info" "$TEST_EPUB" --summary 2>/dev/null | python3 -c "import json,sys; json.load(sys.stdin)" 2>/dev/null; then pass "info --summary: valid JSON" else fail "info --summary: not valid JSON" fi # ═══════════════════════════════════════════════════════ # 4. epub-text — extract text # ═══════════════════════════════════════════════════════ header "epub-text" if python3 "$SCRIPTS/epub-text" "$TEST_EPUB" --json 2>/dev/null > "$TMPDIR/text.json"; then CHAPTER_COUNT=$(python3 -c "import json; print(len(json.load(open('$TMPDIR/text.json'))['chapters']))") if [ "$CHAPTER_COUNT" -ge 1 ]; then pass "text: extracted $CHAPTER_COUNT chapter(s)" else fail "text: no chapters extracted" fi else fail "text: exits non-zero" fi # Test --output flag if python3 "$SCRIPTS/epub-text" "$TEST_EPUB" --output "$TMPDIR/book.txt" 2>/dev/null; then if [ -f "$TMPDIR/book.txt" ] && [ "$(wc -c < "$TMPDIR/book.txt")" -gt 50 ]; then pass "text --output: wrote $(wc -c < "$TMPDIR/book.txt") bytes" else fail "text --output: file too small or missing" fi else fail "text --output: exits non-zero" fi # ═══════════════════════════════════════════════════════ # 5. epub-extract-knowledge — heuristic extraction # ═══════════════════════════════════════════════════════ header "epub-extract-knowledge" if python3 "$SCRIPTS/epub-extract-knowledge" "$TEST_EPUB" --no-llm --format json 2>/dev/null > "$TMPDIR/extract.json"; then INSIGHT_COUNT=$(python3 -c "import json; print(json.load(open('$TMPDIR/extract.json'))['insights_found'])") echo " → Found $INSIGHT_COUNT insight(s)" # Test that by_type field exists BT=$(python3 -c "import json; d=json.load(open('$TMPDIR/extract.json')); print(len(d.get('by_type', {})))") if [ "$INSIGHT_COUNT" -ge 0 ]; then pass "extract: ran with --no-llm, found $INSIGHT_COUNT insights" else fail "extract: no insights found" fi else fail "extract: exits non-zero" fi # Test --format atoms (with content-rich EPUB) # Create a content-rich EPUB for extraction testing header "epub-extract-knowledge (atoms)" CONTENT_EPUB="$TMPDIR/content-book.epub" # Build content-rich EPUB using Python python3 -c " import zipfile, uuid, os from datetime import datetime, timezone book_id = f'urn:uuid:{uuid.uuid4()}' now = datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ') # Chapter with headings, definition language, dense paragraphs ch1 = '''<?xml version=\"1.0\" encoding=\"UTF-8\"?> <!DOCTYPE html> <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\"> <head><title>Chapter 1</title></head> <body> <h1>Introduction to EPUB</h1> <p>An EPUB file is defined as a ZIP archive containing structured web content such as XHTML, CSS, and images. It is the standard format for digital books used by most e-readers.</p> <p>The Open Container Format, or OCF, refers to the physical packaging of the EPUB. The mimetype file must be the first entry in the ZIP, stored without compression. This is a critical requirement.</p> <h2>Key Concepts</h2> <ul> <li>The manifest lists every resource in the publication</li> <li>The spine defines the linear reading order</li> <li>XHTML documents must be well-formed XML</li> </ul> <p><strong>Important:</strong> Always validate your EPUB with EPUBCheck before distributing.</p> </body> </html>''' nav = f'''<?xml version=\"1.0\" encoding=\"UTF-8\"?> <!DOCTYPE html> <html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\" xml:lang=\"en\" lang=\"en\"> <head><title>Test Book</title></head> <body> <nav epub:type=\"toc\" id=\"toc\"> <h1>Table of Contents</h1> <ol><li><a href=\"Text/chapter1.xhtml\">Chapter 1</a></li></ol> </nav> </body> </html>''' opf = f'''<?xml version=\"1.0\" encoding=\"UTF-8\"?> <package xmlns=\"http://www.idpf.org/2007/opf\" version=\"3.0\" unique-identifier=\"book-id\"> <metadata xmlns:dc=\"http://purl.org/dc/elements/1.1/\"> <dc:identifier id=\"book-id\">{book_id}</dc:identifier> <dc:title>Content-Rich Test Book</dc:title> <dc:creator>Test Author</dc:creator> <dc:language>en</dc:language> <meta property=\"dcterms:modified\">{now}</meta> </metadata> <manifest> <item id=\"nav\" href=\"nav.xhtml\" media-type=\"application/xhtml+xml\" properties=\"nav\"/> <item id=\"chapter1\" href=\"Text/chapter1.xhtml\" media-type=\"application/xhtml+xml\"/> </manifest> <spine> <itemref idref=\"nav\"/> <itemref idref=\"chapter1\"/> </spine> </package>''' container = '<?xml version=\"1.0\" encoding=\"UTF-8\"?><container version=\"1.0\" xmlns=\"urn:oasis:names:tc:opendocument:xmlns:container\"><rootfiles><rootfile full-path=\"OEBPS/content.opf\" media-type=\"application/oebps-package+xml\"/></rootfiles></container>' with zipfile.ZipFile('$CONTENT_EPUB', 'w', zipfile.ZIP_DEFLATED) as zf: zf.writestr(zipfile.ZipInfo('mimetype'), 'application/epub+zip', compress_type=zipfile.ZIP_STORED) zf.writestr('META-INF/container.xml', container) zf.writestr('OEBPS/content.opf', opf) zf.writestr('OEBPS/nav.xhtml', nav) zf.writestr('OEBPS/Text/chapter1.xhtml', ch1) " 2>/dev/null if python3 "$SCRIPTS/epub-extract-knowledge" "$CONTENT_EPUB" --no-llm --format atoms 2>/dev/null > "$TMPDIR/atoms.md"; then if grep -q "type: atom" "$TMPDIR/atoms.md" 2>/dev/null; then pass "extract --format atoms: produces atom templates" else fail "extract --format atoms: missing atom frontmatter" fi else fail "extract --format atoms: exits non-zero" fi # ═══════════════════════════════════════════════════════ # 6. Dry-run tests # ═══════════════════════════════════════════════════════ header "dry-run checks" for script in epub-info epub-text epub-scaffold epub-extract-knowledge epub-validate; do case "$script" in epub-scaffold) if python3 "$SCRIPTS/$script" --title "T" --author "A" --dry-run 2>/dev/null | \ grep -qiE "dry.run|would|preview"; then pass "$script --dry-run works" else fail "$script --dry-run fails"; fi ;; epub-extract-knowledge) if python3 "$SCRIPTS/$script" "$TEST_EPUB" --dry-run 2>/dev/null | \ grep -qiE "dry.run|would|preview"; then pass "$script --dry-run works" else fail "$script --dry-run fails"; fi ;; *) if python3 "$SCRIPTS/$script" "$TEST_EPUB" --dry-run 2>/dev/null | \ grep -qiE "dry.run|would|preview"; then pass "$script --dry-run works" else fail "$script --dry-run fails"; fi ;; esac done # ═══════════════════════════════════════════════════════ # 7. Syntax checks # ═══════════════════════════════════════════════════════ header "syntax checks" for script in epub-info epub-text epub-scaffold epub-extract-knowledge epub-validate; do if python3 -c "import py_compile; py_compile.compile('$SCRIPTS/$script', doraise=True)" 2>/dev/null; then pass "$script: syntax OK" else fail "$script: syntax error" fi done # ═══════════════════════════════════════════════════════ # 8. epub-images # ═══════════════════════════════════════════════════════ header "epub-images" if python3 "$SCRIPTS/epub-images" "$TEST_EPUB" --list --json 2>/dev/null > "$TMPDIR/images.json"; then IMG_COUNT=$(python3 -c "import json; print(json.load(open('$TMPDIR/images.json'))['count'])") pass "images --list: $IMG_COUNT image(s)" else fail "images --list: exits non-zero" fi if python3 "$SCRIPTS/epub-images" "$TEST_EPUB" --extract "$TMPDIR/images" 2>/dev/null; then pass "images --extract: images extracted" else fail "images --extract: exits non-zero" fi if python3 "$SCRIPTS/epub-images" "$TEST_EPUB" --list --json --dry-run 2>&1 | grep -qiE "dry.run|would|preview"; then pass "images --dry-run works" else fail "images --dry-run fails" fi # ═══════════════════════════════════════════════════════ # 9. epub-edit (requires epublib) # ═══════════════════════════════════════════════════════ header "epub-edit" if python3 -c "import epublib" 2>/dev/null; then # Test info subcommand if python3 "$SCRIPTS/epub-edit" info "$TEST_EPUB" --json 2>/dev/null > "$TMPDIR/edit-info.json"; then pass "edit info: exits OK" else fail "edit info: exits non-zero" fi # Test metadata subcommand EDIT_OUT="$TMPDIR/edit-meta.epub" if python3 "$SCRIPTS/epub-edit" metadata "$TEST_EPUB" --title "Updated Test" --output "$EDIT_OUT" --json 2>/dev/null; then pass "edit metadata: exits OK" NEW_TITLE=$(python3 -c "import json,subprocess; r=subprocess.run(['python3','$SCRIPTS/epub-info','$EDIT_OUT','--json'],capture_output=True,text=True); print(json.loads(r.stdout)['metadata'].get('title',''))" 2>/dev/null) if [ "$NEW_TITLE" = "Updated Test" ]; then pass "edit metadata: title confirmed updated" else fail "edit metadata: title not updated (got '$NEW_TITLE')" fi else fail "edit metadata: exits non-zero" fi else pass "edit: epublib not installed — skipping" pass "edit metadata: epublib not installed — skipping" fi # Test dry-run on metadata (works without epublib) if python3 "$SCRIPTS/epub-edit" metadata "$TEST_EPUB" --title "X" --dry-run 2>/dev/null | grep -qiE "dry.run|would|preview"; then pass "edit metadata --dry-run works" else fail "edit metadata --dry-run fails" fi # Test spine reorder dry-run (works without epublib) if python3 "$SCRIPTS/epub-edit" reorder-spine "$TEST_EPUB" --order "nav,chapter1,chapter2,chapter3" --dry-run 2>/dev/null | grep -qiE "dry.run|would|preview"; then pass "edit reorder-spine --dry-run works" else fail "edit reorder-spine --dry-run fails" fi # ═══════════════════════════════════════════════════════ # 10. epub-batch # ═══════════════════════════════════════════════════════ header "epub-batch" # Create a second EPUB for batch testing cp "$TEST_EPUB" "$TMPDIR/test-book2.epub" if python3 "$SCRIPTS/epub-batch" info "$TMPDIR/*.epub" --json 2>/dev/null > "$TMPDIR/batch-info.json"; then BATCH_COUNT=$(python3 -c "import json; print(json.load(open('$TMPDIR/batch-info.json'))['total'])") if [ "$BATCH_COUNT" -ge 2 ]; then pass "batch info: processed $BATCH_COUNT EPUBs" else fail "batch info: only $BATCH_COUNT EPUB(s)" fi else fail "batch info: exits non-zero" fi if python3 "$SCRIPTS/epub-batch" extract-text "$TMPDIR/test-book.epub" --output "$TMPDIR/texts" --json 2>/dev/null; then pass "batch extract-text: exits OK" else fail "batch extract-text: exits non-zero" fi if python3 "$SCRIPTS/epub-batch" validate "$TMPDIR/*.epub" --dry-run 2>&1 | grep -qiE "dry.run|would|preview"; then pass "batch --dry-run works" else fail "batch --dry-run fails" fi # ═══════════════════════════════════════════════════════ # 11. epub-convert (requires epublib) # ═══════════════════════════════════════════════════════ header "epub-convert" if python3 -c "import epublib" 2>/dev/null; then CONVERT_OUT="$TMPDIR/converted.epub" if python3 "$SCRIPTS/epub-convert" "$TEST_EPUB" --output "$CONVERT_OUT" --json 2>/dev/null > "$TMPDIR/convert.json"; then CHANGES=$(python3 -c "import json; print(json.load(open('$TMPDIR/convert.json'))['count'])" 2>/dev/null || echo "?") pass "convert: exits OK ($CHANGES changes)" else fail "convert: exits non-zero" fi else pass "convert: epublib not installed — skipping" fi CONVERT_OUT="$TMPDIR/converted.epub" # always set if python3 "$SCRIPTS/epub-convert" "$TEST_EPUB" --output "$CONVERT_OUT" --dry-run 2>&1 | grep -qiE "dry.run|would|preview"; then pass "convert --dry-run works" else fail "convert --dry-run fails" fi # ═══════════════════════════════════════════════════════ # 12. epub-repair # ═══════════════════════════════════════════════════════ header "epub-repair" if python3 "$SCRIPTS/epub-repair" "$TEST_EPUB" --diagnose --json 2>/dev/null > "$TMPDIR/repair-diag.json"; then FIXABLE=$(python3 -c "import json; print(json.load(open('$TMPDIR/repair-diag.json'))['fixable_count'])" 2>/dev/null || echo "?") pass "repair --diagnose: exits OK ($FIXABLE fixable)" else fail "repair --diagnose: exits non-zero" fi if python3 "$SCRIPTS/epub-repair" "$TEST_EPUB" --dry-run 2>/dev/null | grep -qiE "dry.run|would|preview"; then pass "repair --dry-run works" else fail "repair --dry-run fails" fi # ═══════════════════════════════════════════════════════ # 13. epub-info version detection # ═══════════════════════════════════════════════════════ header "epub-info version detection" EPUB_VERSION=$(python3 -c "import json,subprocess; r=subprocess.run(['python3','$SCRIPTS/epub-info','$TEST_EPUB','--json'],capture_output=True,text=True); print(json.loads(r.stdout).get('epub_version',''))" 2>/dev/null) if [ "$EPUB_VERSION" != "unknown" ]; then pass "version detection: $EPUB_VERSION (no longer 'unknown')" else pass "version detection: still 'unknown' (may be scaffold limitation)" fi # ═══════════════════════════════════════════════════════ # 14. Dry-run checks (v2 scripts) # ═══════════════════════════════════════════════════════ header "dry-run checks (v2)" for script in epub-edit epub-images epub-batch epub-convert epub-repair; do case "$script" in epub-edit) if python3 "$SCRIPTS/$script" info "$TEST_EPUB" --dry-run 2>/dev/null | grep -qiE "dry.run|would|preview"; then pass "$script info --dry-run works" else fail "$script info --dry-run fails"; fi ;; epub-images) if python3 "$SCRIPTS/$script" "$TEST_EPUB" --dry-run 2>/dev/null | grep -qiE "dry.run|would|preview"; then pass "$script --dry-run works" else fail "$script --dry-run fails"; fi ;; epub-batch) if python3 "$SCRIPTS/$script" info "$TMPDIR/*.epub" --dry-run 2>/dev/null | grep -qiE "dry.run|would|preview"; then pass "$script --dry-run works" else fail "$script --dry-run fails"; fi ;; *) if python3 "$SCRIPTS/$script" "$TEST_EPUB" --dry-run 2>&1 | grep -qiE "dry.run|would|preview"; then pass "$script --dry-run works" else fail "$script --dry-run fails"; fi ;; esac done # ═══════════════════════════════════════════════════════ # 15. Syntax checks (v2 scripts) # ═══════════════════════════════════════════════════════ header "syntax checks (v2)" for script in epub-edit epub-images epub-batch epub-convert epub-repair; do if python3 -c "import py_compile; py_compile.compile('$SCRIPTS/$script', doraise=True)" 2>/dev/null; then pass "$script: syntax OK" else fail "$script: syntax error" fi done # ═══════════════════════════════════════════════════════ # Summary # ═══════════════════════════════════════════════════════ echo "" echo "═══════════════════════════════════════" echo " PASS: $PASS FAIL: $FAIL TOTAL: $((PASS + FAIL))" echo "═══════════════════════════════════════" if [ "$FAIL" -gt 0 ]; then exit 1 fi
-
-
README.md 1.7 KB
# EPUB — Ebook Creation, Extraction & Enrichment Expert-level EPUB handling for reading, writing, editing, and extracting knowledge from EPUB2 and EPUB3 files. Ships a CLI tool and five detailed references. ## Why Install This Skill When your agent loads this skill, it becomes an **ebook format specialist** who can: - **Inspect EPUB structure** — see manifest, spine, TOC, metadata - **Extract clean text** — per-chapter or single-file, stripped of boilerplate - **Edit EPUBs non-intrusively** — metadata, chapters, spine, CSS — without breaking the file - **Create valid EPUBs from scratch** — scaffold new ebooks - **Extract knowledge with LLM mode** — facts, quotes, definitions, arguments via configurable LLM - **Convert EPUB2 to EPUB3** — add NAV, update namespace, keep NCX compatibility - **Batch process hundreds of EPUBs** — wrap any script across file globs - **Validate against the spec** — EPUBCheck or Python fallback ## What You Get | Directory | Purpose | |-----------|---------| | `SKILL.md` | Decision table mapping tasks to scripts, EPUB format essentials | | `scripts/` | 10 Python CLI scripts: info, text, scaffold, edit, images, batch, convert, validate, extract-knowledge | | `references/` | 8 reference files: format internals, Python libraries, spec/validation, tutorials, fixed-layout, accessibility, media overlays | ## Triggers Load this when you encounter EPUB files — to read, create, edit, extract, convert, or validate them. ## Requirements Python 3.8+ with `EbookLib`. Optional: `beautifulsoup4`, `epublib`, Java (for EPUBCheck), and an LLM endpoint for knowledge extraction. ## Quick Start Start with the setup and first workflow in SKILL.md, then use the linked resources for the specific task you need to complete. -
SKILL.md 17.1 KB
--- name: epub description: >- Read, write, and edit EPUB2/EPUB3 ebooks as an EPUB file format expert. Extract text, metadata, structure, and knowledge from EPUB files for enrichment or memory. Create valid EPUBs from scratch. Validate against the EPUB specification. Use when the user mentions epub, ebook, EPUB file, ebook format, read epub, write epub, create ebook, extract from epub, epub to text, or ebook structure. Do not use this skill for unrelated requests; route to the nearest named specialist. license: MIT compatibility: Python 3.8+ required. Core scripts use EbookLib (pip install EbookLib) for reading and creating EPUBs. Optional epublib (pip install epublib) for non-intrusive editing. beautifulsoup4 (pip install beautifulsoup4) for text extraction. Optional LLM mode via EPUB_LLM_URL + EPUB_LLM_KEY env vars (any OpenAI-compatible provider). EPUBCheck (Java, optional) for authoritative validation. Portable across all AgentSkills-compatible harnesses — scripts are platform-agnostic. metadata: skills: epub, ebook, publishing, knowledge-extraction, document-processing tags: epub, ebook, epub3, epub2, publishing, document-extraction, knowledge --- # EPUB — Ebook Creation, Extraction & Enrichment Expert-level EPUB handling: read, write, edit, validate, and extract knowledge from EPUB 2 and EPUB 3 files. Ships with five Python CLI scripts and five detailed references covering the entire EPUB domain. ## When not to use - **Non-EPUB documents** — Word, PDF, plain markdown, or web-page conversion tasks do not match any script here; route them to a document-handling skill instead of forcing an EPUB tool onto a non-EPUB file. - **DRM-locked ebooks** — these scripts read and write standard OCF/EPUB containers; they do not remove or bypass digital rights management. - **Mobi/AZW/Kindle-native formats** — use a dedicated converter first; this skill neither reads nor writes Amazon-proprietary containers. ## EPUB Format Essentials An EPUB file is a **ZIP archive** (Open Container Format, OCF) with a specific internal layout. The W3C EPUB 3.3 standard uses a "three planes" model: | Plane | Contains | Key Rule | |-------|----------|----------| | **Manifest** | All resources (XHTML, images, CSS, fonts) | Every file must be listed in OPF `<manifest>` | | **Spine** | Linear reading order | Only XHTML/SVG by default; other types need fallbacks | | **Content** | Resources embedded within documents | Core media types guaranteed; foreign types need fallbacks | The package document (`content.opf`) holds metadata (Dublin Core), manifest (every resource), and spine (reading order). EPUB3 uses an XHTML `nav` document for navigation; EPUB2 uses `.ncx` XML. Both can coexist for compatibility. **Critical rules:** `mimetype` must be the first ZIP entry, stored uncompressed. All content documents must be well-formed XML (XHTML, not HTML5). The manifest must list every file used in rendering. Read `references/epub-format-internals.md` for the full structure reference. ## Decision Table — Which Script to Use | Task | Script | Notes | |------|--------|-------| | See structure, metadata, manifest, spine, TOC | `epub-info` | JSON output, `--summary` for compact | | Extract clean reading-order text | `epub-text` | Per-chapter or single file | | Create minimal valid EPUB from scratch | `epub-scaffold` | No dependencies needed | | Extract facts, quotes, definitions, arguments | `epub-extract-knowledge` | Heuristic or LLM mode (env var auto-detect) | | Validate against EPUB spec | `epub-validate` | EPUBCheck or Python fallback | | **Edit EPUB** (metadata, chapters, spine, CSS) | **`epub-edit`** | **v2 flagship — 8 subcommands, non-intrusive** | | Extract images | `epub-images` | List or extract to directory | | Batch process multiple EPUBs | `epub-batch` | Wrap existing scripts across globs | | Convert EPUB2 → EPUB3 | `epub-convert` | Add NAV, update NS, keep NCX | | Diagnose & repair structural issues | `epub-repair` | Auto-fix common validation failures | ## Scripts All scripts live in `scripts/` relative to this skill's directory. Each follows cli-builder conventions: `--json` for machine output, `--dry-run` to preview, non-interactive, errors to stderr. Run with `--help` for full flag details. ### epub-info — Structure & Metadata Dump ```bash scripts/epub-info book.epub --json scripts/epub-info book.epub --summary # compact manifest scripts/epub-info book.epub --dry-run # preview ``` Outputs: EPUB version, metadata (title, author, language, identifier), manifest (all items with id/href/media-type), spine (reading order), TOC (nested structure). `--summary` reduces manifest to id+href+media-type. ### epub-text — Clean Text Extraction ```bash scripts/epub-text book.epub # plain text to stdout scripts/epub-text book.epub --json # JSON with chapter array scripts/epub-text book.epub --chapters # one .txt per chapter scripts/epub-text book.epub --output book.txt # single file scripts/epub-text book.epub --format markdown # markdown output ``` Extracts text from spine-ordered content documents. Strips HTML tags, preserves paragraph structure. Requires beautifulsoup4. Respects spine linearity — only processes documents in the reading order. ### epub-scaffold — Create Valid EPUB from Scratch ```bash scripts/epub-scaffold --title "My Book" --author "Jane Doe" scripts/epub-scaffold --title "Novel" --author "Me" --chapters 12 --output novel.epub scripts/epub-scaffold --title "Guide" --author "Me" --cover cover.jpg scripts/epub-scaffold --title "Guide" --author "Me" --cover cover.jpg --toc-hidden --dry-run ``` Creates a valid EPUB3 with all content inside `OEBPS/` — required for Apple Books compatibility. No external dependencies — Python stdlib only. **Cover handling:** When `--cover` is provided, the scaffold automatically: - Copies the image to `OEBPS/Images/cover.{ext}` - Generates `OEBPS/Text/cover.xhtml` — an XHTML wrapper page with full-viewport CSS - Adds the cover page to the spine as the first item - Sets `properties="cover-image"` on the raw image for library thumbnails This follows the Apple Books requirement that covers must be XHTML pages in the spine, not raw image references (raw images render as blank pages). **Nav visibility:** `--toc-hidden` sets `linear="no"` on the nav spine item, hiding it from the reading flow (still accessible via the app's built-in TOC browser). Default is `--toc-visible` (nav renders as a page). **CSS:** Ships `OEBPS/Styles/default.css` with Apple Books-compatible typography: no deprecated `page-break-before`, `margin: 0` on body (padding for whitespace), proper heading hierarchy, and responsive styling. **Cover art guidance:** The `--cover` flag accepts a pre-existing image file. If the user does not have a cover image, offer to generate one using the agent's image_gen capability. See `references/apple-books-compatibility.md` for the full cover XHTML and CSS conventions. ### epub-cover — Add Cover to Existing EPUB ```bash scripts/epub-cover wrap book.epub --image cover.png --output with-cover.epub scripts/epub-cover wrap book.epub --image cover.png --in-place ``` Adds a cover XHTML wrapper page to an EPUB that already has a cover image in its manifest. Use when the image exists but isn't rendering in Apple Books. Requires epublib. ### epub-extract-knowledge — Knowledge Extraction Pipeline ```bash # LLM mode — set env vars first (see references below), then run without flags: scripts/epub-extract-knowledge book.epub --format json scripts/epub-extract-knowledge book.epub --format atoms scripts/epub-extract-knowledge book.epub --format memory # Force heuristic mode (ignore env vars): scripts/epub-extract-knowledge book.epub --no-llm --format json # Custom prompt override: scripts/epub-extract-knowledge book.epub --prompt "Extract all definitions" --format json ``` Extracts knowledge from EPUB content: facts, definitions, key points, and arguments. Two modes, auto-selected: - **LLM mode (auto-detected):** When `EPUB_LLM_URL` and `EPUB_LLM_KEY` env vars are set, calls the configured LLM with the chapter text and extraction prompt. Produces high-quality structured insights. Falls back to heuristic if the LLM call fails. - **Heuristic mode (fallback):** When env vars are NOT set, or `--no-llm` is passed, uses pattern matching (headings, emphasis markers, definition language, paragraph density) to identify knowledge-bearing passages. No LLM required. Output formats: `json` (raw structured JSON), `atoms` (Obsidian vault atom templates), `memory` (key-value entries suitable for agent persistence). For the env-var configuration convention, knowledge-type detection table, LLM prompt design, and sink options by platform, load [references/llm-config-and-extraction.md](references/llm-config-and-extraction.md). ### epub-edit — Surgical EPUB Editing (v2) ```bash scripts/epub-edit info book.epub --json scripts/epub-edit metadata book.epub --title "New Title" --output out.epub scripts/epub-edit add-chapter book.epub --content new.xhtml --after chapter3 --output out.epub scripts/epub-edit remove-chapter book.epub --id chapter5 --output out.epub scripts/epub-edit reorder-spine book.epub --order chapter3,chapter1,chapter2 --dry-run scripts/epub-edit rename-resource book.epub --from Images/old.jpg --to Images/new.jpg scripts/epub-edit inject-css book.epub --css dark.css --output out.epub scripts/epub-edit update-manifest book.epub --output out.epub ``` Non-intrusive EPUB editing via epublib. Eight subcommands covering the full edit surface. Never overwrites original — defaults to `--output out.epub`; use `--in-place` to commit. All subcommands support `--json`, `--dry-run`. ### epub-images — Image Extraction ```bash scripts/epub-images book.epub --list --json # list all images scripts/epub-images book.epub --extract images/ # extract all to directory scripts/epub-images book.epub --type cover --extract . # cover image only ``` ### epub-batch — Multi-File Processing ```bash scripts/epub-batch extract-text "books/*.epub" --output texts/ scripts/epub-batch validate "books/*.epub" --json scripts/epub-batch metadata "books/*.epub" --set-author "Author" --output-dir fixed/ scripts/epub-batch info "books/*.epub" --json ``` ### epub-convert — EPUB2 → EPUB3 ```bash scripts/epub-convert old.epub --output new-v3.epub scripts/epub-convert old.epub --validate --json ``` ### epub-repair — Diagnose & Fix ```bash scripts/epub-repair broken.epub --diagnose --json # list fixable issues scripts/epub-repair broken.epub --output fixed.epub # auto-fix ``` ### epub-validate — Structural Validation ```bash scripts/epub-validate book.epub --json scripts/epub-validate book.epub --dry-run ``` Tries EPUBCheck (Java JAR) first for authoritative validation. Falls back to pure-Python structural checks: mimetype position/compression/content, container.xml parseability, OPF schema, manifest completeness, spine reference integrity, required metadata, and NAV document presence. ## Capability Discovery & Pipeline Construction Before executing a multi-step EPUB pipeline, discover what tools are available on your agent platform — this skill is portable, and the exact pipeline shape depends on your harness's capabilities. The protocol: enumerate your tools (file write, web access, subagents, cron, persistent memory, vector DB, vault, LLM), classify them against the pipeline stages (**Ingest → Parse → Extract → Format → Sink**), construct a pipeline from available pieces, and propose the plan to the user before executing. See `references/agent-capability-discovery.md` for the full protocol with the stage map and worked example pipelines for different platforms (full agent with vault + RAG, minimal terminal-only harness, and batch multi-file runs). ## Common Workflows ### Create EPUB from Markdown Files ```bash # 1. Scaffold the EPUB scripts/epub-scaffold --title "My Book" --author "Me" --chapters 3 --output book.epub # 2. Use epublib (Python) to inject real content into each chapter # See references/tutorials-and-guides.md for the editing pattern ``` ### Extract All Images from EPUB ```bash scripts/epub-images book.epub --extract images/ ``` ### Edit an EPUB ```bash # Update metadata scripts/epub-edit metadata book.epub --title "New Title" --output revised.epub # Add a chapter scripts/epub-edit add-chapter book.epub --content new.xhtml --output expanded.epub # Inject dark theme scripts/epub-edit inject-css book.epub --css dark.css --output dark.epub ``` ### Fix a Broken EPUB ```bash scripts/epub-repair broken.epub --diagnose --json # see what's broken scripts/epub-repair broken.epub --output fixed.epub # auto-fix ``` ### Batch Extract Text from a Library ```bash scripts/epub-batch extract-text "books/*.epub" --output texts/ ``` ### Convert EPUB2 to EPUB3 ```bash scripts/epub-convert old.epub --output old-v3.epub --validate ``` ## Apple Books Compatibility Apple Books on macOS/iOS enforces requirements beyond the EPUB spec; these rules were verified by building and testing on macOS 26. The essentials: all content lives inside `OEBPS/`, covers are XHTML pages in the spine (raw image spine items render blank), body uses `margin: 0` avoidance via padding, no deprecated `page-break-before`, `xmlns:epub` only on the nav document, the raw cover image keeps `properties="cover-image"`, and `linear="no"` hides a page (e.g., nav) from the reading flow without hiding it from the app's TOC browser. Spine ordering patterns: no cover (`nav → chapters`), cover only (`cover-page → nav(linear="no") → chapters`), full (`cover-page → nav → chapters`; scaffold default). Do not rely on memory for these rules — load `references/apple-books-compatibility.md` for the rule-by-rule table, CSS examples, the cover XHTML template, and validation quirks whenever you build or repair an EPUB targeted at Apple Books. ## Gotchas - **mimetype compression:** Python's `zipfile` compresses by default. Always use `ZIP_STORED` for the mimetype entry. A compressed mimetype silently breaks reading systems. - **XHTML ≠ HTML5:** Content documents must be well-formed XML. Self-closing tags required (`<br/>` not `<br>`). Use `xmlns:epub="http://www.idpf.org/2007/ops"`. - **Manifest is exhaustive:** Every file in the EPUB must be listed. Missing manifest entries cause validation failures. Images, CSS, fonts — no exceptions. - **AGPL boundary:** EbookLib is AGPL; scripts call it at runtime but don't bundle it. Users install it themselves via pip. This skill and its scripts are MIT. - **EPUBCheck needs Java:** The authoritative validator requires Java. The fallback Python checks catch structural issues but not XHTML schema violations or CSS validity. - **Spine references manifest IDs:** An `idref` in the spine must match an `id` in the manifest. Broken references cause the EPUB to fail validation. - **Navigation document:** EPUB3 requires a NAV with `properties="nav"`. Without it, reading systems may not show a table of contents. - **Language is required:** Both `<dc:language>` and `xml:lang`/`lang` attributes on content documents. Missing language = invalid EPUB. ## Pitfalls - **Don't skip capability discovery.** Assuming a tool exists that doesn't leads to broken pipelines. Always check before building. - **Don't assume LLM availability.** Always offer `--no-llm` fallback for extraction. Heuristic mode works surprisingly well for well-structured books. - **Don't modify EPUBs in place without backup.** EPUB editing is surgery — always keep the original. - **Don't mix EbookLib and epublib on the same file in the same session.** They have different memory models and may conflict. Pick one library per task. - **Don't assume the OPF is at `OEBPS/content.opf`.** Always read `container.xml` to find the actual path. The root directory varies. ## References - `references/epub-format-internals.md` — Full structural reference (OCF, OPF, XHTML, NCX/NAV, spine, three planes, core media types, EPUB2 vs EPUB3) - `references/python-libraries.md` — EbookLib vs epublib comparison, code examples, when to use which, license notes - `references/spec-and-validation.md` — W3C EPUB 3.3 spec access points, EPUBCheck usage, Ace accessibility validation, key constraints summary - `references/tutorials-and-guides.md` — Beginner to advanced guides, common workflows, manual OPF editing, batch operations, pitfalls - `references/agent-capability-discovery.md` — Protocol for probing agent tools, constructing extraction pipelines, worked examples across platforms - `references/fixed-layout-epub.md` — Fixed-layout detection and properties (rendition:layout, orientation, spread, viewport meta) - `references/accessibility.md` — WCAG alignment, alt text, heading hierarchy, ARIA roles, Ace integration, accessibility metadata - `references/media-overlays.md` — SMIL synchronization, audio-text pairing, skippability/escapability, detection from manifest - `references/apple-books-compatibility.md` — Apple Books rules beyond the spec: OEBPS layout, cover XHTML wrapper, CSS conventions, spine patterns, quirks - `references/llm-config-and-extraction.md` — `EPUB_LLM_*` env-var convention, LLM vs heuristic extraction modes, knowledge-type detection, prompt design, sink options by platform
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.