Turn technical books into Claude Code plugins.
Franklin reads an EPUB or PDF and produces a full Claude Code plugin — SKILL, reference tree, slash commands, subagents, and plugin packaging — by extracting the book's concepts, principles, and workflows into structured intermediate data, then generating one artifact at a time. Every stage is a separate CLI command so you can iterate cheaply, and every stage writes to disk so crashes resume where they stopped.
The easiest install is via uv or pipx:
uv tool install franklin-book
# or
pipx install franklin-bookOn macOS / Linux you can also install via Homebrew:
brew tap mcrundo/franklin
brew install franklin-bookAll three drop a franklin command onto your PATH. (The distribution is called franklin-book on PyPI and Homebrew because franklin was already taken; the CLI you actually type is still franklin. See docs/homebrew.md for tap maintenance details.)
For development from a clone:
uv sync
uv run franklin doctorFranklin is a Python 3.12+ package managed with uv.
uv run franklin doctorfranklin doctor is a preflight: it verifies your Python version, uv and claude binaries, Anthropic API key, gh authentication (needed for publishing), license state, network reachability, and disk space. Run it once after install to catch setup issues before your first paid run. --skip-network for air-gapped environments, --json for support tooling.
Franklin looks up ANTHROPIC_API_KEY in the environment first, then falls back to the OS keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service) under service name franklin:
# Option 1: environment variable (CI, direnv, 1Password op run)
export ANTHROPIC_API_KEY=sk-ant-...
# Option 2: OS keychain (local dev — stored encrypted at rest)
keyring set franklin ANTHROPIC_API_KEYUse whichever fits your workflow. You do not need to configure anything in Franklin itself.
# Zero-touch: book file → assembled + published plugin
uv run franklin run path/to/book.epub --publish
# Interactive: pick a book, preview costs, select chapters, then run
uv run franklin pick
# Pick and publish in one flow
uv run franklin pick --publish
# Just build, publish later
uv run franklin run path/to/book.epub
uv run franklin publish runs/<slug>
# Curious what it'll cost first?
uv run franklin run path/to/book.epub --estimate
# Process a whole library at once
uv run franklin batch book1.epub book2.epub book3.pdf --cleanThe pipeline has two interactive gates that pause for confirmation:
- Gate 1 (pre-map): shows a cost estimate with a low-high range, lets you edit the chapter selection (spacebar to toggle, Enter to commit). Persists via
map_selection.json. - Gate 2 (post-map, pre-plan): shows what the map extracted — per-chapter counts, cross-chapter concepts, top anti-patterns — so you can verify quality before the expensive Opus plan call.
franklin run chains five stages end-to-end (ingest → map → plan → reduce → assemble) and is resume-safe: re-running picks up from the first incomplete stage. Use --force to restart, --yes to auto-confirm in scripts.
Every stage can be run on its own, reads from disk, and writes to disk — so you can replay just one stage when you change a prompt or want to inspect intermediate state.
- ingest (
franklin ingest <book>) — parse EPUB/PDF into normalized chapter JSON. Deterministic, no LLM calls. PDFs get an optional Tier 4 LLM cleanup pass via--cleanthat fixes extraction artifacts concurrently with a live progress bar. - map (
franklin map <run-dir>) — per-chapter structured extraction. Runs concurrently (default 8 in-flight, tunable with--concurrency). One LLM call per chapter produces a sidecar with concepts, rules, anti-patterns, and workflows. - plan (
franklin plan <run-dir>) — design the plugin architecture from the distilled sidecars (one Opus call). - reduce (
franklin reduce <run-dir>) — generate each artifact file from the plan. Runs concurrently (default 3, tunable with--concurrency). This is the most expensive stage. - assemble (
franklin assemble <run-dir>) — writeplugin.jsonandREADME.md, run link/frontmatter/template validators, and compute the grade card. The generated README is GitHub-ready with install instructions, commands table, and reference index.
franklin fix <run-dir>— interactive re-grade loop. Shows artifacts below B, offers to regenerate all or pick specific ones, re-runs reduce + assemble, shows the new grade. Loops until you're satisfied.franklin validate <run-dir>— quick quality check without re-grading. Catches common prompt-compliance issues (missing problem framing, long command descriptions, agents without checklists).franklin diff <run-a> <run-b>— compare two runs side-by-side: grade delta, per-artifact score changes, which checks fixed or regressed, content size and cost comparison.franklin grade <run-dir>— detailed per-artifact grade report with structural rubric scores, lowest-grade artifacts, and suggested regeneration commands.--jsonfor machine output.franklin costs— actual API spend across all runs with per-run and per-stage breakdown.franklin runs list— table of every run directory with slug, title, date, last completed stage, and grade.franklin review <run-dir>— interactive pruning of the planned artifact list before reduce.franklin inspect <run-dir>— preview the ingest output before committing to the paid stages.franklin stats— aggregate overview: total books, completion rates, average grade, total cost.franklin reduce <run-dir> --artifact <id> --force— regenerate one artifact.
Franklin takes you from a book file to a published, installable Claude Code plugin in one command. franklin publish handles the parts that are usually tedious boilerplate: creating the GitHub repo, wrapping the plugin as a Claude Code marketplace, pushing the initial commit, and printing the exact install command for your users.
# Interactive publish: grade check, fix low artifacts, pick repo name + owner
uv run franklin publish <run-dir>
# Or do it all in one shot from a book file
uv run franklin run path/to/book.epub --publish
# Try it locally before publishing
uv run franklin install <run-dir> --scope local- Grade check — regrades the run and, if anything falls below B, offers to run the fix loop before you publish junk.
- Repo naming — defaults to the plugin name, editable at the prompt.
- Owner selection — lists your personal account plus any orgs you belong to (from
gh auth), so you can publish directly to a team org. - Visibility — public or private, your call.
- Repo creation — if
github.com/<owner>/<repo>doesn't exist, Franklin creates it via theghCLI (or the REST API withGITHUB_TOKENas a fallback). - Marketplace wrapping — the published repo is a self-contained single-plugin Claude Code marketplace:
Users don't need a separate marketplace repo; the plugin repo is the marketplace.
repo/ ├── .claude-plugin/marketplace.json # lists the plugin ├── README.md # GitHub-renderable copy └── <plugin-name>/ # the plugin tree itself ├── .claude-plugin/plugin.json ├── commands/, skills/, agents/, references/ └── README.md - Push — initial commit with a conventional message, push to
main. - Install command printout — the exact two commands to give your users.
claude plugin marketplace add <owner>/<repo>
claude plugin install <plugin-name>@<plugin-name>The marketplace slug matches the plugin name (single-plugin marketplace), so the install command is always <name>@<name>.
Franklin uses gh if it's on your PATH (preferred — reuses your existing gh auth credentials). If not, it falls back to the REST API with GITHUB_TOKEN from the environment. franklin doctor flags either missing.
Process multiple books at once:
uv run franklin batch book1.epub book2.epub book3.pdf --cleanEach book gets its own run directory. All gates are auto-confirmed. A summary table with grades and costs is printed at the end.
Franklin uses the advisor pattern to get Opus-quality output at roughly Sonnet prices: one Opus call produces a high-leverage plan, and many cheap Sonnet calls execute it.
plan(Opus) runs once and outputsplan.json— the full plugin architecture, artifact list, and per-filefeeds_fromwiring. This is the advisory call; it thinks holistically about the book and the plugin shape.reduce(Sonnet) runs N times — once per artifact — and generates each file from the brief Opus wrote. Sonnet never has to reason about the architecture; it just fills in a well-scoped plan.mapandcleanupalso use Sonnet — they're per-chapter executions of a well-defined extraction prompt, not architectural decisions.
The result: a typical 30-artifact book costs $3–5 in API spend (one Opus plan call + ~30 Sonnet calls), with most of the savings coming from Anthropic's prompt caching (90% discount on repeated input tokens across chapters). franklin run --estimate shows a pessimistic budget ceiling before any paid calls — real costs are typically well below it.
The tradeoff is that Opus's advisory call is a single point of failure: if the plan is wrong, every reduce inherits the mistake. franklin review <run-dir> pauses between plan and reduce so you can prune or redirect the plan before paying for execution.
franklin run --estimatepredicts per-stage token counts and dollar cost before any paid calls. Displayed as a$low - $highrange — a budget ceiling, not a prediction. Real costs are typically 30–50% below the high end thanks to prompt caching.franklin pickshows the same estimate as a pre-map gate so you can deselect chapters before paying for them.- Concurrent stages. Map, reduce, and cleanup all run concurrently via
AsyncAnthropicwith bounded semaphores (--concurrencyflag on map and reduce to tune). A 26-chapter PDF goes from ingest to assembled plugin in ~20 minutes. - Auto-clean for PDFs. When you run a PDF without
--clean, franklin asks whether to enable cleanup for better extraction quality. - Resume-on-disk means a flaky network or a burned credit card never costs you more than the calls that were in flight. Re-run the same command; Franklin picks up from
book.json,chapters/,plan.json, oroutput/depending on what already exists. - Per-chapter failures are non-fatal during cleanup and map; the original output is kept and reported in the summary.
- LLM drift is tolerated, not fatal. If a tool-use response slips a stray field onto a sub-object, the validator strips it and logs a warning instead of killing the whole stage. Missing required fields and type errors still raise.
runs/<slug>/
book.json # BookManifest (evolves across stages)
raw/chNN.json # NormalizedChapter — one per chapter from ingest
chapters/chNN.json # ChapterSidecar — one per chapter from map
plan.json # PlanManifest — from plan
output/<plugin>/ # Generated plugin tree — from reduce/assemble
.claude-plugin/plugin.json
skills/<name>/SKILL.md
references/.../*.md
commands/*.md
agents/*.md
metrics.json # Grade card output from assemble
costs.json # Per-stage API spend (JSONL, appended by each stage)
- Runs directory: defaults to
./runs/relative to cwd; override with--outputon any stage command. - License directory: defaults to
~/.config/franklin/; override withFRANKLIN_LICENSE_DIR. - Models:
claude-sonnet-4-6is the default formap,reduce, andcleanup;claude-opus-4-6is the default forplan. Override per-command with--model.
uv run pytest # run the test suite
uv run ruff check . # lint
uv run ruff format . # format
uv run mypy # type check (strict)Prompts live as markdown under src/franklin/llm/prompts/ and are loaded by the prompt renderer — add new ones there rather than inlining strings.