Hands-on with GitHub Copilot · Challenge 02

Lesson 2: Write the task contract, let .github instructions carry the rules

Checkpoint l0210 ptsself-reported — code from verify.pyGitHub Copilot in VS Code

Turn "make it better" into a bounded, testable contract — then make it durable with `.github/copilot-instructions.md` and an `applyTo` instructions file, so every Copilot session starts with the same rules.

Six agent-tool courses share this challenge. GitHub Copilot in VS Code-specific steps are still being written — until they land and pass review, this page defers its canonical to the primary course's copy.

Doing this with your agent? One sentence starts the whole course:

Read https://flypython.com/skills/flypython/SKILL.md and start the FlyPython course `hands-on-with-github-copilot`.

Lesson 2: Write the task contract, let .github instructions carry the rules

Objective

You can read TASK.md as a set of testable statements, trace each statement to a test in tests/test_report_tool.py, and write durable instructions a Copilot session picks up automatically — and you can prove from the response’s References that they were used.

Why this lesson exists

Vague requests produce vague code. “Handle bad rows better” gives an agent permission to guess; “invalid rows are collected in errors with index and reason, valid rows still produce a report” gives it a target and gives you a way to check. In Copilot there is a second failure mode: a rule you typed into one chat does not exist in the next. The contract fixes the task; instructions files fix the working rules.

The lesson

Open TASK.md. Notice what every line has in common: it names an observable behavior, not an implementation. Four statements from the contract, and the tests that pin them:

Contract lineTest
“a JSON file loads into the same record list as CSV”test_load_json_records_returns_list_of_dicts
“invalid rows land in errors with index and reason; valid rows still aggregate”test_invalid_records_are_isolated_with_reasons
“group totals are rounded to two decimals”test_group_totals_are_rounded_to_two_decimals
“the report write is atomic and creates missing parents”test_write_report_creates_missing_parent_directories

Now the durable half. Copilot sessions read two kinds of instructions files:

  • Always-on: .github/copilot-instructions.md at the workspace root (or AGENTS.md, which Copilot also reads). Every request in the workspace gets it.
  • Targeted: .github/instructions/<name>.instructions.md with YAML front matter. applyTo is a glob relative to the workspace root; VS Code attaches the file when the agent creates or modifies a matching file. description lets the agent load it on demand when the task matches.

This course’s working rules only matter when the course folder is being changed, so they belong in a targeted file. Tell the agent:

“Create .github/instructions/flypython-course.instructions.md with front matter name: FlyPython course rules, a one-line description, and applyTo: 'courses/hands-on-with-github-copilot/**', containing these working rules: only starter/report_tool.py may change; tests/, solution/, scenario/ are read-only; one failing test group per turn; run python verify.py starter after each; standard library only.”

Read the file it creates before you approve anything else — the applyTo glob is the part most often wrong.

Then open a new chat session and ask it to change a docstring in starter/report_tool.py and to summarize the rules it is following. Expand References in the response: the instructions file should be listed. If it is not, open the Agent Customizations editor and check the file is discovered, then check that applyTo matches the path the agent edited. Undo the docstring change before you continue (Lesson 3 shows how).

Exercise

Write one contract line for a script you actually own, using the same shape: inputs, outputs, error cases, and “done means <command> exits 0”. Then write two rules for that project and decide which belongs in .github/copilot-instructions.md and which in an applyTo file.

Checkpoint

When you can answer the questions below, claim this checkpoint with python verify.py --attest l02:

  1. Which TASK.md line does test_invalid_records_are_isolated_with_reasons pin, in your own words?
  2. Which mechanism carries rules across sessions — the chat prompt, or an instructions file?
  3. When does an applyTo instructions file get attached, and how did you confirm that yours was?

Expected evidence

Your drafted contract line, your two rules with their file choice, and the References list from the new session showing the instructions file.

Hints

Stuck? Open one at a time.

Hint 1 — What this checkpoint tests

That you can read TASK.md as testable statements, not prose. Every sentence that starts with a function name is a contract line the suite can assert.

Hint 2 — Two kinds of instructions

.github/copilot-instructions.md (or AGENTS.md) is always on for the workspace. A .github/instructions/*.instructions.md file is attached when its applyTo glob matches a file the agent creates or modifies, or loaded on demand when its description matches the task.

Hint 3 — The testability check

If you cannot tell whether a statement is testable, ask: could a suite assert it without reading your mind? Numbers, exit codes, files on disk — never vibes.

Submit

Done? Record it.

Use the 8-character code printed by python verify.py. For a self-reported checkpoint, answer the lesson questions first, then run python verify.py --attest l02.

Youbrowser

Submit the claim code

Your agentauto-submit

Let the agent solve and submit

Hand it this checkpoint (copy button on hover) — it solves, verifies, and submits on its own:

Work on the FlyPython challenge "Hands-on with GitHub Copilot" (course id course-github-copilot), checkpoint l02.
Machine-readable brief: https://flypython.com/api/challenges/hands-on-with-github-copilot
Open the course folder and read TASK.md first — it is the contract.
Rules: smallest change, no new dependencies, never edit tests/ or solution/.
Check starter/ with python verify.py; ask me the lesson questions before using --attest ID for any self-reported checkpoint.
Target: solve only checkpoint l02, and submit it as soon as it passes.

With a token from your agent page (env FLYPYTHON_TOKEN), it records the result directly:

curl -X POST https://flypython.com/api/claims \
  -H "Authorization: Bearer $FLYPYTHON_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"claims":[{"course":"hands-on-with-github-copilot","checkpoint":"l02","code":"<8-char code>"}]}'

Or install the full FlyPython agent skill once and skip the paste.

Files

The starter and verifier

Solving runs on your machine — your agent fetches the course files itself via /api/challenges/hands-on-with-github-copilot/files; you download nothing by hand. Prefer reading the source? Browse the folder on GitHub ↗