[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-82992":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":15,"stars7d":16,"stars30d":17,"stars90d":15,"forks30d":15,"starsTrendScore":15,"compositeScore":18,"rankGlobal":10,"rankLanguage":10,"license":19,"archived":20,"fork":20,"defaultBranch":21,"hasWiki":22,"hasPages":20,"topics":23,"createdAt":10,"pushedAt":10,"updatedAt":29,"readmeContent":30,"aiSummary":31,"trendingCount":15,"starSnapshotCount":15,"syncStatus":32,"lastSyncTime":33,"discoverSource":34},82992,"Canvas_pilot_public","X-isdoingreat\u002FCanvas_pilot_public","X-isdoingreat","An agent lives in Canvas that does all of your homework","https:\u002F\u002Fx.com\u002FX_isdoingreat",null,"Python",80,9,8,0,17,25,54,"GNU Affero General Public License v3.0",false,"main",true,[24,25,26,27,28],"agentic-ai","automation","canvas","canvas-api","homework-assignments","2026-06-12 04:01:39","# Canvas Pilot\n\n[![License: AGPL v3](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FLicense-AGPL%20v3-blue.svg)](.\u002FLICENSE)\n[![Python 3.11+](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fpython-3.11%2B-blue.svg)](https:\u002F\u002Fwww.python.org\u002Fdownloads\u002F)\n\nA [Claude Code](https:\u002F\u002Fclaude.com\u002Fclaude-code) project that scans your school's\nCanvas LMS for pending assignments, plans the work, and dispatches each item to\na course-specific skill that produces a draft (or, where you have explicitly\nauthorized it, submits on your behalf).\n\nYou stay in the loop on the two decisions that matter — what to do and what to\nship. The framework handles the rest.\n\n---\n\n## What it actually does\n\nA typical interaction once you're fully configured:\n\n```\nYou (in Claude Code, this directory):  scan canvas\n\nCanvas Pilot:\n    🔥 URGENT (next 72h)\n    | # | course        | assignment       | due           | proposed skill |\n    | 1 | Code Course A | Set 3 Problem 1  | 4\u002F25 23:59    | canvas-ics33   |\n    | 2 | Writing Course| Tue Wk5 HW Scan  | 4\u002F28 12:30    | canvas-reading-annotation  |\n    ⚠️  SOON (3-7d)\n    | 3 | Quiz Course   | Section 5        | 4\u002F27 23:59    | canvas-inside    |\n\n    Reply: \"approve all\" \u002F \"approve 1, 2\" \u002F \"only urgent\" \u002F \"cancel\"\n\nYou:                                    approve all\n\nCanvas Pilot:\n    [dispatches each item sequentially, runs the per-course skill,\n     produces a draft under runs\u002F\u003Ctoday>\u002F\u003Cassignment>\u002Fdraft\u002F,\n     and writes a status to result.json]\n\n    Done. REPORT.md written at runs\u002F\u003Ctoday>\u002FREPORT.md.\n    Drafts mirrored to final_drafts\u002F for review.\n```\n\nYou review the drafts. You upload manually — unless you have given a specific\nper-course skill standing authorization to auto-submit, in which case Canvas\nPilot uploads after a verification gate passes.\n\n---\n\n## Who this is for\n\n- Students whose school uses Canvas LMS.\n- Whose coursework includes a high share of repeating-structure assignments\n  (weekly problem sets, weekly readings, weekly quizzes).\n- Who want an AI to handle the boring orchestration (scan, dispatch, draft) but\n  keep the human firmly in the loop for review and submission.\n- Who already use Claude Code as their daily editor.\n\nThis is **not** a \"submit my homework for me\" tool. The default behavior is\n*produce drafts, you submit*. Auto-submit is opt-in per skill, per assignment\ntype, with a verification gate in front.\n\n---\n\n## The product flow\n\nThere is **one entry point**: you say `scan canvas` in a Claude Code session in\nthis directory. Everything else is a branch that `canvas-scan` decides based on\nfilesystem state.\n\n```\nYou: \"scan canvas\"\n  │\n  └─→ canvas-scan §0 self-check\n       │\n       ├─ .env missing \u002F CANVAS_BASE empty\n       │    │\n       │    └─→ canvas-setup\n       │         1. Ask for your school's Canvas URL\n       │         2. Silent install of Playwright + Chromium\n       │         3. Pop browser, you log in once\n       │         4. List your active courses, ask which to track\n       │         └─→ when done, hands off to canvas-bootstrap (no exit)\n       │\n       ├─ .env OK but courses.yaml.routes is empty\n       │    │\n       │    └─→ canvas-bootstrap\n       │         • Configures ONE course (cluster) per invocation.\n       │           Not batch — you walk away after each one and\n       │           re-trigger when you want the next.\n       │         • Recommendation order is a hard rule:\n       │             1. 🟢 Non-LDB quiz   ← agent ships end-to-end with\n       │                                    zero human-side config\n       │             2. 🟢 Code course    ← verification is mechanical\n       │                                    (test runner \u002F compile \u002F lint)\n       │             3. 🟡 Writing        ← rubric is bespoke; needs you\n       │                                    to author voice + samples\n       │             4. ⚪ Unclear → route to canvas-generic\n       │                                  (runtime-designed fallback, no\n       │                                   overlay; investigates + designs\n       │                                   pipeline per-assignment)\n       │             5. 🔴 LDB-locked → route to canvas-skip\n       │                                  (Lockdown Browser is\n       │                                   intrinsic can't-do)\n       │         • For categories 1-3 (specific-skill clusters):\n       │           silent deep-investigate\n       │           → spawn 3 sub-agents in parallel (rubric coverage \u002F\n       │             verification checklist \u002F feasibility simulator)\n       │           → single batched ask to you\n       │           → write overlay v1 at _private\u002Fcanvas-\u003Cname>-app.md\n       │           (Category 4 skips this — no overlay needed for canvas-generic)\n       │         • If a pending real assignment exists for the cluster,\n       │           run the FIRST-RUN CALIBRATION LOOP:\n       │             - dispatch the per-course skill, produce one draft\n       │             - you review the draft and give feedback\n       │             - Sub-agent D categorizes each piece of feedback:\n       │                  recurring_pattern → write back into overlay v2\n       │                  one_off           → fix this draft only\n       │                  workflow_change   → write back into overlay v2\n       │             - you confirm the categorization\n       │             - first_run_calibration_done = true\n       │         • Returns to you. Re-trigger scan to configure the\n       │           next cluster.\n       │\n       └─ .env OK + courses.yaml.routes non-empty\n            │\n            └─→ Normal scan\n                 • List pending → write plan.json → STOP.\n                 • You reply with approval (\"approve all\" \u002F \"do 1, 3\" \u002F\n                   \"only urgent\" \u002F \"cancel\").\n                 • canvas-execute reads plan.json + your approval,\n                   dispatches approved items in sequence:\n                     ├─ canvas-ics33\n                     ├─ canvas-reading-annotation  ┐\n                     ├─ canvas-essay               ┘ src\u002Fac_eng_router.py\n                     ├─ canvas-zybooks               picks one of the two\n                     ├─ canvas-inside\n                     ├─ canvas-generic              ← runtime-designed fallback\n                     └─ canvas-skip\n                 • Each per-course skill writes its result to\n                   runs\u002F\u003Ctoday>\u002F\u003Cassignment>\u002Fresult.json.\n                 • When all are done: REPORT.md is written, drafts are\n                   mirrored to final_drafts\u002F for human review.\n```\n\nTwo non-obvious things about this flow:\n\n1. **`canvas-bootstrap` is single-cluster on purpose.** A typical student has\n   3-4 trackable courses. Configuring all four in one session means a wall of\n   text you can't reason about. Configuring one, walking away, coming back\n   tomorrow for the next gives you a tangible deliverable per session and lets\n   you reuse what you learned from the first cluster when you do the next.\n\n2. **The first time you run a per-course skill, it is a co-authoring\n   session with you, not a one-shot.** `canvas-bootstrap`'s overlay v1 is the\n   skill's best guess from reading the cluster. v2 is what you actually want,\n   and it only exists after you've reviewed a real draft and your feedback has\n   been categorized. Plan for ~30 minutes per cluster for the first-run loop.\n   Subsequent runs of the same skill are non-interactive.\n\n---\n\n## Setup walkthrough\n\n### First time on this machine (you're unconfigured)\n\n1. Clone this repo somewhere local.\n2. Open the folder in Claude Code.\n3. Say `scan canvas` (or anything similar — \"check my canvas\", \"do my\n   homework\", `\u002Fcanvas-scan`).\n\nClaude Code dispatches the `canvas-scan` skill. It sees no `.env` and\nauto-dispatches `canvas-setup`:\n\n- Asks for your Canvas instance URL (e.g. `canvas.\u003Cyour-school>.edu`).\n- Installs Playwright + Chromium silently (~150 MB, one-time).\n- Opens a browser. You log in to Canvas with your school SSO once.\n  The skill captures the session cookie and stores it locally.\n- Lists your active courses. You pick which ones to track.\n\n`canvas-setup` then hands off to `canvas-bootstrap`, which starts\nconfiguring your **first** course. You pick a cluster from the\nrecommendation list. The skill investigates it silently, asks you ~5\nquestions in one batch, writes the overlay, and either (a) runs a\ncalibration loop on a pending real assignment if one exists, or (b)\ndefers calibration to your next scan.\n\n### Subsequent sessions\n\nYou say `scan canvas`. If `courses.yaml.routes` has at least one entry\nbut not all your courses, you get the normal scan PLUS a one-line\nreminder that other courses are still unconfigured. You re-trigger\n`canvas-bootstrap` whenever you want to configure another.\n\nOnce all your courses are configured, `scan canvas` is the only command\nyou ever need:\n\n```\nscan canvas\n   → review plan\n   → \"approve all\" \u002F \"approve 1, 2\" \u002F \"only urgent\" \u002F \"cancel\"\n   → wait for drafts\n   → read REPORT.md, eyeball final_drafts\u002F, upload manually (or rely on\n     standing auto-submit authorization for skills you've granted it to)\n```\n\nYou answer ~3 questions per cluster and log into Canvas once per\nsession-cookie-expiry. Everything else happens silently through Claude\nCode's tooling.\n\nPrefer to set up by hand? See [SETUP.md](.\u002FSETUP.md).\n\n---\n\n## The 10 skills\n\nCanvas Pilot ships ten skills under `.claude\u002Fskills\u002F`. Five are\nframework-level (you use them as-is on any course). Four are per-course\nskeletons that load a local overlay file describing your specific school\nand instructor. One additional skill (`canvas-essay`) is part of the\nwriting-course handler. One catch-all (`canvas-generic`) handles\nassignments that don't fit any of the specific skills — it discovers the\nspec, designs a pipeline, and writes a draft at runtime, without an\noverlay.\n\n### Framework skills\n\n| Skill | What it does |\n|---|---|\n| `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. |\n| `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. |\n| `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. |\n| `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\u002F`. |\n| `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. |\n\n### Per-course skeletons (framework + local overlay)\n\nEach per-course skeleton is a generic framework for a class of course.\nThe school- and instructor-specific behavior lives in a local overlay\nfile at `_private\u002Fcanvas-\u003Cname>-app.md`, which is gitignored and never\nleaves your machine. If the overlay does not exist, the skeleton stops\nand tells you to author one (or invoke `canvas-bootstrap` to draft it\ninteractively).\n\n#### `canvas-ics33` — code course\n\nGeneric handler for programming assignments where the spec lives outside\nCanvas, starter code is downloaded, code is written with test coverage,\nand the bundled artifact is submitted to Canvas.\n\n```\nfetch-spec → fetch-references → download-scaffold → constraints-checklist →\ntest-first implement → process_humanize (process-graded courses only) →\naudit (identifier-grounding + numeric-constraint + coverage check) →\nbundle + re-clone verify → submit (if authorized)\n```\n\nLanguage-neutral — the overlay specifies which language's test runner,\nbuild command, and submission format. The same 9-stage prose drives a\nPython+unittest+git-bundle course or a Java+gradle+jar course; only the\noverlay command strings differ.\n\nOverlay specifies: course ID, language + test runner + coverage command +\nsubmission format, instructor's spec URL pattern, scaffold distribution\nmechanism (git bundle \u002F zip \u002F GitHub Classroom \u002F inline \u002F none),\nreference-fetch regex patterns, `process_humanize` knobs (spread days,\ncommit-message register, few-shot examples), auto-submit scope, headless\ncron env var name.\n\n#### `canvas-reading-annotation` — writing course (PDF markup)\n\nGeneric handler for reading-annotation homework — color-coded highlights,\nmargin notes, filled answer blanks per the instructor's rubric.\n\n```\nclassify (reading_annotation \u002F video_exercises \u002F in_class_skip \u002F ...) →\nlocate_reading (overlay's reading_files mapping) →\nextract_text_and_blanks (PyMuPDF underscore-group find) →\nannotate_pdf (color highlights + margin notes in place) →\nfill_answer_blanks (typed answers at ≥90% line width, in target voice) →\nverify (6-check gate: line fill, note density, color family, page count,\n        no overlap, no sticky icons) → submit (if authorized)\n```\n\nOverlay specifies: course IDs, homework module ID, reading-file mapping,\ncolor rubric (vocab family vs content family), voice register\n(free-form description of student voice), instructor rubric verbatim,\nvideo→worksheet pairings.\n\n#### `canvas-essay` — writing course (long-form essay)\n\nGeneric handler for academic-writing essays — autoethnography, reflection\npapers, critical analysis, research essays.\n\n```\nload_persona (MBTI-derived tone vector) →\nparse_spec (walk attached PDFs \u002F module pages \u002F external links) →\nload_sample_essays (few-shot anchor) →\ngenerate (outline → body → revise) →\nfigure_captions + works_cited (3-layer cascade) →\nverify (word count ≥ spec minimum, citation count, figure caption count) →\noutput (.docx \u002F .pdf per overlay) → submit (if authorized)\n```\n\n`src\u002Fac_eng_router.py` routes each writing-course assignment to either\n`canvas-reading-annotation` (short \u002F annotation-shaped) or `canvas-essay`\n(long-form) via a deterministic 6-layer cascade. You do not pick.\n\nOverlay specifies: essay name trigger patterns, voice register specifics,\nsample essay path, citation style (MLA \u002F APA \u002F Chicago), figure caption\nformat, persona-derivation template.\n\n#### `canvas-zybooks` — math \u002F discrete course backed by a zyBook\n\nGeneric handler for assignments where the Canvas description is a table\nof exercise references and the deliverable is solved problems rendered\nas a PDF.\n\n```\nclassify (written HW \u002F take-home exam \u002F reading completion)  →\nfetch-spec (Canvas description table OR attached PDF)  →\nfetch-exercises (zyBook API)  →  solve  →  render-LaTeX-PDF  →\nverify (subquestion count, no placeholder leaks)  →\ndraft-only (GradeScope upload is manual)\n```\n\nOverlay specifies: Canvas course ID, zyBook course code, JWT auth path,\ncourse-context primer for the solver, instructor-specific notation rules\n(e.g. \"name each law you apply, one law per step\"), assignment naming\nconvention.\n\n#### `canvas-inside` — online Canvas quiz\n\nGeneric handler for open quizzes (MCQ, multi-answer, T\u002FF, matching,\nshort-answer, essay) that the student has authorized for auto-take.\n\n```\nclassify (full quiz vs single-question-video-quiz vs unknown) →\n4 safety gates (autorun \u002F human-hours \u002F per-cron rate \u002F whitelist) →\nreading discovery (4-layer hunt: module → files+syllabus → PDF → web) →\nstudy_notes.md → 4-agent arbitration (notes-first \u002F grep-first \u002F\nframework-aware \u002F contrarian) → paced-submit (humanness: timing,\nblur\u002Ffocus, sequence non-linearity, optional strategic miss) →\ncomplete → score-check → retake-with-feedback (Layer 2 gated)\n```\n\nSubmission-pattern human-ness is implemented as named Python helpers\ncalled by the SKILL.md (`src\u002Fquiz_pacing.py`,\n`src\u002Fquiz_focus_events.py`, `src\u002Fquiz_strategic_miss.py`), not as\nconfigurable overlay knobs. Three independent enforcement layers prevent\nbypass of the 4-agent arbitration (canvas_client guard, Stop hook,\nresult.json schema validator).\n\nOverlay specifies: whitelisted course IDs, instructor framework primer\n(prose), expected canonical knowledge, auto-take scope, human-hours\nwindow, max-per-run, strategic-miss default, target-score band, retake\npass-band.\n\n#### `canvas-generic` — runtime-designed fallback\n\nCatch-all for assignments that don't fit any of the 5 specific skills.\nTriggered when `canvas-bootstrap` marks a cluster as `⚠ unclear` \u002F\n`⚠ inline-only-or-unknown` \u002F `⚠ quiz-id-missing` and routes it here\ninstead of forcing a wrong-shape specific skill.\n\nUnlike the specific skills, `canvas-generic` reads **no overlay**. It\nperforms full per-assignment runtime investigation, designs a pipeline\non the fly, and produces a draft + verification log.\n\n```\nfetch-context (description + front_page + modules + syllabus + URLs) →\nfind-rubric (Canvas rubric API + spec grep + module grep + URL fetch) →\nlocate-inputs (download every referenced file to references\u002F) →\nSub-agent A review (investigation completeness; recovery loop) →\nclassify-output (doc_prose \u002F pdf_annotated \u002F pdf_typed \u002F code \u002F\n                 form_answers \u002F mixed) →\ndesign-pipeline (per-mode stage template, rubric-adjusted) →\ngenerate (calls canvas-humanizer for prose; PyMuPDF for pdf_annotated) →\nSub-agent B verification checklist design (from rubric) →\nverify (measured PASS\u002FFAIL\u002FSKIP per check) →\nSub-agent C verification coverage review (catches coverage gaps \u002F\n                                          false-pass risks) →\nexport → draft_ready (never auto-submits)\n```\n\nToken cost: ~3× a specific-skill dispatch on a comparable assignment\n(three sub-agent reviews + investigation phase). Acceptable for\nlow-frequency clusters; for clusters that fire weekly, the signal is to\ngraduate to a specific skill — see the skill's `§11 When to graduate`\nsection.\n\n`canvas-generic` is opt-in by bootstrap routing, not by user request.\nIf you want one of your courses' weekly assignments handled this way,\nre-run bootstrap and accept the `canvas-generic` recommendation for the\nrelevant cluster.\n\n---\n\n## The core rule: `assignment.description` is rarely the real spec\n\n`assignment.name` and `assignment.description` are routing hints, not\nspecs. For most STEM courses they're empty strings. For most non-STEM\ncourses they're a paragraph that doesn't tell you what to actually\nproduce. The real spec usually lives somewhere else:\n\n- An external instructor website linked from the course front page.\n- A reading PDF in a course Files folder.\n- A wiki page in modules.\n- A textbook chapter referenced obliquely.\n- An attached PDF on the assignment itself.\n\nBefore any per-course skill processes an assignment, it should:\n\n1. Read `assignment.description` — but treat it as a hint, not the spec.\n2. Pull `cv.get_front_page(course_id)` to find external pointers.\n3. Pull `cv.list_modules(course_id)` to find reading material \u002F wiki pages.\n4. Walk linked references (other Canvas pages, external URLs, attached files).\n\nPer-course skills document where the spec lives for their specific course\ninside their local application overlay (see below).\n\nWe have shipped this framework into production and tripped on this rule\ntwice on two consecutive nights:\n\n- **Night 1:** Every code-course assignment had `description=\"\"`. The\n  scanner marked them `unsupported`. Post-mortem: the front-page body\n  carried the external instructor URL all along.\n- **Night 2:** A zyBook-backed homework was over-rendered with 162\n  `student_view: false` exercises because the script trusted the\n  zyBook API's \"suggested practice\" flag. Post-mortem: the instructor\n  had specified ~22 exercises in the Canvas description's second\n  column; the \"suggested practice\" first column wasn't supposed to be\n  done. Different signal, different source of truth.\n\nIn both cases the failure mode was \"I trusted what looked like the\nspec and didn't walk the references\". Don't do that.\n\n---\n\n## Local application overlays\n\nThe five per-course skeletons (`canvas-ics33`, `canvas-reading-annotation`,\n`canvas-essay`, `canvas-zybooks`, `canvas-inside`) describe **generic\npatterns** for a class of course. The actual handling logic for your\nspecific school and instructor lives in a **local application overlay**\nat `_private\u002Fcanvas-\u003Cname>-app.md`.\n\nThe overlay is a free-form Markdown file that the skeleton loads as its\nfirst step. It specifies things like:\n\n- Course IDs and routing details.\n- The instructor's external site URL pattern.\n- Reading-PDF filenames, color rubrics, voice register.\n- Auto-submit authorization scope.\n- Whatever else makes \"this skill handles a generic code course\" become\n  \"this skill handles MY school's code course taught by Dr. So-and-so\".\n\n`_private\u002F` is gitignored — the overlay never leaves your machine. If\nyou fork this repo, you author your own overlays (or have Claude Code\nauthor them via the `canvas-bootstrap` skill).\n\nOverlays are also where `canvas-bootstrap`'s first-run calibration loop\nwrites its findings. Overlay v1 is the skill's best initial guess.\nOverlay v2 is what you actually want, derived from your feedback on a\nreal draft. The overlay is the durable artifact; the calibration session\nis throwaway.\n\n---\n\n## Agent stops at can't-do, not shouldn't-do\n\nCanvas Pilot's per-course skills work for the **student**, not for the\ninstructor. A skill never refuses to do an assignment because the\ninstructor wrote a behavioral rule like \"don't use AI\", \"don't\ncollaborate\", \"don't paraphrase\". Whether running the framework on a\ngiven assignment is consistent with the student's school's policies is\nthe student's decision, not the framework's.\n\nA skill stops only when it **physically can't proceed**. Four intrinsic\ncan't-do categories:\n\n1. **Physically impossible.** In-person attendance, paper submission,\n   live signatures, Lockdown Browser quizzes, Respondus proctoring.\n2. **Identity-bound.** Academic honesty contract signing, ID\n   verification, in-person peer review, oral defense.\n3. **Input missing and unobtainable.** Spec cannot be found anywhere;\n   a referenced file cannot be fetched and the student can't supply it.\n4. **Verification failure.** The skill's verification checklist fails\n   after retries.\n\nFor resources that are physically out of reach but might be obtainable\nwith the student's help — a video link, a password-protected download,\nan external-site login — the skill **soft-stops**: it offers to take a\nURL or credential from the student and resumes if given, skips that\nstep and continues with what it can do otherwise.\n\nWhere a skill uses a voice register (e.g. \"writes like a B1-B2\ninternational student\"), the documented reason is **student-identity\nalignment**: the student picks a register that matches who they\nactually are. The register is part of the student's voice, not a\nposture the skill adopts for the assignment.\n\n---\n\n## What Canvas Pilot can do\n\n- Scan all configured courses for pending assignments within a configurable\n  window.\n- Bucket assignments by urgency and propose a per-item skill.\n- Pause and wait for your approval before any work happens. The approval is a\n  filesystem boundary, not a prose instruction.\n- Run per-course skills sequentially. Each produces a draft under\n  `runs\u002F\u003Ctoday>\u002F\u003Cassignment>\u002Fdraft\u002F`.\n- Verify drafts against numeric constraints in the spec (sentence counts, page\n  counts, function counts) before optionally auto-submitting.\n- Write a daily `REPORT.md` with an urgent banner, status per item, and a\n  next-step recommendation.\n- Mirror drafts to a `final_drafts\u002F` folder for human review.\n- Email reminders for assignments due today \u002F tomorrow (separate skill).\n\n## What Canvas Pilot does not do\n\n- Read or write content on your behalf without your approval at the plan-review\n  step.\n- Auto-submit anything unless the per-course overlay explicitly grants standing\n  authorization for that assignment type, *and* the pre-submit verification\n  gate passes.\n- Bypass your instructor's academic-honesty policy. The framework's design and\n  default behavior put you in control of submission; your overlay decisions are\n  your responsibility.\n- Store assignments, drafts, or credentials on any remote service. Everything\n  stays in `runs\u002F`, `_private\u002F`, `sources\u002F`, and `.cookies\u002F` on your machine.\n- Reuse mocks where real Canvas behavior matters. Integration touches the\n  real API or a recorded fixture, not a hand-rolled mock.\n\n---\n\n## Repository layout\n\n```\ncanvas-pilot\u002F\n├── .claude\u002F\n│   ├── settings.json           # hook + permission config\n│   ├── hooks\u002F                  # session hooks (schema, approval, etc.)\n│   └── skills\u002F\n│       ├── canvas-setup\u002F       # first-run install + course selection\n│       ├── canvas-bootstrap\u002F   # per-course overlay drafting\n│       ├── canvas-scan\u002F        # scan → plan.json\n│       ├── canvas-execute\u002F     # dispatch approved items\n│       ├── canvas-skip\u002F        # punt to manual\n│       ├── canvas-ics33\u002F       # code-course skeleton\n│       ├── canvas-reading-annotation\u002F  # writing-course (annotation) skeleton\n│       ├── canvas-essay\u002F       # writing-course (long-form) skeleton\n│       ├── canvas-zybooks\u002F     # math\u002Fdiscrete skeleton\n│       ├── canvas-inside\u002F        # online-quiz skeleton\n│       └── canvas-generic\u002F     # runtime-designed fallback (no overlay)\n├── .agents\u002Fskills\u002F             # Codex sidecar mirrors (optional)\n├── src\u002F                        # framework Python (Canvas client, etc.)\n├── scripts\u002F                    # cron-able helpers (due-date alert, etc.)\n├── _private\u002F                   # gitignored: SECRETS, courses.yaml,\n│                               #             overlays, decision logs\n├── sources\u002F                    # gitignored: your assignment input materials\n├── runs\u002F                       # gitignored: per-day work output\n├── docs\u002F                       # internal design docs (NORTH_STAR, etc.)\n├── tests\u002F\n├── CLAUDE.md                   # loaded by Claude Code on every session\n├── AGENTS.md                   # Codex sidecar entry\n├── SETUP.md                    # manual setup walkthrough\n└── README.md                   # this file\n```\n\n---\n\n## Design principles\n\nThese do not change between versions. Everything in the roadmap respects\nthese principles.\n\n### Skills are pipelines, not monoliths\n\nA real assignment isn't \"one prompt produces one output\". A real\nassignment has stages with distinct skill requirements. Writing a 5-page\nresearch paper is research → outline → draft → humanize → verify, not\none function. Each stage is independently tunable, replaceable, and\ninspectable. Personal design files customize specific stages, not the\nwhole skill.\n\n### The approval gate is a filesystem boundary\n\n`canvas-scan` writes `plan.json` and stops. `canvas-execute` reads it\nafter the user replies with approval. Two skills, two Skill-tool\ndispatches — the user can interrupt between them. Prose instructions\ncannot enforce this; filesystem state can.\n\n### Drafts by default, submission only with standing authorization\n\nDefault behavior: produce a draft, you upload manually. Auto-submit is\nper-skill, per-overlay, gated by a verification log that has to pass\nbefore any upload call. Auto-submit is never the silent default.\n\n### Scope-first onboarding\n\n`canvas-bootstrap` configures one course (or one cluster within a\ncourse) per invocation — a tangible deliverable every time the student\nruns it, rather than batch-processing every course up front and\npresenting a wall of text.\n\n### Output that looks human, by design\n\nFor assignments where authorship signals matter (writing courses,\nextended responses), the pipeline includes a dedicated **humanize\nstage** whose only job is to take the draft and produce output that\nsurvives current AI-content detectors. This is a first-class stage with\nits own verification.\n\nFor assignments where authorship signals don't matter (code, math\nsolutions, MCQ answers), the equivalent concern is **submission-pattern\nhuman-ness** — pacing, timing, focus\u002Fblur events — handled at the\nsubmission stage, not the content stage.\n\n### One assignment = one work directory = one `result.json`\n\nThe Stop hook refuses to release the session until every dispatched\nassignment has produced a valid result. No silent partial completion.\n\n### No mocking on integration boundaries\n\nTests against Canvas use recorded fixtures or a sandbox course; mocks\ndon't catch drift between the spec and the real API.\n\n---\n\n## Git hygiene and critical do-nots\n\n`.gitignore` covers `.env`, `runs\u002F`, `SECRETS.md`, `courses.yaml`,\n`_private\u002F`, `sources\u002F`, `.cookies\u002F`, `__pycache__\u002F`. Trust it.\n\n- **Never** use `git add -f`, `git add -A`, or `git add .` — they\n  bypass or blanket-add. Use `git add \u003Cspecific-paths>` only.\n- **Never** edit `.gitignore` to remove a safety entry, even \"just for\n  testing\".\n- Before any commit, mentally check the staged file list contains only\n  generic framework code. If unsure, run `git diff --cached`.\n\nOther do-nots:\n\n- Do NOT dispatch per-course skills from `canvas-scan`. Scan produces\n  a plan and stops; `canvas-execute` dispatches after the user approves.\n  The two-skill split makes the approval gate a filesystem boundary\n  instead of a prose instruction.\n- Do NOT hardcode course IDs, file IDs, or instructor info in any\n  tracked file. They go in `_private\u002Fcanvas-\u003Cname>-app.md` overlays or\n  in your local gitignored `SECRETS.md` \u002F `courses.yaml`.\n- Do NOT leave the `.scan_in_progress` marker behind. If a run crashes,\n  clean it up before stopping; the Stop hook will refuse to release\n  until every assignment has a valid `result.json`.\n\n---\n\n## What is intentionally NOT in scope\n\n- **Replacing Claude Code.** This is a Claude Code project, not a\n  standalone CLI. The product depends on Claude Code's skill dispatch,\n  tool use, and approval semantics. Trying to factor out Claude Code\n  produces a worse product and an unmaintainable framework.\n- **Supporting LMSes other than Canvas.** Each LMS has enough API\n  surface area that supporting two means supporting two frameworks.\n  Canvas is broad enough; v1.0 is \"good at Canvas\", not \"decent at\n  three LMSes\".\n- **A multi-tenant SaaS.** Canvas Pilot is a per-user local install.\n  Multi-tenant introduces auth, payment, and abuse vectors we don't\n  want to absorb. If you want this as a service, fork it and host it\n  for yourself.\n- **Hand-rolled detector-bypass telemetry.** The humanize stage is a\n  stage in a pipeline, not a research program. We ship what works\n  against current detectors and update when they update. We do not\n  publish \"how to beat detector X\" guides; that work lives in the\n  stage itself.\n- **Academic-integrity arbitration.** Whether running this on a given\n  assignment is appropriate is a decision the operator has to make in\n  light of their school's policies. The framework is opinion-neutral\n  on that question and ships no policy-screening logic.\n\n---\n\n## Pointers\n\n- Per-user \u002F per-quarter data: `SECRETS.md` (gitignored).\n- Course routing: `courses.yaml` (gitignored).\n- Local application overlays: `_private\u002Fcanvas-\u003Cname>-app.md` (gitignored).\n- Student-supplied inputs: `sources\u002F` (gitignored except `README.md`).\n- Latest run report: `runs\u002F\u003Ctoday>\u002FREPORT.md`.\n- Framework skills: `.claude\u002Fskills\u002Fcanvas-{setup,scan,execute,skip,bootstrap}\u002FSKILL.md`.\n- Per-course skill skeletons: `.claude\u002Fskills\u002Fcanvas-{ics33,reading-annotation,essay,zybooks,quiz}\u002FSKILL.md`.\n- Runtime-design fallback: `.claude\u002Fskills\u002Fcanvas-generic\u002FSKILL.md`.\n- Framework auth: `src\u002Fcanvas_client.py`, `src\u002Fcanvas_login.py`.\n- Manual setup walkthrough: [SETUP.md](.\u002FSETUP.md).\n- Internal design doc: `docs\u002FNORTH_STAR.md`.\n\n**Adding a new course mid-term?** Tell Claude Code `design a skill` —\nthis triggers `canvas-bootstrap`, which surveys recurring patterns in\nthe new course and produces an overlay + `courses.yaml` route entry.\n\n---\n\n## License\n\nCopyright (C) 2026 X_isdoingreat\n\nThis framework is free software, licensed under the **GNU Affero General\nPublic License, version 3 or later** (`AGPL-3.0-or-later`). See\n[LICENSE](.\u002FLICENSE) for the full text. You may use, study, modify, and\nredistribute it under those terms; in particular, the AGPL's §13 means that\nif you run a modified version as a network-accessible service, you must\noffer those users the corresponding source.\n\nYou're welcome to fork it and adapt it for your own coursework. The\nframework ships no school-specific or instructor-specific solving logic —\nthat lives in your local, gitignored overlay files. The AGPL covers the\nframework code; your private overlays are yours, and what you do with them\nis on you.\n\nThe framework does not endorse or facilitate academic dishonesty. Whether\na given automation is appropriate for a given course is a decision the\nperson running this software has to make, in light of their own school's\npolicies.\n\n---\n\n## Contact\n\nMaintained by **X_isdoingreat**. Reach me on X at\n[@X_isdoingreat](https:\u002F\u002Fx.com\u002FX_isdoingreat) or by email at\n\u003CX_isdoingreat@proton.me>.\n\n- Security \u002F accidental-leak reports → [SECURITY.md](.\u002FSECURITY.md) (please\n  don't open a public issue for those).\n- Contributing → [CONTRIBUTING.md](.\u002FCONTRIBUTING.md).\n- Community conduct → [CODE_OF_CONDUCT.md](.\u002FCODE_OF_CONDUCT.md).\n","Canvas Pilot 是一个自动化处理学校作业的代理工具，它能够扫描Canvas学习管理系统中的待办作业、规划任务，并通过特定课程技能生成草稿。项目采用Python编写，支持Python 3.11+版本，使用GNU Affero General Public License v3.0开源许可。其核心功能包括自动检测即将到来的任务、为每项任务选择合适的处理技能以及生成初步完成的作业草稿，同时允许用户在关键决策点上保持控制权，如最终提交前的审核。适用于使用Canvas LMS平台的学生，特别是那些经常需要处理重复性结构作业（如每周习题集、阅读材料等）的人群，旨在减轻学生日常作业管理负担的同时确保学术诚信。",2,"2026-06-11 04:09:49","CREATED_QUERY"]