Skip to main content

Extract Notability Learn quizzes, summaries, and note text; export to Anki / JSON / Markdown with a PySide6 GUI

Project description

notability-extractor

Extract Notability Learn content (AI-generated quizzes, summaries, and OCR'd note text) and export it as an Anki .apkg deck, JSON, or Markdown for review.

How it works

Notability Learn generates quizzes via Claude Haiku and summaries via Gemini 2.5 Flash, server-side. Both get cached locally in the app's HTTP cache. Handwriting OCR and PDF text live inside .nbn note bundles.

The tool runs in two phases:

  1. Extract (macOS only): walks the iCloud Drive .nbn bundles and the HTTP cache (Cache.db + fsCachedData/), writes a normalized export directory at ~/notability_export/.
  2. Build (any OS): reads the export directory, merges flashcards into a persistent JSONL archive at ~/.notability_extractor/cards.jsonl, and emits outputs: .apkg for Anki, .json for programmatic review, .md for human reading.

Linux and Windows machines can skip phase 1 by pointing --input-dir at a directory produced on a Mac. Useful if you want to do the Anki packaging on a different machine than the one Notability runs on.

The JSONL archive is the source of truth for flashcards. Both the CLI and the GUI read from and write to it, and the build always reconstructs .apkg from the archive (not the input dir) so edits and tags persist across rebuilds.

Install

From PyPI:

pip install notability-extractor
# or with uv:
uv tool install notability-extractor

From source (for development):

git clone https://github.com/mdeguzis/notability-extractor.git
cd notability-extractor
make install

make install sets up .venv/ for dev work and drops the notability-extractor console script into ~/.local/bin/ so it's runnable from any shell.

Usage

# macOS: auto-extract and build all outputs in the current dir
notability-extractor

# Anywhere: build from a pre-extracted directory
notability-extractor --input-dir ~/notability_export

# Custom output directory
notability-extractor --input-dir ~/notability_export --out-dir ./decks

# macOS: just run phase 1 (produce export dir, no .apkg/json/md)
notability-extractor --extract-only

# Custom Anki deck name (only affects what shows up inside Anki)
notability-extractor --deck-name "Biology 101"

Output filenames are fixed:

File Contents
notability_flashcards.apkg Anki deck (quiz questions only)
notability_flashcards.json Full structured dump for programmatic review
notability_flashcards.md Human-readable flashcards
notability_notes.{json,md} Note transcripts
notability_summaries.{json,md} Generated summaries

Archive management CLI flags

# Open a prompt-driven editor against the archive
notability-extractor --edit-flashcards

# One-shot interactive add
notability-extractor --add-card

# Print archive contents (optionally filter by tag)
notability-extractor --list-cards
notability-extractor --list-cards --tag biology

# Backup / restore round-trip
notability-extractor --backup
notability-extractor --export ~/cards-backup.jsonl
notability-extractor --import ~/cards-backup.jsonl --mode merge
notability-extractor --import ~/cards-backup.jsonl --mode replace

# Launch the GUI
notability-extractor --gui

GUI

A PySide6 desktop companion ships in the same package. After install:

notability-extractor-gui

Pages: Library (browse / edit / add / delete cards with tag filter), Notes (read-only), Summaries (read-only), Build (export apkg / json / md), Settings (theme, paths, backups, schedule).

On Wayland with no DISPLAY set, the GUI auto-applies QT_QPA_PLATFORM=wayland so SSH/login sessions don't need a manual export.

Backups

The archive at ~/.notability_extractor/cards.jsonl is snapshotted on every save to ~/.notability_extractor/backups/cards-YYYYMMDD-HHMMSS.jsonl, hash-deduped so unchanged saves don't make redundant copies. Default retention is the last 10 snapshots (configurable in Settings).

For a scheduled backup when the GUI is closed, run from cron:

0 * * * * notability-extractor --backup

The Settings page surfaces this exact line for convenience.

Importing into Anki

  1. Open Anki on your desktop.
  2. File > Import and select the generated .apkg file.
  3. The deck appears as "Notability Flashcards" (or whatever you passed to --deck-name).

Caveats

  • The Learn cache only contains content from sessions you've actively opened in Notability. If a note has never had Learn run on it, no quiz is cached.
  • Notability does not provide a stable export API. The tool reads on-disk formats that could change between app versions. If extraction breaks after a Notability update, open an issue.
  • iPadOS-only setups need iCloud Drive sync enabled so the .nbn bundles and cache files are present on a Mac. Without sync, you'd need physical access to the iPad's sandbox (not currently supported).

Releasing

Releases are automated via GitHub Actions. To cut a new release:

  1. Bump the version = "X.Y.Z" line in pyproject.toml
  2. Commit and push to main
  3. CI runs: tests pass -> autotag creates vX.Y.Z -> build produces wheel and sdist -> GitHub Release is created -> PyPI publishes via OIDC trusted publishing

No manual tag step. No API tokens in CI.

One-time PyPI setup

(Skip this if the package is already on PyPI with OIDC configured.)

  1. First upload manually with ./upload-to-pypi.sh (needs ~/.pypirc with a PyPI API token) to claim the package name.
  2. On PyPI: project settings -> Publishing -> add trusted publisher with repo mdeguzis/notability-extractor, workflow ci.yml, environment pypi.
  3. On GitHub: repo settings -> Environments -> create pypi environment.

Manual ad-hoc upload

Only needed if CI is broken:

./upload-to-pypi.sh --test   # TestPyPI dry-run first
./upload-to-pypi.sh          # then prod PyPI

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

notability_extractor-0.3.0.tar.gz (124.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

notability_extractor-0.3.0-py3-none-any.whl (61.8 kB view details)

Uploaded Python 3

File details

Details for the file notability_extractor-0.3.0.tar.gz.

File metadata

  • Download URL: notability_extractor-0.3.0.tar.gz
  • Upload date:
  • Size: 124.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for notability_extractor-0.3.0.tar.gz
Algorithm Hash digest
SHA256 44645d10c840620298d43cfa6979348a97ddc2e393fe4957f470339312c04f24
MD5 a9f72cb1b7dc0ba9e1dae90d76401033
BLAKE2b-256 02c01ea76177726130ddc77c7731289a77fdb62fa05dd69d8b5c042a8b194e48

See more details on using hashes here.

File details

Details for the file notability_extractor-0.3.0-py3-none-any.whl.

File metadata

File hashes

Hashes for notability_extractor-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 94f5b338358a0ddf1b0eea416354efe56328422e63bf1e4bc0a89c50eb6109bf
MD5 a738f930d497c07aec46bd238c4ac9a3
BLAKE2b-256 84145c87fd90232a64bf14e3f211386a8f0c5a663564d1c1c2064cb6173b19f7

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page