@vincenthopf/easel
v0.2.1
Published
Read-only Canvas study CLI — a calmer, context-lean front door to deadlines, marks, modules, announcements, reading lists and the library.
Maintainers
Readme
easel turns Canvas into something you can actually live in from the terminal: deadlines, marks, module
content, announcements, discussions, embedded PDFs, and your library — as compact text a human can scan,
or lean JSON a Claude Code agent can read.
It is read-only by design. It only ever asks Canvas for information; it can never submit work, take a
quiz, post, or change anything in your account. That is enforced in the code — the HTTP client exposes
GET only — not just promised in a README.
$ easel today
Due soon
Fri, 17 Jul, 12:00 pm · 11d · BIO101 · Assessment 1 Part B · PROCTORED hands-off
Missing
no missing submissions reported
Announcements
06 Jul, 11:07 am · CHEM101 · Lecture Module 3.2
06 Jul, 07:00 am · BIO101 · Weekly study session times
$ easel marks
BIO101 · 72.0% current grade (graded so far) · 7.2% of final locked in
CHEM101 · 60.0% current grade (graded so far) · 6.0% of final locked in
BIO101 · Assessment 1 Part A · 18/25 · 72.0% · pass
CHEM101 · Module Test 1 · 6/10 · 60.0% · passExample output above uses placeholder subjects and figures.
Install
# Global (recommended for agents)
npm install -g @vincenthopf/easel@latest
# or: pnpm add -g @vincenthopf/easel
# From source
git clone https://github.com/vincenthopf/easel.git && cd easel
pnpm install && pnpm buildSetup
Easiest — run the wizard:
easel initIt asks for your Canvas URL and access token (Canvas → Account → Settings → New Access Token), saves
them to a private config file (~/.config/easel/.env), and checks the token works — so easel runs from
any folder.
Or by hand: cp .env.example .env and fill in:
CANVAS_BASE_URL=https://canvas.youruniversity.edu # your Canvas host
CANVAS_TOKEN=your-token-here
# Optional, for `easel library`:
LIBRARY_BASE_URL=https://library.youruniversity.eduYour token stays local (gitignored .env or the config file) and is sent only to your own Canvas host.
The tool reads only your data — the token can't see anyone else's.
Commands
| Command | What it does |
| --- | --- |
| easel init | Interactive setup: save your Canvas URL, token and library |
| easel today | Briefing: what's genuinely outstanding, missing work, recent announcements |
| easel due [--days N] [--course C] | Upcoming assignments, sorted; submitted items marked done, proctored items flagged |
| easel marks [--course C] | Per-assessment scores, 50% pass-line read, and the graded-so-far current grade |
| easel courses [--all] | Your real subjects (admin shells hidden unless --all) |
| easel modules <course> | Module list and the page slugs inside them |
| easel page <course> <slug> | One module page as clean text |
| easel announcements [--course C] | Recent announcements across subjects |
| easel discussions <course> | Discussion forums for a subject |
| easel files <course> | Every downloadable file link embedded in briefs, pages and announcements |
| easel pull <course/fileId> | Resolve a Canvas file and download it (e.g. an assessment brief PDF) |
| easel library search "<q>" | Search your public library guides — no login |
| easel library fetch <url> | Pull one public library page as clean text |
| easel bug | How (and where) to report a bug |
| easel whoami | The account behind the token |
<course> accepts a subject code (e.g. BIO101) or a numeric Canvas id.
Context-lean by default
Modelled on escli: output stays small unless you ask
for more. On any content command:
- compact by default — one line per item, essentials only
--full— the whole thing--objective "<focus>"— return only the passages relevant to a topic-o <file>— write full content to a file and print just a summary line (path · bytes · title)--json— lean, shaped DTOs (not raw Canvas blobs), for agents
Rate limiting
Every request — Canvas and library alike — is paced like a human: a randomised gap between calls and a
hard ceiling per minute, shared across all invocations on the machine through a lock and state file.
429 and 403 "rate limit exceeded" responses back off exponentially with jitter. An agent hammering
easel in a loop still can't flood your institution's servers.
Tune it in .env: EASEL_MIN_INTERVAL, EASEL_MAX_INTERVAL, EASEL_RPM.
For agents
If you're an agent using this tool: output is designed for you (--json everywhere). If you hit a bug,
wrong output, or a missing capability, report it at https://vjh.io/bugreport so it can be fixed fast.
easel will also tell you when a newer version is available and how to update.
Where the lines are
Fine, by design: reading your own data to organise, understand and plan your study.
Not built, on purpose: anything that writes to Canvas, anything that operates during a proctored (Respondus/webcam) assessment, per-question quiz review, and Canvas conversation/planner/calendar writes. The clean test for any future feature: would you be comfortable declaring this use to your tutor?
Not yet: the browser engine
Reading lists and other external LTI tabs (library databases, online-class tools) aren't Canvas data — they need an authenticated browser session rather than a Canvas API call. That's a planned second phase (a separate, human-paced browser engine), deliberately kept out of the read-only HTTP client for now.
License
MIT.
