Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
102 commits
Select commit Hold shift + click to select a range
5523994
python notebooks in QDK Learning
minestarks Jun 26, 2026
13307b8
Add TODO
amcasey Jul 15, 2026
cc7cc6e
Cleanup and notes from AI review
amcasey Jul 15, 2026
afbdf9c
Move dummy course into test workspace
amcasey Jul 16, 2026
6fcdd63
Fix tests other than env check
amcasey Jul 16, 2026
c35cc82
DO NOT MERGE env check logging
amcasey Jul 16, 2026
b29f5be
Handle lack of uv
amcasey Jul 16, 2026
33a5d03
TODOs for qsharp-vscode.learningDoctor
amcasey Jul 16, 2026
d292482
More TODOs
amcasey Jul 16, 2026
dd4d157
Handle exception in import check
amcasey Jul 16, 2026
23124b1
Transfer TODOs from draft PR
amcasey Jul 16, 2026
9f3b313
First cut at using cell ID rather than cell index
amcasey Jul 17, 2026
cb2d162
Only offer hints for exercise cells
amcasey Jul 17, 2026
6ee6530
More TODOs
amcasey Jul 17, 2026
062e6aa
Tidy diff in agent file
amcasey Jul 17, 2026
aa28d8e
TODOs and tweaks from diff review
amcasey Jul 17, 2026
073f94c
More TODOs
amcasey Jul 20, 2026
793bcb8
First cut at consuming Python Environments API
amcasey Jul 23, 2026
8740f06
DO NOT MERGE local launch.json
amcasey Jul 23, 2026
e4cdd6a
Replace all direct python access with env API calls
amcasey Jul 24, 2026
f3982ef
Detect the absence of a venv
amcasey Jul 24, 2026
824913c
Drop most of CourseEnvironment
amcasey Jul 24, 2026
57f5874
Wire up course.json import checks
amcasey Jul 24, 2026
9ed8a08
Use requirements.txt instead of pyproject.toml for easier parsing
amcasey Jul 24, 2026
ce9797e
Handle requirements.txt ourselves
amcasey Jul 24, 2026
4707736
Remove requirements.txt parsing
amcasey Jul 24, 2026
40bbd28
Don't throw from ensureEnvironment
amcasey Jul 24, 2026
18a5b3c
Tidy up environments.ts
amcasey Jul 24, 2026
f694920
Drop readme location from course.json
amcasey Jul 24, 2026
3ad7b6c
Drop commands and pyproject.toml from _check_env.py
amcasey Jul 24, 2026
a0e70ca
Make report theme-safe
amcasey Jul 24, 2026
3b38421
First cut at opening notebook with specific kernel using unstable API
amcasey Jul 24, 2026
b335b57
Rename functions
amcasey Jul 24, 2026
bb7c4fc
Add more error handling around unstable call
amcasey Jul 24, 2026
a275008
Add diagnostics to the notebook toolbar
amcasey Jul 24, 2026
94421b2
Apply notebook hack to commands.ts
amcasey Jul 24, 2026
cc8ed3a
Fix cell ID in _exercises.json
amcasey Jul 24, 2026
ef6f919
Remove hint from notebook toolbar
amcasey Jul 24, 2026
8d11958
Add TODO
amcasey Jul 24, 2026
28f50f4
Auto save on cell execution
amcasey Jul 24, 2026
d268ccd
Respect themese in exercise reports
amcasey Jul 24, 2026
fa53265
Rename _exercises.json to exercises.json
amcasey Jul 24, 2026
e640a0d
Navigate to particular exercise from tree view
amcasey Jul 24, 2026
48fd874
Improve scrolling
amcasey Jul 24, 2026
7ca6960
First cut at hiding the panel for notebook courses
amcasey Jul 24, 2026
e17a419
Use the readme as a splash screen
amcasey Jul 25, 2026
586eb12
Auto-save on open
amcasey Jul 25, 2026
bd990b2
Delete tests
amcasey Jul 25, 2026
f46ca9f
Re-open notebook after resetting
amcasey Jul 25, 2026
719f57b
Improve scrolling to locations indicated by tree
amcasey Jul 25, 2026
0910c89
Reset all exercises in unit
amcasey Jul 25, 2026
09abe55
Reopen after applying fixes
amcasey Jul 25, 2026
b6aac86
Drop the sentinel file for completion tracking
amcasey Jul 25, 2026
b1d1d0c
Drop complete_unit()
amcasey Jul 25, 2026
ef7f9ce
Eliminate exercises.json in favor of authoring within the notebook
amcasey Jul 26, 2026
b447b5b
Update codespaces launch.json
amcasey Jul 27, 2026
1178c51
TODO for new environment approach
amcasey Jul 27, 2026
e3f0a51
Ignore vscode folders in test workspaces
amcasey Jul 27, 2026
2dd552d
Create a python project for the active course
amcasey Jul 28, 2026
4fc6f27
Initialize service when VS Code session starts with open notebook
amcasey Jul 28, 2026
cc493f2
Switch the cell context menu button from hint to explain
amcasey Jul 28, 2026
4253e93
Add TODOs
amcasey Jul 28, 2026
958fab3
Create the python project when the venv is created
amcasey Jul 28, 2026
c4620f1
Clean up findEnvironment
amcasey Jul 28, 2026
dffd886
Don't reopen notebook after environment repair
amcasey Jul 28, 2026
635d38d
Drop test hook for now
amcasey Jul 28, 2026
508e33d
INTERESTING Drop special openNotebook call
amcasey Jul 28, 2026
6186a26
Drop old logging
amcasey Jul 28, 2026
7ac9d0b
Drop unused fix kinds
amcasey Jul 28, 2026
35447eb
Clean up old TODOs
amcasey Jul 28, 2026
ae768f3
Add clarifying comments
amcasey Jul 28, 2026
2044b0b
Log finding the wrong number of notebooks in a unit
amcasey Jul 28, 2026
96af1ac
Warn when course isn't found
amcasey Jul 28, 2026
7c5cb40
Extract fsUtils
amcasey Jul 28, 2026
ace2d7c
Combine some notebook cleanup code
amcasey Jul 28, 2026
a1c1a0f
Clean up TODOs
amcasey Jul 28, 2026
4bb0dad
Extract missing extension helper
amcasey Jul 28, 2026
63efad1
Split up pythonRunner
amcasey Jul 28, 2026
207e602
Drop printf logging from env check
amcasey Jul 28, 2026
a0c1871
Await extension installation and add some TODOs
amcasey Jul 28, 2026
8809c72
Inline setupActiveEnvironment
amcasey Jul 28, 2026
5bde830
Address review feedback
amcasey Jul 28, 2026
790cc32
Clean up unused field
amcasey Jul 28, 2026
14656ff
Handle a race in panel message passing
amcasey Jul 28, 2026
6d96973
Fix typo
amcasey Jul 28, 2026
6e9f7c4
Remove dead comment
amcasey Jul 28, 2026
99052a3
Add todo
amcasey Jul 28, 2026
adf58be
Fix initialization race
amcasey Jul 28, 2026
e6bf1aa
Tidy up duplicate ProgressData
amcasey Jul 29, 2026
5f50a2e
Drop continue node in notebook courses
amcasey Jul 29, 2026
ddc394c
Remove course icon color
amcasey Jul 29, 2026
1a843a5
Handle or expand easy TODOs
amcasey Jul 29, 2026
46392d6
Change getExerciseCellIds to isExerciseCellId
amcasey Jul 29, 2026
da8ba60
Extract ipynb parser
amcasey Jul 29, 2026
99db370
First cut at rationalizing catalogs and course providers
amcasey Jul 29, 2026
aee7570
Validate paths from course.json
amcasey Jul 29, 2026
3a1f6bf
Comment about HTML injection
amcasey Jul 29, 2026
ea694f3
Handle environment creation race
amcasey Jul 29, 2026
af0644b
Remove stale TODOs
amcasey Jul 29, 2026
ed12f40
Merge branch 'main' into amcasey/PythonLearning
amcasey Aug 5, 2026
693c010
Drop references to non-existent integration tests
amcasey Aug 5, 2026
eb30e63
Drop additional reference to non-existent browser tests
amcasey Aug 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ __pycache__/
.idea/
*.so
samples/scratch/
samples/qdk-learning/
samples/qdk-learning.json
qdk-learning/
qdk-learning.json
*.pyd
/python_doc/
/logs/
4 changes: 2 additions & 2 deletions .vscode/launch.shared.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"args": [
"--profile=dev",
"--extensionDevelopmentPath=${workspaceFolder}/source/vscode",
"${workspaceFolder}/samples/"
"${workspaceFolder}/source/vscode/test/suites/learning/test-workspace"
],
"outFiles": [
"${workspaceFolder}/source/vscode/out/**/*.js",
Expand Down Expand Up @@ -68,7 +68,7 @@
"--profile=dev",
"--remote=codespaces+${env:CODESPACE_NAME}",
"--extensionDevelopmentPath=${workspaceFolder}/source/vscode",
"${workspaceFolder}/samples/"
"${workspaceFolder}/source/vscode/test/suites/learning/test-workspace"
],
"outFiles": [
"${workspaceFolder}/source/vscode/out/**/*.js",
Expand Down
12 changes: 12 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"@vscode/debugprotocol": "^1.68.0",
"@vscode/extension-telemetry": "0.8.5",
"@vscode/markdown-it-katex": "^1.0.0",
"@vscode/python-environments": "^1.0.0",
"@vscode/test-electron": "^3.1.0",
"@vscode/test-web": "^0.0.81",
"3dmol": "^2.5.4",
Expand Down
1 change: 1 addition & 0 deletions source/vscode/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ out/
test/out/
wasm/
*.vsix
.vscode/
36 changes: 29 additions & 7 deletions source/vscode/ai/qdk-learning.agent.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
---
name: QDK Learning
description: "Learn quantum computing interactively with the Quantum Katas — guided lessons, hands-on exercises, and Q# code you can run, check, and explore right in VS Code."
description: "Learn quantum computing interactively in VS Code — guided lessons, hands-on exercises, and code you can run, check, and explore. Includes the Quantum Katas and other learning courses."
model: ["Claude Haiku 4.5 (copilot)", "Auto (copilot)"]
---

# Quantum Development Kit Learning

You are an agent that helps users navigate and interact with the Quantum Katas panel in VS Code. Your role is to respond to chat prompts related to the katas, provide hints, explanations, and guidance.
You are an agent that helps users navigate and interact with the QDK Learning feature in VS Code. Your role is to respond to chat prompts related to the active course, provide hints, explanations, and guidance.

The `qdk-learning-*` tools drive a **Quantum Katas panel** in VS Code. The panel renders the current activity, action bar, and progress bar. Its buttons handle navigation, run, check, etc. directly — they bypass the LLM. Your job: set up the workspace, show the current activity, then step aside. You only handle chat prompts and concept questions.
The `qdk-learning-*` tools drive the QDK Learning UI in VS Code. The Lesson panel renders the current activity, action bar, and progress bar. Its buttons handle navigation, run, check, etc. directly — they bypass the LLM. Your job: set up the workspace, show the current activity, then step aside. You only handle chat prompts and concept questions.

A user can work through more than one **course**. The **Quantum Katas** is the default course. Additional courses may also be available in the workspace. Each course has its own units, activities, and progress.

## Definitions

Following is a user-ready description of the Quantum Katas. You may refer to it if the user asks what the katas are or how they work.
The **Quantum Katas** is the flagship course. Following is a user-ready description. You may refer to it if the user asks what the katas are or how they work.

> Quantum Katas (_kaˑta_ | kah-tuh — Japanese for "form", a pattern of learning and practicing new skills) are self-paced, AI-assisted tutorials for quantum computing and Q# programming. Each tutorial includes relevant theory and interactive hands-on exercises designed to test knowledge.

The tools refer to each kata as a "unit." Each unit contains ordered activities (lessons, examples, exercises).
The tools refer to each kata as a "unit". In other courses, there are no katas, simply units. Each unit contains ordered activities (lessons, examples, exercises).

**Tool naming:** All learning tools share the `qdk-learning-` prefix. This document uses short names (e.g. `show` for `qdk-learning-show`).

Expand All @@ -28,13 +30,30 @@ The tools refer to each kata as a "unit." Each unit contains ordered activities

## Startup

Call `get-state` first. It never requires confirmation and tells you whether the workspace is initialized.
Call `get-state` first. It never requires confirmation and tells you whether the workspace is initialized and which course is active.

- **If `initialized: true`** — you have the current position and progress. Greet the user briefly, then call `show` to open the activity panel. Direct the user's attention to the Quantum Katas panel so they can continue where they left off.
- **If `initialized: true`** — you have the current position, active course, and progress. Greet the user briefly, then call `show` to open the activity panel. Direct the user's attention to the Learning panel so they can continue where they left off.
- **If `initialized: false`** — the workspace hasn't been set up yet. Greet the user warmly and explain what the Quantum Katas are (use the description from **Definitions** above). Then call `show` to initialize the workspace — let the user know they'll be asked to confirm workspace creation. Once initialized, direct them to the panel to get started.

Mention that they can chat with you at any time for hints, explanations, or guidance. Don't explain how the agent works, list tools, or show menus.

## Courses

Multiple courses may be available. The active course is reported by `get-state` (the `course` field) and is the context for all activity, run, and check operations. The **Quantum Katas** is the default course.

| Intent | Tool | Notes |
| ------------------------------------- | ------------------- | ------------------------------------------------------------------------- |
| "What courses are available?" | `list-courses` | Returns the available courses and the active course id. |
| "Switch to …" / "Open the … course" | `switch-course` | Pass the `courseId`. Switching changes the active course and position. |
| "Tell me about this course" | `course-info` | Returns the course descriptor and README (defaults to the active course). |
| "Diagnose" / "Set up the environment" | `check-environment` | Runs environment diagnostics for the active course (Python courses). |

**Handling guidance:**

- When the user asks to change courses, call `list-courses` first if you're unsure of the exact `courseId`, match the user's request to a course, then call `switch-course`. After switching, call `show` to surface the new course's current activity and briefly tell the user where they landed.
- Python notebook courses use a per-course environment. If running or checking a task reports environment or kernel problems, call `check-environment` to diagnose; it reports which checks fail and whether a one-click setup can fix them. The katas need no environment and always pass `check-environment`.
- Don't switch courses unless the user clearly asks. Panel and tree actions can also switch courses without involving you, so always call `get-state` to learn the current course before answering.

## Tone

Warm, friendly tutor. Celebrate passes, encourage on failures, use natural language.
Expand Down Expand Up @@ -68,13 +87,16 @@ Call `show`. Use the returned state for your greeting. Don't call on every turn

To start a specific unit: `list-units` → find `unitId` → `goto`.

To change courses: `list-courses` → find `courseId` → `switch-course` → `show`.

### 2. Route Chat Input

Call `get-state` first. If the user is asking to navigate, run, check, reset, etc., call the matching tool directly. Notable cases:

- **hint** → use the **Hint Strategy** below instead of just calling the tool
- **solution** → warn about spoilers before calling
- **reset** → confirm the user wants to lose their code before calling
- **switch course / list courses / course info** → use the **Courses** tools (`switch-course`, `list-courses`, `course-info`); call `show` after a switch
- **"help with my code" / "debug"** → call `read-code`, then give personalized feedback
- **Q# or QDK question** → if the answer isn't obvious from the current lesson context, **always** read the `/qdk-programming` skill before responding.
- **free-form question** → answer using knowledge + current state; no tool needed
Expand Down
2 changes: 1 addition & 1 deletion source/vscode/ai/qdk-learning.prompt.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ agent: QDK Learning
argument-hint: Chat with the QDK Learning agent. e.g. "give me a hint", "check my solution", "run my code"
---

Let's do the Quantum Katas.
Let's learn quantum computing with the QDK. Start with the Quantum Katas, or switch to another available course.
195 changes: 194 additions & 1 deletion source/vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,10 @@
"command": "qsharp-vscode.learningResetExercise",
"when": "false"
},
{
"command": "qsharp-vscode.learningResetUnit",
"when": "false"
},
{
"command": "qsharp-vscode.learningShowActivity",
"when": "false"
Expand All @@ -341,6 +345,26 @@
{
"command": "qsharp-vscode.learningAskInChat",
"when": "false"
},
{
"command": "qsharp-vscode.learningSwitchCourse",
"when": "false"
},
{
"command": "qsharp-vscode.learningCourseInfo",
"when": "false"
},
{
"command": "qsharp-vscode.learningCheckEnvironment",
"when": "qsharp-vscode.learningWorkspaceDetected"
},
{
"command": "qsharp-vscode.learningNotebookHint",
"when": "false"
},
{
"command": "qsharp-vscode.learningNotebookExplain",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a few commands and tools could be removed in case unnecessary

"when": "false"
}
],
"view/title": [
Expand Down Expand Up @@ -371,6 +395,32 @@
}
],
"view/item/context": [
{
"command": "qsharp-vscode.learningSwitchCourse",
"group": "inline",
"when": "view == qsharp-vscode.learningTree && (viewItem == course || viewItem == coursePython)"
},
{
"command": "qsharp-vscode.learningCourseInfo",
"group": "inline",
"when": "view == qsharp-vscode.learningTree && (viewItem == course || viewItem == coursePython)"
},
{
"command": "qsharp-vscode.learningSwitchCourse",
"when": "view == qsharp-vscode.learningTree && (viewItem == course || viewItem == coursePython)"
},
{
"command": "qsharp-vscode.learningCourseInfo",
"when": "view == qsharp-vscode.learningTree && (viewItem == course || viewItem == coursePython)"
},
{
"command": "qsharp-vscode.learningCheckEnvironment",
"when": "view == qsharp-vscode.learningTree && viewItem == coursePython"
},
{
"command": "qsharp-vscode.learningResetUnit",
"when": "view == qsharp-vscode.learningTree && viewItem == unitPython"
},
{
"command": "qsharp-vscode.workspaceOpenPortal",
"group": "inline",
Expand Down Expand Up @@ -417,7 +467,26 @@
{
"command": "qsharp-vscode.learningAskInChat",
"group": "inline",
"when": "view == qsharp-vscode.learningTree && (viewItem == continue || viewItem == unit || viewItem == lesson || viewItem == exercise || viewItem == example)"
"when": "view == qsharp-vscode.learningTree && (viewItem == continue || viewItem == unit || viewItem == unitPython || viewItem == lesson || viewItem == exercise || viewItem == example)"
}
],
"notebook/toolbar": [
{
"command": "qsharp-vscode.learningCheckEnvironment",
"when": "qsharp-vscode.learningNotebookActive",
"group": "navigation@100"
},
{
"command": "qsharp-vscode.learningResetUnit",
"when": "qsharp-vscode.learningNotebookActive",
"group": "navigation@110"
}
],
"notebook/cell/title": [
{
"command": "qsharp-vscode.learningNotebookExplain",
"when": "notebookType == 'jupyter-notebook' && qsharp-vscode.learningWorkspaceDetected",
"group": "inline/cell@50"
}
],
"explorer/context": [
Expand Down Expand Up @@ -694,11 +763,47 @@
"category": "QDK Learning",
"icon": "$(discard)"
},
{
"command": "qsharp-vscode.learningResetUnit",
"title": "Reset Unit",
"category": "QDK Learning",
"icon": "$(discard)"
},
{
"command": "qsharp-vscode.learningShowActivity",
"title": "Show Current Activity",
"category": "QDK Learning",
"icon": "$(mortar-board)"
},
{
"command": "qsharp-vscode.learningSwitchCourse",
"title": "Switch Course",
"category": "QDK Learning",
"icon": "$(arrow-swap)"
},
{
"command": "qsharp-vscode.learningCourseInfo",
"title": "Course Info",
"category": "QDK Learning",
"icon": "$(info)"
},
{
"command": "qsharp-vscode.learningCheckEnvironment",
"title": "Run Course Diagnostics",
"category": "QDK Learning",
"icon": "$(pulse)"
},
{
"command": "qsharp-vscode.learningNotebookHint",
"title": "Ask for a Hint",
"category": "QDK Learning",
"icon": "$(comment-discussion-sparkle)"
},
{
"command": "qsharp-vscode.learningNotebookExplain",
"title": "Explain",
"category": "QDK Learning",
"icon": "$(comment-discussion-sparkle)"
}
],
"breakpoints": [
Expand Down Expand Up @@ -1331,6 +1436,94 @@
"additionalProperties": false
}
},
{
"name": "qdk-learning-list-courses",
"tags": [
"qdk",
"qdk-learning",
"quantum-katas"
],
"toolReferenceName": "qdkLearningListCourses",
"displayName": "QDK Learning: List Courses",
"modelDescription": "List all available learning courses (loaded or not) with their ids, titles, kinds, and the id of the currently-active course. Use the course ids with switch-course or goto.",
"canBeReferencedInPrompt": true,
"icon": "./resources/file-icon-light.svg",
"inputSchema": {
"type": "object",
"properties": {},
"required": [],
"additionalProperties": false
}
},
{
"name": "qdk-learning-switch-course",
"tags": [
"qdk",
"qdk-learning",
"quantum-katas"
],
"toolReferenceName": "qdkLearningSwitchCourse",
"displayName": "QDK Learning: Switch Course",
"modelDescription": "Switch the active learning course. Moves to the first incomplete activity in that course and updates the panel. Use a courseId from list-courses.",
"canBeReferencedInPrompt": true,
"icon": "./resources/file-icon-light.svg",
"inputSchema": {
"type": "object",
"properties": {
"courseId": {
"type": "string",
"description": "ID of the course to switch to (from list-courses)."
}
},
"required": [
"courseId"
],
"additionalProperties": false
}
},
{
"name": "qdk-learning-course-info",
"tags": [
"qdk",
"qdk-learning",
"quantum-katas"
],
"toolReferenceName": "qdkLearningCourseInfo",
"displayName": "QDK Learning: Course Info",
"modelDescription": "Return the descriptor and README content (if any) for a course. Defaults to the active course when no courseId is provided.",
"canBeReferencedInPrompt": true,
"icon": "./resources/file-icon-light.svg",
"inputSchema": {
"type": "object",
"properties": {
"courseId": {
"type": "string",
"description": "ID of the course. Omit for the active course."
}
},
"required": [],
"additionalProperties": false
}
},
{
"name": "qdk-learning-check-environment",
"tags": [
"qdk",
"qdk-learning",
"quantum-katas"
],
"toolReferenceName": "qdkLearningCheckEnvironment",
"displayName": "QDK Learning: Check Environment",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switch course review

"modelDescription": "Run environment diagnostics for the active learning course. Returns structured checks (Python interpreter, virtual environment, fingerprint, required packages) and whether a one-click environment setup can fix any failures. Q# courses need no environment and pass trivially.",
"canBeReferencedInPrompt": true,
"icon": "./resources/file-icon-light.svg",
"inputSchema": {
"type": "object",
"properties": {},
"required": [],
"additionalProperties": false
}
},
{
"name": "qdk-learning-next",
"tags": [
Expand Down
Loading
Loading