{
  "markdown": "# Flash\n\nSpaced-repetition flashcards you study with your AI. Flash is a small\nself-hosted server: a web app for your decks and an [MCP](https://modelcontextprotocol.io)\nserver that lets Claude, ChatGPT, Grok or any MCP client create cards from\nwhat you're learning, quiz you out loud, grade your answers and file the\nreviews with the [FSRS](https://github.com/open-spaced-repetition/fsrs-rs)\nscheduler. One Rust binary, one SQLite file, no accounts anywhere but yours.\n\nThe hosted version, with self-serve signup, Google/Apple sign-in and a\ncommunity deck library, is at [flashmemorize.com](https://flashmemorize.com).\niOS and Android apps are on the way and not out yet. This repository is\nthe core it all runs on.\n\n## Why not Anki + AnkiConnect?\n\nAnkiConnect is a bridge into the desktop app: it only answers while Anki\nis open on that machine, and it speaks Anki's own JSON, not MCP. Flash is\na server. It is reachable from your phone, from a Claude connector, from\nClaude Code in a terminal, all at once, and the scheduling lives in the\nserver so every surface sees the same queue. It imports `.apkg` decks\nwhole (cloze, hints, images, audio, LaTeX, typed answers, nested decks)\nand exports them back at any time, so trying it costs nothing.\n\n## Five-minute quickstart (Docker)\n\n```\ngit clone https://github.com/flash-cards/flash && cd flash\ncp .env.example .env            # set FLASH_BASE_URL to the URL you'll reach it at\ndocker compose up -d\ndocker compose logs flash | grep enroll\n```\n\nThe first boot finds an empty database and logs a one-time link:\n\n```\nno users yet — enroll the first admin within 24h at:\nhttps://cards.example.com/enroll/<token>\n```\n\nOpen it, add a passkey or a password, and you are the admin. Every later\naccount is created from **Settings → Invite**: there is no public signup\non a self-hosted Flash, by design.\n\nWithout Docker: `cargo build --release -p flash-server`, then run\n`target/release/flash-server` with the same environment variables. The\nbinary embeds its templates and static assets; it writes under\n`FLASH_DATA_DIR`, plus short-lived scratch files for an import or export\nin the system temp directory (the systemd unit gives it a private one).\n\n## Connecting your AI\n\nFlash serves MCP at `/mcp` (Streamable HTTP) with OAuth 2.1: the client\nregisters itself, sends you to Flash's login page, and gets a token\nscoped to your account.\n\n- **Claude.ai / Claude mobile** — Settings → Connectors → Add custom\n  connector → paste `https://<your host>/mcp`. Claude's connectors need a\n  publicly reachable HTTPS origin, so put Flash behind a reverse proxy\n  with a certificate, such as Caddy:\n  ```\n  cards.example.com {\n      reverse_proxy 127.0.0.1:8437 {\n          header_up X-Real-IP {remote_host}\n      }\n  }\n  ```\n  and set `FLASH_CLIENT_IP_HEADER=x-real-ip` so the rate limiters see\n  each visitor rather than the proxy (see the note under Configuration).\n  A tunnel (Cloudflare Tunnel, Tailscale Funnel, ngrok) works the same\n  way if you'd rather not open a port.\n- **Claude Code** — `claude mcp add --transport http flash https://<your host>/mcp`.\n  Claude Code and Claude Desktop run on your own machine, so a LAN address\n  works for the MCP connection as long as `FLASH_BASE_URL` matches what\n  you paste. The web UI itself needs HTTPS or `http://localhost`: its\n  session cookie is marked Secure, and a browser drops it over plain http\n  to any other host (the server says so at boot).\n- **ChatGPT** (Plus and up, Developer mode) — Settings → Apps → add the\n  same URL as an MCP server. **Grok** — Connectors → New → Custom.\n\nOnce connected, say \"quiz me on my pharmacology deck\" and follow along.\nThe web app at `/` is where you import decks, edit cards and read your\nstats.\n\n## Configuration\n\nEverything is an environment variable; the core needs only the first\nthree. Optional groups are all-or-nothing: a partial set is a boot error,\nan absent set turns the feature off.\n\n| Variable | Default | What it does |\n|---|---|---|\n| `FLASH_BASE_URL` | — | The public origin (`https://cards.example.com`). Passkeys, OAuth and every link in a mail are minted against it, so it must be what browsers actually see. A hostname, not an IP address: passkeys are bound to a domain, and `http://localhost:8437` is fine for a trial. |\n| `FLASH_BIND` | `127.0.0.1:8437` | Listen address. The Docker image sets `0.0.0.0:8437`. |\n| `FLASH_CLIENT_IP_HEADER` | unset | Header holding the real client address when a proxy is in front (`x-real-ip`, `cf-connecting-ip`). Unset uses the TCP peer. See the note below the table. |\n| `FLASH_DATA_DIR` | `./data` | The SQLite database, import scratch space and media. Back this directory up. |\n| `FLASH_SUPPORT_EMAIL` | unset | Shown on the pages that print a contact address. |\n| `RESEND_API_KEY` + `FLASH_EMAIL_FROM` | unset | Outbound mail through [Resend](https://resend.com), the one provider supported today. The core sends exactly one kind of mail, the password-reset link, so without this there is simply no self-service reset. Both or neither. |\n| `FLASH_DEV_MAIL_LOG=1` | unset | Instead of a provider, log the mail (and its link) to stdout. |\n| `FLASH_MEDIA_R2_ENDPOINT`, `FLASH_MEDIA_R2_BUCKET`, `FLASH_MEDIA_R2_ACCESS_KEY_ID`, `FLASH_MEDIA_R2_SECRET_ACCESS_KEY` | unset | Keep media blobs in any S3-compatible bucket (S3, R2, MinIO, B2) instead of under the data directory. Most installs leave this unset. All four or none. |\n\nAccounts are created by an admin (the enroll link above, then\nSettings → Invite). Each account signs in with passkeys, a password, or\nboth, and always keeps at least one method. Studying, reviewing and export\nare never gated by anything.\n\nThe sign-in, API and web-mutation rate limiters key on the client\naddress. Behind a reverse proxy every request arrives from the proxy's\naddress, so without more configuration the whole instance shares one\nbucket and the server says so in its log on every boot. Tell Flash which\nheader carries the real address with `FLASH_CLIENT_IP_HEADER`:\n`x-real-ip` for Caddy (with the `header_up` line above) and nginx (with\n`proxy_set_header X-Real-IP $remote_addr`), `cf-connecting-ip` for\nCloudflare. `x-forwarded-for` works too: the rightmost address, the one\nyour proxy appended, is the one used. Only name a header when nothing\nbut the proxy can reach the port: a header is forgeable by anyone who\ncan connect directly. Values that are not addresses are ignored in\nfavour of the peer, and IPv6 clients are keyed by their /64.\n\n## What is here, and what isn't\n\n```\ncrates/\n├── flash-core     the scheduler wrapper, queue policy and domain types (no IO)\n├── flash-store    SQLite: migrations, decks, cards, reviews, media, .apkg/CSV import and export\n└── flash-server   the binary: web UI (askama + htmx), passkeys and passwords,\n                   OAuth 2.1 + MCP, the JSON API the mobile apps use\n```\n\nThe server exposes a small extension seam (`flash_server::ext`,\n`flash_store::ext`) that the hosted product plugs its billing, sign-in\nproviders, plans and community into. None of that is in this repository,\nand the core never depends on it: what you run here is complete.\n\n## Contributing and support\n\nIssues and pull requests are welcome; see [CONTRIBUTING.md](CONTRIBUTING.md)\nfor how the code is laid out, how to run the tests, and the contributor\nlicense agreement. This is one person's project and the hosted service is\nwhere the time goes, so bug reports get read and fixed as they come, and\nfeature requests are weighed against the roadmap rather than promised. If\nyou would rather not run a server, the hosted version is a sign-up away.\n\n## License\n\nAGPL-3.0-only. See [LICENSE](LICENSE) and [THIRD_PARTY.md](THIRD_PARTY.md)\nfor the embedded assets. Contributions are accepted under the CLA in\n[CLA.md](CLA.md), which lets the same code power the hosted service.\n",
  "bytes": 7824,
  "sha": "3d94e89fcf50eddb01385d89f53894a486274be8560127b14b2c7d5cf58ab9e1",
  "repo_slug": "flash-cards/flash",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_com_flashmemorize_flash_542416a7/readme"
}