Read-only CLI client for D2L Brightspace student APIs, built for AI agents
Project description
d2l-cli gives any AI agent — Claude Code, OpenClaw, Cursor, Copilot, Gemini CLI, anything that can run a command — read-only access to your D2L Brightspace courses. Grades, due dates, assignments, quizzes, syllabi, announcements, lecture files. You stop clicking through D2L and start asking questions.
Works at any school on Brightspace. Kennesaw State and Georgia State are one-word presets.
Set up in one message
Paste this into your AI agent:
Fetch and follow the instructions from
https://raw.githubusercontent.com/Aaryan-Kapoor/d2l-cli/main/INSTALL_FOR_AGENTS.md
Set up d2l-cli for me end to end. You should only need me twice: to tell you
my school, and to log in when a browser window opens.
That's the whole setup. The agent installs the CLI, installs its own d2l skill, configures your school, opens a browser for your normal SSO login (it never sees your password — the CLI just captures the API token), verifies everything with d2l doctor, and interviews you once about your courses so future sessions already know how you work.
After that, your login refreshes itself: the CLI silently renews the token from your saved session, so you'll rarely be asked to sign in again.
Then just ask
"What are my grades this semester?"
"What's due next week?"
Prompts worth stealing
The point of an agent is autonomy — don't ask for data, ask for outcomes. Copy these:
The weekly plan
Check every one of my courses. Build me a plan for the next 7 days: everything
due or overdue, ranked by grade impact — pull each course's grading weights
from the syllabus before ranking. Tell me what to start first and why.
The grade audit
Pull my grades for every course. For each one: where am I losing points, what's
my current standing, and exactly what do I need on the remaining work to finish
with an A? Check the syllabus for grading weights before doing any math.
The study session
I have a data structures exam coming up. Find and download the relevant lecture
notes and study materials, read them, then quiz me one question at a time until
I stop missing. Track which topics I'm weakest on.
The assignment kickoff
Download the starter files and instructions for the next assignment due in data
structures into a new folder. Read the instructions and walk me through a plan
of attack — but don't write any solution code for me.
The policy cheat sheet
Read the syllabus for every one of my courses and make me a one-page cheat
sheet: grading weights, late policies, exam dates, and instructor contact info.
The morning briefing (works great as a scheduled/recurring agent task)
Run `d2l --md dump --since 24` and brief me: new announcements, new grades,
anything newly due or changed. If nothing happened, just say so in one line.
How it works
- Your agent runs
d2l— a small Python CLI that talks to Brightspace's own student API. Every call is a GET; the tool physically cannot submit, post, or change anything. - Auth is your normal browser login.
d2l loginopens a real browser window, you sign in through your school's SSO like always, and the CLI captures the short-lived API token. Tokens expire hourly, but the CLI silently refreshes them from your saved browser session — you sign in roughly once per device, not once per hour. - The agent carries a skill. The bundled skill (
d2l skill install) teaches any agent the commands, the safety rules, and the onboarding workflow, so a brand-new session is productive immediately.
Manual setup (no agent)
pipx install "d2l-cli[login]"
d2l setup # pick your school
d2l login # browser opens — log in like normal
d2l courses
No pipx? Use python -m pip install --user "d2l-cli[login]" (on Windows: py -m pip install --user "d2l-cli[login]") and make sure Python's user scripts directory is on your PATH — pip prints its exact location in a warning if it isn't.
d2l login uses Playwright's bundled Chromium if you have it, and automatically falls back to your installed Chrome or Edge — so no 150 MB browser download is required on most machines.
Commands
d2l [--json | --md] <command>
Setup:
setup [--school NAME | --host URL] Configure your school (~/.d2l/config.json)
doctor Diagnose config/auth/API state + next step
skill install DIR Install the bundled agent skill
update [--ref REF] Update to the latest release
Identity:
login [--headless] [--channel X] Browser-based token capture
token Token status (no API call)
whoami Current user info
Courses:
courses [--all] List enrolled courses
Academics:
grades COURSE [--final] Grades for a course or across all
assignments COURSE Assignments + due dates
quizzes COURSE Quiz list + dates
syllabus COURSE Full syllabus from SimpleSyllabus
Content:
content COURSE [--toc] Course modules and topics
discussions COURSE Forums, topics, posts
news [COURSE] [--since DATE] Announcements
Scheduling:
calendar [--course X] [--days N] Calendar events
due [--days N] Items due soon
overdue Overdue items
updates [COURSE] Unread update counts
Downloads:
download COURSE ASSIGNMENT [-o DIR] Assignment attachments
download-content COURSE MODULE [-o DIR] Content files (notes, slides)
AI snapshot:
dump [--course X] [--shallow] [--since N] Full academic snapshot
Onboarding:
onboard [--force] [--yes] Create/update the course SOP + state
Every COURSE argument takes fuzzy names ("data structures", "calc"), course codes, or numeric IDs. Output is human tables by default, --json for machines, --md for AI consumption — put the flag before the command.
Your school
d2l setup # interactive picker
d2l setup --school ksu # Kennesaw State preset (includes SimpleSyllabus)
d2l setup --school gsu # Georgia State preset
d2l setup --host https://your-school.view.usg.edu # any Brightspace school
d2l setup --syllabus-host https://your-school.simplesyllabus.com # optional
Config lives in ~/.d2l/config.json; D2L_HOST overrides it per-run. At a school that isn't a preset yet? It still works with --host — and a one-line PR to schools.py adds your school as a preset for everyone after you.
For agent developers
AGENTS.mdat the repo root is the standing instruction file picked up by Claude Code, Cursor, Copilot, Codex, Windsurf, Aider, and friends.d2l skill install <dir>emits the bundled portable skill (SKILL.md + references) into any skill system — no repo checkout needed.d2l --json doctorreports every setup check with anext_stepcommand, so agents never guess state.- Every command is machine-readable with
--json;d2l --md dumpis the one-shot full-context snapshot.
Headless servers: run d2l login once on a machine with a browser, copy ~/.d2l/ to the server, and the automatic headless refresh keeps the token alive off the saved session cookies (they last for weeks).
Strictly read-only
Every API call this tool makes is a GET. It cannot submit assignments, post to discussions, modify grades, mark items read, or change anything on D2L — by design, not by policy. Your agent gets eyes, not hands.
Disclaimer
This is a personal project and is not affiliated with, endorsed by, or associated with D2L, Brightspace, or any university. Just something I built for myself and thought was worth sharing.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file d2l_cli-0.2.0.tar.gz.
File metadata
- Download URL: d2l_cli-0.2.0.tar.gz
- Upload date:
- Size: 48.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cc3005cbb6f0b14b22a0e62a939337e38c179307aac9be3ac1d2d71aed855c15
|
|
| MD5 |
36dfeb96438bbf314b570aeb64b39009
|
|
| BLAKE2b-256 |
be7b3acc22a5dc918c71ed909dff3ea0cbec7076ca4ce37bd4007a66f684d15d
|
Provenance
The following attestation bundles were made for d2l_cli-0.2.0.tar.gz:
Publisher:
publish.yml on Aaryan-Kapoor/d2l-cli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
d2l_cli-0.2.0.tar.gz -
Subject digest:
cc3005cbb6f0b14b22a0e62a939337e38c179307aac9be3ac1d2d71aed855c15 - Sigstore transparency entry: 2082559785
- Sigstore integration time:
-
Permalink:
Aaryan-Kapoor/d2l-cli@802d2952993e1427476b65e6e2c5890c74583df5 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/Aaryan-Kapoor
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@802d2952993e1427476b65e6e2c5890c74583df5 -
Trigger Event:
push
-
Statement type:
File details
Details for the file d2l_cli-0.2.0-py3-none-any.whl.
File metadata
- Download URL: d2l_cli-0.2.0-py3-none-any.whl
- Upload date:
- Size: 52.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6f3972835d9ebdf69f562a91e68091769d80de62467e6c129d53f810de7f539a
|
|
| MD5 |
c5d365ae7449eb7599f62b72105611f8
|
|
| BLAKE2b-256 |
01f8bb1b7694fb27e44447b4c4f20e70df9bb1ecb3ba6ed5a6ae45db01840224
|
Provenance
The following attestation bundles were made for d2l_cli-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on Aaryan-Kapoor/d2l-cli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
d2l_cli-0.2.0-py3-none-any.whl -
Subject digest:
6f3972835d9ebdf69f562a91e68091769d80de62467e6c129d53f810de7f539a - Sigstore transparency entry: 2082559793
- Sigstore integration time:
-
Permalink:
Aaryan-Kapoor/d2l-cli@802d2952993e1427476b65e6e2c5890c74583df5 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/Aaryan-Kapoor
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@802d2952993e1427476b65e6e2c5890c74583df5 -
Trigger Event:
push
-
Statement type: