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:
- Extract (macOS only): walks the iCloud Drive
.nbnbundles and the HTTP cache (Cache.db+fsCachedData/), writes a normalized export directory at~/notability_export/. - Build (any OS): reads the export directory, merges flashcards into a
persistent JSONL archive at
~/.notability_extractor/cards.jsonl, and emits outputs:.apkgfor Anki,.jsonfor programmatic review,.mdfor 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
- Open Anki on your desktop.
File > Importand select the generated.apkgfile.- 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
.nbnbundles 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:
- Bump the
version = "X.Y.Z"line inpyproject.toml - Commit and push to
main - 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.)
- First upload manually with
./upload-to-pypi.sh(needs~/.pypircwith a PyPI API token) to claim the package name. - On PyPI: project settings -> Publishing -> add trusted publisher with
repo
mdeguzis/notability-extractor, workflowci.yml, environmentpypi. - On GitHub: repo settings -> Environments -> create
pypienvironment.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file notability_extractor-0.2.0.tar.gz.
File metadata
- Download URL: notability_extractor-0.2.0.tar.gz
- Upload date:
- Size: 115.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
424fe2b46386cc76dc77c803ac16360629515a5e2333dd8336cb8b7cffdd40aa
|
|
| MD5 |
b7ccbf014755e6ac644ea7380c32364a
|
|
| BLAKE2b-256 |
93def538d03c8223f798e9246fd14edca0bcc61cd578d69f1a965c70c27f08df
|
File details
Details for the file notability_extractor-0.2.0-py3-none-any.whl.
File metadata
- Download URL: notability_extractor-0.2.0-py3-none-any.whl
- Upload date:
- Size: 55.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3056dfa9e1b32d1659db3028ff3b277265890e68665776549d3ac889dd0abbd2
|
|
| MD5 |
1160ef3c3afb0601093e7886378f07bb
|
|
| BLAKE2b-256 |
5679cf866856e918a84525709965b65c45d9fc5e3b67ac8001babec6c1649c01
|