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.5.tar.gz (25.7 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.5-py3-none-any.whl (30.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: mdsr-0.2.5.tar.gz
  • Upload date:
  • Size: 25.7 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.5.tar.gz
Algorithm Hash digest
SHA256 7d3b98d092929d448ae6b8f67b87fe44fabf88b902ef878e078add3da1859110
MD5 d88cb5d08e4f09906afc07d829491360
BLAKE2b-256 23f92b042c26d09547c2f3b2367edc53d50343b386fb9d40b3608d1e36fd6e7f

See more details on using hashes here.

File details

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

File metadata

  • Download URL: mdsr-0.2.5-py3-none-any.whl
  • Upload date:
  • Size: 30.4 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.5-py3-none-any.whl
Algorithm Hash digest
SHA256 39a402d477df402fb65cc5916106d27407c468f0b1120ac826393981eb35d372
MD5 a476797e6bd5f621709108a48b609c33
BLAKE2b-256 251cb06b6c7ed3d19c2a77f47c0d1d124f48cde4d29ba18076c5cf80dcd01f38

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