Skip to content

X-isdoingreat/Canvas_pilot_public

Canvas Pilot

License: AGPL v3 Python 3.11+

A Claude Code project that scans your school's Canvas LMS for pending assignments, plans the work, and dispatches each item to a course-specific skill that produces a draft (or, where you have explicitly authorized it, submits on your behalf).

You stay in the loop on the two decisions that matter — what to do and what to ship. The framework handles the rest.


What it actually does

A typical interaction once you're fully configured:

You (in Claude Code, this directory):  scan canvas

Canvas Pilot:
    🔥 URGENT (next 72h)
    | # | course        | assignment       | due           | proposed skill |
    | 1 | Code Course A | Set 3 Problem 1  | 4/25 23:59    | canvas-ics33   |
    | 2 | Writing Course| Tue Wk5 HW Scan  | 4/28 12:30    | canvas-reading-annotation  |
    ⚠️  SOON (3-7d)
    | 3 | Quiz Course   | Section 5        | 4/27 23:59    | canvas-inside    |

    Reply: "approve all" / "approve 1, 2" / "only urgent" / "cancel"

You:                                    approve all

Canvas Pilot:
    [dispatches each item sequentially, runs the per-course skill,
     produces a draft under runs/<today>/<assignment>/draft/,
     and writes a status to result.json]

    Done. REPORT.md written at runs/<today>/REPORT.md.
    Drafts mirrored to final_drafts/ for review.

You review the drafts. You upload manually — unless you have given a specific per-course skill standing authorization to auto-submit, in which case Canvas Pilot uploads after a verification gate passes.


Who this is for

  • Students whose school uses Canvas LMS.
  • Whose coursework includes a high share of repeating-structure assignments (weekly problem sets, weekly readings, weekly quizzes).
  • Who want an AI to handle the boring orchestration (scan, dispatch, draft) but keep the human firmly in the loop for review and submission.
  • Who already use Claude Code as their daily editor.

This is not a "submit my homework for me" tool. The default behavior is produce drafts, you submit. Auto-submit is opt-in per skill, per assignment type, with a verification gate in front.


The product flow

There is one entry point: you say scan canvas in a Claude Code session in this directory. Everything else is a branch that canvas-scan decides based on filesystem state.

You: "scan canvas"
  │
  └─→ canvas-scan §0 self-check
       │
       ├─ .env missing / CANVAS_BASE empty
       │    │
       │    └─→ canvas-setup
       │         1. Ask for your school's Canvas URL
       │         2. Silent install of Playwright + Chromium
       │         3. Pop browser, you log in once
       │         4. List your active courses, ask which to track
       │         └─→ when done, hands off to canvas-bootstrap (no exit)
       │
       ├─ .env OK but courses.yaml.routes is empty
       │    │
       │    └─→ canvas-bootstrap
       │         • Configures ONE course (cluster) per invocation.
       │           Not batch — you walk away after each one and
       │           re-trigger when you want the next.
       │         • Recommendation order is a hard rule:
       │             1. 🟢 Non-LDB quiz   ← agent ships end-to-end with
       │                                    zero human-side config
       │             2. 🟢 Code course    ← verification is mechanical
       │                                    (test runner / compile / lint)
       │             3. 🟡 Writing        ← rubric is bespoke; needs you
       │                                    to author voice + samples
       │             4. ⚪ Unclear → route to canvas-generic
       │                                  (runtime-designed fallback, no
       │                                   overlay; investigates + designs
       │                                   pipeline per-assignment)
       │             5. 🔴 LDB-locked → route to canvas-skip
       │                                  (Lockdown Browser is
       │                                   intrinsic can't-do)
       │         • For categories 1-3 (specific-skill clusters):
       │           silent deep-investigate
       │           → spawn 3 sub-agents in parallel (rubric coverage /
       │             verification checklist / feasibility simulator)
       │           → single batched ask to you
       │           → write overlay v1 at _private/canvas-<name>-app.md
       │           (Category 4 skips this — no overlay needed for canvas-generic)
       │         • If a pending real assignment exists for the cluster,
       │           run the FIRST-RUN CALIBRATION LOOP:
       │             - dispatch the per-course skill, produce one draft
       │             - you review the draft and give feedback
       │             - Sub-agent D categorizes each piece of feedback:
       │                  recurring_pattern → write back into overlay v2
       │                  one_off           → fix this draft only
       │                  workflow_change   → write back into overlay v2
       │             - you confirm the categorization
       │             - first_run_calibration_done = true
       │         • Returns to you. Re-trigger scan to configure the
       │           next cluster.
       │
       └─ .env OK + courses.yaml.routes non-empty
            │
            └─→ Normal scan
                 • List pending → write plan.json → STOP.
                 • You reply with approval ("approve all" / "do 1, 3" /
                   "only urgent" / "cancel").
                 • canvas-execute reads plan.json + your approval,
                   dispatches approved items in sequence:
                     ├─ canvas-ics33
                     ├─ canvas-reading-annotation  ┐
                     ├─ canvas-essay               ┘ src/ac_eng_router.py
                     ├─ canvas-zybooks               picks one of the two
                     ├─ canvas-inside
                     ├─ canvas-generic              ← runtime-designed fallback
                     └─ canvas-skip
                 • Each per-course skill writes its result to
                   runs/<today>/<assignment>/result.json.
                 • When all are done: REPORT.md is written, drafts are
                   mirrored to final_drafts/ for human review.

Two non-obvious things about this flow:

  1. canvas-bootstrap is single-cluster on purpose. A typical student has 3-4 trackable courses. Configuring all four in one session means a wall of text you can't reason about. Configuring one, walking away, coming back tomorrow for the next gives you a tangible deliverable per session and lets you reuse what you learned from the first cluster when you do the next.

  2. The first time you run a per-course skill, it is a co-authoring session with you, not a one-shot. canvas-bootstrap's overlay v1 is the skill's best guess from reading the cluster. v2 is what you actually want, and it only exists after you've reviewed a real draft and your feedback has been categorized. Plan for ~30 minutes per cluster for the first-run loop. Subsequent runs of the same skill are non-interactive.


Setup walkthrough

First time on this machine (you're unconfigured)

  1. Clone this repo somewhere local.
  2. Open the folder in Claude Code.
  3. Say scan canvas (or anything similar — "check my canvas", "do my homework", /canvas-scan).

Claude Code dispatches the canvas-scan skill. It sees no .env and auto-dispatches canvas-setup:

  • Asks for your Canvas instance URL (e.g. canvas.<your-school>.edu).
  • Installs Playwright + Chromium silently (~150 MB, one-time).
  • Opens a browser. You log in to Canvas with your school SSO once. The skill captures the session cookie and stores it locally.
  • Lists your active courses. You pick which ones to track.

canvas-setup then hands off to canvas-bootstrap, which starts configuring your first course. You pick a cluster from the recommendation list. The skill investigates it silently, asks you ~5 questions in one batch, writes the overlay, and either (a) runs a calibration loop on a pending real assignment if one exists, or (b) defers calibration to your next scan.

Subsequent sessions

You say scan canvas. If courses.yaml.routes has at least one entry but not all your courses, you get the normal scan PLUS a one-line reminder that other courses are still unconfigured. You re-trigger canvas-bootstrap whenever you want to configure another.

Once all your courses are configured, scan canvas is the only command you ever need:

scan canvas
   → review plan
   → "approve all" / "approve 1, 2" / "only urgent" / "cancel"
   → wait for drafts
   → read REPORT.md, eyeball final_drafts/, upload manually (or rely on
     standing auto-submit authorization for skills you've granted it to)

You answer ~3 questions per cluster and log into Canvas once per session-cookie-expiry. Everything else happens silently through Claude Code's tooling.

Prefer to set up by hand? See SETUP.md.


The 10 skills

Canvas Pilot ships ten skills under .claude/skills/. Five are framework-level (you use them as-is on any course). Four are per-course skeletons that load a local overlay file describing your specific school and instructor. One additional skill (canvas-essay) is part of the writing-course handler. One catch-all (canvas-generic) handles assignments that don't fit any of the specific skills — it discovers the spec, designs a pipeline, and writes a draft at runtime, without an overlay.

Framework skills

Skill What it does
canvas-setup First-run install: ask for Canvas URL, silent dependency install, pop browser for one login, list courses, save selection. Auto-dispatched by canvas-scan when .env is missing.
canvas-bootstrap Surveys a new course's recurring patterns and drafts a per-course overlay. Runs one cluster per invocation, scope-first. Includes the first-run calibration loop that turns the student's feedback on a real draft into overlay v2.
canvas-scan Reads courses.yaml, queries Canvas for assignments in the pending window, writes plan.json, stops. Also acts as the entry-point router that dispatches canvas-setup or canvas-bootstrap when the repo is not yet fully configured.
canvas-execute Reads the user's approval reply against plan.json, dispatches approved items to their per-course skill, gathers results, writes REPORT.md, mirrors drafts to final_drafts/.
canvas-skip Punts an assignment to manual handling. Logs to the daily todo.md, returns skipped status. Used for Lockdown Browser quizzes and any other intrinsic can't-do.

Per-course skeletons (framework + local overlay)

Each per-course skeleton is a generic framework for a class of course. The school- and instructor-specific behavior lives in a local overlay file at _private/canvas-<name>-app.md, which is gitignored and never leaves your machine. If the overlay does not exist, the skeleton stops and tells you to author one (or invoke canvas-bootstrap to draft it interactively).

canvas-ics33 — code course

Generic handler for programming assignments where the spec lives outside Canvas, starter code is downloaded, code is written with test coverage, and the bundled artifact is submitted to Canvas.

fetch-spec → fetch-references → download-scaffold → constraints-checklist →
test-first implement → process_humanize (process-graded courses only) →
audit (identifier-grounding + numeric-constraint + coverage check) →
bundle + re-clone verify → submit (if authorized)

Language-neutral — the overlay specifies which language's test runner, build command, and submission format. The same 9-stage prose drives a Python+unittest+git-bundle course or a Java+gradle+jar course; only the overlay command strings differ.

Overlay specifies: course ID, language + test runner + coverage command + submission format, instructor's spec URL pattern, scaffold distribution mechanism (git bundle / zip / GitHub Classroom / inline / none), reference-fetch regex patterns, process_humanize knobs (spread days, commit-message register, few-shot examples), auto-submit scope, headless cron env var name.

canvas-reading-annotation — writing course (PDF markup)

Generic handler for reading-annotation homework — color-coded highlights, margin notes, filled answer blanks per the instructor's rubric.

classify (reading_annotation / video_exercises / in_class_skip / ...) →
locate_reading (overlay's reading_files mapping) →
extract_text_and_blanks (PyMuPDF underscore-group find) →
annotate_pdf (color highlights + margin notes in place) →
fill_answer_blanks (typed answers at ≥90% line width, in target voice) →
verify (6-check gate: line fill, note density, color family, page count,
        no overlap, no sticky icons) → submit (if authorized)

Overlay specifies: course IDs, homework module ID, reading-file mapping, color rubric (vocab family vs content family), voice register (free-form description of student voice), instructor rubric verbatim, video→worksheet pairings.

canvas-essay — writing course (long-form essay)

Generic handler for academic-writing essays — autoethnography, reflection papers, critical analysis, research essays.

load_persona (MBTI-derived tone vector) →
parse_spec (walk attached PDFs / module pages / external links) →
load_sample_essays (few-shot anchor) →
generate (outline → body → revise) →
figure_captions + works_cited (3-layer cascade) →
verify (word count ≥ spec minimum, citation count, figure caption count) →
output (.docx / .pdf per overlay) → submit (if authorized)

src/ac_eng_router.py routes each writing-course assignment to either canvas-reading-annotation (short / annotation-shaped) or canvas-essay (long-form) via a deterministic 6-layer cascade. You do not pick.

Overlay specifies: essay name trigger patterns, voice register specifics, sample essay path, citation style (MLA / APA / Chicago), figure caption format, persona-derivation template.

canvas-zybooks — math / discrete course backed by a zyBook

Generic handler for assignments where the Canvas description is a table of exercise references and the deliverable is solved problems rendered as a PDF.

classify (written HW / take-home exam / reading completion)  →
fetch-spec (Canvas description table OR attached PDF)  →
fetch-exercises (zyBook API)  →  solve  →  render-LaTeX-PDF  →
verify (subquestion count, no placeholder leaks)  →
draft-only (GradeScope upload is manual)

Overlay specifies: Canvas course ID, zyBook course code, JWT auth path, course-context primer for the solver, instructor-specific notation rules (e.g. "name each law you apply, one law per step"), assignment naming convention.

canvas-inside — online Canvas quiz

Generic handler for open quizzes (MCQ, multi-answer, T/F, matching, short-answer, essay) that the student has authorized for auto-take.

classify (full quiz vs single-question-video-quiz vs unknown) →
4 safety gates (autorun / human-hours / per-cron rate / whitelist) →
reading discovery (4-layer hunt: module → files+syllabus → PDF → web) →
study_notes.md → 4-agent arbitration (notes-first / grep-first /
framework-aware / contrarian) → paced-submit (humanness: timing,
blur/focus, sequence non-linearity, optional strategic miss) →
complete → score-check → retake-with-feedback (Layer 2 gated)

Submission-pattern human-ness is implemented as named Python helpers called by the SKILL.md (src/quiz_pacing.py, src/quiz_focus_events.py, src/quiz_strategic_miss.py), not as configurable overlay knobs. Three independent enforcement layers prevent bypass of the 4-agent arbitration (canvas_client guard, Stop hook, result.json schema validator).

Overlay specifies: whitelisted course IDs, instructor framework primer (prose), expected canonical knowledge, auto-take scope, human-hours window, max-per-run, strategic-miss default, target-score band, retake pass-band.

canvas-generic — runtime-designed fallback

Catch-all for assignments that don't fit any of the 5 specific skills. Triggered when canvas-bootstrap marks a cluster as ⚠ unclear / ⚠ inline-only-or-unknown / ⚠ quiz-id-missing and routes it here instead of forcing a wrong-shape specific skill.

Unlike the specific skills, canvas-generic reads no overlay. It performs full per-assignment runtime investigation, designs a pipeline on the fly, and produces a draft + verification log.

fetch-context (description + front_page + modules + syllabus + URLs) →
find-rubric (Canvas rubric API + spec grep + module grep + URL fetch) →
locate-inputs (download every referenced file to references/) →
Sub-agent A review (investigation completeness; recovery loop) →
classify-output (doc_prose / pdf_annotated / pdf_typed / code /
                 form_answers / mixed) →
design-pipeline (per-mode stage template, rubric-adjusted) →
generate (calls canvas-humanizer for prose; PyMuPDF for pdf_annotated) →
Sub-agent B verification checklist design (from rubric) →
verify (measured PASS/FAIL/SKIP per check) →
Sub-agent C verification coverage review (catches coverage gaps /
                                          false-pass risks) →
export → draft_ready (never auto-submits)

Token cost: ~3× a specific-skill dispatch on a comparable assignment (three sub-agent reviews + investigation phase). Acceptable for low-frequency clusters; for clusters that fire weekly, the signal is to graduate to a specific skill — see the skill's §11 When to graduate section.

canvas-generic is opt-in by bootstrap routing, not by user request. If you want one of your courses' weekly assignments handled this way, re-run bootstrap and accept the canvas-generic recommendation for the relevant cluster.


The core rule: assignment.description is rarely the real spec

assignment.name and assignment.description are routing hints, not specs. For most STEM courses they're empty strings. For most non-STEM courses they're a paragraph that doesn't tell you what to actually produce. The real spec usually lives somewhere else:

  • An external instructor website linked from the course front page.
  • A reading PDF in a course Files folder.
  • A wiki page in modules.
  • A textbook chapter referenced obliquely.
  • An attached PDF on the assignment itself.

Before any per-course skill processes an assignment, it should:

  1. Read assignment.description — but treat it as a hint, not the spec.
  2. Pull cv.get_front_page(course_id) to find external pointers.
  3. Pull cv.list_modules(course_id) to find reading material / wiki pages.
  4. Walk linked references (other Canvas pages, external URLs, attached files).

Per-course skills document where the spec lives for their specific course inside their local application overlay (see below).

We have shipped this framework into production and tripped on this rule twice on two consecutive nights:

  • Night 1: Every code-course assignment had description="". The scanner marked them unsupported. Post-mortem: the front-page body carried the external instructor URL all along.
  • Night 2: A zyBook-backed homework was over-rendered with 162 student_view: false exercises because the script trusted the zyBook API's "suggested practice" flag. Post-mortem: the instructor had specified ~22 exercises in the Canvas description's second column; the "suggested practice" first column wasn't supposed to be done. Different signal, different source of truth.

In both cases the failure mode was "I trusted what looked like the spec and didn't walk the references". Don't do that.


Local application overlays

The five per-course skeletons (canvas-ics33, canvas-reading-annotation, canvas-essay, canvas-zybooks, canvas-inside) describe generic patterns for a class of course. The actual handling logic for your specific school and instructor lives in a local application overlay at _private/canvas-<name>-app.md.

The overlay is a free-form Markdown file that the skeleton loads as its first step. It specifies things like:

  • Course IDs and routing details.
  • The instructor's external site URL pattern.
  • Reading-PDF filenames, color rubrics, voice register.
  • Auto-submit authorization scope.
  • Whatever else makes "this skill handles a generic code course" become "this skill handles MY school's code course taught by Dr. So-and-so".

_private/ is gitignored — the overlay never leaves your machine. If you fork this repo, you author your own overlays (or have Claude Code author them via the canvas-bootstrap skill).

Overlays are also where canvas-bootstrap's first-run calibration loop writes its findings. Overlay v1 is the skill's best initial guess. Overlay v2 is what you actually want, derived from your feedback on a real draft. The overlay is the durable artifact; the calibration session is throwaway.


Agent stops at can't-do, not shouldn't-do

Canvas Pilot's per-course skills work for the student, not for the instructor. A skill never refuses to do an assignment because the instructor wrote a behavioral rule like "don't use AI", "don't collaborate", "don't paraphrase". Whether running the framework on a given assignment is consistent with the student's school's policies is the student's decision, not the framework's.

A skill stops only when it physically can't proceed. Four intrinsic can't-do categories:

  1. Physically impossible. In-person attendance, paper submission, live signatures, Lockdown Browser quizzes, Respondus proctoring.
  2. Identity-bound. Academic honesty contract signing, ID verification, in-person peer review, oral defense.
  3. Input missing and unobtainable. Spec cannot be found anywhere; a referenced file cannot be fetched and the student can't supply it.
  4. Verification failure. The skill's verification checklist fails after retries.

For resources that are physically out of reach but might be obtainable with the student's help — a video link, a password-protected download, an external-site login — the skill soft-stops: it offers to take a URL or credential from the student and resumes if given, skips that step and continues with what it can do otherwise.

Where a skill uses a voice register (e.g. "writes like a B1-B2 international student"), the documented reason is student-identity alignment: the student picks a register that matches who they actually are. The register is part of the student's voice, not a posture the skill adopts for the assignment.


What Canvas Pilot can do

  • Scan all configured courses for pending assignments within a configurable window.
  • Bucket assignments by urgency and propose a per-item skill.
  • Pause and wait for your approval before any work happens. The approval is a filesystem boundary, not a prose instruction.
  • Run per-course skills sequentially. Each produces a draft under runs/<today>/<assignment>/draft/.
  • Verify drafts against numeric constraints in the spec (sentence counts, page counts, function counts) before optionally auto-submitting.
  • Write a daily REPORT.md with an urgent banner, status per item, and a next-step recommendation.
  • Mirror drafts to a final_drafts/ folder for human review.
  • Email reminders for assignments due today / tomorrow (separate skill).

What Canvas Pilot does not do

  • Read or write content on your behalf without your approval at the plan-review step.
  • Auto-submit anything unless the per-course overlay explicitly grants standing authorization for that assignment type, and the pre-submit verification gate passes.
  • Bypass your instructor's academic-honesty policy. The framework's design and default behavior put you in control of submission; your overlay decisions are your responsibility.
  • Store assignments, drafts, or credentials on any remote service. Everything stays in runs/, _private/, sources/, and .cookies/ on your machine.
  • Reuse mocks where real Canvas behavior matters. Integration touches the real API or a recorded fixture, not a hand-rolled mock.

Repository layout

canvas-pilot/
├── .claude/
│   ├── settings.json           # hook + permission config
│   ├── hooks/                  # session hooks (schema, approval, etc.)
│   └── skills/
│       ├── canvas-setup/       # first-run install + course selection
│       ├── canvas-bootstrap/   # per-course overlay drafting
│       ├── canvas-scan/        # scan → plan.json
│       ├── canvas-execute/     # dispatch approved items
│       ├── canvas-skip/        # punt to manual
│       ├── canvas-ics33/       # code-course skeleton
│       ├── canvas-reading-annotation/  # writing-course (annotation) skeleton
│       ├── canvas-essay/       # writing-course (long-form) skeleton
│       ├── canvas-zybooks/     # math/discrete skeleton
│       ├── canvas-inside/        # online-quiz skeleton
│       └── canvas-generic/     # runtime-designed fallback (no overlay)
├── .agents/skills/             # Codex sidecar mirrors (optional)
├── src/                        # framework Python (Canvas client, etc.)
├── scripts/                    # cron-able helpers (due-date alert, etc.)
├── _private/                   # gitignored: SECRETS, courses.yaml,
│                               #             overlays, decision logs
├── sources/                    # gitignored: your assignment input materials
├── runs/                       # gitignored: per-day work output
├── docs/                       # internal design docs (NORTH_STAR, etc.)
├── tests/
├── CLAUDE.md                   # loaded by Claude Code on every session
├── AGENTS.md                   # Codex sidecar entry
├── SETUP.md                    # manual setup walkthrough
└── README.md                   # this file

Design principles

These do not change between versions. Everything in the roadmap respects these principles.

Skills are pipelines, not monoliths

A real assignment isn't "one prompt produces one output". A real assignment has stages with distinct skill requirements. Writing a 5-page research paper is research → outline → draft → humanize → verify, not one function. Each stage is independently tunable, replaceable, and inspectable. Personal design files customize specific stages, not the whole skill.

The approval gate is a filesystem boundary

canvas-scan writes plan.json and stops. canvas-execute reads it after the user replies with approval. Two skills, two Skill-tool dispatches — the user can interrupt between them. Prose instructions cannot enforce this; filesystem state can.

Drafts by default, submission only with standing authorization

Default behavior: produce a draft, you upload manually. Auto-submit is per-skill, per-overlay, gated by a verification log that has to pass before any upload call. Auto-submit is never the silent default.

Scope-first onboarding

canvas-bootstrap configures one course (or one cluster within a course) per invocation — a tangible deliverable every time the student runs it, rather than batch-processing every course up front and presenting a wall of text.

Output that looks human, by design

For assignments where authorship signals matter (writing courses, extended responses), the pipeline includes a dedicated humanize stage whose only job is to take the draft and produce output that survives current AI-content detectors. This is a first-class stage with its own verification.

For assignments where authorship signals don't matter (code, math solutions, MCQ answers), the equivalent concern is submission-pattern human-ness — pacing, timing, focus/blur events — handled at the submission stage, not the content stage.

One assignment = one work directory = one result.json

The Stop hook refuses to release the session until every dispatched assignment has produced a valid result. No silent partial completion.

No mocking on integration boundaries

Tests against Canvas use recorded fixtures or a sandbox course; mocks don't catch drift between the spec and the real API.


Git hygiene and critical do-nots

.gitignore covers .env, runs/, SECRETS.md, courses.yaml, _private/, sources/, .cookies/, __pycache__/. Trust it.

  • Never use git add -f, git add -A, or git add . — they bypass or blanket-add. Use git add <specific-paths> only.
  • Never edit .gitignore to remove a safety entry, even "just for testing".
  • Before any commit, mentally check the staged file list contains only generic framework code. If unsure, run git diff --cached.

Other do-nots:

  • Do NOT dispatch per-course skills from canvas-scan. Scan produces a plan and stops; canvas-execute dispatches after the user approves. The two-skill split makes the approval gate a filesystem boundary instead of a prose instruction.
  • Do NOT hardcode course IDs, file IDs, or instructor info in any tracked file. They go in _private/canvas-<name>-app.md overlays or in your local gitignored SECRETS.md / courses.yaml.
  • Do NOT leave the .scan_in_progress marker behind. If a run crashes, clean it up before stopping; the Stop hook will refuse to release until every assignment has a valid result.json.

What is intentionally NOT in scope

  • Replacing Claude Code. This is a Claude Code project, not a standalone CLI. The product depends on Claude Code's skill dispatch, tool use, and approval semantics. Trying to factor out Claude Code produces a worse product and an unmaintainable framework.
  • Supporting LMSes other than Canvas. Each LMS has enough API surface area that supporting two means supporting two frameworks. Canvas is broad enough; v1.0 is "good at Canvas", not "decent at three LMSes".
  • A multi-tenant SaaS. Canvas Pilot is a per-user local install. Multi-tenant introduces auth, payment, and abuse vectors we don't want to absorb. If you want this as a service, fork it and host it for yourself.
  • Hand-rolled detector-bypass telemetry. The humanize stage is a stage in a pipeline, not a research program. We ship what works against current detectors and update when they update. We do not publish "how to beat detector X" guides; that work lives in the stage itself.
  • Academic-integrity arbitration. Whether running this on a given assignment is appropriate is a decision the operator has to make in light of their school's policies. The framework is opinion-neutral on that question and ships no policy-screening logic.

Pointers

  • Per-user / per-quarter data: SECRETS.md (gitignored).
  • Course routing: courses.yaml (gitignored).
  • Local application overlays: _private/canvas-<name>-app.md (gitignored).
  • Student-supplied inputs: sources/ (gitignored except README.md).
  • Latest run report: runs/<today>/REPORT.md.
  • Framework skills: .claude/skills/canvas-{setup,scan,execute,skip,bootstrap}/SKILL.md.
  • Per-course skill skeletons: .claude/skills/canvas-{ics33,reading-annotation,essay,zybooks,quiz}/SKILL.md.
  • Runtime-design fallback: .claude/skills/canvas-generic/SKILL.md.
  • Framework auth: src/canvas_client.py, src/canvas_login.py.
  • Manual setup walkthrough: SETUP.md.
  • Internal design doc: docs/NORTH_STAR.md.

Adding a new course mid-term? Tell Claude Code design a skill — this triggers canvas-bootstrap, which surveys recurring patterns in the new course and produces an overlay + courses.yaml route entry.


License

Copyright (C) 2026 X_isdoingreat

This framework is free software, licensed under the GNU Affero General Public License, version 3 or later (AGPL-3.0-or-later). See LICENSE for the full text. You may use, study, modify, and redistribute it under those terms; in particular, the AGPL's §13 means that if you run a modified version as a network-accessible service, you must offer those users the corresponding source.

You're welcome to fork it and adapt it for your own coursework. The framework ships no school-specific or instructor-specific solving logic — that lives in your local, gitignored overlay files. The AGPL covers the framework code; your private overlays are yours, and what you do with them is on you.

The framework does not endorse or facilitate academic dishonesty. Whether a given automation is appropriate for a given course is a decision the person running this software has to make, in light of their own school's policies.


Contact

Maintained by X_isdoingreat. Reach me on X at @X_isdoingreat or by email at X_isdoingreat@proton.me.

About

An agent lives in Canvas that does all of your homework

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages