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 (--overwrite required 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_DB
  • BOOKFLOW_APPLE_BOOKS_LIBRARY_DB

Legacy-compatible aliases are also supported:

  • APPLE_BOOKS_EXPORTER_ANNOTATION_DB
  • APPLE_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:

  1. Absolute physical location
  2. Range start
  3. Creation timestamp
  4. 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 entrypoint
  • lib/bookflow/cli.rb: command parsing and orchestration
  • lib/bookflow/apple_books/database.rb: read-only SQLite access + schema validation
  • lib/bookflow/apple_books/extract.rb: grouping/filtering/sorting
  • lib/bookflow/apple_books/render_markdown.rb: markdown rendering
  • test/: unit and integration-style tests with fixture databases