Skip to content

Lab 01: Get your copy and explore the repo

Time
About 30 minutes
Level
intro
Platforms
Windows 11, macOS
Copilot surfaces
github.com, VS Code, Copilot CLI
You'll use
repo-setup, validation, synthetic-data
Starts from
None needed
Ends at
None needed
Last verified
Not yet run end to end on Windows 11

Works on macOS

Nobody has run this lab end to end on Windows 11 yet. The steps follow the current docs for each tool, but menu labels may differ. The verify command at the end is the source of truth, and feedback is welcome.

You need your own repository, because later labs create branches, commits, pull requests, custom instructions, and local run files. The upstream repo is the template and checkpoint source. Your copy is the workspace where you can experiment safely. By the end of this lab, the local validation passes even though the semantic model is still intentionally weak.

  • Template copy: a new GitHub repo created from the upstream lab repo. Lab checks fail if origin still points at the upstream repo.
  • Upstream remote: a read-only remote named upstream, used by checkpoint restore. See Scripts.
  • Synthetic data: deterministic CSV files committed to the repo. See Synthetic data model.
  • Validation: local checks for data, expected answers, TMDL, PBIR bindings, customizations, and hygiene.
  • Recommended extensions: VS Code prompts you to install the repo’s extensions from .vscode/extensions.json.
  • Finish Lab 00 or have equivalent tools installed.
  • Sign in to GitHub in your browser.
  • Use a short local path on Windows, for example C:\src\contoso-pharmacy-lab. Spaces work, but short paths make tooling errors easier to read.

Step 1. Create your own repository from the template

Section titled “Step 1. Create your own repository from the template”
  1. Open the upstream repo in your browser: https://github.com/sabajamalian/fabric-powerbi-ai-devops-demo.
  2. Select Use this template > Create a new repository.
  3. Pick your GitHub user or organization as Owner.
  4. Name it contoso-pharmacy-lab or another short name.
  5. Choose public or private visibility.
  6. Leave Include all branches off.
  7. Select Create repository.

You should see: a new repo under your account. Its file list looks like the upstream repo, but the URL starts with https://github.com/<your-github-user>/.

Terminal window
mkdir C:\src -Force
git clone https://github.com/<your-github-user>/contoso-pharmacy-lab.git C:\src\contoso-pharmacy-lab
cd C:\src\contoso-pharmacy-lab
git remote -v

You should see: origin points at your copy, not sabajamalian/fabric-powerbi-ai-devops-demo.

The checkpoint scripts fetch known-good lab states from upstream. They need a remote named exactly upstream.

Terminal window
git remote add upstream https://github.com/sabajamalian/fabric-powerbi-ai-devops-demo.git
git remote -v

You should see: two remotes. origin is your copy. upstream is https://github.com/sabajamalian/fabric-powerbi-ai-devops-demo.git.

Step 4. Initialize the development environment

Section titled “Step 4. Initialize the development environment”

First run the prerequisite check from the repo root. It installs nothing.

Terminal window
pwsh ./scripts/Test-Prerequisites.ps1
pwsh ./scripts/Initialize-DevEnvironment.ps1

The initialization script finds Python 3.12, creates .venv, installs pinned hashed packages, installs the pharmacy_demo tools in editable mode, and runs validation.

scripts/Initialize-DevEnvironment.ps1 (lines 35-64)
$system = Find-SystemPython
if (-not $system) {
Write-Host 'Python 3.12 or later was not found. Run scripts/Test-Prerequisites.ps1 for the install command.' -ForegroundColor Red
exit 1
}
Write-Host "Using Python $($system.Version) at $($system.Command)"
if ($Force -and (Test-Path -LiteralPath $venv)) {
Write-Host 'Removing the existing .venv'
Remove-Item -LiteralPath $venv -Recurse -Force
}
if (-not (Get-VenvPython -Root $root)) {
Write-Host "Creating $venv"
$createArgs = @($system.Arguments) + @('-m', 'venv', $venv)
& $system.Command @createArgs
if ($LASTEXITCODE -ne 0) { throw 'python -m venv failed.' }
}
$python = Get-VenvPython -Root $root
Write-Section 'Pinned packages'
$requirements = Join-Path $root 'tools' 'python' 'requirements-dev.txt'
& $python -m pip install --disable-pip-version-check --quiet --require-hashes -r $requirements
if ($LASTEXITCODE -ne 0) { throw 'pip install of the pinned requirements failed.' }
# setuptools is pinned in requirements-dev.txt, so the editable build doesn't fetch anything unhashed.
& $python -m pip install --disable-pip-version-check --quiet --no-deps --no-build-isolation -e (Join-Path $root 'tools' 'python')
if ($LASTEXITCODE -ne 0) { throw 'Installing the pharmacy_demo package failed.' }
Write-Host 'Installed pharmacy_demo and its pinned dependencies.'
if ($Site) {
Write-Section 'Lab site packages'

You should see: Installed pharmacy_demo and its pinned dependencies., then validation output. If validation fails, fix the first required prerequisite before moving on.

The committed CSVs are generated from a fixed seed. This check proves nothing drifted during clone or setup.

Terminal window
pwsh ./scripts/New-SyntheticData.ps1 -Check
data/README.md (lines 1-18)
# Synthetic data
Everything in this folder is synthetic. It was produced by a seeded random generator and describes fictional stores, generic medication names, and anonymous fill events. There are no patients, prescribers, members, addresses, or health records, and the repository is not meant to hold PHI. Don't add real data here, even for a quick test.
## What's here
| Path | What it is |
|---|---|
| `generated/dim_date.csv` | One row per day, 2024-01-01 to 2025-12-31 (731 rows). |
| `generated/dim_store.csv` | 12 fictional stores in four regions. |
| `generated/dim_med.csv` | 60 generic medications in eight therapeutic categories. Codes like `M001` aren't real drug codes. |
| `generated/fact_rx_fill.csv` | About 41,500 fill events, new and refill. |
| `schema/tables.json` | Column names, types, and descriptions for every file. |
The column names are short, database-style codes on purpose (`rgn`, `ther_cat`, `proc_mins`, `fill_typ`). The baseline semantic model copies them as-is, and the labs turn them into business names with Copilot's help.
## The signals the questions depend on

You should see: output that says the generated data matches the seed, or no findings and exit code 0.

Terminal window
pwsh ./scripts/Invoke-Validation.ps1

Validation checks that the repo is mechanically correct. It does not say the model is AI-ready.

scripts/Invoke-Validation.ps1 (lines 2-16)
<#
.SYNOPSIS
Runs every validation step that doesn't need a Fabric tenant or Power BI Desktop.
.DESCRIPTION
Checks that the synthetic data matches the seed, the expected answers are current, the question
and run files match their schemas, the TMDL lints clean, every report visual binds to a field
that exists, and the repository hygiene rules pass (no PHI-like columns, identifiers, secrets,
forbidden files, or dashes in prose). This is the same check CI runs on every pull request.
.PARAMETER Only
Run only these steps, comma-separated: data, expected, questions, runs, tmdl, bindings, customizations, hygiene.
.PARAMETER Json
Print results as JSON.
.PARAMETER Tests
Also run the Python unit tests (pytest) and the Pester tests.
.EXAMPLE

You should see: PASS lines for data, expected answers, questions, runs, TMDL, bindings, customizations, and hygiene.

Step 7. Open the repo in VS Code and install recommended extensions

Section titled “Step 7. Open the repo in VS Code and install recommended extensions”
Terminal window
code .
  1. If VS Code asks whether you trust the authors, select Yes, I trust the authors.
  2. If VS Code offers recommended extensions, select Install.
  3. If the prompt doesn’t appear, open Extensions with Ctrl+Shift+X (macOS: Cmd+Shift+X), or View > Extensions.
  4. In the Extensions view, select Filter > Recommended.
  5. Install the workspace recommendations.
.vscode/extensions.json
{
// Recommended extensions for the Contoso Pharmacy lab. VS Code offers to install them when you
// open the folder. Nothing installs automatically.
"recommendations": [
"GitHub.copilot-chat",
"analysis-services.TMDL",
"analysis-services.powerbi-modeling-mcp",
"ms-vscode.powershell",
"ms-python.python",
"charliermarsh.ruff",
"redhat.vscode-yaml",
"astro-build.astro-vscode"
]
}

You should see: Copilot Chat, TMDL, Power BI Modeling MCP, PowerShell, Python, Ruff, YAML, and Astro extensions listed as installed or already available.

Open Explorer with Ctrl+Shift+E (macOS: Cmd+Shift+E), or View > Explorer. Expand the main folders.

  • Directoryfabric/
    • ContosoPharmacy.pbip
    • DirectoryContosoPharmacy.SemanticModel/definition/
      • …
    • DirectoryContosoPharmacy.Report/definition/
      • …
  • Directorydata/
    • Directorygenerated/
      • …
    • Directoryschema/
      • …
  • Directoryevaluation/
    • Directoryexpected/
      • …
    • Directoryruns/
      • …
  • Directory.github/
    • Directoryagents/
      • …
    • Directoryinstructions/
      • …
    • Directoryprompts/
      • …
    • Directoryskills/
      • …
    • Directoryhooks/
      • …
    • Directoryworkflows/
      • …
  • Directory.vscode/
    • …
  • Directoryscripts/
    • …
  • Directorylab/
    • …
  • Directorytools/python/pharmacy_demo/
    • …

The always-on repo instructions describe the same map for agents:

.github/copilot-instructions.md (lines 9-24)
## 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. |

You should see: the Power BI project under fabric/, Copilot customizations under .github/, validation contracts under lab/, and Python tooling under tools/python/pharmacy_demo/.

You should not have created source changes yet. Local outputs such as .venv are ignored.

Terminal window
git status --short

You should see: no tracked file changes. If you installed VS Code extensions or created .venv, those should not appear in git status.

Run the Lab 01 check from the repo root. Then run the Lab 00 check if you want the full workstation report.

Run this from the repo root in a PowerShell 7 terminal (Terminal > New Terminal in VS Code):

Terminal window
pwsh ./scripts/lab/Test-LabProgress.ps1 -Lab 01

When everything is done you should see:

Expected output
PASS L01-not-upstream You're working in your own copy, not the upstream repo
PASS L01-upstream-remote Remote 'upstream' points at the lab repo
PASS L01-venv Python environment .venv with the pharmacy_demo tools
PASS L01-data Synthetic data matches the fixed seed
PASS L01-validation Repository validation passes
Lab 01: 5 of 5 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.

CheckWhat it looks atIf it fails
L01-not-upstreamYou're working in your own copy, not the upstream repoCreate a repo from the template (Use this template), then clone that one. Go to step 1
L01-upstream-remoteRemote 'upstream' points at the lab repogit remote add upstream https://github.com/sabajamalian/fabric-powerbi-ai-devops-demo.git Go to step 3
L01-venvPython environment .venv with the pharmacy_demo toolsRun pwsh ./scripts/Initialize-DevEnvironment.ps1 Go to step 4
L01-dataSynthetic data matches the fixed seedRun pwsh ./scripts/New-SyntheticData.ps1 to regenerate it. Go to step 5
L01-validationRepository validation passesRun pwsh ./scripts/Invoke-Validation.ps1 and fix the first error it prints. Go to step 6
The template button is missing

Make sure you’re on the upstream repo page, not a file view or a fork page. If GitHub changes the button label, use the green Code button menu and look for template creation from there.

The clone fails with a long path error on Windows

Run git config --global core.longpaths true, open a new PowerShell 7 terminal, and clone to a shorter folder such as C:\src\contoso-pharmacy-lab.

PowerShell blocks a script

Open PowerShell 7 and run Set-ExecutionPolicy -Scope CurrentUser RemoteSigned. If your device policy blocks that, run the script with pwsh -ExecutionPolicy Bypass -File ./scripts/Initialize-DevEnvironment.ps1.

Python packages fail behind a proxy

Use your company’s approved proxy settings for pip. The script uses pinned hashes, so don’t remove --require-hashes or install unpinned packages to work around the proxy.

Validation passes, but the model still looks bad

That’s expected. Validation checks whether the repo is internally consistent. The baseline model is intentionally weak, and the later labs improve its AI readiness.

Why do you create your own repo instead of working in the upstream template?

Show the answer

Because the lab checks require origin to be your copy, and later labs need your branches and pull requests.

Your copy is where you make commits and PRs. The upstream remote stays read-only and supplies checkpoints.

What does Invoke-Validation.ps1 prove at this point?

Show the answer

The repo parses, generated data matches, expected answers are current, TMDL lints, report bindings resolve, and hygiene checks pass.

Validation is a mechanical repo check. AI readiness comes later.

Why are synthetic CSV files committed to the repo?

Show the answer

So every learner and CI run uses the same deterministic data with no Fabric tenant.

The data is synthetic and deterministic, so the lab can run offline and the grader can compare exact expected answers.

You created your own template copy, added the upstream remote, initialized .venv, confirmed the synthetic data, ran validation, installed recommended VS Code extensions, and checked that the working tree is clean. Next you open the PBIP and inspect the baseline model.

Next: Lab 02: Meet the baseline model

  • Run pwsh ./scripts/lab/Test-LabProgress.ps1 -Lab 00 now that the repo exists.
  • Open Scripts and compare the generated reference with the comment-based help in the PowerShell files.