A self-driving archive + study system for University of Waterloo Learn (Desire2Learn / Brightspace).
It reuses your logged-in browser session to pull everything from your courses via the raw D2L JSON
API, organizes it into a markdown-twinned Semester / Course / Week vault, and helps you do
assignments grounded only in your class material, with citations — all driveable from Claude Code.
Built and verified on term 1265 (Spring 2026) = "2B": 5 courses, 129/129 content topics, all lectures/labs/tutorials/slides/PDFs, assignments, announcement attachments, discussions, grades.
python3 -m venv .learn/.venv
.learn/.venv/bin/python -m pip install -r .learn/requirements.txt
# browser engine (one tool): Vercel agent-browser
npm install -g agent-browser && agent-browser install
PY=.learn/.venv/bin/python
$PY .learn/learn.py auth # log in to Learn once in the agent-browser window (WatIAM + Duo)
$PY .learn/learn.py calibrate # probe the live API -> .learn/calibration.json
$PY .learn/learn.py sync # incremental: ingest -> outlines -> convert -> index -> audit
$PY .learn/learn.py ground MSE232 Lab 4 # grounded, cited assignment pack
$PY .learn/learn.py submit MSE232 "Lab 4" solution.pdf # DRY RUN preview of a Dropbox submission
$PY .learn/learn.py submit MSE232 "Lab 4" solution.pdf --confirm # actually submit (gated)
$PY .learn/learn.py verify # health check -> .learn/AUDIT.md- Browser (one tool):
agent-browser(Vercel, CDP) wrapped by.learn/agent_browser.pyharvests the logged-in session (HttpOnlyd2lSessionVal+ XSRF, validated with an in-pagewhoami) and renders SPA pages. No second login; it reuses your authenticated session. - Retrieval (the bulk): the raw D2L JSON API (
/d2l/api/le|lp/...) viarequestswith those cookies — content, assignments, announcements, discussions, quizzes (metadata), grades. - Vault: each file lands under
<SEMESTER>/<COURSE>/content/<week>/…with a.mdtwin, plusINDEX.md,_meta/*.json, and acontent_map.json. Term- and structure-agnostic (no hardcoding). - Grounded assignments:
ground.pyassembles the exact class sources + a strict cite-everything policy; drafts are for your review. - Submitting:
submit.pyresolves the right Dropbox folder, validates your file, and submits via the D2L API with read-back verification — dry-run by default, real submit only on--confirm, nothing submitted unless you explicitly say so. (The actual submit can't be tested in advance, so the first real submission is done supervised; success is reported only after the API read-back confirms it.)
RUNBOOK.md— full operator guide (sync, term selection, remote/phone trigger, troubleshooting).docs/SELF_HOSTING.md— design + execution plan for running it fully self-hosted/headless (one always-on box, phone-only login) — for a future build session.CLAUDE.md/AGENTS.md— agent instructions;.claude/skills/— the skills (learn-sync,learn-assignment,learn-study,agent-browser).
This is for archiving and studying your own coursework; it respects UW's academic-integrity policy.