Skip to main content

mdsr

Spaced repetition for an Obsidian vault. You write flashcards as callouts inside your notes; mdsr parses them, schedules them with FSRS, and serves a small web UI for reviewing.

Card syntax

> [!sr] What is ...?
> The ...

> [!sr-bi] Cat
> Katze
  • [!sr] — one card, front (the question) → back.
  • [!sr-bi] — two cards, front ↔ back, marked as siblings (reviewing one hides the other until the next study day).
  • Obsidian's fold markers work: [!sr]- (collapsed) and [!sr]+ (expanded). Both are equivalent to [!sr].
  • LaTeX, code, images, wikilinks — anything Obsidian renders works here too.

Card identity is sha256(front). Editing the back keeps the schedule. Editing the front creates a new card (the old one is trashed; you can merge its schedule onto the new card from the sidebar).

Run

uv tool install mdsr
sr --vault /path/to/your/vault
# or, clone-on-first-run into $XDG_DATA_HOME/mdsr/vaults/:
sr --vault git@github.com:you/notes.git

If --vault is a git clone (or a git URL, which gets cloned on first run and reused after), the server runs git pull --ff-only every --poll-seconds (default 60), re-parses changed files, and updates card state. You can let trash get auto-purged after --trash-purge-days (default 30). If --vault is a plain directory it skips the pull and detects changes via per-file mtime instead.

Open http://127.0.0.1:8765, sr --help lists all flags.

[!TIP] With the Obsidian web viewer plugin, you can use mdsr directly within Obsidian.

Storage

mdsr only reads from the vault. Schedule state lives in SQLite under your XDG data dir:

~/.local/share/mdsr/<vault-basename>-<hash8>.db

The hash is the first 8 chars of sha256(resolved-vault-path), so running against two different vaults gives you two independent DBs automatically.

Override with --db-path if you want a specific location.

Deploy on a VPS

A single Python process. Bind it to 127.0.0.1 and reach it via Tailscale.

Keep it running with systemd

The sr command runs in the foreground and exits when its shell dies, so on a server you want something to (re)start it: daemonize at boot, restart on crash, survive logout. A user-level systemd unit:

[Unit]
Description=mdsr review server
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=%h/.local/bin/sr --vault %h/vault --host 127.0.0.1 --port 8765
Restart=on-failure
RestartSec=10

[Install]
WantedBy=default.target
systemctl --user daemon-reload
systemctl --user enable --now mdsr
loginctl enable-linger $USER   # keep the unit running after logout

Expose it on your tailnet

Simplest case — mdsr owns the whole hostname:

tailscale serve --bg --https=443 http://127.0.0.1:8765

Reachable at https://<machine>.<tailnet>.ts.net.

To put it under a URL path (e.g. /sr, leaving room for other services on the same host), tell mdsr its prefix with --root-path and forward the entire hostname to it:

sr --vault ~/vault --port 8765 --root-path /sr
tailscale serve --bg --https=443 http://127.0.0.1:8765

Reachable at https://<machine>.<tailnet>.ts.net/sr/. mdsr answers at /sr/*; other paths 404 at the app layer. For real path-based routing across multiple services, put a reverse proxy (Caddy, nginx) between tailscale and the backends.

TODO

  • Core: Properly render note content,images (parsing and rendering step via https://onyx.md)
  • Cosmetic: Make wikilinks resolve to published vault (once vault is published via onyx)?
  • Cosmetic: Same/configurable css styles as onyx site

Develop

make dev      # uv sync --group dev
make test
make check    # lint + format
make fix      # ruff fix + format
make build    # uv build → dist/
make release-{patch,minor,major} # bumps pyproject.toml version, commits and git tags
make publish  # requires UV_PUBLISH_TOKEN

Inspiration

Release files for mdsr 0.2.6

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mdsr 0.2.6
File Size Uploaded
mdsr-0.2.6.tar.gz 25.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for mdsr 0.2.6
File Interpreter ABI Platform
mdsr-0.2.6-py3-none-any.whl Python 3 none any Details

Total release size: 56.3 kB

Release files / mdsr-0.2.6.tar.gz

Download URL mdsr-0.2.6.tar.gz
Size 25.8 kB
Tags Source
SHA-256 checksum
How to use checksums
27432e5fc9c5ec59ab3cdff5bd8bf4dc4751e973f7634615f02da78a2f8fb0be
BLAKE2b-256 checksum
How to use checksums
2921059b713895b2d3f767cb7c00468c2e908c9ec4975f5fa6178637f0d9babc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.4 {"installer":{"name":"uv","version":"0.11.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / mdsr-0.2.6-py3-none-any.whl

Download URL mdsr-0.2.6-py3-none-any.whl
Size 30.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2024c3f515583420794e58babb293a074786db7ef24cabcf6f75b284ad63e187
BLAKE2b-256 checksum
How to use checksums
73102de617fe7fb0cf906679ce8e7d9caad6db6e58d8d87be6b6d7018272202d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.4 {"installer":{"name":"uv","version":"0.11.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

0.2.6 This release

2 release files

0.2.5

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page