使用说明
Laurus
Canvas LMS from your terminal.
Courses, assignments, grades, files, and deadlines - without opening a browser. Built for students, powered by agents.
What is this?
Laurus is a CLI and MCP server for Canvas LMS -the platform used by thousands of universities. One binary, two modes:
laurus next # CLI: what's due next?
laurus mcp serve # MCP: plug into Claude, Symphony, or OpenClaw
Works with any Canvas instance. Laurus is Latin for "laurel", the tree of academic achievement.
Install
# macOS
brew install chrismdemian/tap/laurus
# Windows
scoop bucket add laurus https://github.com/chrismdemian/scoop-bucket
scoop install laurus
# From source (requires Go 1.26+)
go install github.com/chrismdemian/laurus@latest
Pre-built binaries for Linux, macOS, and Windows are available on the Releases page.
Quick Start
# 1. First-run setup (prompts for Canvas URL + API token)
laurus setup
# 2. See what's due
laurus next
# 3. Check your grades
laurus grades
# 4. Plug into Claude / Symphony / Cursor (see MCP section below)
laurus mcp serve
Features
CLI Mode
The daily drivers. Fast, scriptable, pipe-friendly.
| Command | Description |
|---|---|
laurus course <course> |
Course details, including the front page for wiki courses (--home, --syllabus) |
laurus download <course> <file> |
Download a file by name, numeric file ID, or Canvas file link (<course> is used only for name lookups) |
laurus next |
Next due assignment across all courses |
laurus assignments |
All upcoming assignments, sorted by urgency |
laurus grades |
Current grades across all courses |
laurus grades --what-if "CSC108:85" |
Simulate final grades |
laurus announcements |
Recent announcements across all courses |
laurus sync |
Sync Canvas data + course files to local cache |
laurus submit <course> <assignment> <file> |
Submit from the terminal |
laurus calendar --export |
Export deadlines to .ics |
laurus inbox |
Read and send Canvas messages |
laurus search <query> |
AI-powered semantic search across courses |
Some courses set their default view to the wiki and keep the syllabus, schedule
and reading list on the course front page rather than in the syllabus tab.
laurus course <course> shows the front page inline and reports the course's
default view; --home shows only the front page, and --syllabus falls back to
it when the syllabus is empty on a course whose default view is the wiki.
Those courses often hide the Files tab too, so file names cannot be searched.
Copy the file link from the front page and pass its ID:
laurus download <course> 44730205, or paste the whole URL. The MCP
server exposes the same thing through get_front_page, and get_course carries
default_view and front_page.
Every command supports --json for scripting. laurus status reads only the local cache and laurus courses --cached serves from it; other commands are live and refresh the cache as they go.
MCP Server Mode
Plug Canvas into any AI assistant. Claude, Symphony, Cursor, OpenClaw -anything that speaks MCP.
laurus mcp serve # add --read-only to hide every tool that writes to Canvas
// claude_desktop_config.json
{
"mcpServers": {
"canvas": {
"command": "laurus",
"args": ["mcp", "serve"]
}
}
}
Works with Claude Desktop, Claude Code, Symphony, Cursor, and any MCP-compatible client. The same config format applies to all of them.
Reads are cache-first with an honest stamp: every tool result is an
envelope {as_of, stale, source, data} where source is cache (served
from the local sync cache, refreshed automatically when older than the
tool's freshness tier: 5 min for anything carrying grades, 30 min for
announcements and discussions, 1 h for file metadata, 4 h for modules and
pages), live (fetched just now), or local (search_local_files: read
from the downloaded files on disk, no Canvas call). Time-critical tools (next assignment,
overdue, calendar, todo, search, office hours, inbox, unread count,
reading a conversation, grade calculations) are always live. Pass
fresh: true to any cache-served tool to force a refresh, call
laurus_sync to refresh everything and get the error list, and use
search_local_files to grep the course files you downloaded with
laurus sync files or laurus download-all (their contents are treated
as untrusted text).
Grade Calculator
The first tool to match Canvas's exact grade calculation algorithm: weighted groups, drop-lowest rules (Kane & Kane bisection), extra credit, excused assignments. No more broken third-party calculators.
laurus grades CSC108 --detailed # per-assignment breakdown with rubric
laurus grades --what-if "CSC108:A" # simulate final exam scores
laurus grades --gpa # compute GPA across all courses
Offline Mode
Everything is cached locally in SQLite. Check grades on the subway. Review assignments on a plane.
laurus sync # sync all data + files
laurus assignments --cached # read from cache, no network
Shell Integration
Ambient awareness without opening anything.
# ~/.config/starship.toml
[custom.canvas]
command = "laurus status --short"
format = "[$output]($style) "
style = "yellow"
interval = 300
# ~/.tmux.conf
set -g status-right '#(laurus status --short)'
set -g status-interval 300
Background Notifications
Get desktop notifications for new grades, announcements, and upcoming deadlines.
laurus daemon install # install background polling (systemd/launchd/Task Scheduler)
laurus daemon status # check if it's running
laurus daemon uninstall # remove it
laurus watch # or run manually in the foreground
Architecture
┌─────────────────────────────────────────────────────┐
│ laurus binary │
├───────────────┬──────────────────┬──────────────────┤
│ CLI Mode │ MCP Mode │ Daemon Mode │
│ (cobra) │ (mcp-go) │ (background) │
├───────────────┴──────────────────┴──────────────────┤
│ Core Library │
│ │
│ ┌──────────┐ ┌───────────┐ ┌────────────────┐ │
│ │ Canvas │ │ Grade │ │ HTML Renderer │ │
│ │ API │ │ Calculator│ │ │ │
│ │ Client │ │ (exact) │ │ │ │
│ ├──────────┤ ├───────────┤ ├────────────────┤ │
│ │ GraphQL │ │ File Sync │ │ Notification │ │
│ │ + REST │ │ Engine │ │ Engine │ │
│ ├──────────┤ ├───────────┤ ├────────────────┤ │
│ │ SQLite │ │ Auth & │ │ Calendar │ │
│ │ Cache │ │ Keychain │ │ Export │ │
│ └──────────┘ └───────────┘ └────────────────┘ │
└─────────────────────────────────────────────────────┘
- REST + GraphQL hybrid - GraphQL for bulk queries (courses + assignments + submissions in one call), REST for mutations and file uploads
- SQLite cache with WAL mode - offline reads, incremental sync, sub-millisecond lookups
- OS keychain for token storage (Keychain on macOS, Credential Manager on Windows, Secret Service on Linux)
- Smart polling -
graded_sinceandstart_dateparameters for efficient change detection
Supported Canvas Features
Laurus covers the full Canvas student API surface:
| Category | Endpoints | Status |
|---|---|---|
| Courses | List, details, syllabus, people | Done |
| Assignments | List, view, submit, rubrics | Done |
| Grades | Current/final, weighted, what-if | Done |
| Modules | List, tree view, completion tracking | Done |
| Files | Browse, download, sync | Done |
| Announcements | List, filter, unread | Done |
| Discussions | List, read threads, post replies | Done |
| Calendar | Events, deadlines, iCal export | Done |
| Inbox | Read, send, reply | Done |
| Planner | Todo items, mark complete | Done |
| Quizzes | View details, results | Done |
| Groups | List, files, discussions | Done |
| Search | AI-powered Smart Search | Done |
| Analytics | Activity stats, history | Done |
| Office Hours | View slots, book appointments | Done |
Configuration
laurus setup
# Prompts for Canvas URL, opens browser with token instructions, stores token in OS keychain
Config lives in your OS config directory:
- Linux:
~/.config/laurus/config.toml - macOS:
~/Library/Application Support/laurus/config.toml - Windows:
%AppData%\laurus\config.toml
canvas_url = "https://q.utoronto.ca" # your institution's Canvas URL
sync_dir = "~/School" # where `laurus sync files` puts course files
theme = "auto" # auto, dark, light
Environment variables override the file and the keychain, so a headless machine needs no config at all:
| Variable | Overrides |
|---|---|
CANVAS_TOKEN |
the stored API token |
CANVAS_URL |
canvas_url in config.toml |
The token is stored in the OS keychain (macOS Keychain, Windows Credential
Manager, Secret Service on Linux) with a credentials file next to
config.toml as the fallback.
Setting up with a coding agent (non-interactive)
Everything below is safe to hand to an agent. The human's only inputs are their Canvas API token (Canvas > Account > Settings > New Access Token) and their institution's Canvas URL. Nothing prompts; missing values are an error, not a hung form.
# 1. Configure: validates the token against Canvas, stores it, saves the URL.
laurus setup --token "$CANVAS_TOKEN" --url https://canvas.school.edu --yes
# Same, keeping the token out of argv and shell history:
echo "$CANVAS_TOKEN" | laurus setup --token-stdin --url https://canvas.school.edu --yes
# 2. Verify. Exit code is non-zero when any check fails.
laurus doctor --json && echo ok
# 3. Wire it into Claude Code (token already in the keychain after step 1):
claude mcp add laurus -- laurus mcp serve
# Or skip setup entirely and pass everything through the environment:
claude mcp add laurus -e CANVAS_TOKEN=... -e CANVAS_URL=https://canvas.school.edu -- laurus mcp serve
laurus mcp install --client claude-code|cursor|vscode writes the entry
for you, merging with the servers already there and doing nothing on a
second run:
laurus mcp install --client claude-code # project: ./.mcp.json
laurus mcp install --client claude-code --scope user # user: ~/.claude.json (backed up to .bak first)
laurus mcp install --client cursor --scope user # ~/.cursor/mcp.json
laurus mcp install --client vscode --scope user # VS Code user mcp.json
laurus mcp install --client vscode --read-only --print # show the entry, write nothing
The entry passes CANVAS_TOKEN through from the environment in the
client's own syntax (${CANVAS_TOKEN} for Claude Code, ${env:CANVAS_TOKEN}
for Cursor and VS Code), so no token is written to disk; --no-env drops
that when the token is already in the keychain. The Claude Code project
form it writes:
{
"mcpServers": {
"laurus": {
"command": "laurus",
"type": "stdio",
"args": ["mcp", "serve"],
"env": { "CANVAS_TOKEN": "${CANVAS_TOKEN}" }
}
}
}
Add "CANVAS_URL": "https://canvas.school.edu" to env if laurus setup
was never run on that machine. Add --read-only to the serve args when the assistant should never be
able to submit, post, send, or book anything in Canvas; the write tools are
then not registered at all.
Contributing
See CONTRIBUTING.md for development setup and guidelines.
