Obsankipy is a Python tool that synchronizes Markdown notes from an Obsidian vault into Anki flashcards using the AnkiConnect API. It was inspired by the Obsidian_to_Anki plugin but is implemented entirely in Python, allowing it to run independently without the Obsidian application, thus enabling better automation.
With this tool, you can quickly create Anki cards directly from your keyboard — no need to navigate the Anki GUI. By integrating your Obsidian personal knowledge base with Anki’s FSRS algorithm, you can seamlessly combine spaced repetition and active recall for more efficient learning.
- Features
- Requirements
- Installation
- Quick Start
- Configuration
- Supported Note Types
- Advanced Usage
- Examples
- Contributing
- License
- Multiple Card Types: Supports basic, reversed, type-in-the-answer, and cloze cards
- Rich Media Support: Handles images, audio files, mathematical formulas, and code blocks
- Smart Synchronization: Automatically moves notes when the target deck changes
- Flexible Filtering: Excludes files or directories from scanning via configuration
- Remote Support: Works with local or remote AnkiConnect instances
- Debug Logging: Optional debug logging to
.obsankipy.logfile
- Automatic Deck Management: Notes are always placed in the correct target deck
- Pattern-based Exclusion: Use Unix patterns to exclude specific files from scanning
- Directory Filtering: Exclude dotted directories and custom directory patterns
- Remote Anki Integration: Connect to remote Anki instances for automation
- Hash-based Change Detection: Only processes modified files for efficiency
- Anki: Running in the background
- uv: Modern Python package manager
- AnkiConnect: Anki plugin for API access
- Python: 3.12 or higher (Installed automatically by uv)
- CSS for syntax highlighting: If you want your codeblocks to have syntax highlighting. See
examples/styles.css. - Remote Anki setup: For automation scenarios (see anki-desktop-docker)
git clone https://github.com/mlcivilengineer/obsankipy.git cd obsankipyLinux / macOS:
curl -LsSf https://astral.sh/uv/install.sh | shWindows:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"- Open Anki
- Go to Tools → Add-ons
- Click "Get Add-ons..." and enter code:
2055492159 - Restart Anki
Make sure Anki is open and running in the background, then run the following command in your terminal or PowerShell:
uv run src/obsankipy.py examples/vault/.obsankipy/config.yaml✅ Important:
Run this command from the root of the project directory (where examples/ and src/ are located).
This example uses the sample config located at examples/vault/.obsankipy/config.yaml.
🧠 This will synchronize the notes and media from the example Obsidian vault to your Anki setup using the provided configuration.
uv run src/obsankipy.py path/to/config.yaml --debugAll required Python packages are installed automatically on first run.
Create a .obsankipy directory inside your vault with a config.yaml file. The configuration has three main sections:
vault: dir_path: .. # relative to the configuration file location medias_dir_path: ../Medias exclude_dotted_dirs_from_scan: true # Excludes directories starting with '.' exclude_dirs_from_scan: # Custom directories to exclude - Templater - Templates file_patterns_to_exclude: # Unix patterns for file exclusion - ".*" # Excludes files starting with '.' - "*.tmp" # Excludes temporary files regex: basic: - '(?<=#spaced)\s*\n([\s\S]*?)\n([\s\S]*?(?=\+\+\+|---|<!--|$(?![\r\n])))' - '^Q: ((?:.+\n)*)\n*A: ([\s\S]*?(?=\+\+\+|---|<!--ID: ))' - '(?<=#spacedbigfront)\s*\n([\s\S]*?)\s*!!!\s*([\s\S]*?(?=\+\+\+|<!--|$(?![\r\n])))' basic_reversed: - '(?<=#reversed)\s*\n([\s\S]*?)\n([\s\S]*?(?=\+\+\+|---|<!--|$(?![\r\n])))' type_answer: - '(?<=#type)\s*\n([\s\S]*?)\n([\s\S]*?(?=\+\+\+|---|<!--|$(?![\r\n])))' cloze: - '((?!.*{{c\d+::[^}]*}[^}]).*{{c\d+::[^}]*}}.*\n)' globals: anki: deck_name: Default # Default deck for new cards tags: # Default tags for all cards - Obsidian - Flashcards url: http://localhost:8765 # AnkiConnect URL fine_grained_image_import: false # Advanced image handlingdir_path: Path to your Obsidian vault. If you decide to use relative paths, it will be relative to the config file path.medias_dir_path: Path to media files (images, audio). If you decide to use relative paths, it will be relative to the config file path.exclude_dotted_dirs_from_scan: Skip directories starting with '.'exclude_dirs_from_scan: List of specific directories to skipfile_patterns_to_exclude: Unix patterns for file exclusion
Define patterns for different note types. Each pattern must capture:
- Group 1: Question/Front of card
- Group 2: Answer/Back of card
deck_name: Default Anki decktags: Default tags applied to all cardsurl: AnkiConnect endpoint- fine_grained_image_import (bool):
Whenfalse(default), image imports compare files by filename only for better performance.
Whentrue, image contents are also compared, so changes are detected even if the filename stays the same (slower performance).
All the basic anki note types are supported. You can customize how all the note types will be captured. The default way that they will be captured is the following:
#spaced What is the capital of France? Paris is the capital of France. +++#spacedbigfront What is the capital of France? Is it bigger than Berlin? !!! Paris is the capital of France. No it is not bigger +++#reversed Python A high-level programming language +++#type What does CPU stand for? Central Processing Unit +++The {{c1::mitochondria}} is the {{c2::powerhouse}} of the cell.Q: What is machine learning? A: A subset of artificial intelligence that enables computers to learn without being explicitly programmed. +++You can define custom regex patterns for note extraction. Requirements:
- Group 1: Question content
- Group 2: Answer content
- Positive lookahead: Define note termination patterns
Example pattern breakdown:
([\s\S]*?(?=\+\+\+|---|<!--|$(?![\r\n])))([\s\S]*?): Non-greedy capture of any character(?=\+\+\+|---|<!--|$(?![\r\n])): Lookahead for terminators:\+\+\+: Three plus symbols---: Three hyphens<!--: HTML comment start$(?![\r\n]): End of file
Control card properties using YAML frontmatter:
--- target deck: Spanish Vocabulary tags: spanish, verbs, beginner --- #spaced How do you say "to speak" in Spanish? hablar +++# Markdown format  # Wikilink format ![[image.png]] # External URLs ![[audio_file.mp3]]# Display math $$E = mc^2$$ # Inline math The quadratic formula is $x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}$def fibonacci(n): if n <= 1: return n return fibonacci(n-1) + fibonacci(n-2)For automation or remote deployments:
-
Configure remote URL:
globals: anki: url: http://remote-server:8765
-
Docker deployment: Consider using anki-desktop-docker
See examples/vault/test file.md for a comprehensive example showing:
- Multiple card types
- Media embedding
- Math formulas
- Code blocks
- Wikilinks
- Use file exclusion patterns to skip unnecessary files
- Exclude template directories from scanning
- Use specific regex patterns to avoid false matches
This project ships a ready-to-use stylesheet for code blocks at examples/styles.css. It gives you full-width, horizontally scrollable code blocks with consistent dark backgrounds on mobile.
You can use it in Anki by:
- Open Anki Desktop → Tools → Manage Note Types.
- Select your note type → Cards….
- Click the Styling tab (applies to both Front and Back).
- Paste the contents of examples/styles.css at the top and click Save.
- Sync. AnkiDroid/AnkiMobile will now render code blocks with this style.
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request
To update your local copy of this repo with the latest changes from the main branch, run:
git pull origin mainThis project is licensed under the GNU General Public License v3.0 - see the LICENSE file for details.
- Inspired by the Obsidian_to_Anki plugin
- Built with modern Python tooling using
uv - Leverages the powerful AnkiConnect API
Need help? Check the examples directory or open an issue on GitHub.