Skip to main content

spaced repetition over an obsidian vault

Project description

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

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

mdsr-0.2.6.tar.gz (25.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mdsr-0.2.6-py3-none-any.whl (30.5 kB view details)

Uploaded Python 3

File details

Details for the file mdsr-0.2.6.tar.gz.

File metadata

  • Download URL: mdsr-0.2.6.tar.gz
  • Upload date:
  • Size: 25.8 kB
  • Tags: Source
  • Uploaded using 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}

File hashes

Hashes for mdsr-0.2.6.tar.gz
Algorithm Hash digest
SHA256 27432e5fc9c5ec59ab3cdff5bd8bf4dc4751e973f7634615f02da78a2f8fb0be
MD5 3ce8407d317d520e1239b456e5089c3f
BLAKE2b-256 2921059b713895b2d3f767cb7c00468c2e908c9ec4975f5fa6178637f0d9babc

See more details on using hashes here.

File details

Details for the file mdsr-0.2.6-py3-none-any.whl.

File metadata

  • Download URL: mdsr-0.2.6-py3-none-any.whl
  • Upload date:
  • Size: 30.5 kB
  • Tags: Python 3
  • Uploaded using 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}

File hashes

Hashes for mdsr-0.2.6-py3-none-any.whl
Algorithm Hash digest
SHA256 2024c3f515583420794e58babb293a074786db7ef24cabcf6f75b284ad63e187
MD5 81c2e6d1b71dc1b80feb44770b9eaa85
BLAKE2b-256 73102de617fe7fb0cf906679ce8e7d9caad6db6e58d8d87be6b6d7018272202d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page