Extension edit tutorial (#2806)

* canvas-extension: new edit-tutorial extension

* canvas-extension: new edit-tutorial extension

* canvas-extension: new edit-tutorial extension

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Apply edits from code review

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Apply edits from code review

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Apply edits from code review

* Apply edits from code review

* Apply edits from code review

* Apply edits from code review

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Apply edits from code review

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Apply edits from code review

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Apply edits from code review

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Apply edits from code review

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* improve: create tutorial from past commits

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Apply edit from code review

* Apply edit from code review

* Apply edits from code review

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Apply edit from code review

* apply review, preserve canvas in repo project sessions

Apply edit from code review

improve: preserve canvas render in project from repo

code-review: perform local code review

resolve: preserving canvas for repo projects

resolve: preserving canvas for repo projects

code-review: perform local code review

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Apply edit from code review

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Apply edit from code review

* Apply edit from code review

* Apply edits from code review

* Apply edits from code review

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Apply edits from code review

* resolve: reviewed formatting error

* Apply edit from code review

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
John Haugabook
2026-08-28 10:15:13 +10:00
committed by GitHub
co-authored by Copilot Autofix powered by AI
parent bbde357dbd
commit f118344017
10 changed files with 3487 additions and 0 deletions
+197
View File
@@ -0,0 +1,197 @@
# Edit Tutorial
A canvas extension that turns a set of code changes into an interactive lesson: the
edits the agent made in the current session, or the changes in a commit (the last
commit by default) when the agent made none. The lesson is a step-by-step walkthrough
of each change, comprehension quizzes, and a hands-on exercise the learner finishes in
the canvas in order to understand the updates to the source code.
![Edit Tutorial canvas preview](assets/preview.png)
## Prerequisites
- **Node.js 20.19 or newer** because the Copilot SDK requires `node ^20.19.0 || >=22.12.0`.
- The GitHub Copilot app canvas / UI-extensions experiment enabled.
## Install
Drop this folder at `~/.copilot/extensions/edit-tutorial/` for user scope, or in a repository at
`.github/extensions/edit-tutorial/` for project scope. Then install dependencies from inside the
copied folder:
```sh
# User scope
cd ~/.copilot/extensions/edit-tutorial
# Or project scope, from the repository root
cd .github/extensions/edit-tutorial
npm install
```
Reload extensions in the GitHub Copilot app, then when updating a repository using the Copilot app,
add a line like:
```text
Start an edit tutorial for the update.
```
at the end of the prompt to start the `edit-tutorial` canvas. To learn an existing
change without the agent editing anything, ask on its own:
```text
Start an edit tutorial from the last commit.
```
## What It Does
- **Two sources**: the code edits the agent made in the current session, or the
changes in a commit when there are no session edits. The most recent commit is the
default; name any commit to learn that one instead.
- **Lesson history**: each newly titled lesson joins a history of up to 10. When
more than one exists, arrows under the progress counter let the learner flip
between lessons, each keeping its own progress. Republishing the active lesson with
the same title replaces it instead of adding a new one.
- **Walkthrough**: one step per focused edit, each with the file, an explanation, a
before/after code view with change highlighting, and an optional multiple-choice quiz.
- **Exercise**: finishing the walkthrough unlocks a hands-on task that applies the same
technique as the session's edits, but as a slight variation (a different function,
module, or parameter values), so the learner writes the change themselves instead of
rereading it.
- **Completion**: local regex checks validate the attempt, hints reveal one at a time,
a reference solution unlocks after repeated failed attempts, and the learner can send
their code to the agent for a coaching review. Passing the checks, or an approving
review, completes the lesson.
- **Persistence**: lesson content and learner progress are saved to the session
workspace, so reopening the canvas resumes where the learner left off. Each save
also refreshes a read-only HTML snapshot of the rendered lesson, so the tutorial
survives an app restart as a readable artifact instead of raw state data. All
Edit Tutorial canvases open in one session share this same lesson state, so a
second canvas is another view of the same lessons, not a separate copy.
For example, if the agent added retry-with-backoff logic to `fetchUser`, the lesson
walks through that change and then asks the learner to apply the same pattern to
`fetchOrders` with a different attempt cap and starting delay.
## Preserved Artifact
The live canvas is served by the extension process on a loopback port, so it cannot
outlive the app. Two files are written to the session workspace on every save:
| File | Purpose |
| --- | --- |
| `files/edit-tutorial-state.json` | Machine state used to restore the live canvas on reopen |
| `files/edit-tutorial-artifact.html` | Self-contained, read-only rendering of the lesson and progress |
After the app is closed and reopened, the conversation can preserve the HTML artifact
in place of the live canvas: it renders the full walkthrough, quiz results, revealed
hints, and the learner's exercise attempt, with no scripts, no token, and no server
behind it. When the history holds several lessons, the artifact shows the active one
and labels it ("Lesson 2 of 3"). The artifact also embeds the state document, lesson
history included, in a non-executing JSON block, so the lessons can be rebuilt from
the artifact alone if the state file is ever lost.
That rebuild is automatic. A chat resumes the same session, so the canvas restores
from the state file directly. A project reopens into a fresh session whose workspace
holds only what was preserved from the conversation; when the canvas opens and finds
no state file, the extension scans the workspace for a preserved artifact (under its
original name or a copied one) and restores the lessons and progress from its
embedded state block, so the canvas survives wherever the artifact does.
Reopening the canvas is automatic. In a session attached to a repository, the app
brings the workspace files back after a restart but does not reopen the canvas on
its own. Shortly after the session starts, the extension checks a few times whether
a lesson is stored while no canvas has opened, waiting out the app still restoring
files, and then sends the session a reopen request itself, the same message a
stranded learner would type by hand, at most one message per session start. It also hands
the agent the same instruction as context at session start and on each prompt. A
canvas the learner closed on purpose stays closed, and if the canvas still does not
come back, the manual paths below always work.
### If the canvas does not come back after a restart
Three manual paths bring the lesson back immediately in a repository session, best
first:
- **Reopen from the app menu**: click the "+" icon, choose "Extensions", then
"Edit Tutorial". The canvas opens and restores the stored lessons and progress
from disk on its own. This is the fastest path and needs no agent turn.
- **Continue by asking**: ask Copilot to "reopen the edit-tutorial canvas". Opening
the canvas restores everything the same way; nothing is lost by the canvas having
been closed, and asking does not rebuild or reset the lesson.
- **Read it now**: in the session's Files panel, open `edit-tutorial-artifact.html`
and choose "Open in browser". That page is the preserved lesson, progress
included, as a read-only snapshot, and it tells you how to resume.
## Usage
1. Let the agent make a change to your code, then open the Edit Tutorial canvas and
click "Build my tutorial" (or just ask: "teach me what you changed"). If the agent
made no edits in the session, the lesson is built from the last commit instead;
you can also ask for that directly: "teach me the last commit".
2. The agent reviews the session's edits, or the commit's changes, and publishes the
lesson to the canvas with the `set_tutorial` action.
3. Work through the steps, answer the quizzes, and finish the exercise in the canvas
editor.
## Canvas Actions
| Action | Purpose |
| --- | --- |
| `set_tutorial` | Publish a lesson (title, summary, source, steps, exercise); a new title adds to the lesson history, the active title replaces |
| `get_progress` | Read the learner's step progress and current exercise attempt |
| `approve_exercise` | Mark the exercise complete after a successful review |
| `reset_progress` | Restart the current lesson without changing its content |
### Example `set_tutorial` Payload
Quizzes are optional per step. Each `solutionChecks` entry is a JavaScript regular
expression the learner's attempt must match; its `hint` is shown when the check fails.
<details>
<summary>Show Details</summary>
```json
{
"title": "Retry with exponential",
"summary": "The API client now retries transient failures with exponential.",
"source": "Commit a1b2c3d: retry transient API failures",
"steps": [
{
"file": "src/api/client.js",
"heading": "Wrap the request in a retry loop",
"explanation": "The single request call becomes a bounded loop.",
"before": "const res = await get(\"/users/\" + id);",
"after": "for (let attempt = 1; attempt <= maxAttempts; attempt++) { ... }",
"quiz": {
"question": "Why bound the loop?",
"options": ["To avoid retrying forever", "To speed up requests"],
"answerIndex": 0,
"why": "A bounded loop guarantees the call eventually settles."
}
}
],
"exercise": {
"heading": "Your turn: retry the orders endpoint",
"brief": "Apply the same pattern to fetchOrders, capped at 5 attempts.",
"file": "src/api/orders.js",
"starterCode": "async function fetchOrders(customerId) { ... }",
"hints": ["Start from the loop shape used in fetchUser."],
"solutionChecks": [
{ "pattern": "maxAttempts\\s*=\\s*5", "hint": "Cap the attempts at 5" }
],
"solution": "async function fetchOrders(customerId) { ... }"
}
}
```
</details>
## Distribution
This extension is shipped through the `edit-tutorial` plugin:
```bash
copilot plugin install edit-tutorial@awesome-copilot
```