English | 简体中文
Canvas CLI gives AI agents a controlled interface to Canvas LMS. Agents can inspect courses and assignments, download course files, prepare submissions, work through Classic Quizzes with user-provided answers, and access more than 1,100 Canvas REST API operations.
Commands return structured JSON or YAML. Read operations run directly; writes
such as uploads and submissions require --confirm, so an agent can show the
exact action before executing it.
Give the repository URL to an agent:
Install Canvas CLI from https://github.com/hhe48203-ctrl/canvas-cli.
Use the Go version declared by the repository, install the canvas binary in a
user-writable directory on PATH, and verify it with canvas --help. Do not use
sudo or change my shell configuration without asking. I will set the Canvas
token myself; do not ask me to paste it into chat.
Or install it manually:
git clone https://github.com/hhe48203-ctrl/canvas-cli.git
cd canvas-cli
go build -o canvas .
mkdir -p "$HOME/.local/bin"
install -m 0755 canvas "$HOME/.local/bin/canvas"Canvas CLI requires the Go version declared in go.mod.
Update an installed binary to the latest main build with:
canvas --updateThe update requires Go and write access to the installed binary.
For troubleshooting or a bug report, run canvas --version. It reports the
local build metadata without contacting Canvas.
Create a Canvas access token in Account → Settings → Approved Integrations, then keep it in an environment variable:
export CANVAS_BASE_URL="https://canvas.example.edu"
export CANVAS_API_TOKEN="your-token"
canvas auth status
canvas auth set-url "https://canvas.example.edu"CANVAS_API_TOKEN is never written by the CLI. Do not put it in prompts, source
files, command arguments, or commits.
skills/canvas-lms/SKILL.md is a standalone
skill with this workflow. Copy it into the canvas-lms skill folder for any
skill-supporting agent environment. For Codex, from this checkout:
mkdir -p "$HOME/.codex/skills/canvas-lms"
cp skills/canvas-lms/SKILL.md "$HOME/.codex/skills/canvas-lms/SKILL.md"Example request:
Find my active biology course, list assignments due this week, and prepare the next submission. Show me the course, assignment, and files before submitting.
# Courses and assignments
canvas courses list --all-pages --json
canvas assignments list COURSE_ID --all-pages --json
canvas assignments show COURSE_ID ASSIGNMENT_ID --json
# Files
canvas files list COURSE_ID --all-pages --json
canvas files download FILE_ID --destination ./lecture.pdf
# Text, URL, or multi-file submissions
canvas assignments submit COURSE_ID ASSIGNMENT_ID \
--text "My response" --confirm --json
canvas assignments submit COURSE_ID ASSIGNMENT_ID \
--url "https://example.com/work" --confirm --json
canvas assignments submit COURSE_ID ASSIGNMENT_ID \
--file answer.pdf --file appendix.pdf --confirm --json
# Classic Quizzes
canvas quizzes list COURSE_ID --all-pages --json
canvas quizzes start COURSE_ID QUIZ_ID --confirm --json
canvas quizzes questions SUBMISSION_ID --all-pages --json
canvas quizzes answer SUBMISSION_ID \
--answers-file answers.json --confirm --json
canvas quizzes complete COURSE_ID QUIZ_ID SUBMISSION_ID \
--attempt ATTEMPT --validation-token TOKEN --confirm --jsonUse canvas --help or canvas <command> --help for all flags and examples.
The generated catalog covers more than 1,100 operations from the official Canvas REST API documentation:
canvas api search modules
canvas api describe context_modules_api.create
canvas api invoke courses.list \
--query enrollment_type=student --all-pages --json
canvas api invoke METHOD /api/v1/example \
--query key=value --body request.json --confirm --jsonapi describe shows the method, path, and parameters. api invoke accepts
repeatable --path, --query, --header, and --form values, plus --body
and --all-pages; write methods require --confirm.
The authoritative API reference is the Instructure Developer Documentation.
--jsonand--yamlreturn stable success or error envelopes.--all-pagesfollows Canvas pagination links without reconstructing them.- File uploads stream data and complete Canvas' multi-step upload flow.
- Mutating operations require
--confirm. - Quiz answers must come from the user; the CLI does not solve or guess them.
- Canvas permissions and institutional policies still apply.
Usage logging is on by default and stays on your computer; nothing is uploaded. Disable it in the agent's environment with:
export CANVAS_USAGE_LOG=0Unset the variable to re-enable it. Each completed CLI invocation appends one
JSONL record, including argument and execution failures. Pagination and file
transfers produce one command summary. Help and completion have their own
kind so they can be excluded from usage statistics.
| Fields | Meaning |
|---|---|
time, version |
UTC completion time; module version, Git revision, or devel when unavailable |
kind, command |
command, help, or completion; registered command path |
operation_id |
Recognized catalog ID for api invoke / api describe, when available |
duration_ms, exit_code |
Command duration and exit code (0 or 1) |
error_kind |
On failure: arguments, confirmation_required, configuration, http, network, io, or execution |
http_status |
Last received HTTP response status, when available; a later network/local failure may still leave this status present |
Only these fields are stored. Logs exclude argument values, raw URLs, tokens, file paths, request/response bodies, and original error messages. Unknown operation IDs are omitted. Logging failures do not change stdout, stderr, or the command's exit code. Forced termination may leave no record, and command success does not establish that an agent completed the user's task.
Daily files are named YYYY-MM-DD.jsonl in the system user cache directory:
- macOS:
~/Library/Caches/canvas-cli/logs - Linux:
${XDG_CACHE_HOME:-$HOME/.cache}/canvas-cli/logs - Windows:
%LocalAppData%\canvas-cli\logs
Directories use mode 0700 and files 0600 on Unix. Each logged invocation
cleans up files older than the current UTC day and six preceding days. Each
daily file has a 10 MiB soft limit: new records are skipped after the limit is
reached, with at most one record crossing the limit. Logging resumes
in a new file the next UTC day. Disabling logging does not delete existing logs.
Writers use native file locks to serialize tail repair and append. Failed writes are rolled back; an unfinished trailing record from an interrupted write is removed before the next append. If native locking is unavailable, logging is skipped and the command still runs normally.
After running commands, use jq to summarize call counts, failure rates (0–1),
and average duration, excluding help and completion:
case "$(uname -s)" in
Darwin) canvas_log_dir="$HOME/Library/Caches/canvas-cli/logs" ;;
*) canvas_log_dir="${XDG_CACHE_HOME:-$HOME/.cache}/canvas-cli/logs" ;;
esac
jq -s '
map(select(.kind == "command"))
| group_by([.command, .operation_id])
| map({
command: .[0].command,
operation_id: .[0].operation_id,
calls: length,
failure_rate: ((map(select(.exit_code != 0)) | length) / length),
avg_duration_ms: ((map(.duration_ms) | add) / length)
})
| sort_by(-.calls)
' "$canvas_log_dir"/*.jsonlgo test ./...
go build ./...
scripts/update-api-catalog.shThe script refreshes the embedded catalog from Instructure's official API documentation. See CONTRIBUTING.md for the contribution workflow.