Convert Markdown files into Anki cards via AnkiConnect
Project description
Markdown to Anki
markdown-to-anki is a lightweight Python CLI that automatically converts raw Markdown files into Anki cards using AnkiConnect. It's designed for learners and note-takers who prefer writing in Markdown and want to seamlessly sync their content into Anki.
Installation
pip install markdown-to-anki
Requires Python 3.10+ and AnkiConnect running in your Anki app.
Getting Started
Open Anki, then register note models once:
m2a --folder ~/notes/anki init
Then sync your notes anytime:
m2a --folder ~/notes/anki sync
Commands
| Command | Description |
|---|---|
m2a check |
Verify the AnkiConnect server is reachable. |
m2a init |
Register note models in Anki. Run once before your first sync. |
m2a sync |
Import media and notes, then trigger an AnkiWeb sync. |
m2a sync_web |
Trigger an AnkiWeb sync only (no re-import). Useful for cron. |
Only files modified within the last TIME_RANGE seconds (default 2 hours) are processed.
Force a full sync — to re-sync all notes regardless of modification time, touch every Markdown file first:
find ~/notes/anki -name "*.md" -exec touch {} + m2a --folder ~/notes/anki sync
Configuration
Settings are resolved in this order — highest priority wins:
CLI flag > environment variable / .env > config file > default
CLI flags
m2a --folder ~/notes/anki --url http://localhost:8765 sync
m2a --resources ~/my-templates init
| Flag | Description | Default |
|---|---|---|
--folder |
Path to your Markdown notes dir | see Config file |
--url |
AnkiConnect URL | http://localhost:8765 |
--resources |
Path to custom card templates/styles directory | built-in resources |
Config file
Create ~/.config/markdown-to-anki/config.yaml (respects $XDG_CONFIG_HOME):
md_folder: ~/notes/anki
time_range: 7200
anki_url: http://localhost:8765
resources_dir: ~/notes/anki-templates
Environment variables / .env
Place a .env file in the directory where you run m2a, or set the variables in your shell:
MD_FOLDER=~/notes/anki
TIME_RANGE=7200
ANKI_URL=http://localhost:8765
M2A_RESOURCES_DIR=~/notes/anki-templates
Markdown Style
Each Markdown file may contain one or more cards. Use YAML frontmatter for per-file metadata and the comment separators below to split cards and fields:
---
deck: M2A::Example::Math
tags: math, theorem
model: m2a-basic
# skip: 1 # uncomment to skip this file
---
<!--CARD-->
### Front of card 1
<!--FIELD-->
Back of card 1
<!--CARD-->
<!--TAGS: hard, exam-->
### Front of card 2
<!--FIELD-->
Back of card 2
Supported metadata keys: deck, tags, model, skip.
Per-card tags via <!--TAGS: a, b--> (anywhere inside a card section) are merged with the file-level tags from frontmatter.
Built-in note types
| Model | Fields | Description |
|---|---|---|
m2a-basic |
Front, Back | Simple front → back card |
m2a-basic-reverse |
Front, Back | Front → back and back → front |
m2a-cloze |
Text, Extra | Cloze deletion card |
m2a-english |
Word, Audio, Meaning | Vocabulary card with audio support |
Cloze cards
Use Anki's native {{c1::...}} syntax in the Text field. Multiple deletions (c1, c2, …) are supported in a single card.
---
deck: M2A::Example::Cloze
model: m2a-cloze
---
<!--CARD-->
The capital of {{c1::France}} is {{c2::Paris}}.
<!--FIELD-->
European geography.
<!--CARD-->
{{c1::Water}} boils at {{c2::100}}°C at standard pressure.
<!--FIELD-->
Basic chemistry fact.
The Text field holds the cloze content; Extra is shown on the back and can hold supplementary notes.
Custom Resources
Point --resources (or resources_dir / M2A_RESOURCES_DIR) at your own directory to override built-in templates/styles and define new note types. Only the files you provide are overridden — everything else falls back to the built-in defaults.
Override built-in templates or styles
Mirror the built-in layout under your resources directory:
my-resources/
└── anki/
├── styles/
│ └── basic.css # overrides the built-in basic.css
└── templates/
└── basic/
└── front.html # overrides the built-in front template
Define custom note types
Place a YAML file per model inside a models/ subdirectory:
my-resources/
├── models/
│ └── my-vocab.yaml
├── styles/
│ └── my-vocab.css
└── templates/
└── my-vocab/
├── front.html
└── back.html
models/my-vocab.yaml:
name: my-vocab
fields:
- Word
- Definition
- Example
is_cloze: false
css_file: styles/my-vocab.css # relative to my-resources/
templates:
- name: word-to-definition
front_file: templates/my-vocab/front.html
back_file: templates/my-vocab/back.html
Inline CSS and HTML are also supported instead of file references:
name: my-simple
fields:
- Question
- Hint
- Answer
css: ".card { font-family: sans-serif; }"
templates:
- name: card
front: "<div>{{Question}}</div><div class='hint'>{{Hint}}</div>"
back: "<div>{{Answer}}</div>"
Fields map to <!--FIELD--> sections in order. A card with three fields uses two separators:
---
model: my-vocab
deck: Languages::English
---
<!--CARD-->
hello
<!--FIELD-->
A common English greeting.
<!--FIELD-->
"Hello, how are you?" — used when meeting someone.
Run m2a --resources my-resources/ init once to register your custom models in Anki, then use m2a --resources my-resources/ sync as usual.
Limitation
- DO NOT use dark theme in Anki — the rendered Markdown style does not support it.
- Attachments (images, audio) must be placed in the same directory as the Markdown file, or a subdirectory of it.
Cronjob
Automatically sync your notes to AnkiWeb hourly:
crontab -e
# sync hourly (replace /usr/local/bin/m2a with the output of: which m2a)
5 * * * * /usr/local/bin/m2a --folder ~/notes/anki sync_web &>/dev/null
Examples
See the example notes for working Markdown files covering basic cards, cloze deletions, math, code, and audio.
License
This project is open-sourced and licensed under the MIT license.
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 markdown_to_anki-0.2.0.tar.gz.
File metadata
- Download URL: markdown_to_anki-0.2.0.tar.gz
- Upload date:
- Size: 79.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0976704c2fd1253fb55374ad496ff2ea86fb53f81ef25252a35b36b34fda01e0
|
|
| MD5 |
a28363e90a94df922b7d3ed0de3ea679
|
|
| BLAKE2b-256 |
587a85f2fada81a069465078087dcb907c96a57efb7201b02aa3d6b434589d31
|
File details
Details for the file markdown_to_anki-0.2.0-py3-none-any.whl.
File metadata
- Download URL: markdown_to_anki-0.2.0-py3-none-any.whl
- Upload date:
- Size: 21.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8022ac2cb691478788f2ef1a84f76f44a100ff4d6af44ce593e33b36bf1ce96d
|
|
| MD5 |
b304f62178302eced1d5e6513d85b46a
|
|
| BLAKE2b-256 |
ac34a1496f58694e7a6fcd54df77230014315f31f88632d632caddab4cafb7ac
|