D0

davidchen-006/brightspace-bar

Developer tools
52 stars Quality 70 Trend 70

MacOS menu bar app for Brightspace. Never log in again. See every due date on one calendar. Click a course. Go straight there. Agents can read your courses and add assignments.

Overview

Menu bar app for Brightspace (D2L). Never log in again. See every due date on one calendar. Click a course. Go straight there. Agents can read your courses and add assignments. - — each current course is a row with a GitHub-contributions-style grid of the coming weeks: darker squares mean heavier work (assignment < quiz < test), today is outlined. - on top, folding every course's grid into one. - — a popup lists that day's items; clicking one opens it in a persistent, already-signed-in Chromium (each click adds a tab). - — per-course counts and the next due item, right beside the grid. - — add assignments/quizzes/tests with a date picker from each course's submenu; they render in the grid like fetched ones and delete with an ✕ from the popup. - — a bsb CLI and a matching skill let an AI agent read your courses, syllabi, files and grades through the app's own session and put syllabus dates on the heatmap. See Agents. - every 30 minutes, silently, via a session the app never sees.

README

Brightspace Bar 📅 — No More Login. No More Friction.

Menu bar app for Brightspace (D2L). Never log in again. See every due date on one calendar. Click a course. Go straight there. Agents can read your courses and add assignments.

What it does

  • A heatmap per course — each current course is a row with a GitHub-contributions-style grid of the coming weeks: darker squares mean heavier work (assignment < quiz < test), today is outlined.
  • An “All classes” aggregate on top, folding every course’s grid into one.
  • Hover a day, see the work — a popup lists that day’s items; clicking one opens it in a persistent, already-signed-in Chromium (each click adds a tab).
  • “This week” at a glance — per-course counts and the next due item, right beside the grid.
  • Your own items — add assignments/quizzes/tests with a date picker from each course’s submenu; they render in the grid like fetched ones and delete with an ✕ from the popup.
  • Agent-native — a bsb CLI and a matching skill let an AI agent read your courses, syllabi, files and grades through the app’s own session and put syllabus dates on the heatmap. See Agents.
  • Background refresh every 30 minutes, silently, via a session the app never sees.

How it stays safe

The app is two halves with a deliberate wall between them:

  • A Swift menu-bar app that renders cached JSON. It contains no network code and no credentials — it cannot log in by construction.
  • A Node daemon (session-capture/) that owns the browser session: a one-time interactive login into a persistent Chromium profile, then silent cookie/JWT renewal on a ladder that only escalates as far as it must.

Your email and password are typed into Microsoft’s real login page in a real (headless) Chromium. They live only in the daemon’s world — credentials.json, mode 0600, under ~/Library/Application Support/BrightspaceBar — never in the repo, never in logs, and never in the Swift process (invariant D7). The app spawns the daemon with no arguments and lets it climb its whole ladder, full login included, so a dead session heals itself from a timer tick; the MFA number reaches you on the menu-bar icon (invariant D8). The daemon attempts that full login at most once per four hours, so a night away is a push or two, not a phone that will not stop.

Supported

  • macOS 14+
  • Xcode Command Line Tools with Swift 6.2+ (xcode-select --install)
  • Node 22+ (brew install node)
  • Playwright’s Chromium, which make setup downloads. If make start or the daemon log ever says “the daemon’s Chromium is not installed”, run cd session-capture && npx playwright install chromium from the repo root — in that directory specifically, so it fetches the build the pinned Playwright looks for.
  • Purdue Brightspace via Entra specifically — the SAML entityId is Purdue-hardcoded today; PRs generalising it are welcome.

This is a build-from-source app today — no binary release yet. The latest tagged state is v0.2.0 (release notes).

Quick Start

git clone https://github.com/DavidChen-006/Brightspace-Bar.git
cd Brightspace-Bar
make setup    # checks prerequisites, installs the daemon's dependencies and the agent skill
make start    # THE one command — see below

make start does everything: it builds the app, prompts for your credentials in the terminal on first run, launches the menu bar, and performs the headless login — no browser window; the MFA verification number appears on the menu-bar icon, you type it into Authenticator on your phone, and the icon reverts. After that, the daemon refreshes the session silently for weeks. If courses ever stop refreshing, run make start again.

There are two ways to sign in, and the rule for choosing is short:

  • make start — the default. No browser window; the MFA number goes on the icon. Use it first, and every time after.
  • make login — the same flow with the browser visible. Use it when make start put no number on the icon and the menu stayed empty, when your Microsoft sign-in is not an Authenticator number match (a text, a code, a “choose a method” page, a setup step), or when you simply want to watch the sign-in happen.

make login opens a Chromium window, types your stored credentials in for you, and you finish whatever Microsoft asks in that window. It stores the same credentials and writes the same session and browser profile as make start, so everything after it — the silent refresh, the next automatic login — works exactly as if the headless login had succeeded. Both paths are tested end to end from an empty install.

Three things that follow from that:

  • You never type your credentials twice. make login reuses what make start stored and types it into the window for you. It prompts only when nothing is stored.
  • A wrong password does not get stuck. If Microsoft rejects the stored password, the daemon says so, removes the stored file, and the next make start or make login asks again. If you corrected it in the make login window and signed in, you are asked once more in the terminal for the password that worked, so automatic logins have it.
  • To start over, make reset. It deletes the session and browser profile and keeps your credentials; the next make start or make login signs in from scratch. Neither command ever deletes your credentials.

Day to day, make start (or make login) is needed once. When the session later dies, the app’s own timer signs in again and puts the number on the icon; you only run a command if that did not work for you, and then it is make login. If you’ve quit the app and just want it back, make run is the “reopen” gesture: build and launch, nothing else (there’s no .app bundle to double-click yet).

Agents

The app is deterministic on purpose: it shows what the D2L API reports as work. An AI agent can read a syllabus — and most professors put half their deadlines there and nowhere else. bsb is the bridge:

./bsb courses                                  # your current courses and their ids
./bsb syllabus --course 1641791 --out ./syl    # overview text + every syllabus file, downloaded
./bsb work --course 1641791                    # what Brightspace already lists as due
./bsb add --course 1641791 --kind assignment --title "First Critical Response" --due 2026-10-19
./bsb add --batch items.json                   # many at once, validated as a whole
./bsb --help                                   # content, fetch, overview, grades, api, …

Items an agent adds appear on the heatmap the moment the file lands — no relaunch, no click — and delete like hand-entered ones. The rules are structural: every Brightspace call bsb makes is a GET, the only file it writes is the app’s own manual-items.json, and the bearer token never leaves your tenant.

The skill — how your agent learns this

An agent does not know bsb exists until it reads the skill in skills/brightspace/: the commands, the read endpoints, the write contract, and the syllabus-to-calendar recipe. It follows the Agent Skills format, so any agent that reads skills can use it. Three ways to install it, pick one:

You use… Do this
make setup (already ran it) Done — setup symlinks the skill into ~/.claude/skills, ~/.agents/skills and ~/.codex/skills. make skill re-runs just that step.
Claude Code, Codex, Cursor, Gemini CLI, Copilot, OpenCode… without cloning npx skills add DavidChen-006/Brightspace-Bar — the skills CLI installs it into each agent’s skills folder. Run make setup in your checkout once, so the copied skill can find the CLI.
Claude Code inside this repo Nothing — .claude/skills/brightspace is in the repo, so it is a project skill the moment you open the folder.

Then start a new agent session and ask in plain words: “read my PHIL 219 syllabus and put the due dates on my calendar”, or “what’s due this week in CS 252”. In Claude Code you can also invoke it directly as /brightspace. The skill tells the agent to show you the list before it writes anything, and how you undo it.

Environment configuration

See session-capture/.env.example for the knobs. Normally you never touch env vars: credentials are entered once via the make start prompt and stored with mode 0600 under ~/Library/Application Support/BrightspaceBar — never in the repo. When BS_EMAIL and BS_PASSWORD are both set in the environment, they override the stored file.

Project layout

Path What it is
BrightspaceBar/ The Swift package: the menu-bar app and its modules (Modules//), tests included
session-capture/ The Node daemon: login ladder, data fetch, deep-link opener — and src/bsb.mjs, the agent CLI
skills/brightspace/ The agent skill: how to use bsb, the read endpoints, the write contract
bsb The CLI’s entry point (./bsb --help)
docs/ Design documents

The numbered experiment-* probes that de-risked each design decision live on the experiments branch — kept as engineering notes, off the main tree.

Architecture

The deep dive lives in docs/architecture.md and BrightspaceBar/ARCHITECTURE.md. The short version, enforced by tests: the GUI imports only the CourseMenu contract module; adapters translate between pipelines and the menu model; the composition root is main.swift. See CONTRIBUTING.md.

Looking for something to pick up? The open issues include good first issues with acceptance criteria spelled out.

Development

make -C BrightspaceBar build  # build the Swift app (or: cd BrightspaceBar && swift build)
make test                     # full suite, from the repo root
make -C BrightspaceBar run    # run the app from source

License

MIT.

View this README on GitHub

Recommended Tools

Try a different keyword or remove a filter.

Install

npx skillfish add davidchen-006/brightspace-bar