Lab 03: Repository and path instructions
At a glance
Section titled “At a glance”Why this matters
Section titled “Why this matters”Before you build custom agents, you need to know what context Copilot already reads. Repository instructions set the rules for every chat. Path instructions add file-specific rules only when their applyTo pattern matches. AGENTS.md gives multi-agent tools a shared guide. This lab shows how to prove which files shaped an answer by checking References in VS Code.
Concepts
Section titled “Concepts”- Repository instructions:
.github/copilot-instructions.md, automatically applied to chat requests in the workspace. - Path instructions:
.github/instructions/*.instructions.md, applied whenapplyTomatches the files in context or the task. - AGENTS.md: a root agent guide read by VS Code and other agent tools when enabled.
- References: the expandable list in a VS Code Chat response that shows instruction files, prompt files, and other context used.
- Customization diagnostics: a VS Code view that helps when instructions are not applied.
Before you begin
Section titled “Before you begin”- Finish Lab 01 and open the repo in VS Code.
- Copilot Chat works in VS Code.
- Leave Power BI Desktop closed. You don’t need it in this lab.
Step 1. Read the always-on instructions
Section titled “Step 1. Read the always-on instructions”Open each file in VS Code:
- Keyboard: Ctrl+P (macOS: Cmd+P), type the file name, press Enter.
- Command Palette: Ctrl+Shift+P (macOS: Cmd+Shift+P), run File: Open File.
- Menu: File > Open File.
Start with the repository instructions:
# Copilot instructions for the Contoso Pharmacy lab
This repository is a hands-on lab. It teaches GitHub Copilot's agent features (instructions, prompt files, skills, custom agents, handoffs, hooks, MCP, the Copilot CLI, the cloud agent, and code review) using a Power BI semantic model stored as code.
## Synthetic data only
Every row of data here is synthetic and generated from a fixed seed. Never add real patient, customer, employee, or tenant data, names, identifiers, or screenshots. Never add credentials, tokens, tenant IDs, workspace IDs, or connection strings. Use placeholders such as `${input:...}` or `${env:...}`.
## Repository map
| Path | What it holds ||---|---|| `fabric/ContosoPharmacy.pbip` | Power BI Project. Open it in Power BI Desktop (Windows only). || `fabric/ContosoPharmacy.SemanticModel/definition/` | The semantic model as TMDL. This is what most tasks change. || `fabric/ContosoPharmacy.Report/definition/` | The report as PBIR JSON. Field references must match model names. || `fabric/ai-prep/` | Drafts for Power BI's Prep data for AI (AI instructions, schema, synonyms, verified answers). || `data/generated/` | Synthetic CSVs. Generated; never edit by hand. || `evaluation/` | Business questions, run files, and the grading rubric. Expected answers are hidden from agents. || `rules/` | Naming conventions and required model objects, read by the checks and the skills. || `tools/python/pharmacy_demo/` | Python tools behind every script: data generation, lint, conventions, grading, lab checks, hooks. || `scripts/` | PowerShell 7 entry points. Learners run these. || `lab/` | Lab verification contract (`checks.yaml`) and checkpoint manifest (`checkpoints.json`). || `site/` | The self-paced lab site (Astro Starlight), published to GitHub Pages. || `.github/agents`, `skills`, `prompts`, `instructions`, `hooks` | The Copilot customizations the labs teach. |
## Commands
Windows PowerShell 7 is the primary shell. The same scripts run in `pwsh` on macOS and Linux.
| Task | Command ||---|---|| Set up the Python environment | `pwsh ./scripts/Initialize-DevEnvironment.ps1` || Validate everything (no Fabric tenant needed) | `pwsh ./scripts/Invoke-Validation.ps1` || TMDL lint only | `pwsh ./scripts/Invoke-Validation.ps1 -Only tmdl` |Then read the shared agent guide:
# Agent guide
Instructions for any coding agent working in this repository. GitHub Copilot also reads `.github/copilot-instructions.md`, which has the full repository map.
## What this repo is
A self-paced lab that improves a Power BI semantic model (PBIP with TMDL and PBIR) using GitHub Copilot's agent features. All data is synthetic. It never needs a Microsoft Fabric tenant.
## Set up and validate
```powershellpwsh ./scripts/Initialize-DevEnvironment.ps1 # creates .venv from hashed lock filespwsh ./scripts/Invoke-Validation.ps1 # data, expected answers, runs, TMDL lint, bindings, customizations, hygienepwsh ./scripts/Invoke-Validation.ps1 -Tests # plus pytest and Pester```
On macOS or Linux the same commands work in `pwsh`. Python tools can also run directly: `.venv/bin/python -m pharmacy_demo validate`.
## Boundaries
- Never edit generated files: `data/generated/**`, `evaluation/expected/**`, `fabric/**/.pbi/cache.abf`, `fabric/**/.pbi/localSettings.json`, or `fabric/**/Copilot/**`.- Never read expected answers or reference DAX while answering the business questions.- Never add real people, customers, credentials, tenant IDs, or workspace IDs.- Never force push or change global Git config.- Repository hooks in `.github/hooks/guardrails.json` enforce the first, second, and fourth rules for Copilot CLI, VS Code, and the cloud agent.
## Custom agents
| Agent | Use it to ||---|---|| `question-tester` | Answer the five business questions from the model and grade the run || `model-assessor` | Review the model against the conventions without changing it || `model-improver` | Fix names, descriptions, relationships, measures, and AI prep drafts || `model-reviewer` | Review a model pull request || `lab-author` | Write or update lab pages (maintainers) |You should see: the repo map, synthetic data boundaries, validation commands, and a rule that agents should not read expected answers while answering business questions.
Step 2. Ask Copilot a repo-wide question
Section titled “Step 2. Ask Copilot a repo-wide question”- Open Copilot Chat: Ctrl+Alt+I (macOS: Ctrl+Cmd+I), or View > Chat.
- Select Ask or a normal chat mode, not a custom agent.
- Ask:
What naming convention should measures follow here? - When the answer finishes, expand References, Used references, or the references list shown under the response. The exact label can vary by VS Code version.
VS Code settings in this repo make instruction usage visible:
{ // Copilot customization: these are the defaults today, set explicitly so the lab behaves the same // if a default changes. "chat.useAgentsMdFile": true, "chat.includeApplyingInstructions": true, "chat.includeReferencedInstructions": true, "chat.useHooks": true,
// Start MCP servers only after you've run them once yourself (Lab 04). "chat.mcp.autostart": "onlyNew",You should see: the answer mentions format strings, descriptions, display folders, or rules/naming-conventions.yaml. The References list includes .github/copilot-instructions.md and may include AGENTS.md.
Step 3. Compare path instructions for TMDL and Python
Section titled “Step 3. Compare path instructions for TMDL and Python”Open a TMDL file first:
- Open
fabric/ContosoPharmacy.SemanticModel/definition/tables/fact_rx_fill.tmdl. - Ask Copilot:
How should I write a description for this column? - Expand the response References.
---applyTo: "fabric/**/*.tmdl"description: Rules for editing the Contoso Pharmacy semantic model in TMDL.---# TMDL files
- Indent with tabs, one level per nesting depth. Properties of an object sit one tab deeper than the object line.- Put descriptions on the line directly above the object as `/// text`. Keep them under 200 characters, because Power BI Copilot reads only the first 200.- Quote names that contain spaces or special characters with single quotes: `column 'Store Key'`, `measure 'MoM %'`. In DAX, refer to columns as `'Table Name'[Column Name]` and to measures as `[Measure Name]`.- Never change or remove a `lineageTag`. When you add an object, leave `lineageTag` out; Desktop adds one when it saves.- When you rename a column, keep `sourceColumn` pointing at the CSV header. Rename references in `relationships.tmdl`, measures, sort-by columns, hierarchies, `cultures/en-US.tmdl`, and the report.- Set `summarizeBy: none` on keys, IDs, years, month numbers, and other numbers that must not be added up. Only the columns listed as `additive` in `rules/naming-conventions.yaml` may summarize.- Hide keys and sort helpers with `isHidden`.- Every measure needs a description, a `formatString`, and a `displayFolder` from the list in `rules/naming-conventions.yaml`.- Relationships to Date, Store, and Medication are many-to-one and single direction. Don't add `crossFilteringBehavior: bothDirections`.- Don't edit `expressions.tmdl` unless the task is about the data source. The `DataFolderPath` parameter must stay a placeholder path, never a personal path.- After editing, run `pwsh ./scripts/Invoke-Validation.ps1 -Only tmdl`. Load the `tmdl-authoring` skill for syntax details.Then compare with Python:
- Open
tools/python/pharmacy_demo/labcheck/checks.py. - Ask Copilot:
What style should I follow if I add a helper function here? - Expand the response References.
---applyTo: "tools/python/**/*.py"description: Conventions for the pharmacy_demo Python tools.---# Python tools
- Target Python 3.12 or later. Use `pathlib.Path` for every path and open text files with `encoding="utf-8"`. Write files with `newline="\n"` so output matches on Windows and Linux.- Never hardcode `/usr`, `/bin`, `/tmp`, drive letters, or a user's home folder. Find the repo root with `pharmacy_demo.paths.repo_root()`.- The command-line entry point is `pharmacy_demo/cli.py`. Every PowerShell script in `scripts/` wraps one subcommand, so keep flags stable.- Output meant for other tools goes to stdout as JSON when `--json` is set. Human output is short, one line per finding.- Exit codes: 0 pass, 1 findings or failure, 2 usage or setup error.- Dependencies are pinned with hashes in `tools/python/requirements*.txt`. Don't add a package without updating those files.- Add or update tests in `tools/python/tests/`. Run `.venv/bin/python -m pytest -q tools/python/tests` (on Windows, `.venv\Scripts\python`) and `ruff check tools/python`.- Modules under `pharmacy_demo/modelgen/` and `samples.py` hold lab answers. They're for maintainers only; agents helping learners shouldn't read them.You should see: the TMDL answer references tmdl.instructions.md and talks about /// descriptions, tabs, lineage tags, and validation. The Python answer references python.instructions.md and talks about Python 3.12, pathlib.Path, UTF-8, exit codes, and tests.
Step 4. Create a path instructions file for rules
Section titled “Step 4. Create a path instructions file for rules”The lab check requires a new .github/instructions/*.instructions.md file whose applyTo pattern matches real repo files. Create rules.instructions.md for the YAML rules under rules/.
@'---applyTo: 'rules/**'description: Rules for editing lab convention YAML files.---# Rule files
- Keep rule IDs stable because scripts, skills, and lab checks refer to them.- Explain why a rule exists before changing thresholds or required objects.- Run `pwsh ./scripts/Invoke-Validation.ps1 -Only customizations` after editing rules.'@ | Set-Content -Path .github/instructions/rules.instructions.md -Encoding utf8cat > .github/instructions/rules.instructions.md <<'RULES'---applyTo: 'rules/**'description: Rules for editing lab convention YAML files.---# Rule files
- Keep rule IDs stable because scripts, skills, and lab checks refer to them.- Explain why a rule exists before changing thresholds or required objects.- Run `pwsh ./scripts/Invoke-Validation.ps1 -Only customizations` after editing rules.RULESOpen rules/naming-conventions.yaml, then ask Copilot: What should I be careful about before changing a convention rule?
You should see: the response uses your new guidance, and References includes .github/instructions/rules.instructions.md. The file has non-empty frontmatter with applyTo: 'rules/**', and that pattern matches real files under rules/.
Step 5. Review the shipped path instructions
Section titled “Step 5. Review the shipped path instructions”Open each shipped file under .github/instructions/. They are scoped to different parts of the repo:
tmdl.instructions.mdfor semantic model TMDL.pbir.instructions.mdfor report JSON.python.instructions.mdfor Python tools.powershell.instructions.mdfor scripts.evaluation.instructions.mdfor business questions and run files.site.instructions.mdfor the lab site.
---applyTo: "fabric/**/*.Report/**"description: Rules for the Contoso Pharmacy report in PBIR format.---# PBIR report files
- The report is PBIR: one `visual.json` per visual under `definition/pages/<page>/visuals/<visual>/`. Folder names are stable IDs; don't rename them.- A field reference has an `Entity` (table name) and a `Property` (column or measure name). Both must match the semantic model exactly, including spaces and case.- When the model renames a table, column, or measure, update every `Entity`, `Property`, and `queryRef` that uses the old name. Also update `nativeQueryRef` and any `displayName` that shows the old name.- Don't change visual positions, sizes, or formatting unless the task asks for it.- Keep JSON valid and keep the `$schema` line. Two-space indentation, as Desktop writes it.- After editing, run `pwsh ./scripts/Test-ReportBindings.ps1`. The `pbir-rebinding` skill has the full procedure.---applyTo: "scripts/**/*.ps1"description: Conventions for the lab's PowerShell 7 scripts.---# PowerShell scripts
- Target PowerShell 7.2 or later (`#Requires -Version 7.2`). Scripts must run on Windows, macOS, and Linux under `pwsh`.- Start every script with comment-based help (`.SYNOPSIS`, `.DESCRIPTION`, `.PARAMETER`, `.EXAMPLE`) and `[CmdletBinding(PositionalBinding = $false)]`. The lab site generates its script reference from the help.- Take list parameters as comma-separated strings and split them inside the script, so `-Rule C07,C08` works the same from any shell.- Dot-source `_Common.ps1` for `Get-RepoRoot`, `Get-VenvPython`, and `Invoke-PharmacyDemo`. Build paths with `Join-Path` and quote them with `-LiteralPath`, because learners clone into folders with spaces.- Never install software. Check for it and print the install command instead.- Pass arguments to external tools as arrays. Use `Invoke-Git -Arguments @(...)` from `_Checkpoints.ps1` for Git.- Wrap single results in `@()` before indexing, because PowerShell unrolls one-item arrays.- Guard Windows-only code with `$IsWindows` and exit 0 with a clear SKIP message elsewhere.- Run `Invoke-ScriptAnalyzer -Path scripts -Recurse -Settings PSScriptAnalyzerSettings.psd1` and `Invoke-Pester -Path scripts/tests` before you commit.View .github/instructions/powershell.instructions.md on GitHub
---applyTo: "evaluation/**"description: Rules for business questions, run files, and grading.---# Evaluation files
- `evaluation/expected/*.json` are generated by the DuckDB oracle from the synthetic CSVs. Never edit them. Maintainers regenerate them with `pwsh ./scripts/Update-ExpectedResults.ps1`.- When you answer questions as the `question-tester` agent, don't open `evaluation/questions.yaml` or anything under `evaluation/expected/`. Use `pwsh ./scripts/Get-BusinessQuestions.ps1`, which leaves out the reference answers.- A run file lives at `evaluation/runs/<label>.json` and must match `evaluation/run.schema.json`. Labels are lowercase with hyphens, for example `local-baseline`.- Each answer's `rows` use the `answer_columns` names from the questions output, in that order. Put every assumption you made in `assumptions`.- Never write the `grade` block yourself. `pwsh ./scripts/Grade-QuestionRun.ps1 -Run <label>` writes it.- `sample-*.json` runs are illustrative and committed. `local-*.json` runs are yours and gitignored.- Scoring rules are in `evaluation/rubric.md`.View .github/instructions/evaluation.instructions.md on GitHub
---applyTo: "site/**"description: Rules for the self-paced lab site (Astro Starlight).---# Lab site
- Lab pages live in `site/src/content/docs/labs/NN-slug.mdx` and follow the ten-section template. Load the `lab-page-authoring` skill before writing or editing a lab page.- Show repository files with the `RepoFile` component, never by pasting their contents, so the site can't drift from the repo.- Every lab ends with a `VerifyStep` whose `lab` matches an entry in `lab/checks.yaml`. Step headings use ids `step-1`, `step-2`, and so on, because lab check hints link to them.- Windows PowerShell 7 comes first in every tab set. Mark Windows-only steps with `PlatformBadge`.- No analytics, external scripts, fonts, or images from other hosts. `npm run check` fails the build if the output references another site.- Write in plain, direct language: short sentences, no em or en dashes, no emojis. Screenshots show synthetic data and a demo account only.- Run `npm run check` and `npm run build` in `site/` before you commit.You should see: each file has frontmatter with applyTo, followed by short rules for that path. They are instructions, not scripts, so they guide Copilot but don’t enforce anything by themselves.
Step 6. Check instruction diagnostics and settings
Section titled “Step 6. Check instruction diagnostics and settings”If a reference is missing, use VS Code’s diagnostics before editing files blindly.
- Open the Command Palette: Ctrl+Shift+P (macOS: Cmd+Shift+P), or View > Command Palette.
- Run Chat: Configure Instructions to see available instruction files.
- Run Chat: Open Customizations if your VS Code version has the Agent Customizations editor.
- In the Chat view, open the More Actions menu, then look for Diagnostics when an instruction file is not applied.
- Confirm these settings are enabled in
.vscode/settings.json:chat.includeApplyingInstructions,chat.includeReferencedInstructions, andchat.useAgentsMdFile.
The VS Code docs say to use References when an applyTo pattern may not be matching, and to check those settings when instructions aren’t applied.
You should see: your workspace instruction files listed, with source locations. No JSON or YAML parse errors should appear for rules.instructions.md.
Step 7. Compare which surfaces read which instructions
Section titled “Step 7. Compare which surfaces read which instructions”Read the customization reference before later labs add agents, prompts, skills, MCP, hooks, and code review.
- Open Copilot customization.
- Open Copilot surfaces.
- Compare VS Code Chat, Copilot CLI, Copilot cloud agent, and Copilot code review.
- Note which surfaces use repository instructions, path instructions, and
AGENTS.md.
You should see: repository instructions and path instructions are shared context, while enforcement comes from validation scripts, CI, hooks, and code review.
Step 8. Check the diff you created
Section titled “Step 8. Check the diff you created”git status --short .github/instructionsgit diff -- .github/instructions/rules.instructions.mdgit status --short .github/instructionsgit diff -- .github/instructions/rules.instructions.mdYou should see: one new file, .github/instructions/rules.instructions.md, with the applyTo: 'rules/**' frontmatter and the three rules you added.
Verify your work
Section titled “Verify your work”Run this from the repo root in a PowerShell 7 terminal (Terminal > New Terminal in VS Code):
pwsh ./scripts/lab/Test-LabProgress.ps1 -Lab 03pwsh ./scripts/lab/Test-LabProgress.ps1 -Lab 03Checks marked Windows only print SKIP on macOS. SKIP doesn't count as a failure.
When everything is done you should see:
PASS L03-instructions You added a path instructions file whose applyTo matches repo files
Lab 03: 1 of 1 checks passed.Each FAIL line prints a hint and a link back to the step on this page that fixes it. The command exits with code 0 when every required check passes.
| Check | What it looks at | If it fails |
|---|---|---|
L03-instructions | You added a path instructions file whose applyTo matches repo files | Create .github/instructions/rules.instructions.md with applyTo: 'rules/**'. Go to step 4 |
Troubleshooting
Section titled “Troubleshooting”References don’t show any instruction files
Check .vscode/settings.json for chat.includeApplyingInstructions, chat.includeReferencedInstructions, and chat.useAgentsMdFile. Then reload VS Code with Developer: Reload Window from the Command Palette.
Your new instructions file doesn’t apply
Check the frontmatter exactly. The lab check expects a new .github/instructions/*.instructions.md file, an applyTo value, non-empty body text, and a glob that matches real repo files. rules/** matches the files in rules/.
Copilot answers with generic Power BI advice
Make sure the repo folder is the VS Code workspace root. If you opened only fabric/, VS Code won’t find .github/copilot-instructions.md or AGENTS.md at the root.
The Command Palette labels differ from the lab
VS Code Copilot UI labels move. Use the closest command with Instructions, Customizations, or Diagnostics in the name, then confirm the file names in References.
Knowledge check
Section titled “Knowledge check”Recap and next
Section titled “Recap and next”You read the repo’s always-on instructions, confirmed path instructions in VS Code References, created a new rules-scoped instructions file, and learned where to diagnose missing instruction context. Next you connect MCP so agents can inspect the Power BI model with tools.
Go further
Section titled “Go further”- Add one more rule to
rules.instructions.md, ask a rules question again, and see whether the answer changes. - Open Copilot customization and map instructions, skills, prompts, agents, hooks, and MCP to the labs that use them.
Something wrong or unclear on this page? Open a lab feedback issue. The form is prefilled with this page's name. Nothing is sent until you submit it, and please don't include screenshots of real accounts.