---
name: update-module
description: "Add, replace, or rearrange content within an existing module."
---

# Update Module Skill

> **Plugin**: ASU Canvas Course Builder
> **Run**: `/update-module`
> **Invokes**: quiz-generator, assignment-generator, discussion-generator, rubric-creator, interactive-content, notebooklm, images

## Purpose
> **Edit discipline**: Preserve original structure. Replace only fields the user explicitly named. Do not delete placeholders, instructor notes, or template scaffolding unless told to.

Make targeted changes to a single module that has already been built in Canvas. This is the **post-build editing tool** — use it when:

- A module needs a new or revised assessment
- Page content needs updating (new resources, corrected content, updated media)
- Interactive activities need to be added, replaced, or reordered
- A rubric needs revising
- Media (audio primer or lecture video) needs re-embedding
- Module items need reordering

This skill operates on **one module at a time** and preserves all existing Canvas IDs (pages, assignments, quizzes, discussions) unless explicitly replacing them.

## Staging-Server Preview (Write Safety Guard)

Every Canvas write in this skill follows `CLAUDE.md` §Write Safety Guard. Do not skip the preview step:

1. **Stage first** — write the content to `courses/{id}/staging/pages/{key}` via `scripts/staging_manager.py`. Never call a Canvas body write without a staged artifact.
2. **Start the preview server** — run `scripts/ensure_staging_server.py` (idempotent; returns the base URL whether or not the server was already up).
3. **Show the preview URL** — print `http://127.0.0.1:8111/courses/{id}/preview/pages/{key}` on its own line. Always `127.0.0.1`, never `localhost`.
4. **Require an explicit push verb** — accept only `push`, `approved`, `deploy`, `ship it`, or an equivalent affirmative with deployment intent. Do NOT accept `ok`/`yes`/`sure`/`confirm` alone — re-ask if the reply is ambiguous.
5. **Push via the script** — `scripts/push_to_canvas.py` only (backup → push → verify → clear-staging). Never call `canvas_api.update_*` directly.

## Prerequisites

- Canvas API credentials configured (`.env` exists)
- `course-config.json` exists in the working directory
- The target module has already been created in Canvas (via `/course-build` or manually)

---

## Step 1: Identify the Module

Ask: "Which module would you like to update?"

Accept any of:
- Module number: `3`, `M3`, `Module 3`
- Module title: `"Membranes & Excitability"`
- Canvas module ID: `2872310`

If `course-config.json` exists, display the module list for reference:
```
Your modules:
  M0: Getting Started
  M1: Homeostasis
  M2: Body Fluids, Transport & Gradients
  ...
```

Resolve the module number, then fetch the current module state from Canvas:
- `GET /api/v1/courses/{id}/modules/{module_id}/items` — current module items
- Cross-reference with `course-config.json` for objectives and assessment details

---

## Step 2: Show Current State

Display the module's current contents:

```
Module 3: Membranes & Excitability

  Pages:
    1. Module Overview (m3-overview)
    2. Prepare to Learn (m3-prepare-to-learn)
    3. Lesson: Membranes & Excitability (m3-lesson-membranes)
    4. Knowledge Check 3 (m3-knowledge-check)
    5. Guided Practice 3 (m3-guided-practice)
    6. Create an Artifact 3 (m3-create-artifact)
    7. Conclusion & Next Steps (m3-conclusion)

  Assessments:
    - Knowledge Check: Quiz #1962366 (15 pts, 5 questions)
    - Guided Practice: Assignment #7258604 (10 pts)
    - Create an Artifact: Assignment #7258585 + Rubric #1284795 (30 pts)
    - Discussion: Topic #7430437 (25 pts)

  Media:
    - Audio primer: File #127948436 (embedded in Prepare to Learn)
    - Lecture video: File #127955569 (embedded in Lesson)

  Interactives:
    - AP Phase Sequencing (File #127967617, Guided Practice)
    - Dialog Cards (File #127967618, Prepare to Learn)
    - Nernst Fill-Blanks (File #127967619, Guided Practice)
```

---

## Step 3: What to Update

Ask: "What would you like to change?" and handle the following operations:

### Update Page Content

```
/update-module → update page → [page name or number]
```

- Fetch current page HTML from Canvas
- Show a summary of current content
- Ask what to change (add section, replace content, update resource links, etc.)
- Default to **Minimal-Diff Edit**:
  - preserve existing structure, styles, headings, and layout
  - make the smallest reasonable HTML change
  - do not add new design elements, wrappers, callouts, cards, button rows, or ASUCB component patterns unless the user explicitly asks for redesign or visual enhancement
- Only switch to **Design Enhancement** if the user explicitly asks to redesign, polish, improve layout, modernize, or otherwise upgrade presentation
- Before pushing, summarize the intended change in plain language:
  - "I will update the existing page content without redesigning the layout."
  - or "I will revise the page and also upgrade the visual design."
- Stage the revised HTML first: `${ASUCB_PLUGIN_ROOT:-${CODEX_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}}/bin/python3 scripts/staging_manager.py --stage --course-id {id} --type pages --id {slug} --file {path-to-updated-html}`
- Preview the staged diff with the user and get approval before any live write
- Push via `${ASUCB_PLUGIN_ROOT:-${CODEX_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}}/bin/python3 scripts/push_to_canvas.py --type page --slug {slug} --course-id {id}`
- `push_to_canvas.py` handles backup → push → verify → clear staging → update progress automatically

### Page Edit Modes

Use this decision rule whenever an existing page is being changed:

| User intent | Mode | Behavior |
|---|---|---|
| "edit this page", "update this section", "fix the wording", "swap these links", "add this paragraph" | **Minimal-Diff Edit** | Preserve existing page design; only change the requested content |
| "redesign this page", "make it more engaging", "improve the layout", "upgrade the visuals" | **Design Enhancement** | Apply ASUCB page design patterns and visual improvements |

If the request is ambiguous, assume **Minimal-Diff Edit** and say so before making changes.

### Replace an Assessment

```
/update-module → replace assessment → [KC | artifact | discussion | GP]
```

- **Knowledge Check**: Invoke `/quiz-generator` with current module objectives. Creates a new quiz and replaces the old one in the module items.
- **Artifact**: Invoke `/assignment-generator` then `/rubric-creator`. Creates a new assignment+rubric and replaces the old one.
- **Discussion**: Invoke `/discussion-generator` then `/rubric-creator`. Creates a new discussion topic and replaces the old one.
- **Guided Practice**: Update the GP assignment description.

When replacing: offer to delete the old Canvas object or keep it as a backup (unpublished).

### Update a Rubric

```
/update-module → update rubric → [artifact | discussion]
```

- Fetch the current rubric from Canvas
- Show current criteria and descriptors
- Ask what to change (add/remove criterion, revise descriptors, adjust point distribution)
- Update via `PUT /api/v1/courses/{id}/rubrics/{rubric_id}`

### Add/Replace Interactive Activities

```
/update-module → add interactive → [type]
/update-module → replace interactive → [activity name]
```

- For **add**: Invoke `/interactive-content` to design the new activity, generate HTML, upload to Canvas, and embed in the target page
- For **replace**: Upload the new file, stage the updated page HTML, preview the diff, then push via `push_to_canvas.py`; optionally delete the old file after verification

### Update Media

```
/update-module → update media → [audio | video]
```

- For a new audio primer or lecture video:
  1. Invoke `notebooklm` (Mode 1: Audio Primer or Mode 2: Lecture Video) to generate the prompt
  2. Guide user through NotebookLM generation
  3. Upload new media file to Canvas
  4. Stage the updated page HTML with the new embed, preview the diff, and push via `push_to_canvas.py`
  5. Upload new VTT captions and update the expandable transcript

### Reorder Module Items

```
/update-module → reorder
```

- Show current item order with position numbers
- Ask which items to move (e.g., "move item 5 to position 3")
- Use `PUT /api/v1/courses/{id}/modules/{module_id}/items/{item_id}` with `position` parameter

### Add/Update Images

```
/update-module → add images → [page name or number]
/update-module → replace image → [description]
```

- For **add images**: Fetch the target page HTML, analyze it for image opportunities. Follow the **Search-First Principle** from `standards/image-generation-guidelines.md`:
  1. For scientific/technical/historical content → use `images` (Mode 1: Search), only offer AI generation if search fails and user approves
  2. For custom diagrams/conceptual illustrations → use `images` (Mode 2: Generate) with Nano Banana
  3. **Choose layout based on page context**: scan existing page layout and vary between full-width (Component 13) and side-by-side (Component 14) placements. Don't stack multiple full-width images — use Image + Concept Cards to create visual rhythm.
  4. Limit to 1-3 images per page
- For **replace image**: Download the new image, upload to Canvas, stage the updated page HTML with the new `<img>` src plus alt text/caption changes, preview the diff, push via `push_to_canvas.py`, and update `course-config.json`

### Add a New Page

```
/update-module → add page → [title]
```

- Create the new page content from the appropriate template, stage it, preview the diff, and push it to Canvas via `${ASUCB_PLUGIN_ROOT:-${CODEX_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}}/bin/python3 scripts/push_to_canvas.py --type page --slug {slug} --course-id {id}`
- Add it to the module at the specified position
- Populate with content

---

## Step 4: Verify Changes and Update Progress

After applying changes:

1. Re-fetch the module items from Canvas to confirm the update
2. If a page was modified, run a quick accessibility check on that page only
3. **Update build progress**: After any successful push, call `${ASUCB_PLUGIN_ROOT:-${CODEX_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}}/bin/python3 scripts/progress_tracker.py --course-id {COURSE_ID} --update {MOD_NUM} {PAGE_TYPE} complete` for each page/assessment modified. When passing through `push_to_canvas.py`, provide `module_num` and `page_type` parameters so progress is tracked automatically. Also log the edit: `${ASUCB_PLUGIN_ROOT:-${CODEX_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}}/bin/python3 scripts/progress_tracker.py --course-id {COURSE_ID} --history "revised" "module {N} {page_type}" --reason "{reason}"`
4. Show a summary of what changed:
   ```
   Changes applied to Module 3:
     ✓ Knowledge Check quiz replaced (old: #1962366 → new: #1962374)
     ✓ 5 new questions created
     ✓ Module item updated to point to new quiz
     ✓ Knowledge Check page button URL updated
   ```

---

## Safety Features

### Non-Destructive by Default
- When replacing an assessment, the old Canvas object is **unpublished but not deleted** by default
- The user must explicitly confirm deletion of old objects
- Page updates can be previewed before pushing

### Alignment Check
- When replacing an assessment, verify the new version still aligns with module objectives from `course-config.json`
- Warn if point totals change (affects grading weights)
- Warn if a rubric criterion no longer maps to a module objective

### Config Sync
- After changes, prompt the user to update `course-config.json` if the module structure has changed
- Specifically: new assessment types, changed point values, added/removed pages

---

## Output

The skill produces:
1. Updated Canvas module with requested changes applied
2. Change log (what was modified, old → new IDs)
3. Alignment verification (objectives still covered)
4. Reminder to update `course-config.json` if structural changes were made
