Lesson 1: Set up Copilot in VS Code, install the FlyPython Skill, fetch the course
Objective
By the end of this lesson GitHub Copilot is running in VS Code with the
session controls set for supervised work, the FlyPython Skill is available
to it, and the agent has fetched this course’s files into your working
folder — you downloaded nothing by hand. With the folder in place you run
the course’s objective check and explain what “the starter fails” means in
test names. No code is changed in this lesson.
Step 1 — Get Copilot running in VS Code
Install VS Code, sign in to GitHub Copilot when VS Code prompts you, then
File → Open Folder on an empty working folder. Open the Chat view and
set the controls in the chat input:
| Control | Choose | Why |
|---|
| Session Target | Copilot | the day-to-day Copilot harness on your machine |
| Agent | Agent | it can read files and run commands |
| Permissions | Manual permissions | commands and tool calls wait for your approval |
If the Agents window offers a Code isolation choice, pick Folder:
a New Worktree session is always Allow all, which removes the approval
prompts this course relies on.
Step 2 — (Optional) Pre-install the FlyPython Skill
Optional: Step 3’s entry sentence reads the Skill straight from its URL,
so the course works without this step — pre-installing just saves a
permission round-trip on later sessions.
VS Code discovers Agent Skills in .github/skills/<name>/SKILL.md, and the
folder name must match the name field inside the file or the skill does
not load. The FlyPython Skill is named flypython-challenges:
mkdir -p .github/skills/flypython-challenges
curl -s https://flypython.com/skills/flypython/SKILL.md -o .github/skills/flypython-challenges/SKILL.md
If your setup blocks the network, download the file in a browser and save
it to the same path. The Skill is one file, the same in every tool: it
tells the agent how to authorize you, fetch course files, verify, and
submit claim codes.
Step 3 — Let the agent fetch this course (you download nothing)
Start a new chat session in the working folder and paste this one
sentence:
Read https://flypython.com/skills/flypython/SKILL.md and start the FlyPython course hands-on-with-github-copilot.
Copilot asks before fetching the URL and before each command — read each
request, then approve it. The agent gives you an authorization link with a
short code. Open it, log in, make sure the code matches what the agent
showed you, and click Allow — then tell the agent “done”. It takes a token
once and writes this course’s files to
courses/hands-on-with-github-copilot/.
Prerequisite: these courses need a coding agent that can run commands
and reach the network. A chat-only web AI cannot do them.
Why this lesson exists
Most AI-written Python dies the same way: the demo input works, the real
input arrives, and the script crashes on row 3 — or worse, quietly produces
a wrong number. The fix does not start with a better prompt. It starts with
turning “it’s broken” into a command that anyone can run and get the same
answer. With Manual permissions, Copilot runs that command only after you
have read it.
Warm-up (2 minutes)
Open starter/report_tool.py in the editor and read it top to bottom. It
looks reasonable: functions with docstrings, type hints, a CLI. This is
exactly what AI-generated code looks like — clean surface, missing
behavior. Now open TASK.md and keep it next to you.
The lesson
The course files are in courses/hands-on-with-github-copilot/ now — no
download happened on your side. Ask the agent to survey them without
changing anything:
“Read COURSE.md — it is the teaching contract for this folder. Then read
TASK.md and starter/report_tool.py. Do not change any file. Tell me which
behaviors the tests expect that the starter does not have.”
When it asks to run the learner’s command, approve it — this is your
single check for the rest of the course:
python verify.py
You should see the starter reproduce five real-world failure classes
plus two end-to-end consequences — seven named failing tests in all —
mapped to test names:
| Failing test | Real-world meaning |
|---|
test_load_json_records_returns_list_of_dicts | the tool only handles CSV; the API scenario crashes |
test_unsupported_suffix_raises_value_error | an .xlsx upload becomes a confusing crash instead of a clear rejection |
test_invalid_records_are_isolated_with_reasons | one empty cell aborts the entire run — no partial report, no reason |
test_group_totals_are_rounded_to_two_decimals | 0.1 + 0.2 prints as 0.30000000000000004 in your report |
test_write_report_creates_missing_parent_directories | the tool cannot write into a fresh output directory |
test_run_scenario_writes_report_file, test_main_prints_summary_and_returns_zero | end-to-end consequences of the above |
If you want the missing behaviors as exact failing test names, the
maintainer command prints them:
python verify.py starter --expect-failure
(The reference solution/ exists so maintainers can prove the target is
reachable. You never need to run it, and it is never the completion
standard — your implementation in starter/ is.)
Exercise
Pick the scenario skin you most identify with (excel-report,
data-monitor, or api-tool), open its data file, and find the rows that
will be rejected. Write down, before running anything, which test each bad
row will trigger. Then check yourself against the table above — and ask the
agent to confirm, not to fix.
Checkpoint
Run python verify.py in the course folder. You pass this lesson when you
can answer, without looking:
- Which five behaviors separate starter from solution, and which two
failing tests are their end-to-end consequences?
- Why does
python verify.py exit non-zero on purpose — what state is
it reporting, and why is that a success condition rather than an error?
- What does the row you found in the exercise do to the starter — crash,
isolate, or silently pass?
Once you can answer, claim the checkpoint with
python verify.py --attest l01.
Expected evidence
The transcript of the default command, and your three answers. Keep them;
Lesson 4 will ask for them again.