Personal spaced-repetition agent that emails one FSRS-scheduled Learn + Quiz digest every weekday morning, covering DSA, System Design, ML/AI, Fullstack, and research papers.
Engineered by Anmol Sharma | GitHub Profile | Live Portfolio
Built on FSRS scheduling, proportional topic allocation, DSA curriculum order, Gemini-generated quizzes, Resend delivery, and GitHub Actions.
Portfolio: Scholar-Loop owns retain knowledge on a schedule only. Not ops (Ozyman), not job boards (Disha), not creative synthesis (IdeaForge). See docs/portfolio-product-boundaries.md.
| Doc | Purpose |
|---|---|
| PROJECT_STATE.md | Current state, constraints, next tasks |
| SESSION_HANDOFF.md | Latest session notes for resuming work |
| ARCHITECTURE.md | System design and trade-offs |
| TASKS.md | Roadmap and task list |
| docs/setup.md | Env, commands, deployment |
| AGENTS.md | Guidance for coding agents |
knowledge/*.md ──► scripts/init_db.py ──► data/user.db (FSRS state)
│
agent/send_daily.py --mode daily
│
┌──────────────────────────────────────┴───────────────────────┐
│ Part 1 · Learn 2–3 due notes (~1500 words), FSRS updated │
│ Part 2 · Quiz 1–2 earlier notes, 3–6 questions (Gemini) │
│ Answers at the bottom, below a divider │
└──────────────────────────────────────┬───────────────────────┘
│
Resend ──► your inbox (Mon–Fri ~07:45 IST)
│
GitHub Actions commits data/user.db with [skip ci]
One email, Monday to Friday. Nothing on weekends.
- Part 1 · Today's notes. Full note content: code, tables, and explanations. Due reviews come first, then new notes; DSA follows its
sequenceorder. Capped at about 1,500 words with at least 2 notes. Each note gets a passive FSRSGoodreview, which schedules its next due date. - Part 2 · Active recall. 3 questions each for 1–2 notes you studied earlier. Today's Learn notes are never quizzed. Picks rotate: least recently quizzed first, then weakest memory (lowest FSRS stability). The quiz does not change FSRS scheduling.
- Answers. At the bottom, below a dashed divider, so you can test yourself before scrolling.
Subject: 📚 Scholar-Loop: System Design and DSA — Learn & Quiz
If Gemini fails, the email still goes out with the Learn notes and a "Quiz unavailable today" notice, and the GitHub run shows a warning. An LLM outage never blocks your notes, and it can't fail silently either.
| Topic | Notes | Weight | Role |
|---|---|---|---|
dsa/ |
41 | 28% | Algorithms + math foundations; sequence curriculum |
ml-ai/ |
60 | 22% | DL, RL, CV, NLP, transformers |
papers/ |
70 | 20% | Paper summaries (Transformer → DeepSeek-R1, …) |
system-design/ |
21 | 16% | Distributed systems, agentic AI, ML system design |
fullstack/ |
31 | 14% | Python, FastAPI, TypeScript, React, SQL |
Not in rotation: knowledge/archive/ (retired notes) and knowledge/obsidian/ (raw guides waiting to be ingested).
git clone https://github.com/anmolsharma152/Scholar-Loop
cd Scholar-Loop
python -m venv .venv && source .venv/bin/activate
pip install -r requirements-dev.txt
cp .env.example .env # fill in RESEND_API_KEY, RECIPIENT, GEMINI_API_KEY
set -a && source .env && set +a
python scripts/init_db.py # knowledge/ → data/user.dbpython agent/send_daily.py --dry-run
# prints the Learn and Quiz picks: path, due, stability (S), review_count, sequence
python agent/send_daily.py --preview /tmp/scholar.html
# builds the full email including the Gemini quiz, writes the HTML, prints its size.
# Sends nothing and leaves scheduling data unchanged.python agent/send_daily.py # combined daily email (default)
python agent/send_daily.py --mode learn # Learn notes only
python agent/send_daily.py --mode quiz # Quiz onlypython scripts/convert_notes.py ~/Downloads/some-paper.pdf
python scripts/ingest_obsidian.py knowledge/obsidian/some-guide.md ml-aiScheduling state lives in data/user.db, not frontmatter.
---
topic: dsa # dsa | system-design | ml-ai | fullstack | papers
difficulty: medium # easy | medium | hard
tags: [arrays, sliding-window]
sequence: 4 # optional; DSA uses this for syllabus order
---
# Your Note TitleWorkflow: .github/workflows/daily-email.yml
| Cron (UTC) | Days | IST | Command |
|---|---|---|---|
47 1 * * 1-5 |
Mon–Fri | 07:17 (arrives ~07:45–08:15) | python agent/send_daily.py --mode daily |
GitHub's scheduler is best-effort and sometimes runs late. Manual run: Actions → daily-email → Run workflow (choose daily, learn, or quiz).
Tests run on every code push to main via .github/workflows/tests.yml.
Secrets (Settings → Secrets and variables → Actions):
| Secret | Required | Source |
|---|---|---|
RESEND_API_KEY |
Yes | resend.com/api-keys |
RECIPIENT |
Yes | Your inbox |
GEMINI_API_KEY |
Yes (for the quiz) | aistudio.google.com |
| Variable | Required | Default | Purpose |
|---|---|---|---|
RESEND_API_KEY |
Yes | — | Email delivery |
RECIPIENT |
Yes | — | Destination address |
GEMINI_API_KEY |
Yes | — | Quiz, convert_notes, ingest_obsidian |
LLM_MODEL |
No | gemini-flash-latest |
Override the Gemini model |
gemini-flash-latest is Google's alias for the newest Flash model, so retired model versions don't break the pipeline.
pip install -r requirements-dev.txt
python -m pytest tests/ -q| Path | Role |
|---|---|
agent/send_daily.py |
Note selection, FSRS, quiz rotation, email rendering |
agent/llm_router.py |
Gemini client (OpenAI-compatible endpoint, retries) |
scripts/init_db.py |
Schema + migrate notes into SQLite |
scripts/convert_notes.py |
PDF/DOCX → study notes via Gemini |
scripts/ingest_obsidian.py |
Chunk large Obsidian guides into study notes via Gemini |
requirements.txt |
Runtime deps (daily email) |
requirements-dev.txt |
+ conversion scripts and pytest |
| Version | Status | Description |
|---|---|---|
| MVP | ✅ | Weighted pick, email delivery |
| V1 | ✅ | SQLite FSRS, topic weights, Learn/Quiz split |
| V1.1 | ✅ | Real passive FSRS (fsrs 6.x), DSA sequence, dry-run logging, tests |
| V1.2 | ✅ | Gemini Flash, one combined weekday email, quiz rotation, tests in CI |
| V1.5 | Planned | One-click Again/Hard/Good/Easy grading from the email |
| V2 | Planned | Multi-user, OAuth, per-user FSRS |