# Canvas Toolchain — Module View > Looking for what you can **install**? That list — installable modules and companion programs, generated from `module-catalog.json` — is [`docs/modules.md`](modules.md). This page is the internal architecture breakdown instead: every capability area of the toolchain, engineer-facing, whether or not it's separately installable. A capability-by-capability breakdown of the toolchain. Each **module** below is a self-contained functional area: what it is, **why it was created** (the problem it solves), what it does, and the commands (MCP tools) that belong to it. > Two senses of "module" live here: > - **Plug-in modules** — true opt-in units enabled at config time via `~/.command-and-control/modules.json` (today: Lecture Video, Oral Assessment, Group Builder, Roster & Identity Manager, PeerAssessment Export, and — installed through the module channel rather than bundled — Announcements Auditor). These follow the `CanvasToolchainModule` contract. > - **Functional modules** — the natural capability groupings inside the core packages (analysis, design, publishing, …). They aren't separately installable, but they're how the toolchain decomposes. > > For exact parameters of any command, see [`commands-and-credentials.md`](commands-and-credentials.md) §2. For the visual map, see [`visual-guide/`](visual-guide/README.md). For how to publish or install a module through the channel, see the runbook: [`docs/module-channel.md`](module-channel.md). --- ## Module index | # | Module | Kind | One-line purpose | | --- | --- | --- | --- | | 0 | [Command & Control coordinator](#0-command--control--the-coordinator) | Core | The single entrypoint that orchestrates everything | | 1 | [Plug-in module system](#1-plug-in-module-system) | Core | Ship capabilities as opt-in modules without a new installer | | 2 | [Lecture Video](#2-lecture-video-plug-in-module) | Plug-in | Embed lecture video + pull transcripts (Panopto first) | | 3 | [Curriculum Intelligence](#3-curriculum-intelligence) | Core | Find what's stale, plan next semester | | 4 | [Canvas Design Studio](#4-canvas-design-studio) | Core | Generate Canvas-safe HTML | | 5 | [Transcript pipeline](#5-transcript-pipeline) | Functional | Fetch, enrich, and verify lecture transcripts | | 6 | [Lecture Answers (course Q&A)](#6-lecture-answers--course-qa) | Functional | "Did I cover this?" over your own course | | 7 | [Publishing + snapshots/rollback](#7-publishing--snapshotsrollback) | Functional | Safe, reversible publishing to Canvas | | 8 | [Resource Registry](#8-resource-registry) | Functional | Install templates/themes/prompts (free + premium) | | 9 | [Institution discovery + usage feedback](#9-institution-discovery--usage-feedback) | Functional | Detect your tools; tell the author what to build | | 10 | [Shared LLM + model routing](#10-shared-llm--model-routing) | Core lib | Anthropic or local Ollama, your choice | | 11 | [Layout adapter](#11-layout-adapter) | Functional | Turn pasted/Figma HTML into Canvas-safe templates | | 12 | [Course health dashboard](#12-course-health-dashboard) | Functional | One glance: how are my courses doing? | | 13 | [AI Assessment Scale (AIAS)](#13-ai-assessment-scale-aias) | Functional | Label assignments with an AI-use policy | | 14 | [Native installer](#14-native-installer) | Tooling | One double-click setup instead of eight commands | | 15 | [Oral Assessment](#15-oral-assessment-plug-in-module) | Plug-in | Design oral/video assessments (Rhetorix-first) | | 16 | [Group Builder](#16-group-builder-plug-in-module) | Plug-in | Create & rotate balanced student groups | | 17 | [Roster & Identity Manager](#17-roster--identity-manager-plug-in-module) | Plug-in | PeopleSoft → de-identified roster + lifetime pseudonyms | | 18 | [PeerAssessment Export](#18-peerassessment-export-plug-in-module) | Plug-in | Canvas group set → PeerAssessment.com import CSV | | 19 | [Canvas Rubric Sync](#19-canvas-rubric-sync) | Functional | Pull a Canvas rubric, triage changes, rewrite for students | | 20 | [Announcements Auditor](#20-announcements-auditor-channel-native-plug-in-module) | Plug-in (channel) | Find stale scheduled announcements after a course copy; recreate them | --- ## 0. Command & Control — the coordinator **What it is.** **Canvas Toolchain — Command & Control** (`@canvas-toolchain/command-and-control`, bin `canvas-toolchain-server`) is the single professor-facing MCP server. You talk to it; it runs everything else. It re-exports the tools of Curriculum Intelligence, Design Studio, and the Canvas Backup downloader so you never juggle three servers. **Why it was created.** The toolchain is three independent apps (Canvas Backup, CI, CDS) plus a Python sidecar. Asking a professor to wire up and drive all of them is a non-starter. C&C presents one surface and stitches them together **by data contract, not code dependency** — each app stays independently usable and testable, while the coordinator owns the cross-cutting concerns (model routing, credentials, module registry, workflow status). **What it does.** Orchestrates the high-level workflows (`analyze → plan → update → publish`), routes LLM calls to the active provider, manages credentials and modules, and reports health. It is deliberately thin: domain logic lives in the worker apps. **Commands.** `setup_cc`, `get_cc_status`, `set_active_llm_provider`, `show_canvas_capabilities`, `preview_canvas_pattern`, and the workflow umbrellas `analyze_course`, `plan_next_semester`, `update_course_materials`, `full_pipeline`. (Plus everything re-exported from the other modules.) --- ## 1. Plug-in module system **What it is.** The `CanvasToolchainModule` contract (`packages/module-contract`), a manifest loader, and a registry in C&C (`src/modules/registry.ts`) that read `~/.command-and-control/modules.json` at startup to decide which capabilities to expose — plus, since v2.0, **the module channel**: a way to ship a module (or a fix to one) *without a new installer release* at all. **Why it was created.** Every new integration (video platform, lab tool, …) used to mean editing core packages and shipping a new installer. The goal of #78 (module-architecture spec, 2026-06-07) was to *"make tool support truly pluggable — the base install edits Canvas pages (core); every other capability becomes an opt-in module that can be enabled without shipping a new installer release."* The 2026-06-08 first cut decoupled *enablement* from installation (all modules shipped in the bundle; the manifest just gated them). v2.0 finishes the job by decoupling *distribution* too: modules are now built into single-file, hash-pinned `.mjs` artifacts committed to this repo under `modules///`, fetched at install time over `raw.githubusercontent.com`, with `module-catalog.json` on `main` as the single source of truth for what exists and what its bytes must hash to. **What it does.** Loading now happens in two phases (`loadModules()` in `src/modules/registry.ts`): phase 1 loads the static, bundled `KNOWN_MODULES` map exactly as before; phase 2 loads any **installed channel artifacts** — re-hashing each artifact file against its recorded sha256 immediately before every dynamic import, so a tampered or corrupted file is refused, never loaded (the same hash is also verified once at install time — see below). If a module id exists both bundled and installed, the **semver-newer version wins** (equal versions keep the bundled copy, since no download is needed), which is how a module fix ships between installer releases. Every failure mode — missing, corrupt, tampered, contract-violating, or throwing — is **fail-soft**: the module is skipped with a logged warning and the server always starts; only artifacts that pass the re-hash and the contract check ever load, which is the **fail-closed** half of the same guarantee. You flip any module on/off post-install with `set_module_enabled` (takes effect on the next client reconnect — no hot-reload). Three tools drive the channel itself, all following the toolchain's confirm-gate idiom: - **`browse_module_catalog`** (read-only) — fetches `module-catalog.json` (5 s timeout, 24 h cache) and merges it with local state, reporting each catalog module as `bundled` / `not installed` / `installed (enabled)` / `installed (disabled)` / `update available (vX → vY)`, plus any pending installer-GUI requests. `clearPending: true` discards stale requests. - **`install_module`** — a **two-call confirm gate** (same idiom as `wave_deep_check`): call 1 previews name, version, description, size, source URL, sha256, and handles with no side effects (a host too old for the module gets a refusal with upgrade guidance instead of a preview); call 2 (`confirm: true`) downloads the artifact, **verifies its sha256 against the catalog entry, refusing on any mismatch**, then places it, records it in `installed-modules.json`, and enables it. On an upgrade, the previous version's artifact and hash are retained until the new version loads successfully once, so a bad release can be rolled back without a re-download. - **`uninstall_module`** — removes a channel-installed artifact and its record, and disables it in `modules.json`. **Bundled modules cannot be uninstalled** — only disabled via `set_module_enabled`. The Go + Fyne installer's "Additional modules" picker screen only *requests* a module — it fetches the catalog, lists what's not yet installed, and on finish writes chosen ids to `~/.command-and-control/pending-module-installs.json`. **No download or install logic exists in Go.** C&C surfaces a pending request as a one-line chat nudge, but fulfillment always goes through the same `install_module` confirm gate: the GUI checkbox is a request, never an authorization — chat's confirmed `install_module` call is the only place code installation is actually authorized. **Publishing** a module version (commit its artifact under `modules///` → update `module-catalog.json` → PR, gated by `npm run verify:modules` and a `docs/modules.md` drift check) is documented in full in the runbook: [`docs/module-channel.md`](module-channel.md). **Commands.** `list_modules`, `set_module_enabled`, `browse_module_catalog`, `install_module`, `uninstall_module`. --- ## 2. Lecture Video (plug-in module) **What it is.** The first real plug-in module (`packages/module-video`). A `VideoProvider` adapter layer with **Panopto** as provider #1 (Zoom/Teams/Meet/YouTube/TechSmith are future providers). **Why it was created.** Panopto code used to be smeared across Canvas Design Studio and C&C — hard to maintain, impossible to disable. Extracting it into a module *"proves the contract on one real extraction so converting the rest later is mechanical"* (#78). The cross-package import was deleted; token handling is now internal to the module. It also models the adapter pattern so a second video provider is a one-file addition. **What it does.** Authenticates to the video platform (OAuth2 for Panopto), downloads transcripts, and produces embeds. It writes VTT + `_sessions.json` to the known transcript location so Curriculum Intelligence ingests it **unchanged** — decoupled by data contract. **Commands.** `setup_panopto`, plus the transcript tools it owns (see Module 5). Enable it with `set_module_enabled` (module: video). --- ## 3. Curriculum Intelligence **What it is.** **Canvas Toolchain — Curriculum Intelligence** (`@canvas-toolchain/curriculum-intelligence`, bin `canvas-toolchain-curriculum-intelligence`; package path `packages/curriculum-intelligence`) is the analysis-and-planning brain. Reads past Canvas archives and lecture transcripts, scores topic currency, diffs semesters, and plans the next term. **Why it was created.** Professors in fast-moving fields face one recurring problem: *what I taught last semester is already outdated.* CI exists to answer "how stale is my course, and what should next semester look like?" — ingesting the past, scoring what aged out (evergreen vs. current vs. dated), and emitting KEEP/UPDATE/DROP/ADD verdicts plus a recommended outline. **What it does.** Ingests archives → builds a topic map → diffs against prior semesters → scores currency (optionally with live news signals) → drafts updated briefs and an outline → tracks a long-run trajectory (churn rate, unstable topics, true evergreens). Output feeds Canvas Design Studio. **Commands.** `setup_course`, `get_course_state`, `ingest_canvas_archive`, `list_assignments`, `list_pages`, `list_modules`, `list_resources`, `diff_semesters`, `fetch_news_feed`, `scan_recent_developments`, `suggest_topics`, `score_topic_currency`, `recommend_for_topic`, `import_previous_shell`, `fetch_academic_calendar`, `shift_dates`, `generate_recommended_outline`, `draft_assignment_brief`, `update_examples`, `export_course_folder`, `analyze_course`, `get_course_trajectory`, `generate_ideas_file`. --- ## 4. Canvas Design Studio **What it is.** **Canvas Toolchain — Design Studio** (`@canvas-toolchain/canvas-design-studio`, bin `canvas-toolchain-design-studio`; package path `packages/canvas-design-studio`) is the presentation layer. A KB-backed generator of **Canvas-safe HTML**, plus design critique/redesign and interactive widgets. **Why it was created.** Canvas's RCE sanitizer silently strips `