A Python CLI to manage Anki decks, note types (models), and notes from YAML configuration.
AnkiDAY = Anki - Deck as YAML
Disclaimer: This project is NOT affiliated with, endorsed by, or connected to Anki or the AnkiWeb service. AnkiDAY is an independent third-party tool that interacts with Anki through the AnkiConnect add-on. All trademarks are property of their respective owners.
- Default backend: AnkiConnect (localhost:8765)
- Future backend: Anki Python API (out-of-process collection manipulation)
Features
- Create/update/delete decks
- Create/update note types (fields, templates, CSS)
- Cloze deletion models: Full support for creating proper cloze models with
isCloze: true - Upsert notes idempotently using a model-defined unique field
- Media file support: Automatically upload images, audio, and other media files
- Optional pruning of entities not present in config
- Validate config and print a diff before applying
- Python 3.10+: Ensure you have Python 3.10 or later installed
- Windows: Download from python.org (make sure to check "Add to PATH")
- macOS: Use Homebrew (
brew install python) or download from python.org - Linux: Use your package manager (
apt install python3,dnf install python3, etc.)
- Anki Desktop: Download and install Anki for your platform
- AnkiConnect Add-on:
- Open Anki
- Go to Tools → Add-ons → Get Add-ons
- Enter code:
2055492159 - Click OK and restart Anki
- Verify AnkiConnect is working by visiting http://127.0.0.1:8765 in your browser (should show a simple page)
Method 1: From source (recommended)
git clone https://github.com/yourusername/ankiday.git
cd ankiday
pip install -e .Method 2: Direct installation (when published)
pip install ankidayNote: On some systems (especially macOS), you may need to add Python's bin directory to your PATH or create a symlink. See the troubleshooting section below if the
ankidaycommand is not found after installation.
- macOS: Tested and fully supported
- Linux: Should work (cross-platform dependencies)
- Windows: Should work but untested (see Windows-specific instructions below)
ankiday --helpIf ankiday command is not found:
-
Find where ankiday was installed:
python3 -c "import sys; print(sys.executable.replace('/python3', '/ankiday'))" -
Test the command directly:
# Use the path from step 1, for example: /Library/Frameworks/Python.framework/Versions/3.12/bin/ankiday --help -
Fix the PATH (choose one method):
Option A - Add to PATH permanently:
# Replace with your actual path from step 1 echo 'export PATH="/Library/Frameworks/Python.framework/Versions/3.12/bin:$PATH"' >> ~/.zshrc source ~/.zshrc
Option B - Create symlink:
# Replace with your actual path from step 1 sudo ln -sf /Library/Frameworks/Python.framework/Versions/3.12/bin/ankiday /usr/local/bin/ankiday -
Verify it works:
ankiday --help
Windows users (untested):
If ankiday command is not found on Windows:
-
Find ankiday location:
python -c "import sys; print(sys.executable.replace('python.exe', 'Scripts\\ankiday.exe'))" -
Test command directly:
# Use the path from step 1, for example: C:\Python310\Scripts\ankiday.exe --help
-
Add to PATH (PowerShell):
# Replace with your actual path from step 1 $env:PATH += ";C:\Python310\Scripts" # To make permanent, add to your PowerShell profile
-
Alternative - Use full path:
C:\Python310\Scripts\ankiday.exe validate -f config.yaml
Windows Note: AnkiDAY uses cross-platform Python libraries and should work on Windows, but hasn't been tested. The main difference is using
.exeextensions and different path syntax. Please report any Windows-specific issues!
Important: Always keep Anki running with the AnkiConnect add-on enabled when using AnkiDAY.
- Start Anki and ensure AnkiConnect is running (visit http://127.0.0.1:8765 to verify)
- Create a config file: See the example at
examples/config.example.yaml - IDE Support (optional): Add this line at the top of your YAML files for autocompletion:
# yaml-language-server: $schema=../schema/ankiday-config.schema.json - Validate your config:
ankiday validate -f examples/config.example.yaml
- Preview changes (dry-run):
ankiday diff -f examples/config.example.yaml
- Apply the configuration:
ankiday apply -f examples/config.example.yaml
Validate config
ankiday validate -f examples/config.example.yamlShow a diff of intended changes (no side effects)
ankiday diff -f examples/config.example.yamlApply changes
ankiday apply -f examples/config.example.yamlList current entities from Anki
ankiday list --decks --models --notes-limit 20Delete entities explicitly (dangerous)
ankiday delete --deck "My::Deck" --model "MyModel" --note-query "deck:My::Deck tag:obsolete"When working with separate model definition files, you can skip model validation using the --skip-model-validation flag:
# Validate config without checking if models are defined in the same file
ankiday validate -f notes.yaml --skip-model-validation
# Generate diff relying on models that exist in Anki
ankiday diff -f notes.yaml --skip-model-validation
# Apply notes that reference externally defined models
ankiday apply -f notes.yaml --skip-model-validationUse Case: When you have:
- Model definitions in a separate file (e.g.,
models.yaml) - Note definitions that reference those models in other files
- Models already applied to Anki from previous operations
Workflow:
- Apply your models file:
ankiday apply -f models.yaml - Apply notes files:
ankiday apply -f notes.yaml --skip-model-validation
AnkiConnect will still validate that referenced models exist during actual note creation.
All commands support the --verbose (or -v) flag for detailed output:
# Show detailed output during operations
ankiday diff -f config.yaml --verbose
ankiday apply -f config.yaml --verbose
ankiday list --decks --verboseWhat verbose mode shows:
- Backend Operations: AnkiConnect API calls, parameters, and responses
- Planning Phase: Analysis of existing vs desired entities, step-by-step plan generation
- Apply Phase: Progress through each planned step, detailed execution status
- Media Processing: File uploads, existing file detection, processing results
- Success/Failure: Detailed status for each operation
Example comparison:
Normal output:
Planned changes:
- [deck.create] Create deck 'Languages::Spanish'
- [model.create] Create model 'BasicExt' with 3 fields and 1 templates
Verbose output:
[VERBOSE] Invoking AnkiConnect action: deckNames
[VERBOSE] Action deckNames completed successfully
[PLANNER] Starting plan generation
[PLANNER] Analyzing deck configuration
[PLANNER] Found 1 existing decks, 1 desired decks
[PLANNER] Plan generation complete. Generated 2 steps
Planned changes:
- [deck.create] Create deck 'Languages::Spanish'
- [model.create] Create model 'BasicExt' with 3 fields and 1 templates
Benefits:
- Debugging: Shows exactly which AnkiConnect operations fail
- Learning: Understand how AnkiDAY works internally
- Monitoring: Track progress during long operations
- Development: Useful for extending and debugging AnkiDAY
Configuration design (YAML)
version: 1
backend: ankiConnect # or "ankiPython" (not yet implemented)
server:
url: http://127.0.0.1:8765
timeoutSeconds: 30
prune:
decks: false
models: false
notes: false # prune notes not in config within targeted decks/models
models:
- name: BasicExt
css: |
.card { font-family: -apple-system, BlinkMacSystemFont, sans-serif; font-size: 20px; }
fields: [Front, Back, Extra]
templates:
- name: Card 1
qfmt: "{{Front}}"
afmt: "{{Front}}<hr id=answer>{{Back}}<br>{{Extra}}"
uniqueField: Front # used to upsert notes
# Decks can be nested with ::
decks:
- name: Languages::Spanish
config: {}
notes:
- model: BasicExt
deck: Languages::Spanish
fields:
Front: "hola"
Back: "hello"
Extra: "greeting"
tags: [spanish, greeting]
media: # Optional: list of media files to upload
- "audio/hola.mp3"
- "images/hola.jpg"
- model: BasicExt
deck: Languages::Spanish
fields:
Front: "adiós"
Back: "goodbye"
tags: [spanish]IDE Integration: Full YAML schema support with autocompletion, validation, and documentation.
- Schema file:
schema/ankiday-config.schema.json - Documentation: See
docs/SCHEMA.mdfor IDE setup instructions - Examples:
- Basic:
examples/config.example.yaml - Comprehensive:
examples/config.comprehensive.yaml - Media Support:
examples/config.with-media.yaml
- Basic:
Supported IDEs: VS Code, JetBrains IDEs, Neovim, Sublime Text
AnkiDAY supports automatic upload and management of media files (images, audio, video) for your flashcards.
Add media files to your notes using the media field:
notes:
- model: LanguageModel
deck: Spanish
fields:
Word: "hola"
Audio: "[sound:hola.mp3]" # Reference the uploaded audio
Image: "<img src='hola.jpg'>" # Reference the uploaded image
media:
- "audio/hola.mp3" # Will be uploaded as "hola.mp3"
- "images/hola.jpg" # Will be uploaded as "hola.jpg"
tags: [spanish]The media field accepts a list of file paths:
- Relative paths: Resolved relative to your config file's directory
- Absolute paths: Used as-is
- File types: Images (PNG, JPG, SVG, etc.), Audio (MP3, WAV, etc.), Video (MP4, etc.)
Images:
<img src="filename.jpg" alt="Description">Audio/Video:
[sound:filename.mp3]
[sound:pronunciation.wav]my-flashcards/
├── config.yaml
├── media/
│ ├── images/
│ │ └── spain_flag.png
│ └── audio/
│ └── hola.mp3
└── README.md
- Automatic Upload: Media files are uploaded to Anki when applying configuration
- Idempotent: Files are only uploaded once, preventing duplicates
- Path Resolution: Supports both relative and absolute file paths
- Error Handling: Reports missing files and upload failures
- Multiple Formats: Supports various image, audio, and video formats
- Place media files in your project directory
- Reference them in the
mediafield of your notes - Reference uploaded files in note fields using HTML or
[sound:]syntax - Run
ankiday applyto upload media and create/update notes
- Idempotent upsert: Each model specifies a uniqueField; notes are matched using AnkiConnect findNotes with a field filter plus deck restriction.
- Non-destructive by default: pruning is disabled. Turn it on per entity type to delete unmanaged entities.
- Backend abstraction: all Anki operations go through a backend interface; you can add an Anki Python backend later.
- YAML schema: JSON Schema provides IDE support with validation, autocompletion, and inline documentation.
Limitations
- Template and CSS updates use model-wide operations (styling/templates). Field reordering is supported, but removing a field that has data in Anki may require manual cleanup.