Bookflow
bookflow is a local Ruby CLI that exports Apple Books highlights and notes from macOS SQLite databases into deterministic Markdown files (one file per book).
Features
- Reads Apple Books annotation and library metadata from local SQLite databases
- Exports one Markdown file per book
- Deterministic filenames and stable annotation ordering
- Case-insensitive filtering by book title/author
- Dry-run mode for previewing exports
- Safe overwrite behavior (
--overwriterequired when files already exist)
Requirements
- macOS (Apple Books database paths are macOS container paths)
- Ruby
>= 3.1 - Bundler
Install
From RubyGems (after publish):
gem install bookflow
For local development:
bundle install
Usage
Run the CLI via Bundler:
bundle exec ruby bin/bookflow export apple-books
Or directly after making it executable:
./bin/bookflow export apple-books
Command
bookflow export apple-books [options]
Options
-
--output-dir <path>- Output directory for Markdown files
- Default:
./exports
-
--book <substring>- Case-insensitive filter applied to book title and author
-
--overwrite- Overwrite existing output files
-
--dry-run- Print files that would be written, without writing any files
Apple Books Database Paths
By default, bookflow reads:
- Annotation DB:
~/Library/Containers/com.apple.iBooksX/Data/Documents/AEAnnotation/AEAnnotation_v10312011_1727_local.sqlite
- Library DB:
~/Library/Containers/com.apple.iBooksX/Data/Documents/BKLibrary/BKLibrary-1-091020131601.sqlite
Environment Variable Overrides
You can override database paths:
BOOKFLOW_APPLE_BOOKS_ANNOTATION_DBBOOKFLOW_APPLE_BOOKS_LIBRARY_DB
Legacy-compatible aliases are also supported:
APPLE_BOOKS_EXPORTER_ANNOTATION_DBAPPLE_BOOKS_EXPORTER_LIBRARY_DB
Example:
BOOKFLOW_APPLE_BOOKS_ANNOTATION_DB=/tmp/annotations.sqlite \
BOOKFLOW_APPLE_BOOKS_LIBRARY_DB=/tmp/library.sqlite \
bundle exec ruby bin/bookflow export apple-books --output-dir ./exports --dry-run
Examples
Export all annotations to ./exports:
bundle exec ruby bin/bookflow export apple-books
Only export books matching "metz" in title or author:
bundle exec ruby bin/bookflow export apple-books --book metz
Preview output without writing files:
bundle exec ruby bin/bookflow export apple-books --dry-run
Overwrite existing files:
bundle exec ruby bin/bookflow export apple-books --overwrite
Output
Each exported Markdown file contains:
- Book metadata (title, author, asset id, source path)
- Export timestamp
- Ordered annotations (highlight text, note text, location metadata, created timestamp)
Annotation ordering is deterministic and prioritizes reading position:
- Absolute physical location
- Range start
- Creation timestamp
- Annotation primary key (
Z_PK)
Run Tests
bundle exec rake test
Release
bundle exec rake test
gem build bookflow.gemspec
gem signin
gem push bookflow-$(ruby -Ilib -e 'require "bookflow/version"; print Bookflow::VERSION').gem
Project Structure
bin/bookflow: CLI entrypointlib/bookflow/cli.rb: command parsing and orchestrationlib/bookflow/apple_books/database.rb: read-only SQLite access + schema validationlib/bookflow/apple_books/extract.rb: grouping/filtering/sortinglib/bookflow/apple_books/render_markdown.rb: markdown renderingtest/: unit and integration-style tests with fixture databases