A Python CLI tool for reading, exporting, and working with Apple Notes directly from the SQLite database.
Explore the docs Β»
Report Bug
Β·
Request Feature
Table of Contents
Apple Notes is closed system and accessing your notes programmatically is challenging. noted provides direct read access to your Apple Notes database, allowing you to:
- Search and browse your entire notes library from the command line
- Export notes in multiple formats (Markdown, JSON, HTML)
- Extract attachments including images, PDFs, and other files
- Parse complex content including tables stored in Apple's CRDT format
The tool works by safely copying and reading the Apple Notes SQLite database β it never modifies your original notes. It aims to be relatively fast for large-ish Notes databases (2000+ with heavy attachment usage).
I am NOT a software developer. This was built 100% in an initial 30 minute, vibe-coded session because I needed something that worked with a large-ish number of Notes. Other features were added over a couple hours. It does exactly what I need it to and maybe it saves someone some hours or tokens if they need a similar utility.
- Rich terminal output with syntax highlighting and formatted tables
- Full export with folder structure intact
- Multiple export formats: Markdown, JSON, HTML
- Attachment extraction with manifest generation
- 7zip archive creation good for notes that have lots of attachments
- Table parsing from Apple's proprietary CRDT format
- UUID and row ID support for note identification
- Automatic database caching with smart refresh detection
- Debug mode for detailed note metadata
Claude Code - AI-powered development
Python 3.14+
Typer - CLI framework
Rich - Terminal formatting
- betterproto - Protobuf parsing
- py7zr - 7zip archive creation
- loguru - Logging
- macOS (Apple Notes database access required)
- Python 3.14+
- uv - Fast Python package manager
This was dveloped and tested solely on macOS Tahoe 26.2 with Notes Version 4.13 (3146.61.8).
Install uv if you haven't already:
curl -LsSf https://astral.sh/uv/install.sh | sh-
Clone the repository:
git clone https://github.com/tdemarest/noted.git cd noted -
Install dependencies:
uv sync
-
Verify installation:
uv run noted --help
-
(Optional) Set up shell completion for tab-completion support:
Zsh (default on macOS) - Add to your
~/.zshrc:# noted completion _noted_completion() { eval $(env _TYPER_COMPLETE_ARGS="${words[1,$CURRENT]}" _NOTED_COMPLETE=complete_zsh uv run noted) } noted() { uv run noted "$@" } compdef _noted_completion noted
Bash - Add to your
~/.bashrc:# noted completion _noted_completion() { COMPREPLY=( $(env _TYPER_COMPLETE_ARGS="${COMP_WORDS[*]}" _NOTED_COMPLETE=complete_bash uv run noted) ) } noted() { uv run noted "$@" } complete -F _noted_completion noted
After adding, reload your shell or run
source ~/.zshrc(or~/.bashrc).Note: This uses a shell function instead of an alias. Aliases expand before completion runs, which breaks the completion registration.
Now you can use
noteddirectly (withoutuv run) and get tab completion:noted list --<TAB> # Shows: --folder, --limit, --search, --deep, --tree, --verbose noted export <TAB> # Shows note IDs and options
The CLI automatically caches a copy of the Apple Notes database to ~/.cache/noted/ and refreshes it when the source database changes. It's best to close Apple Notes when using noted otherwise the workign database and cache
will be refreshed frequently defeating the purpose of the cache.
List all notes, sorted by most recently modified:
uv run noted listFilter by folder and limit results:
uv run noted list --folder "Work" --limit 10Display notes and folders in a hierarchical tree:
# Show folder hierarchy with note counts
uv run noted list --tree
# Include individual notes with status icons
uv run noted list --tree --verbose
# Filter to specific folder
uv run noted list --tree -f "Work"Tree view shows icons for: π folders, ποΈ trash, π notes, π locked, β /π² checklists, and attachment types.
Search titles and folder names:
uv run noted list --search "meeting"
uv run noted list -s "project" --limit 20Deep search inside note content using FTS5 full-text search:
# Search note content
uv run noted list --search "budget" --deep
# Boolean operators (must be UPPERCASE)
uv run noted list -s 'budget AND Q2' --deep
uv run noted list -s '(budget OR cost) NOT personal' --deep
# Column-specific search
uv run noted list -s 'title:meeting AND content:deadline' --deepSee USAGE.md for complete FTS5 query syntax documentation.
Get comprehensive statistics about your notes:
# Show all statistics
uv run noted stats
# Include folder breakdown
uv run noted stats --by-folder
# JSON output for scripting
uv run noted stats --json
# Clear cache and rebuild
uv run noted stats --delete cacheView a note with rich terminal formatting. You can use either the row ID or UUID:
# By row ID
uv run noted view 42
# By UUID
uv run noted view "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE"Enable debug mode for detailed metadata (UUID, row ID, attachment stats):
uv run noted --debug view 42
uv run noted -d view 42Export notes in different formats:
# Markdown
uv run noted view 42 --markdown
uv run noted view 42 --markdown -o ./my_note.md
# JSON
uv run noted view 42 --json
# HTML
uv run noted view 42 --htmlExport a single note with all its attachments using the export command:
# Export to current directory (default: markdown)
uv run noted export 42
# Creates: ./Note Title.md and ./Note Title_attachments/
# Export in different formats
uv run noted export 42 --markdown # Markdown (default)
uv run noted export 42 --json # JSON
uv run noted export 42 --json-styled # JSON with styling metadata
uv run noted export 42 --html # Standalone HTML5
# Export to specific path
uv run noted export 42 -o ./backup/my_note
uv run noted export 42 --json -o ./backup/my_note.json
# Export as 7zip archive
uv run noted export 42 --zip
# Creates: ./Note Title.7zExport ALL notes with nested folder structure mirroring Apple Notes:
# Export all notes
uv run noted export --all
# Creates: ./notes_export/ with full folder hierarchy
# Example: notes_export/Work/Projects/Meeting Notes.md
# Export with 7zip archive
uv run noted export --all --zip
# Creates: ./notes_export/ AND ./notes_export.7z
# Progress: "Exporting notes... 150/150 notes" then "Creating archive... 412/412 files"
# Export to custom directory
uv run noted export --all -o ~/Backups/notes_2026-01-29
# Export only notes from a specific folder (matches anywhere in path)
uv run noted export --all --folder "Work"
# Export excluding deleted notes
uv run noted export --all --exclude-deleted
# Verbose mode (show each note as exported)
uv run noted export --all --verboseThe full export creates an index.json manifest at the root with statistics and note metadata.
Each note's attachments directory includes a manifest.json:
{
"note_id": 42,
"note_identifier": "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE",
"note_title": "My Note",
"exported_at": "2026-01-29T10:30:00.000Z",
"attachments": [
{
"identifier": "11111111-2222-3333-4444-555555555555",
"filename": "photo.jpg",
"type_uti": "public.jpeg",
"exported": true
}
]
}Apple Notes that are password-protected cannot be read by this tool:
- Locked notes are detected and skipped (content is encrypted)
- A placeholder markdown file is created explaining the note is locked
- The
index.jsonmanifest marks these with"locked": true - Summary shows: "3 locked notes (placeholders created)"
To export locked notes: Unlock them in Apple Notes first, then run the export again.
Force a refresh of the cached database and search index:
# Clear cache and FTS index (forces fresh copy)
uv run noted refresh
# Check FTS index status
uv run noted index
# Force rebuild FTS index
uv run noted index --rebuildFor comprehensive documentation including FTS5 query syntax, export options, and more, see USAGE.md.
noted accesses your Apple Notes by:
-
Copying the database - The SQLite database at
~/Library/Group Containers/group.com.apple.notes/NoteStore.sqliteis copied to a cache directory. The original is never modified. -
Parsing note content - Note bodies are stored as gzip-compressed protobuf data. The tool decompresses and parses this format to extract text, formatting, and embedded content.
-
Extracting attachments - Attachments (images, PDFs, etc.) are stored as files on disk, with the database containing references. The tool resolves these references and copies files during export.
-
Parsing tables - Apple Notes tables use a CRDT (Conflict-free Replicated Data Type) format for sync. The tool reverse-engineers this format to reconstruct tables in display order.
| Table | Purpose |
|---|---|
ZICCLOUDSYNCINGOBJECT |
Notes, folders, and attachments |
ZICNOTEDATA |
Compressed note content (protobuf) |
| Type | UTI | Exportable |
|---|---|---|
| Images | public.jpeg, public.png, public.heic |
Yes |
| PDFs | com.adobe.pdf, public.pdf |
Yes |
| Drawings | com.apple.drawing |
Yes |
| Tables | com.apple.notes.table |
Rendered inline |
| Links | public.url |
Rendered inline |
- List notes with folder filtering
- Tree view with folder hierarchy
- Database statistics
- View notes with rich formatting
- Export to Markdown, JSON, HTML
- Extract attachments
- Parse embedded tables
- 7zip archive export
- UUID-based note lookup
- Full export with nested folder hierarchy
- Progress bars for export operations
- Locked note detection and placeholders
- FTS5 full-text search with boolean operators
- Search index management
- PDF export
See the open issues for a full list of proposed features and known issues.
Contributions are welcome! If you have a suggestion that would make this better:
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/amazing-feature) - Make your changes
- Run tests:
uv run pytest - Run linting:
uv run ruff check . - Commit your Changes (
git commit -m 'feat: add amazing feature') - Push to the Branch (
git push origin feature/amazing-feature) - Open a Pull Request
# Install with dev dependencies
uv sync
# Run tests
uv run pytest
# Run linting
uv run ruff check .
# Run type checking
uv run pyrefly check src/Distributed under the MIT License. See LICENSE for more information.
- Claude Code - AI pair programmer that wrote the vast majority of this codebase
- Best-README-Template - README structure
- Typer - CLI framework
- Rich - Terminal formatting
- Apple Notes reverse engineering community for database structure insights