diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 62c23253..4e6b963e 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -60,6 +60,8 @@ This is a crowdfunding platform for games with a developer theme. The applicatio - `scripts/setup-env.sh`: Performs installation of all Python and Node dependencies - `scripts/run-server-tests.sh`: Calls setup-env, then runs all Python tests - `scripts/start-app.sh`: Calls setup-env, then starts both backend and frontend servers + - `scripts/new-scenario.py`: Scaffolds a new workshop scenario (run with `python scripts/new-scenario.py `) + - `scripts/validate-scenario.py`: Validates a scenario's structure and configuration (run with `python scripts/validate-scenario.py ` or `--all`) ## Repository Structure @@ -75,4 +77,8 @@ This is a crowdfunding platform for games with a developer theme. The applicatio - `src/styles/`: CSS and Tailwind configuration - `scripts/`: Development and deployment scripts - `data/`: Database files +- `scenarios/`: Workshop scenario packs (one subdirectory per scenario) + - Each scenario has a `scenario.yml` and optional `overrides/` for exercise-specific content +- `docs/authoring/`: Documentation for workshop authors +- `.github/prompts/`: Copilot prompt files (e.g. `create-scenario-app.prompt.md`) - `README.md`: Project documentation diff --git a/.github/prompts/create-scenario-app.prompt.md b/.github/prompts/create-scenario-app.prompt.md new file mode 100644 index 00000000..c3e14613 --- /dev/null +++ b/.github/prompts/create-scenario-app.prompt.md @@ -0,0 +1,93 @@ +--- +description: Create or update a sample application to use as a workshop scenario +mode: agent +--- + +# Create or update a workshop scenario application + +You are helping a workshop author create or update a sample application that will be used as the hands-on codebase for the "Agents in the SDLC" workshop. The workshop teaches learners how to use GitHub Copilot's agent capabilities across the software development lifecycle. + +## Your task + +${input:task:Choose one — (a) Create a brand-new sample application, or (b) Adapt an existing application to fit the workshop. Describe your choice and the application concept here.} + +## Workshop exercise requirements + +The sample application must support the following exercises. Review each requirement and confirm your application design meets it before generating code. + +### Exercise 1 — MCP and issue creation +- No application requirements (learners create GitHub issues for their backlog). + +### Exercise 2 — Custom instructions +- The application must have an API with unit tests. +- The application must have a UI (frontend). +- The codebase should lack docstrings/comment headers so learners can add them. +- A `.github/copilot-instructions.md` should NOT exist yet (learners create it). +- A `.github/instructions/` directory with one or more `*.instructions.md` files for specific languages or file types IS expected (learners reference these). + +### Exercise 3 — Copilot agent mode (implement a new feature) +- The application must have an API endpoint that returns a list of the primary entities (e.g. `/api/games`). +- The primary entities must have at least two categorical attributes suitable for filtering (e.g. `category` and `publisher`). +- The application must have a frontend page that displays those entities. +- The existing filtering functionality must NOT be implemented yet — learners implement it. +- The API must have a test suite that Copilot can run as part of implementing the feature. + +### Exercise 4 — Copilot coding agent (async tasks) +- The application must lack docstrings/comment headers (first async task: add them). +- The application must have a set of CRUD endpoints that are partially implemented — specifically, only the "read" (GET) endpoints exist. Learners assign the task of adding create/update/delete endpoints to Copilot coding agent. +- A `.github/workflows/copilot-setup-steps.yml` must exist that installs all dependencies and runs tests. This file is pre-created ahead of the workshop. + +### Exercise 5 — Custom agents (accessibility) +- The application must have a UI with a dark colour scheme. +- The UI must not yet have a high-contrast or accessibility toggle — learners add it with a custom accessibility agent. +- A `.github/agents/accessibility.md` custom agent definition must exist that describes how to implement accessibility features for this UI. + +### Exercise 6 — Managing agents +- No additional application requirements. + +### Exercise 7 — Iterating on Copilot's work +- No additional application requirements beyond what exercises 4 and 5 created. + +## Application structure requirements + +- The application must be runnable inside a **GitHub Codespace** using a `.devcontainer/` configuration. +- A `scripts/` directory must contain: + - `setup-env.sh` — installs all dependencies. + - `run-server-tests.sh` — calls setup and runs backend tests. + - `start-app.sh` — calls setup and starts both frontend and backend servers. +- The application must use a **database** (SQLite is fine) with seed data so it works out of the box. +- **Separate frontend and backend** processes are required (e.g. a Python/Node API on one port, a Svelte/React/Vue SPA on another). + +## What to generate + +1. **Describe the application concept** — company name, what the app does, primary entities, and tech stack. +2. **Review each exercise requirement** and confirm the application design satisfies it. Note any gaps. +3. **Generate the full application** including: + - Backend API with seed data and tests (only GET endpoints for the primary entities). + - Frontend displaying the primary entities (no filtering yet). + - `.devcontainer/devcontainer.json` for Codespaces. + - `scripts/setup-env.sh`, `scripts/run-server-tests.sh`, `scripts/start-app.sh`. + - `.github/workflows/copilot-setup-steps.yml`. + - `.github/agents/accessibility.md`. + - `.github/instructions/` with relevant instruction files for the chosen stack. + - A `README.md` describing the application and how to run it. +4. **Do NOT generate**: + - `.github/copilot-instructions.md` (learners create this in exercise 2). + - Filter endpoints or filter UI (learners build these in exercise 3). + - Create/update/delete endpoints (learners assign these to coding agent in exercise 4). + - Docstrings or comment headers (learners add these via coding agent in exercise 4). + - High-contrast mode (learners build this with the custom agent in exercise 5). + +## Validation checklist + +Before finishing, confirm: + +- [ ] Application runs in a fresh Codespace with `scripts/start-app.sh`. +- [ ] Backend tests pass with `scripts/run-server-tests.sh`. +- [ ] `copilot-setup-steps.yml` completes successfully when triggered via `workflow_dispatch`. +- [ ] Primary entities list endpoint returns at least 8–10 seed records. +- [ ] Each entity has at least two categorical attributes suitable for filtering. +- [ ] The UI renders the entity list with no errors. +- [ ] Dark colour scheme is present in the UI. +- [ ] `accessibility.md` custom agent exists in `.github/agents/`. +- [ ] No filtering, no CRUD-write endpoints, no docstrings in the initial state. diff --git a/.github/workflows/render-exercises.yml b/.github/workflows/render-exercises.yml new file mode 100644 index 00000000..e81644cc --- /dev/null +++ b/.github/workflows/render-exercises.yml @@ -0,0 +1,44 @@ +name: "Render Exercises" + +# Runs whenever workshop content or scenario steps change, and on demand. +on: + push: + branches: [main] + paths: + - "workshop-content/**" + - "scenarios/**" + pull_request: + branches: [main] + paths: + - "workshop-content/**" + - "scenarios/**" + workflow_dispatch: + +jobs: + render: + name: Render all scenarios + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.x" + + - name: Validate all scenarios + run: python scripts/validate-scenario.py --all + + - name: Render all scenarios + run: python scripts/render-scenario.py --all rendered/ + + - name: Upload rendered exercises + uses: actions/upload-artifact@v4 + with: + name: rendered-exercises + path: rendered/ + retention-days: 30 diff --git a/client/package-lock.json b/client/package-lock.json index 6011fa3d..d4b233e8 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1633,7 +1633,6 @@ "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-5.1.1.tgz", "integrity": "sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ==", "license": "MIT", - "peer": true, "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", "debug": "^4.4.1", @@ -2172,7 +2171,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2325,7 +2323,6 @@ "resolved": "https://registry.npmjs.org/astro/-/astro-5.15.5.tgz", "integrity": "sha512-A56u4H6gFHEb0yRHcGTOADBb7jmEwfDjQpkqVV/Z+ZWlu6mYuwCrIcOUtZjNno0chrRKmOeZWDofW23ql18y3w==", "license": "MIT", - "peer": true, "dependencies": { "@astrojs/compiler": "^2.12.2", "@astrojs/internal-helpers": "0.7.4", @@ -2561,7 +2558,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -5291,7 +5287,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -5669,7 +5664,6 @@ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.46.1.tgz", "integrity": "sha512-33xGNBsDJAkzt0PvninskHlWnTIPgDtTwhg0U38CUoNP/7H6wI2Cz6dUeoNPbjdTdsYTGuiFFASuUOWovH0SyQ==", "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -5935,7 +5929,6 @@ "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.43.5.tgz", "integrity": "sha512-HQoZArIewxQVNedseDsgMgnRSC4XOXczxXLF9rOJaPIJkg58INOPUiL8aEtzqZIXNSZJyw8NmqObwg/voajiHQ==", "license": "MIT", - "peer": true, "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", @@ -6108,7 +6101,6 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -6497,7 +6489,6 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", @@ -6939,6 +6930,22 @@ "prettier": "2.8.7" } }, + "node_modules/yaml-language-server/node_modules/prettier": { + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz", + "integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==", + "license": "MIT", + "optional": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/yaml-language-server/node_modules/request-light": { "version": "0.5.8", "resolved": "https://registry.npmjs.org/request-light/-/request-light-0.5.8.tgz", @@ -7109,7 +7116,6 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/docs/authoring/README.md b/docs/authoring/README.md new file mode 100644 index 00000000..4b6c56fc --- /dev/null +++ b/docs/authoring/README.md @@ -0,0 +1,16 @@ +# Workshop Authoring Documentation + +This directory contains documentation for **workshop authors** — people who want to contribute content or add new scenario applications to the "Agents in the SDLC" workshop. + +## Contents + +| File | Purpose | +|---|---| +| [new-scenario-guide.md](./new-scenario-guide.md) | Step-by-step guide for adding a new scenario application | + +## Quick links + +- **Scenario directory**: [`scenarios/`](../../scenarios/) — existing scenario packs +- **Scaffolding script**: `python scripts/new-scenario.py ` +- **Validation script**: `python scripts/validate-scenario.py ` +- **AI prompt for app creation**: [`.github/prompts/create-scenario-app.prompt.md`](../../.github/prompts/create-scenario-app.prompt.md) diff --git a/docs/authoring/new-scenario-guide.md b/docs/authoring/new-scenario-guide.md new file mode 100644 index 00000000..16e42485 --- /dev/null +++ b/docs/authoring/new-scenario-guide.md @@ -0,0 +1,240 @@ +# Authoring Guide — Adding a New Workshop Scenario + +This guide walks you through every step needed to introduce a new sample application into the "Agents in the SDLC" workshop. After following it, learners will be able to use your application as the concrete codebase they work with while exploring GitHub Copilot's agent capabilities. + +## Prerequisites + +- Python 3.9 or later (for the scaffolding and validation scripts). +- A sample application repository accessible on GitHub. If you don't have one yet, see [Using the AI prompt to create a sample app](#using-the-ai-prompt-to-create-a-sample-app). +- Familiarity with the workshop structure — skim through `workshop-content/README.md` and a couple of the exercise files before you begin. + +--- + +## Step 1 — Understand what makes a good workshop scenario + +A scenario application should: + +- **Be small enough to navigate quickly.** Learners spend time in the codebase during exercises; a sprawling monorepo is hard to work with in a short workshop. +- **Have clear separation between frontend and backend** (even if it's a single-language stack). Exercises like 3 and 4 assume there is both a UI and an API to update. +- **Have a test suite** that Copilot can run and iterate against. +- **Tell a story.** Learners take on the role of a developer at a fictional company. Choose a company concept that is interesting and lends itself to obvious feature work. +- **Be deployable in a GitHub Codespace.** The `.devcontainer/` configuration in the main repo drives the learner environment. + +Exercises you may want to **skip** for a particular scenario: + +| Exercise | Common reason to skip | +|---|---| +| `3-copilot-agent-mode-vscode` | App has no frontend, or frontend is purely static | +| `5-custom-agents` | Scenario doesn't include an accessibility use case | + +Skipped exercises are listed in `scenario.yml` and are omitted when the workshop is rendered for that scenario. + +--- + +## Step 2 — Create the scaffolding + +Use the scaffolding script to get started: + +```bash +python scripts/new-scenario.py +``` + +Replace `` with a short, lowercase, hyphenated identifier (e.g. `java-bookstore`, `node-blog`). + +The script creates: + +``` +scenarios/ + / + scenario.yml ← pre-filled template; edit this next + steps/ + README.md ← placeholder for exercise steps files +``` + +--- + +## Step 3 — Fill in `scenario.yml` + +Open `scenarios//scenario.yml` and complete every field: + +```yaml +name: +description: > + One or two sentences describing the application. + +repository: / # GitHub repo for your sample app + +tech_stack: + frontend: + name: + language: + notes: > + Any notes relevant to the exercises. + backend: + name: + language: + notes: > + Any notes relevant to the exercises. + database: + +variables: + company_name: + company_description: + product_type: + primary_entities: + filter_feature: + new_endpoints_feature: + accessibility_feature: + documentation_feature: + +skip: + # List exercise filenames (without .md) that do NOT apply to your scenario + # - 5-custom-agents +``` + +### Required variables + +| Variable | Used in | Example | +|---|---|---| +| `company_name` | All exercises | `Tailspin Toys` | +| `company_description` | README, exercise intros | `a crowdfunding platform for board games` | +| `product_type` | README scenario section | `crowdfunding platform` | +| `primary_entities` | Exercises 3 & 4 | `games, publishers, categories` | +| `filter_feature` | Exercise 3 | `filter games by category and publisher` | +| `new_endpoints_feature` | Exercise 4 | `endpoints to create, update, and delete games` | +| `accessibility_feature` | Exercise 5 | `high-contrast mode toggle` | +| `documentation_feature` | Exercise 4 | `docstrings for all functions` | + +--- + +## Step 4 — Identify which exercises to skip + +Work through `workshop-content/` one exercise at a time and ask: *"Can a learner complete this exercise with my application?"* + +Common mismatches: + +- **Exercise 3** asks learners to add a filter feature that spans frontend and backend. If your app has no frontend, skip it. +- **Exercise 5** builds an accessibility agent for a dark-themed UI. If your app uses a different colour scheme or has no significant CSS layer, you may want to skip it or provide an alternative task in an override. + +Add each exercise to be skipped to the `skip` list in `scenario.yml`. + +--- + +## Step 5 — Write exercise steps files (as needed) + +The core exercises in `workshop-content/` are generic templates. Each contains a `## Scenario` section and other sections describing tasks in application-neutral language. When your scenario needs scenario-specific content — your company name, tech-stack details, feature descriptions — create a steps file. + +A steps file lives at: + +``` +scenarios//steps/.md +``` + +It contains **only the `## ` sections that differ from the core**. When exercises are rendered for your scenario, each matching section in the steps file replaces its counterpart in the core exercise. Sections not present in the steps file are taken unchanged from the core. + +> [!TIP] +> Only include the sections that genuinely differ. If only `## Scenario` needs to change, your steps file only needs that one section. + +### Minimal steps file example + +If only the `## Scenario` section needs to change for exercise 1: + +```markdown +## Scenario + +You are a developer for . You've been +assigned tasks to introduce new functionality. To file your backlog of issues +you'll enlist the help of Copilot Chat in agent mode and the GitHub MCP server. +``` + +### Multi-section steps file example + +If exercises 3 needs a custom scenario description and application startup instructions: + +```markdown +## Scenario + +As the list of grows, wants to allow users +to filter by . With the help of Copilot Agent Mode you'll add +the new feature! + +## Running the application + +The application is a . It has two main +components: a frontend written in and a backend written +in . + +### Starting the application + +...your tech-stack-specific startup steps here... +``` + +--- + +## Step 6 — Validate your scenario + +Run the validation script to catch common problems: + +```bash +python scripts/validate-scenario.py +``` + +The script checks: + +- All required fields are present in `scenario.yml`. +- Every exercise listed in `skip` exists in `workshop-content/`. +- Every steps file in `steps/` corresponds to an exercise in `workshop-content/`. +- No steps file exists for an exercise in the `skip` list (that would be a conflict). + +Fix any issues reported before continuing. + +--- + +## Step 7 — Update the scenarios table + +Add your scenario to the table in `scenarios/README.md`: + +```markdown +| `` | | | 🚧 In progress | +``` + +Change the status to ✅ once the scenario is complete and validated. + +--- + +## Step 8 — Test the scenario end-to-end + +Follow the workshop yourself from start to finish using your scenario: + +1. Clone your sample app repository into a codespace. +2. Work through each exercise (skipping those listed in `skip`). +3. Verify that every prompt in the exercises produces reasonable output from Copilot for your tech stack. +4. Adjust `scenario.yml` variables and/or override files as needed based on your experience. + +--- + +## Using the AI prompt to create a sample app + +If you need to create or adapt a sample application for your scenario, use the prompt file at `.github/prompts/create-scenario-app.prompt.md`. Open it in VS Code with GitHub Copilot Chat in **agent mode** and follow the instructions embedded in the prompt. + +The prompt guides Copilot to: + +- Create a minimal but realistic application matching your tech stack. +- Include a working test suite. +- Structure the code in a way that maps cleanly to the workshop exercises. +- Add a `.devcontainer/` configuration for Codespaces. + +--- + +## Checklist + +Use this checklist to track your progress: + +- [ ] Identified and evaluated a suitable sample application +- [ ] Created scaffolding with `scripts/new-scenario.py` +- [ ] Completed all fields in `scenario.yml` +- [ ] Identified exercises to skip +- [ ] Written steps files for exercises with scenario-specific content +- [ ] Validated with `scripts/validate-scenario.py` (zero errors) +- [ ] Updated `scenarios/README.md` table +- [ ] Tested the scenario end-to-end diff --git a/rendered/tailspin-toys-dotnet/0-prereqs.md b/rendered/tailspin-toys-dotnet/0-prereqs.md new file mode 100644 index 00000000..0b76b958 --- /dev/null +++ b/rendered/tailspin-toys-dotnet/0-prereqs.md @@ -0,0 +1,47 @@ +# Exercise 0: Prerequisites + +Before you get started on the lab, there's a few tasks you need to complete to get everything ready. You need to get a copy of the repository which includes the code, then spin up a [codespace][codespaces] to use to create your code. + +## Setting up the Lab Repository + +To create a copy of the repository for the code you'll create an instance from the [template][template-repository]. The new instance will contain all of the necessary files for the lab, and you'll use it as you work through the exercises. + +1. In a new browser window, navigate to the GitHub repository for this lab: `https://github.com/github-samples/agents-in-sdlc`. +2. Create your own copy of the repository by selecting the **Use this template** button on the lab repository page. Then select **Create a new repository**. + + ![Use this template button](images/ex0-use-template.png) + +3. If you are completing the workshop as part of an event being led by GitHub or Microsoft, follow the instructions provided by the mentors. Otherwise, you can create the new repository in an organization where you have access to Copilot coding agent and can assign issues to Copilot. + + ![Input the repository template settings](images/ex0-repository-settings.png) + +4. Make a note of the repository path you created (**organization-or-user-name/repository-name**), as you will be referring to this later in the lab. + +## Creating a codespace + +Next up, you'll be using a codespace to complete the lab exercises. [GitHub Codespaces][codespaces] are a cloud-based development environment that allows you to write, run, and debug code directly in your browser. It provides a fully-featured IDE with support for multiple programming languages, extensions, and tools. + +1. Navigate to your newly created repository. +2. Select the green **Code** button. + + ![Select the Code button](images/ex0-code-button.png) + +3. Select the **Codespaces** tab and select the **+** button to create a new Codespace. + + ![Create a new codespace](images/ex0-create-codespace.png) + +The creation of the codespace will take several minutes, although it's still far quicker than having to manually install all the services! That said, you can use this time to explore other features of GitHub Copilot, which we'll turn your attention to next! + +> [!IMPORTANT] +> You'll return to the codespace in a future exercise. For the time being, leave it open in a tab in your browser. + +## Summary + +Congratulations, you have created a copy of the lab repository! You also began the creation process of your codespace, which you'll use when you begin writing code. + +## Next step + +Let's explore how you can use Model Context Protocol (MCP) to interact with external services! You can do this by [setting up the backlog with Copilot agent mode and GitHub's MCP Server](./1-mcp.md). + +[codespaces]: https://github.com/features/codespaces +[template-repository]: https://docs.github.com/repositories/creating-and-managing-repositories/creating-a-template-repository diff --git a/rendered/tailspin-toys-dotnet/1-mcp.md b/rendered/tailspin-toys-dotnet/1-mcp.md new file mode 100644 index 00000000..1ad7d494 --- /dev/null +++ b/rendered/tailspin-toys-dotnet/1-mcp.md @@ -0,0 +1,230 @@ +# Exercise 1 - Setting up the backlog with Copilot agent mode and GitHub's MCP Server + +| [← Prerequisites][previous-lesson] | [Next lesson: Custom instructions →][next-lesson] | +|:--|--:| + +There's more to writing code than just writing code. Issues need to be filed, external services need to be called, and information needs to be gathered. Typically this involves interacting with external tools, which can break a developer's flow. Through the power of Model Context Protocol (MCP), you can access all of this functionality right from Copilot! + +## Scenario + +You are a part-time developer for Tailspin Toys - a crowdfunding platform for board games with a developer theme. You've been assigned various tasks to introduce new functionality to the website. Being a good team member, you want to file issues to track your work. To help future you, you've decided to enlist the help of Copilot. You will set up your backlog of work for the rest of the lab, using GitHub Copilot Chat agent mode and the GitHub Model Context Protocol (MCP) server to create the issues for you. + +In this exercise, you will: + +- use Model Context Protocol (MCP), which provides access to external tools and capabilities. +- set up the GitHub MCP server in your repository. +- use GitHub Copilot Chat agent mode to create issues in your repository. + +By the end of this exercise, you will have created a backlog of GitHub issues for use throughout the remainder of the lab. + +## What is agent mode and Model Context Protocol (MCP)? + +Agent mode in GitHub Copilot Chat transforms Copilot into an AI agent that can perform actions on your behalf. This mode allows you to interact with Copilot in a more dynamic way, enabling it to use tools and execute tasks, like running tests or terminal commands, reading problems from the editor, and using those insights to update your code. This allows for a more interactive and collaborative workflow, enabling you to leverage the capabilities of AI in your development process. + +[Model Context Protocol (MCP)][mcp-blog-post] provides AI agents with a way to communicate with external tools and services. By using MCP, AI agents can communicate with external tools and services in real-time. This allows them to access up-to-date information (using resources) and perform actions on your behalf (using tools). + +These tools and resources are accessed through an MCP server, which acts as a bridge between the AI agent and the external tools and services. The MCP server is responsible for managing the communication between the AI agent and the external tools (such as existing APIs or local tools like NPM packages). Each MCP server represents a different set of tools and resources that the AI agent can access. + +![Diagram showing the inner works of agent mode and how it interacts with context, LLM and tools - including tools contributed by MCP servers and VS Code extensions](images/ex1-mcp-diagram.png) + +A couple of popular existing MCP servers are: + +- **[GitHub MCP Server][github-mcp-server]**: This server provides access to a set of APIs for managing your GitHub repositories. It allows the AI agent to perform actions such as creating new repositories, updating existing ones, and managing issues and pull requests. +- **[Playwright MCP Server][playwright-mcp-server]**: This server provides browser automation capabilities using Playwright. It allows the AI agent to perform actions such as navigating to web pages, filling out forms, and clicking buttons. + +There are many other MCP servers available that provide access to different tools and resources. GitHub hosts an [MCP registry][mcp-registry] to enhance discoverability and contributions to the ecosystem. + +> [!IMPORTANT] +> With regard to security, treat MCP servers as you would any other dependency in your project. Before using an MCP server, carefully review its source code, verify the publisher, and consider the security implications. Only use MCP servers that you trust and be cautious about granting access to sensitive resources or operations. + +## Ensure your codespace is ready + +In a [prior exercise][prereqs-lesson] you launched the codespace you'll use for the remainder of the coding exercises in this lab. Let's put the final touches on it before you begin using it. + +The setup process for the codespace installed and setup many [VS Code extensions][vscode-extensions]. As with any software, updates may be needed. When your codespace is created you'll need to ensure everything is up-to-date. + +1. Return to the tab where you started your codespace. If you closed the tab, return to your repository, select **Code** > **Codespaces** and then the name of the codespace. +2. Select **Extensions** on the workbench on the left side of your codespace. + + ![Screenshot of the extensions window with multiple extensions showing either Update or Reload Window buttons](images/ex1-extensions-updates.png) + +3. Select **Update** on any extensions with an **Update** button. Repeat as necessary. +4. Select **Reload Window** on any extensions with a **Reload Window** button to reload the codespace. +5. When prompted by a dialog, select **Reload** to reload the window. This will ensure the latest version is being used. + +## Using GitHub Copilot Chat and agent mode + +To access GitHub Copilot Chat agent mode, you need to have the GitHub Copilot Chat extension installed in your IDE, which should already be the case if you are using a GitHub Codespace. + +> [!TIP] +> If you do not have the GitHub Copilot Chat extension installed, you can [install it from the Visual Studio Code Marketplace][copilot-chat-extension]. Or open the Extensions view in Visual Studio Code, search for **GitHub Copilot Chat**, and select **Install**. + +Once you have the extension installed, you may need to authenticate with your GitHub account to enable it. + +1. Return to your codespace. +2. If you don't already see Copilot Chat on the right side of your editor, select the **Copilot Chat** icon at the top of your codespace. +3. Type a message like "Hello world" in the Copilot Chat window and press enter. This should activate Copilot Chat. +4. Alternatively, if you are not authenticated you will be prompted to sign in to your GitHub account. Follow the instructions to authenticate. + + ![Example of Copilot Chat authentication prompt](images/ex1-copilot-authentication.png) + +5. After authentication, you should see the Copilot Chat window appear. +6. Switch to agent mode by selecting the dropdown in the Copilot Chat window and selecting **Agent**. + + ![Example of switching to agent mode](images/shared-agent-mode-dropdown.png) + +7. Set the model to **Claude Sonnet 4.5**. + + ![Example of selecting the Claude Sonnet 4.5 model](images/ex1-select-model.png) + +> [!IMPORTANT] +> The authors of this workshop are not indicating a preference towards one model or another. When building this workshop, we used Claude Sonnet 4.5, and as such are including that in the instructions. The hope is the code suggestions you receive will be relatively consistent to ensure a good experience. However, because LLMs are probabilistic, you may notice the suggestions received differ from what is indicated in the workshop. This is perfectly normal and expected. + +8. The chat pane should update to indicate that you are now in agent mode. You should see a tools icon on the same line as the mode and model, which you utilized earlier, showing that you can configure tools for GitHub Copilot to use. + +Typically, the number of tools available will be set to 0 when setting up a new project, as you have not configured any MCP servers yet. But to help you get started, the project has a **.vscode/mcp.json** file with an example configuration for the [GitHub MCP server][github-mcp-server]. Let's go and explore that next. + +## Setting up the GitHub MCP server + +The **.vscode/mcp.json** file is used to configure the MCP servers that are available in this Visual Studio Code workspace. The MCP servers provide access to external tools and resources that GitHub Copilot can use to perform actions on your behalf. + +1. Open **.vscode/mcp.json** file in your repository. +2. You should see a JSON structure similar to the following: + + ```json + { + "servers": { + "github": { + "type": "http", + "url": "https://api.githubcopilot.com/mcp/" + } + } + } + ``` + +This configuration provides GitHub Copilot access to several additional tools so that it can interact with GitHub repositories, issues, pull requests, and more. This particular configuration uses the [remote GitHub MCP server][remote-github-mcp-server]. By using this approach, you don't need to worry about running the MCP server locally (and the associated management, like keeping it up to date), and you can authenticate to the remote server using OAuth 2.0 instead of a personal access token (PAT). + +The MCP server configuration is defined in the **servers** section of the **mcp.json** file. Each MCP server is defined by a unique name (in this case, github) and its type (in this case, **http**). When using local MCP servers, the type may be **stdio** and have a **command** and **args** field to specify how to start the MCP server. You can find out more about the configuration format in the [VS Code documentation][vscode-mcp-config]. In some configurations (not for the remote GitHub MCP server with OAuth), you may also see an **inputs** section. This defines any inputs (like sensitive tokens) that the MCP server may require. You can read more about the configuration properties in the [VS Code documentation][vscode-mcp-config] + +To utilize an MCP server it needs to be "started". This will allow GitHub Copilot to communicate with the server and perform the tasks you request. + +> [!NOTE] The exact authentication flow may vary a little bit. + +1. Inside VS Code, open **.vscode/mcp.json**. +2. To start the GitHub MCP server, select **Start** above the GitHub server. + + ![The start button above the GitHub MCP server entry](images/ex1-start-mcp-server.png) + +3. You should see a popup asking you to authenticate to GitHub. + + ![A popup showing that the GitHub MCP server wants to authenticate to GitHub](images/ex1-mcp-auth-popup.png) + +4. Select **Continue** on the user account that you're using for this lab. + + ![A popup showing the user account selection for GitHub authentication](images/ex1-mcp-select-account.png) + +5. If the page appears, select **Authorize visual-studio-code** to allow the GitHub MCP server to login as your selected user account. Once complete, the page should say "You can now close the window.". + + ![A popup showing the authorization for visual-studio-code app](images/ex1-mcp-authorize-vscode.png) + +6. After navigating back to the GitHub Codespace, you should see that the GitHub MCP server has started. You can check this in two places: + - The line in **.vscode/mcp.json** which previously said start should now present several options, and show a number of tools available. + - Select the tools icon in the Copilot Chat pane to see the tools available. Scroll down the list that appears at the top of the screen, and you should see a list of tools from the GitHub MCP server. + +That's it! You can now use Copilot Chat in agent mode to create issues, manage pull requests, and more. + +## Creating a backlog of tasks + +Now that you have set up the GitHub MCP server, you can use Copilot Agent mode to create a backlog of tasks for use in the rest of the lab. + +1. Return to the Copilot Chat pane. Ensure **Agent** is selected for the mode and **Claude Sonnet 4.5** is selected for the model. +2. Type or paste the following prompt to create the issues you'll be working on in the lab: + + ```markdown + In my GitHub repo, create GitHub issues for our Tailspin Toys backlog. Each issue should include: + - A clear title + - A brief description of the task and why it is important to the project + - A checkbox list of acceptance criteria + + From our recent planning meeting, the upcoming backlog includes the following tasks: + + 1. Allow users to filter games by category and publisher + 2. Update our repository coding standards (including rules about code formatting and documentation) in a custom instructions file + 3. Stretch Goal: Implement pagination on the game list page + ``` + +3. Press enter or select the **Send** button to send the prompt to Copilot. +4. GitHub Copilot should process the request and respond with a dialog box asking you to confirm the creation of the issues. + + ![Example of Copilot Chat dialog box asking for confirmation to run the create issue command](images/ex1-create-issue-dialog.png) + +> [!IMPORTANT] +> Remember, AI can make mistakes, so make sure to review the issues before confirming. + +5. Select **see more** in **Run open new issue** box to see the details of the issue that will be created. +6. Ensure the details in the **owner** and **repo**, **title** and **body** of the issue look correct. You can make any desired edits by double clicking the body and updating the content with the correct information. +7. After reviewing the generated content, select **Continue** to create the issue. + + ![Example of the expanded dialog box showing the GitHub Issue that will be created](images/ex1-create-issue-review.png) + +8. Repeat steps 4-6 for the remainder of the issues. Alternatively, if you are comfortable with Copilot automatically creating the issues you can select the down-arrow next to **Continue** and select **Allow in this session** to allow Copilot to create the issues for this session (the current chat). + + ![Example of allowing Copilot to automatically create issues](images/ex1-create-issue-allow.png) + +> [!IMPORTANT] +> Ensure you are comfortable with Copilot automatically performing tasks on your behalf before you selecting **Allow in this session** or a similar option. + +9. In a separate browser tab, navigate to your GitHub repository and select the issues tab. +10. You should see a list of issues that have been created by Copilot. Each issue should include a clear title and a checkbox list of acceptance criteria. + +You should notice that the issues are fairly detailed. This is where you benefit from the power of Large Language Models (LLMs) and Model Context Protocol (MCP), as it has been able to create a clear initial issue description. + +![Example of issues created in GitHub](images/ex1-github-issues-created.png) + +## Summary and next steps + +Congratulations, you have created issues on GitHub using Copilot Chat and MCP! + +To recap, in this exercise you: + +- used Model Context Protocol (MCP), which provides access to external tools and capabilities. +- set up the GitHub MCP server in your repository. +- used GitHub Copilot Chat agent mode to create issues in your repository. + +With the GitHub MCP server configured, you can now use GitHub Copilot Chat Agent Mode to perform additional actions on your behalf, like creating new repositories, managing pull requests, and searching for information across your repositories. + +You can now continue to the next exercise, where you will learn how to [provide Copilot guidance with custom instructions][next-lesson] to ensure code is generated following your organization's defined patterns and practices. + +### Optional exploration exercise – Set up the Microsoft Playwright MCP server + +If you are feeling adventurous, you can try installing and configuring another MCP server, such as the [Microsoft Playwright MCP server][playwright-mcp-server]. This will allow you to use GitHub Copilot Chat Agent Mode to perform browser automation tasks, such as navigating to web pages, filling out forms, and clicking buttons. + +You can find the instructions for installing and configuring the Playwright MCP server in the [Playwright MCP repository][playwright-mcp-server]. + +Notice that the setup process is similar to the GitHub MCP server, but you do not need to provide any credentials like the GitHub Personal Access Token. This is because the Playwright MCP server does not require authentication to access its capabilities. + +## Resources + +- [What the heck is MCP and why is everyone talking about it?][mcp-blog-post] +- [GitHub MCP Server][github-mcp-server] +- [Microsoft Playwright MCP Server][playwright-mcp-server] +- [GitHub MCP Registry][mcp-registry] +- [VS Code Extensions][vscode-extensions] +- [GitHub Copilot Chat Extension][copilot-chat-extension] + +--- + +| [← Prerequisites][previous-lesson] | [Next lesson: Custom instructions →][next-lesson] | +|:--|--:| + +[previous-lesson]: ./0-prereqs.md +[next-lesson]: ./2-custom-instructions.md +[prereqs-lesson]: ./0-prereqs.md +[mcp-blog-post]: https://github.blog/ai-and-ml/llms/what-the-heck-is-mcp-and-why-is-everyone-talking-about-it/ +[github-mcp-server]: https://github.com/github/github-mcp-server +[playwright-mcp-server]: https://github.com/microsoft/playwright-mcp +[mcp-registry]: https://github.com/mcp +[vscode-extensions]: https://code.visualstudio.com/docs/configure/extensions/extension-marketplace +[copilot-chat-extension]: https://marketplace.visualstudio.com/items?itemName=GitHub.copilot +[remote-github-mcp-server]: https://github.blog/changelog/2025-06-12-remote-github-mcp-server-is-now-available-in-public-preview/ +[vscode-mcp-config]: https://code.visualstudio.com/docs/copilot/chat/mcp-servers#_configuration-format diff --git a/rendered/tailspin-toys-dotnet/2-custom-instructions.md b/rendered/tailspin-toys-dotnet/2-custom-instructions.md new file mode 100644 index 00000000..16eebffe --- /dev/null +++ b/rendered/tailspin-toys-dotnet/2-custom-instructions.md @@ -0,0 +1,251 @@ +# Exercise 2 - Providing context to Copilot with instruction files + +| [← Previous lesson: Model Context Protocol (MCP)][previous-lesson] | [Next lesson: Copilot agent mode →][next-lesson] | +|:--|--:| + +Context is key across many aspects of life, and when working with generative AI. If you're performing a task which needs to be completed a particular way, or if a piece of background information is important, you want to ensure Copilot has access to that information. You can use [instruction files][instruction-files] to provide guidance so that Copilot not only understands what you want it to do but also how you want it to be done. + +In this exercise, you will learn how to: + +- provide Copilot with project-specific context, coding guidelines and documentation standards using [repository custom instructions][repository-custom-instructions] **.github/copilot-instructions.md**. +- provide path instruction files to guide Copilot for repetitive or templated tasks on specific types of files. +- implement both repository-wide instructions and task-specific instructions. + +> [!IMPORTANT] +> Note that the code generated may diverge from some of the standards you set. AI tools like Copilot are non-deterministic, and may not always provide the same result. The other files in the codebase do not contain documentation or comment headers, which could lead Copilot in another direction. Consistency is key, so making sure that your code follows the established patterns is important. You can always follow-up in chat and ask Copilot to follow your coding standards, which will help guide it in the right direction. + +## Scenario + +As any good dev shop, Tailspin Toys has a set of guidelines and requirements for development practices. These include: + +- API always needs unit tests. +- UI should be in dark mode and have a modern feel. +- Documentation should be added to code in the form of XML documentation comments. +- A block of comments should be added to the head of each file describing what the file does. + +Through the use of instruction files you'll ensure Copilot has the right information to perform the tasks in alignment with the practices highlighted. + +## Before you begin + +You're going to be making some code changes, so you should follow the usual practice of creating a new branch to work in. This will allow you to make changes without affecting the main branch until you're ready. + +1. Return to your codespace from the previous exercise. +2. Open a new terminal window inside your codespace by selecting Ctl+\`. +3. Create and switch to a new branch by running the following command in the terminal: + + ```bash + git checkout -b add-filters + ``` + +## Custom instructions + +Custom instructions allow you to provide context and preferences to Copilot chat, so that it can better understand your coding style and requirements. This is a powerful feature that can help you steer Copilot to get more relevant suggestions and code snippets. You can specify your preferred coding conventions, libraries, and even the types of comments you like to include in your code. You can create instructions for your entire repository, or for specific types of files for task-level context. + +There are two types of instructions files: + +- **.github/copilot-instructions.md**, a single instruction file sent to Copilot for **every** chat prompt for the repository. This file should contain project-level information, context which is relevant for most chat requests sent to Copilot. This could include the tech stack being used, an overview of what's being built and best practices, and other global guidance for Copilot. +- **\*.instructions.md** files can be created for specific tasks or file types. You can use **\*.instructions.md** files to provide guidelines for particular languages (like C# or TypeScript), or for tasks like creating an ASP.NET Core controller or a new set of unit tests. + +> [!NOTE] +> When working in your IDE, instructions files are only used for code generation in Copilot Chat, and not used for code completions or next edit suggestions. +> +> Copilot coding agent will utilize both repository level and \*.instructions with `applyTo` header matter when generating code. + +## Best practices for managing instructions files + +A full conversation about creating instructions files is beyond the scope of the workshop. However, the examples provided in the sample project provide a representative example of how to approach their management. At a high level: + +- Keep instructions in **copilot-instructions.md** focused on project-level guidance, such as a description of what's being built, the structure of the project, and global coding standards. +- Use **\*.instructions.md** files to provide specific instructions for file types (unit tests, API controllers, frontend components), or for specific tasks. +- Use natural language in your instructions files. Keep guidance clear. Provide examples of how code should (and shouldn't) look. + +There isn't one specific way to create instructions files, just as there isn't one specific way to use AI. You will find through experimentation what works best for your project. The guidance provided here and the [resources](#resources) below should help you get started. + +> [!TIP] +> Every project using GitHub Copilot should have a robust collection of instructions files to provide context and best guide code generation. As you explore the instructions files in the project, you may notice there are ones for numerous types of files and tasks, including [UI updates](../.github/instructions/ui.instructions.md) and [Astro](../.github/instructions/astro.instructions.md). The investment made in instructions files will greatly enhance the quality of code suggestion from Copilot, ensuring it better matches the style and requirements your organization has. +> +> You can even have Copilot aid in generating instructions files by selecting the gear icon for **Configure Chat** in Copilot chat and selecting **Generate Agent Instructions**. +> +> ![Screenshot of option in GitHub Copilot chat with configure chat highlighted and generate agent instructions highlighted](./images/ex2-generate-instructions.png) + +## Use GitHub Copilot Chat before updating custom instructions + +To see the impact of custom instructions, you'll start by sending a prompt with the current version of the files. You'll then make some updates, send the same prompt again, and note the difference. + +1. Return to your codespace. +2. Close any open files in your codespace from the previous exercises. This will ensure Copilot has the context you want it to have. +3. Open `server/TailspinToys.Api/Controllers/PublishersController.cs`, an empty controller file. +4. If **Copilot chat** is not already open, open it by selecting the Copilot icon towards the top of your codespace. +5. Create a new chat session by typing `/clear` into the chat window and selecting Enter (or return on a Mac). +6. Select **Ask** from the modes dropdown. + + ![Chat mode selection dialog with Ask mode highlighted](./images/ex2-select-chat-mode.png) + +7. Send the following prompt to create a new endpoint to return all publishers: + + ```plaintext + Create a new endpoint to return a list of all publishers. It should return the name and id for all publishers. + ``` + +8. Copilot explores the project to learn how best to implement the code, and generates a list of suggestions, which may include code for `PublishersController.cs` and tests to ensure the new code runs correctly. +9. Explore the code, noticing the generated code uses C# types and nullable reference types because, as you'll see, the custom instructions includes the directive to include them. +10. Notice the generated code **is missing** XML documentation comments or a file header comment - or both! + +> [!IMPORTANT] +> As highlighted previously, GitHub Copilot and LLM tools are probabilistic, not deterministic. As a result, the exact code generated may vary, and there's even a chance it'll abide by your rules without you spelling it out! But to aid consistency in code you should always document anything you want to ensure Copilot should understand about how you want your code generated. + +## Add new repository standards to copilot-instructions.md + +As highlighted previously, `copilot-instructions.md` is designed to provide project-level information to Copilot. Let's ensure repository coding standards are documented to improve code suggestions from Copilot chat. + +1. Return to your codespace. +2. Open `.github/copilot-instructions.md`. +3. Explore the file, noting the brief description of the project and sections for **Code standards**, **Scripts** and **GitHub Actions Workflows**. These are applicable to any interactions you'd have with Copilot, are robust, and provide clear guidance on what you're doing and how you want to accomplish it. +4. Locate the **Code formatting requirements** section. Note how it contains a note to use C# nullable reference types and standard C# naming conventions. That's why you saw those in the code generated previously. +5. Add the following lines of markdown right below the note about nullable reference types to instruct Copilot to add XML documentation comments and file headers: + + ```markdown + - Every public type, method, and property should have XML documentation comments (``, ``, ``). + - Before the namespace declaration, add a comment block to the file that explains its purpose. + ``` + +6. Close **copilot-instructions.md**. +7. Select **New Chat** in Copilot chat to clear the buffer and start a new conversation. +8. Return to **server/TailspinToys.Api/Controllers/PublishersController.cs** to ensure focus is set correctly. +9. Send the same prompt as before to create the endpoint. + + ```plaintext + Create a new endpoint to return a list of all publishers. It should return the name and id for all publishers. + ``` + +10. Notice how the newly generated code includes a file header comment at the top which resembles the following: + + ```csharp + // PublishersController.cs + // Provides API endpoints for retrieving publisher information + // for the Tailspin Toys crowdfunding platform. + ``` + +11. Notice how the newly generated code includes XML documentation comments inside the action method which resemble the following: + + ```csharp + /// + /// Returns a list of all publishers with their id and name. + /// + /// A JSON array of publisher objects containing id and name. + ``` + +12. Notice the generated code now includes XML documentation as well as a comment block at the top! +13. Also note how the existing code isn't updated, but of course you could ask Copilot to perform that operation if you so desired! +14. **Don't implement the suggested changes**, as you'll be doing that in the next section. + +> [!NOTE] +> If you accepted the changes, you can always select the **Undo** button towards the top right of the Copilot chat window. + +From this section, you explored how the custom instructions file has provided Copilot with the context it needs to generate code that follows the established guidelines. + +## Instructions for specific tasks or files + +Coding is often repetitive, with developers performing similar tasks on a regular basis. Copilot is wonderful for allowing you to offload the mundane, like adding endpoints, generating tests, or building a new component. But all code has a set of requirements, and often require a particular template or structure to be followed. **\*.instructions.md** files allow you to provide tailored guidance for these types of tasks and files. They can be added manually when using Copilot Chat, or can have an `applyTo:` tag added to the top of the file to have Copilot automatically use them for specific files. + +## Explore a task-specific custom instructions file + +You want to create a new endpoint to list all publishers, following the same pattern used for the existing [games controller][games-controller], and to create tests which follow the same pattern as the existing [games controller tests][games-tests]. An instruction file has already been created; let's explore it and see the difference in code it generates. + +1. Open `.github/instructions/csharp-tests.instructions.md`. +2. Note the `applyTo:` section at the top, which contains a filter for all test files in the `server/TailspinToys.Tests` directory ending in `Tests.cs`. Whenever Copilot Chat interacts with a file which matches this pattern it will automatically use the guidance provided in this file. +3. Note the file contains guidance about how xUnit tests should be created, and how to use the EF Core in-memory provider for testing database functionality. +4. Open `.github/instructions/csharp-api.instructions.md`. +5. Review the following entries inside the instruction file, which includes: + + - an overview of requirements, including that tests must be created, and controllers inherit from `ControllerBase` with `[ApiController]`. + - a link to the previously mentioned `csharp-tests.instructions.md` file. + - links to two existing files which follow the patterns you want — both the games controller and its tests. Notice how these are set up as normal markdown links, allowing an instruction file to incorporate additional files for context. + +6. Return to `server/TailspinToys.Api/Controllers/PublishersController.cs` to ensure focus is set correctly. +7. Return to Copilot Chat and select **New Chat** to start a new session. +8. Select **Edit** from the mode dropdown, which will allow Copilot to update multiple files. + + ![Copilot Chat mode selector with Edit chosen and highlighted](./images/ex2-select-edit-mode.png) + +> [!NOTE] +> If you have any issues running the tests in this part of the exercise, please undo your changes and retry from the above step using **Agent** mode instead. + +9. Select the **Add Context** button to open the context dialog +10. If prompted to allow the codespace to see text and images copied to the clipboard, select **Allow**. +11. Select **Instructions** from the dropdown at the top of your codespace. + +> [!TIP] +> If the list of options is long, you can type **instructions** to filter to the Instructions option then select **Instructions**. + +12. Select **csharp-api .github/instructions** to add the instruction file to the context. + + ![Screenshot showing the instruction file being added into Copilot Chat](images/ex2-add-instructions-file.png) + +13. Send the same prompt as before to generate the desired endpoint: + + ```plaintext + Create a new endpoint to return a list of all publishers. It should return the name and id for all publishers. + ``` + +> [!NOTE] +> While the up-arrow shortcut to resend a prior command is handy, it will reset any context you might add as well. If you added in the instructions file as context, then use the up arrow, it will remove the instructions file. For this particular step, make sure you copy/paste (or type) the command to avoid accidentally removing context. + +14. Note the **References** section and how it uses the **csharp-api.instructions.md** file to provide context. If you use instructions files with Copilot agent mode, you will notice that Copilot explores and reads the files referenced in the instructions file. + + ![Screenshot of the references section, showing the included instructions file](./images/ex2-copilot-instructions-references.png) + +15. Copilot generates the files. Notice how it generates updates across multiple files, like **PublishersController.cs** and **PublishersControllerTests.cs** + +> [!NOTE] +> Note that the code generated may diverge from some of the standards we set. AI tools like Copilot are non-deterministic, and may not always provide the same result. The other files in our codebase do not contain XML documentation comments or comment headers, which could lead Copilot in another direction. Consistency is key, so making sure that your code follows the established patterns is important. You can always follow-up in chat and ask Copilot to follow your coding standards, which will help guide it in the right direction. + +16. After reviewing the code, select **Keep** in Copilot Chat to accept the changes. +17. Open a terminal window by selecting Ctl+\`. +18. Run the tests by running the script with the following command: + + ```sh + ./scripts/run-server-tests.sh + ``` + +19. Once the code is correct, and all tests pass, open the **Source Control** panel on the left of the Codespace and review the changes made by Copilot. +20. Stage the changes by selecting the **+** icon in the **Source Control** panel. +21. Generate a commit message using the **Sparkle** button. + + ![Screenshot of the Source Control panel showing the changes made](images/ex2-source-control-changes.png) + +22. Commit the changes to your repository by selecting **Commit**. + +## Summary and next steps + +Congratulations! You explored how to ensure Copilot has the right context to generate code following the practices your organization has set forth. This can be done at a repository level with the **.github/copilot-instructions.md** file, or on a task basis with instruction files. You explored how to: + +- provide Copilot with project-specific context, coding guidelines and documentation standards using custom instructions (.github/copilot-instructions.md). +- use instruction files to guide Copilot for repetitive or templated tasks. +- implement both repository-wide instructions and task-specific instructions. + +Next we'll use [agent mode to add functionality to the site][next-lesson]. + +## Resources + +- [Instruction files for GitHub Copilot customization][instruction-files] +- [5 tips for writing better custom instructions for Copilot][copilot-instructions-five-tips] +- [Best practices for creating custom instructions][instructions-best-practices] +- [Personal custom instructions for GitHub Copilot][personal-instructions] +- [Awesome Copilot - a collection of instructions files and other resources][awesome-copilot] + +--- + +| [← Previous lesson: Model Context Protocol (MCP)][previous-lesson] | [Next lesson: Copilot agent mode →][next-lesson] | +|:--|--:| + +[previous-lesson]: ./1-mcp.md +[next-lesson]: ./3-copilot-agent-mode-vscode.md +[instruction-files]: https://code.visualstudio.com/docs/copilot/copilot-customization +[games-controller]: ../server/TailspinToys.Api/Controllers/GamesController.cs +[games-tests]: ../server/TailspinToys.Tests/GamesControllerTests.cs +[instructions-best-practices]: https://docs.github.com/enterprise-cloud@latest/copilot/using-github-copilot/coding-agent/best-practices-for-using-copilot-to-work-on-tasks#adding-custom-instructions-to-your-repository +[personal-instructions]: https://docs.github.com/copilot/customizing-copilot/adding-personal-custom-instructions-for-github-copilot +[copilot-instructions-five-tips]: https://github.blog/ai-and-ml/github-copilot/5-tips-for-writing-better-custom-instructions-for-copilot/ +[awesome-copilot]: https://github.com/github/awesome-copilot +[repository-custom-instructions]: https://docs.github.com/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot diff --git a/rendered/tailspin-toys-dotnet/3-copilot-agent-mode-vscode.md b/rendered/tailspin-toys-dotnet/3-copilot-agent-mode-vscode.md new file mode 100644 index 00000000..2e705414 --- /dev/null +++ b/rendered/tailspin-toys-dotnet/3-copilot-agent-mode-vscode.md @@ -0,0 +1,223 @@ +# Exercise 3 - Adding new functionality with Copilot Agent Mode + +| [← Previous lesson: Custom instructions][previous-lesson] | [Next lesson: GitHub Copilot coding agent →][next-lesson] | +|:--|--:| + +Even the simplest of updates to an application typically require updates to multiple files and operations to be performed like running tests. As a developer your flow typically involves tracking down all the necessary files, making the changes, running the tests, debugging, figuring out which file was missed, making another update... The list goes on and on. + +This is where Copilot Agent Mode comes into play. + +Copilot Agent Mode is built to act more autonomously in your IDE. It behaves in a similar fashion to a developer, starting by exploring the existing project structure, performing the necessary updates, running tasks like tests, and automatically fixing any discovered mistakes. Let's explore how you can use Agent Mode to introduce new functionality to your site. + +> [!NOTE] +> While the names are similar, agent mode and coding agent are built for two different types of experiences. Agent mode performs its tasks in your IDE, allowing for quick feedback cycles and interaction. Coding agent is designed as a peer programmer, working asynchronously like a member of the team, interacting with you via issues and pull requests. + +In this exercise, you will learn how: + +- Copilot Agent Mode can explore your project, identify relevant files, and make coordinated changes. +- GitHub Copilot Agent Mode can implement new features across both backend and frontend codebases. +- to review changes and tests generated by Copilot Agent Mode before merging into your codebase. + +## Scenario + +As the list of games grows, you want to allow users to filter by category. This will require updating both the API and UI, and updating the tests for the API. With the help of Copilot Agent Mode you'll work with your AI pair programmer to add the new feature! + +## Running the application + +Before you make any changes, let's explore the Tailspin Toys website to understand its current functionality. + +The website is a crowdfunding platform for board games with a developer theme. It allows users to list games and display details about them. The website has two main components: the front-end (written in Svelte) and the backend (written in C#). + +### Starting the application + +To make running the website easier, a script has been provided that will start both the front-end and back-end servers. You can run this script in your GitHub Codespace with the following instructions: + +1. Return to your codespace. You'll continue working in your current branch. +2. Open a new terminal window inside your codespace by selecting Ctl + \`. +3. Run the following script to start the application: + + ```bash + scripts/start-app.sh + ``` + + Once the script is running, you should see output indicating that both the front-end and back-end servers are running, similar to the below: + + ```bash + Server (ASP.NET Core) running at: http://localhost:5100 + Client (Astro) server running at: http://localhost:4321 + ``` + +> [!NOTE] +> If a dialog box opens prompting you to open a browser window for `http://localhost:5100` close it by selecting the **x**. + +4. Open the website by using Ctrl-**Click** (or Cmd-**Click** on a Mac) on the client address `http://localhost:4321` in the terminal. + +> [!NOTE] +> When using a codespace, selecting a link for the localhost URL from the Codespace terminal will automatically redirect you to `https://-4321.app.github.dev/`. This is a private tunnel to your codespace, which is now hosting your web server! + +### Exploring the application + +Once the application is running, you can explore its functionality. The main features of the website include: + +- **Home Page**: Displays a list of board games with their titles, images, and descriptions. +- **Game Details Page**: When you select a game, you'll be brought to a details page with more information about the game, including its title, description, publisher and category. +## Explore the backlog with Copilot + +The initial implementation of the application is functional, but we want to enhance it by adding new capabilities. Let's start off by reviewing the backlog. Ask GitHub Copilot to show you the backlog of items that we created in the previous exercise. + +1. Return to your codespace. +2. Open **Copilot Chat**. +3. Create a new chat session by selecting the **New Chat** button, which will remove any previous context. +4. Ensure **Agent** is selected from the list of modes. +5. Select **Claude Sonnet 4.5** from the list of available models. + +> [!IMPORTANT] +> The authors of this lab are not indicating a preference towards one model or another. When building this lab, we used Claude Sonnet 4.5, and as such are including that in the instructions. The hope is the code suggestions you receive will be relatively consistent to ensure a good experience. However, because LLMs are probabilistic, you may notice the suggestions received differ from what is indicated in the lab. This is perfectly normal and expected. + +6. Open the GitHub Copilot Chat, if it is not already open. +7. Switch to **Agent** mode, if you are not already in agent mode. +8. Select **Claude Sonnet 4.5** from the list of available models. + +> [!IMPORTANT] +> The authors of this lab are not indicating a preference towards one model or another. When building this lab, we used Claude Sonnet 4.5, and as such are including that in the instructions. The hope is the code suggestions you receive will be relatively consistent to ensure a good experience. However, because LLMs are probabilistic, you may notice the suggestions received differ from what is indicated in the lab. This is perfectly normal and expected. + +> [!NOTE] +> Because of the probabilistic nature of LLMs, Copilot may utilize a different MCP command, but should still be able to complete the task. + +8. Ask Copilot about the backlog of issues by sending the following prompt to Copilot: + + ```plaintext + Please show me the backlog of items from my GitHub repository. Help me prioritize them based on those which will be most useful to the user. + ``` +9. Select **Continue** to run the command to list all issues. +10. Review the generated list of issues. + +Notice how Copilot has even prioritized the items for you, based on the ones that it thinks will be most useful to the user. + +## Review instructions files + +Before kicking off the agent to generate the code, it's a good time to review the instructions file you'll use to provide Copilot context for its work. You're going to take advantage of the [user interface (UI)](../.github/instructions/ui.instructions.md) file, which contains context on how to approach adding functionality to the website. + +1. In your codespace, navigate to **.github/instructions/ui.instructions.md**. +2. Take note of the overall guidance on how to approach adding functionality. This includes: + - An overview of the architecture. + - Principles for component design, testability and accessibility. + - Links to specific instructions files for various file types, including: + - Astro + - Svelte + - Tailwind CSS + +> [!TIP] +> Instructions files allow you to reference both other instructions files and files in your project. The paths are relative to the location of the instructions file. This allows for reuse, breaking down complex instructions into smaller more manageable chunks, and providing examples and templates. + +## Implement the filtering functionality + +To implement filtering, no less than three separate updates will need to be made to the application: + +- A new endpoint added to the API +- A new set of tests for the new endpoint +- Updates to the UI to introduce the functionality + +In addition, the tests need to run (and pass) before you merge everything into your codebase. Copilot Agent Mode can perform these tasks for you! Let's add the functionality. + +1. You can continue in the current conversation with Copilot, or start a new one by selecting **New Chat**. +2. Select **Add Context**, **Instructions**, and **ui** as the instructions file. + + ![Screenshot showing an example of selecting the UI instructions file](images/ex3-select-instructions-file.png) + +3. Ensure **Agent** mode is still selected. + + ![Screenshot of Copilot Chat mode selection with Agent highlighted](./images/shared-agent-mode-dropdown.png) + +4. Ensure **Claude Sonnet 4.5** is still selected for the model. +5. Prompt Copilot to implement the functionality based on the issue you created earlier by using the following prompt: + + ```plaintext + Please update the site to include the filtering feature based on the requirements from the related GitHub issue in the backlog. Ensure all tests are passing before completion. The server is already running, so you do not need to start it up. + ``` + +6. Watch as Copilot begins by exploring the project, locating the files associated with the desired functionality. You should see it finding both the API and UI definitions, as well as the tests. It then begins modifying the files and running the tests. + + ![Screenshot showing Copilot exploring the project files](images/ex3-agent-mode-explores.png) + +> [!NOTE] +> You will notice that Copilot will perform several tasks, like exploring the project, modifying files, and running tests. It may take a few minutes depending on the complexity of the task and the codebase. During that process, you may notice **Keep** and **Undo** buttons appear in the code editor. When Copilot is finished, you will have a **Keep** or **Undo** for all of the changes, so you do not need to select them while work is in progress. + +7. As prompted by Copilot, select **Continue** to run the tests. + + ![Screenshot showing a dialog in the Copilot Chat pane asking the user to confirm they are happy to run tests](images/ex3-agent-mode-run-tests.png) + +8. You may experience some pauses and even see some tests fail throughout the process. That's okay! Copilot works back and forth between code generation and tests until it completes the task and doesn't detect any errors. + + ![Screenshot showing a complete Chat session with Copilot Agent Mode](images/ex3-agent-mode-proposed-changes.png) + +9. Explore the generated code for any potential issues. + +> [!IMPORTANT] +> Remember, it's always important to review the code that Copilot or any AI tools generate. + +10. Return to the browser with the website running. Explore the new functionality! +11. Once you've confirmed everything works and reviewed the code, select **Keep** in the Copilot Chat window. + +## Publish the branch and create a pull request + +With your changes created locally you're ready to create a pull request (PR) to allow for your team to review your suggested changes and work through your DevOps process. The first step in that process is to publish the branch. Let's take care of that first. + +1. Navigate to the **Source Control** panel in the Codespace and review the changes made by Copilot. +2. Stage the changes by selecting the **+** icon. +3. Generate a commit message using the **Sparkle** button. + + ![Screenshot of the Source Control panel showing the changes made](images/ex3-source-control-changes.png) + +4. Select **Publish** to push the branch to your repository. + +## Create the pull request + +There are several ways to create a pull request, including through github.com and the GitHub command-line interface (CLI). But since you're already working with GitHub Copilot, let's let it create the PR for you! You can have it find the relevant issue and create the PR with an association to the located issue. + +1. Navigate to the Copilot Chat panel and select **New Chat** to start a new session. +2. Ask Copilot to create a PR for you: + + ```plaintext + Find the issue in the repo related to the filtering feature. Create a new pull request for the current add-filters branch, and associate it with the correct issue. + ``` + +3. As needed, select **Continue** to allow Copilot to perform the tasks necessary to gather information and perform operations. +4. Notice how Copilot searches through the issues, finds the right one, and creates the PR. +5. Select the link generated by Copilot to review your pull request, but please **don't merge it yet**. + +## Summary and next steps + +Congratulations! In this exercise, we explored how to use GitHub Copilot Agent Mode to add new capabilities to the application. We learned how: + +- GitHub Copilot Agent Mode can implement new features across both backend and frontend codebases. +- Copilot Agent Mode can explore your project, identify relevant files, and make coordinated changes. +- to review changes and tests generated by Copilot Agent Mode before merging into your codebase. + +Now let's [return to our coding agent][next-lesson] to see how well it did with the issues we assigned to it. + +### Bonus exploration exercise – Implement paging + +As the list of games grows there will be a need for paging to be enabled. Using the skills you learned in this exercise, prompt Copilot to update the site to implement paging. Some considerations for the code include: + +- follow the existing best practices, including using the existing instructions files. +- consider how you want paging implemented, if you want to allow the user to select the page size or for it to be hard-coded. +- as you create the prompt ensure you provide Copilot with the necessary guidance to create the implementation as you desire. +- you may need to iterate with GitHub Copilot, asking for changes and providing context. This is the normal flow when working with Copilot! + +## Resources + +- [Coding agent 101][coding-agent-101] +- [Copilot ask, edit, and agent modes: What they do and when to use them][choose-mode] +- [Agent mode in VS Code][vs-code-agent-mode] + +--- + +| [← Previous lesson: Custom instructions][previous-lesson] | [Next lesson: GitHub Copilot coding agent →][next-lesson] | +|:--|--:| + +[previous-lesson]: ./2-custom-instructions.md +[next-lesson]: ./4-copilot-coding-agent.md +[coding-agent-101]: https://github.blog/ai-and-ml/github-copilot/agent-mode-101-all-about-github-copilots-powerful-mode/ +[choose-mode]: https://github.blog/ai-and-ml/github-copilot/copilot-ask-edit-and-agent-modes-what-they-do-and-when-to-use-them/ +[vs-code-agent-mode]: https://code.visualstudio.com/docs/copilot/chat/chat-agent-mode diff --git a/rendered/tailspin-toys-dotnet/4-copilot-coding-agent.md b/rendered/tailspin-toys-dotnet/4-copilot-coding-agent.md new file mode 100644 index 00000000..cddb60ee --- /dev/null +++ b/rendered/tailspin-toys-dotnet/4-copilot-coding-agent.md @@ -0,0 +1,200 @@ +# Exercise 4 - GitHub Copilot coding agent + +| [← Previous lesson: Copilot agent mode][previous-lesson] | [Next lesson: Reviewing coding agent →][next-lesson] | +|:--|--:| + +There are likely very few, if any, organizations who don't struggle with tech debt. This could be unresolved security issues, legacy code requiring updates, or feature requests which have languished on the backlog because there just wasn't the time to implement them. GitHub Copilot's coding agent is built to perform tasks such as updating code and adding functionality, all in an autonomous fashion. Once the agent completes its work, it generates a draft PR ready for a human developer to review. This allows offloading of tedious tasks and an acceleration of the development process, and frees developers to focus on larger picture items. + +You'll explore the following with Copilot coding agent: + +- customizing the environment for generating code. +- ensuring operations are performed securely. +- the importance of clearly scoped issues. +- assigning issues to Copilot. + +## Scenario + +Tailspin Toys has some tech debt they'd like to address. The contractors initially hired to create the first version of the site left the documentation in an unideal state - and by that you'll notice it's completely lacking. As a first step, they'd like to see XML documentation comments added to all public types, methods and properties in the application. + +Additionally, the design team is ready to get to work on building the UX for managing games. They don't need a full implementation yet, but they at least need some endpoints they can use for testing. Specifically, they need endpoints for the games API which will allow them to create, update and delete games. This is currently a blocker, but there are other issues which are of higher priority at the moment. + +These are both examples of tasks which can quickly find themselves deprioritized, and are great to assign to Copilot coding agent. Copilot coding agent can then work on them asynchronously, allowing the developer to focus on other tasks, then return to review Copilot's work and ensure everything is as expected. + +## Introducing GitHub Copilot coding agent + +[GitHub Copilot coding agent][coding-agent-overview] can perform tasks in the background, much in the same way a human developer would. And, just like with working with a human developer, this can be done in multiple ways, including [assigning a GitHub issue to Copilot][assign-issue]. Once assigned, Copilot will create a draft pull request to track its progress, setup an environment, and begin working on the task. You can dig into Copilot's session while it's still in flight or after its completed. Once its ready for you to review the proposed solution, it'll tag you in the pull request! + +## The importance of well-scoped instructions + +While it can often feel like it, there is no magic in GitHub Copilot. There are no magic solutions available, where you can with just a couple of sentences snap your fingers and let AI perform the entire task for you. In fact, even seemingly straight-forward operations can often have fair amount of complexity when you peel back the layers. + +As a result, you want to [be mindful about how you approach assigning tasks to Copilot coding agent][coding-agent-best-practices]. Working with Copilot as an AI pair programmer is typically the best approach. Approach tasks, big and small, following the same strategy you would without Copilot - work in stages, learn, experiment, and adapt accordingly. + +As always, the fundamentals of software development do not change with the addition of generative AI. + +## Setting up the dev environment for the Copilot coding agent + +Creating code, regardless of who's involved, typically requires a specific environment and some setup scripts to be run to ensure everything is in a good state. This holds true when assigning tasks to Copilot, which is performing tasks in a similar fashion to a SWE. + +Coding agent uses [GitHub Actions][github-actions] for its environment when doing its work. You can customize this environment by creating a [special setup workflow][setup-workflow], configured in the **.github/workflows/copilot-setup-steps.yml** file, to run before it gets to work. This enables it to have access to the required development tools and dependencies. This has been pre-configured ahead of the lab to help the lab flow and allow this learning opportunity. It makes sure that Copilot has access to .NET, Node.JS, and the required dependencies for the client and server: + +```yaml +name: "Copilot Setup Steps" + +# Allows you to test the setup steps from your repository's "Actions" tab +on: workflow_dispatch + +jobs: + copilot-setup-steps: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Checkout code + uses: actions/checkout@v4 + + # Backend setup - .NET + - name: Set up .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: "8.0" + + - name: Restore .NET dependencies + run: dotnet restore server/TailspinToys.sln + + - name: Build .NET project + run: dotnet build server/TailspinToys.sln --no-restore + + # Frontend setup - Node.js + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + cache: "npm" + cache-dependency-path: "./client/package.json" + + - name: Install JavaScript dependencies + working-directory: ./client + run: npm ci +``` + +It looks like any other GitHub workflow file, but it has a few key points: + +- It contains a single job called **copilot-setup-steps**. This job is executed in GitHub Actions before Copilot starts working on the pull request. +- Notice the **workflow_dispatch** trigger, which allows you to run the workflow manually from the Actions tab of your repository. This is useful for testing that the workflow runs successfully instead of waiting for Copilot to run it. + +## Adding documentation + +While everyone understands the importance of documentation, most projects have either outdated information or lack it altogether. This is the type of tech debt which often goes unaddressed, slowing productivity and making it more difficult to maintain the codebase or bring new developers into the team. Fortunately, Copilot shines at creating documentation, and this is a perfect issue to assign to Copilot coding agent. It'll work in the background to generate the necessary documentation. In a future exercise you'll return to review its work. + +1. Navigate to your repository on github.com in a new browser tab. +2. Select the **Issues** tab. +3. Select **New issue** to open the new issue dialog. +4. Select **Blank issue** to create the new issue. +5. Set the **Title** to `Code lacks documentation`. +6. Set the **Description** to: + + ```plaintext + Our organization has a requirement that all functions have XML documentation comments (or the language equivalent). Unfortunately, recent updates haven't followed this standard. We need to update the existing code to ensure XML documentation comments (or the equivalent) are included with every public type, method, and property. + ``` + +7. Select **Create** to create the issue. +8. On the right side, select **Assign to Copilot** to open the assignment dialog. + + ![Assigning Copilot to an issue](images/shared-assign-copilot.png) + +9. Select **Assign**. + + ![Copilot assignment details](images/ex4-assign-copilot-details.png) + +10. Select the **Pull Requests** tab. +11. Open the newly generated pull request (PR), which will be titled something similar to **[WIP]: Code lacks documentation**. If a new PR doesn't appear on the list, wait for a moment or two and refresh the browser window. +12. After a few minutes, you should see that Copilot has created a todo list. + +> [!NOTE] +> It make take several minutes for the todo list from Copilot to appear in the PR. Copilot is creating its environment (running the workflow highlighted previously), analyzing the project, and determining the best approach to tackling the problem. + +13. Review the list and the tasks it's going to complete. +14. Scroll down the pull request timeline, and you should see an update that Copilot has started working on the issue. +15. Select the **View session** button. + + ![Copilot session view](images/ex4-view-session.png) + +> [!IMPORTANT] +> You may need to refresh the window to see the updated indicator. + +16. Notice that you can scroll through the live session, and how Copilot is solving the problem. That includes exploring the code and understanding the state, how Copilot pauses to think and decide on the appropriate plan and also creating code. + +This will likely take several minutes. One of the primary goals of Copilot coding agent is to allow it to perform tasks asynchronously, freeing us to focus on other tasks. We're going to take advantage of that very feature by both assigning another task to Copilot coding agent, then turning our attention to writing some code to add features to our application. + +## Create new API endpoints + +As has been highlighted, one of the great advantages of GitHub Copilot coding agent is the ability to divide work, where you can focus on one set of tasks while it focuses on another. While creating the endpoints for modifying games for the design team might not necessarily take a long time, it's still time which could be used for other tasks. Let's assign it to Copilot coding agent! + +1. Return to your repository on github.com. +2. Select the **Issues** tab. +3. Select **New issue** to open the new issue dialogue. +4. Select **Blank issue** to use the blank template. +5. Set the **Title** to: `Add endpoints to create and edit games` +6. Set the **Description** to: + + ```markdown + We're going to be creating functionality in the future to allow for the submission (and editing) of games. For now we just want the endpoints so we can explore how we want to create the UX and do some acceptance testing. Our requirements are: + + - Add new endpoints to the Games API to support creating, updating and deleting games + - There should be appropriate error handling for all new endpoints + - There should be unit tests created for all new endpoints + - Before creating the PR, ensure all tests pass + ``` + +7. Select **Create** to create the issue. +8. On the right side, select **Assign to Copilot** to open the assignment dialog. + + ![Assigning Copilot to an issue](images/shared-assign-copilot.png) + +9. Select **Assign**. + +Shortly after, you should see a set of 👀 on the first comment in the issue, indicating Copilot is on the job! + +![Copilot uses the eyes emoji to indicate it's working on the issue](images/ex4-issue-eyes-emoji.png) + +9. Select **Assign** to assign the issue to Copilot coding agent. + +Copilot is now diligently working on your second request! Copilot coding agent works in a similar fashion to a SWE, so you don't need to actively monitor it, but instead review once it's completed. Let's turn your attention to writing code and adding other features. +## Summary and next steps + +With coding agent working diligently in the background, you can now turn your attention to your next lesson, [creating and using custom agents][next-lesson]. [Copilot coding agent can also use MCP servers][coding-agent-mcp], and has custom instructions available to it, which you explored in earlier modules. + +## Summary and next steps + +This lesson explored [GitHub Copilot coding agent][copilot-agents], your AI peer programmer. With coding agent you can assign issues to Copilot to perform asynchronously. You can use Copilot to address tech debt, create new features, or aid in migrating code from one framework to another. + +You explored these concepts: + +- customizing the environment for generating code. +- ensuring operations are performed securely. +- the importance of clearly scoped issues. +- assigning issues to Copilot. + +With coding agent working diligently in the background, we can now turn our attention to our next lesson, [creating and using custom agents][next-lesson]. [Copilot coding agent can also use MCP servers][coding-agent-mcp], and has custom instructions available to it, which we explored in earlier modules. + +## Resources + +- [About Copilot coding agent][copilot-agents] +- [Assigning GitHub issues to Copilot][assign-issue] +- [Copilot coding agent setup workflow best practices][coding-agent-best-practices] + +--- + +| [← Previous lesson: Copilot agent mode][previous-lesson] | [Next lesson: Custom agents →][next-lesson] | +|:--|--:| + +[coding-agent-overview]: https://docs.github.com/copilot/using-github-copilot/coding-agent/about-assigning-tasks-to-copilot#overview-of-copilot-coding-agent +[coding-agent-mcp]: https://docs.github.com/copilot/how-tos/agents/copilot-coding-agent/extending-copilot-coding-agent-with-mcp +[assign-issue]: https://docs.github.com/copilot/using-github-copilot/coding-agent/using-copilot-to-work-on-an-issue +[setup-workflow]: https://docs.github.com/copilot/using-github-copilot/coding-agent/best-practices-for-using-copilot-to-work-on-tasks#pre-installing-dependencies-in-github-copilots-environment +[copilot-agents]: https://docs.github.com/copilot/using-github-copilot/coding-agent/about-assigning-tasks-to-copilot +[coding-agent-best-practices]: https://docs.github.com/copilot/using-github-copilot/coding-agent/best-practices-for-using-copilot-to-work-on-tasks +[github-actions]: https://docs.github.com/actions +[next-lesson]: ./5-custom-agents.md +[previous-lesson]: ./3-copilot-agent-mode-vscode.md diff --git a/rendered/tailspin-toys-dotnet/5-custom-agents.md b/rendered/tailspin-toys-dotnet/5-custom-agents.md new file mode 100644 index 00000000..3256c9a8 --- /dev/null +++ b/rendered/tailspin-toys-dotnet/5-custom-agents.md @@ -0,0 +1,93 @@ +# Exercise 5 - Custom agents + +| [← Previous lesson: GitHub Copilot coding agent][previous-lesson] | [Next lesson: Managing agents →][next-lesson] | +|:--|--:| + +[Custom agents][custom-agents] in GitHub Copilot allow you to create specialized AI assistants tailored to specific tasks or domains within your development workflow. By defining agents through markdown files in the `.github/agents` folder of your repository, you can provide Copilot with focused instructions, best practices, coding patterns, and domain-specific knowledge that guide it to perform particular types of work more effectively. This allows teams to codify their expertise and standards into reusable agents. You might create an accessibility agent that ensures [WCAG][wcag] compliance, a security agent that follows secure coding practices, or a testing agent that maintains consistent test patterns—enabling developers to leverage these specialized capabilities on-demand for faster, more consistent implementations. + +You'll explore the following with custom agents: + +- how to create a custom agent. +- assigning a task to a custom agent. + +## Scenario + +Tailspin Toys is committed to ensuring their crowdfunding platform is accessible to all users, regardless of their visual abilities or preferences. Recent user feedback has highlighted that some users find the current dark theme difficult to read due to insufficient contrast between text and background colors. To address this accessibility concern, the design team has requested the implementation of a high-contrast mode that users can toggle on and off. + +Because accessibility is critical, you want to ensure this is implemented as quickly as possible. You're going to utilize a custom agent to generate the functionality. +## Custom agents + +Custom agents are defined by markdown files in the **.github/agents** folder of your project. The markdown files will contain guidance for Copilot on how best to perform at task. + +## Reviewing the accessibility custom agent + +A custom agent has already been created for you for accessibility. Let's review the contents to understand how it will guide Copilot. + +1. Return to your codespace. +2. Open **.github/agents/accessibility.md**. +3. Note the header section with the name and description of the agent. + +> [!IMPORTANT] +> This section is required for custom agents. + +4. From there, scan and review the next sections which highlight: + - Core responsibilities when generating code for an accessible website. + - Best practices for accessibility. + - Code examples for HTML, CSS and JavaScript. + - A list of common pitfalls and mistakes. + +> [!NOTE] +> There is no "best markdown" for a custom agent. As with anything in AI, you will want to test and explore to determine what works best for your environments and scenarios. + +## Create and assign an issue + +Mission control is the central location for working with all agents for your environment. You can assign tasks to Copilot coding agent, monitor tasks, and even redirect and provide additional guidance. Let's start by assigning a task to create the high contrast mode to Copilot. + +1. Navigate to your repository. +2. Select the issues tab. +3. Select **New issue** to open the new issue dialog. +4. Select **Blank issue** to create the new issue. +5. Set the **Title** to `Add high contrast mode to website`. +6. Set the **Description** to: + + ```plaintext + We need a high contrast mode for the site. There should be a toggle for high contrast which the user can set. It should store the setting in local storage on the browser. + ``` + +7. Select **Create** to create the issue. +8. On the right side, select **Assign to Copilot** to open the assignment dialog. +9. Select **Accessibility agent** from the list of custom agents. + + ![Screenshot of coding agent assignment, with custom agent and accessibility highlighted](./images/ex5-select-custom-agent.png) + +10. Select **Assign**. +11. Copilot gets to work on the task in the background! + +## Summary and next steps + +This lesson explored [custom agents][custom-agents] in GitHub Copilot, specialized AI assistants tailored to specific tasks and domains. With custom agents you can codify your team's expertise and standards into reusable agents that guide Copilot to perform particular types of work more effectively. + +You explored these concepts: + +- how to create a custom agent. +- assigning a task to a custom agent. + +With Copilot working on implementing the high contrast mode, we can now turn our attention to our next lesson, [using Copilot HQ to monitor and guide agent sessions][next-lesson]. Custom agents help ensure that Copilot follows your organization's best practices and domain-specific requirements, enabling faster and more consistent implementations across your team. + +## Resources + +- [Custom agents][custom-agents] +- [Preparing to use custom agents in your organization][org-custom-agents] +- [Preparing to use custom agents in your enterprise][enterprise-custom-agents] + +--- + +| [← Previous lesson: GitHub Copilot coding agent][previous-lesson] | [Next lesson: Managing agents →][next-lesson] | +|:--|--:| + +[custom-agents]: https://docs.github.com/copilot/concepts/agents/coding-agent/about-custom-agents +[wcag]: https://www.w3.org/WAI/standards-guidelines/wcag/ +[org-custom-agents]: https://docs.github.com/copilot/how-tos/administer-copilot/manage-for-organization/prepare-for-custom-agents +[enterprise-custom-agents]: https://docs.github.com/copilot/how-tos/administer-copilot/manage-for-enterprise/manage-agents/prepare-for-custom-agents +[next-lesson]: ./6-managing-agents.md +[previous-lesson]: ./4-copilot-coding-agent.md diff --git a/rendered/tailspin-toys-dotnet/6-managing-agents.md b/rendered/tailspin-toys-dotnet/6-managing-agents.md new file mode 100644 index 00000000..7c00bf5a --- /dev/null +++ b/rendered/tailspin-toys-dotnet/6-managing-agents.md @@ -0,0 +1,88 @@ +# Exercise 6 - Monitoring and managing agents + +| [← Previous lesson: Custom agents][previous-lesson] | [Next lesson: Iterating on Copilot's work →][next-lesson] | +|:--|--:| + +In the last couple of exercises you asked Copilot coding agent to take on three separate tasks focused on improving the user experience and adding functionality. While coding agent is built to operate asynchronously and autonomously, the ability to monitor these tasks is still important. + +There are numerous tools available to you to manage tasks assigned to coding agent, including [the agents page][agents-page] on GitHub.com. From this mission control you can see all agent tasks with open pull requests (PRs). You can explore the operations performed, and even steer an in-progress session to help guide it. + +In this lesson you will: + +- explore the agents page to monitor coding agent tasks. +- steer an in-flight session to request additional functionality. + +## Scenario + +After assigning the agent to create a high-contrast mode, the team realized it would be a good time to add a light mode as well. Since work was already being done to update the style of the site and add toggle functionality, it seemed logical to include this functionality. You want to steer the agent's work to ensure it adds a light mode as well as high contrast. + +## Review Copilot coding agent tasks + +Let's see the current status of all tasks assigned to Copilot coding agent. + +1. Navigate to agents page at [https://github.com/copilot/agents](https://github.com/copilot/agents). +2. Note the list of tasks, both on the main pane and on the left pane. You should see the list of the tasks you've assigned to Copilot, including: + - Updating documentation for your codebase. + - Generating new API endpoints for games. + - Adding a high contrast mode for the website. +3. Select one of the running tasks. Review the tasks which have been performed by Copilot. These can include: + - Checking out the code from the repository. + - Creating the environment for Copilot to work. + - Setting up MCP servers. + - Performing various steps to complete the assigned task. + +> [!NOTE] +> The exact steps listed will vary depending on the state of Copilot's work and the approach it took. + +4. Also note the pull request (PR) pane which appears on the right side. This allows you to see the PR and files changed for additional monitoring. +## Steering coding agent + +Now that you've seen the tasks which are active, let's request Copilot include the light mode toggle while it works on the high-contrast mode. + +1. Select the session which refers to adding a high contrast mode. The exact title will vary depending on the name Copilot uses and the current state of work. + + ![Accessibility session in mission control](images/ex6-accessibility-session.png) + +2. Watch the session for a few of minutes, until it indicates it's completed the setup and begun its work. You'll know this has happened when you start seeing messages similar to the ones below. +3. In the **Steer active session while Copilot is working** dialog, add the following prompt: + + ``` + While we are working on a high contrast mode, let's also add a light mode. There should be a switch for this mode as well where users can select their desired display mode. + ``` + + ![Screenshot of the coding agent task in the agents page with the steer active session while copilot is working dialogue highlighted](./images/ex6-steer-coding-agent-task.png) + +4. Press Enter to send the prompt. +5. Notice how Copilot acknowledges the prompt and includes it in its flow. + +## Let Copilot do its work + +Just like before, Copilot will get to work on the updated task! It will incorporate the new request into its flow after it completes the particular step it's working on when you sent the message. + +As before, this will take several minutes, so it's a good time to pause and reflect on everything you've learned and explored thus far. + +## Summary and next steps + +This lesson explored the Copilot agents page, your central hub for monitoring and guiding GitHub Copilot coding agent tasks. With this mission control you can track all active and completed tasks, review the work being performed, and even redirect in-flight tasks to adjust scope or provide additional guidance. + +You explored these concepts: + +- explored Copilot HQ and the agents page to monitor coding agent tasks. +- redirected an in-flight session to request additional functionality. + +With Copilot completing its work on the accessibility features, we can now turn our attention to our next lesson, [iterating on the pull requests Copilot created][next-lesson]. Mission control provides visibility into agent work and enables dynamic collaboration with coding agents as they work on tasks. + +## Resources + +- [Copilot HQ agents page][agents-page] +- [Custom agents][custom-agents] + +--- + +| [← Previous lesson: Custom agents][previous-lesson] | [Next lesson: Iterating on coding agent's work →][next-lesson] | +|:--|--:| + +[agents-page]: https://github.blog/changelog/2025-10-28-a-agents-page-to-assign-steer-and-track-copilot-coding-agent-tasks +[custom-agents]: https://docs.github.com/copilot/concepts/agents/coding-agent/about-custom-agents +[next-lesson]: ./7-iterating-copilot-work.md +[previous-lesson]: ./5-custom-agents.md diff --git a/rendered/tailspin-toys-dotnet/7-iterating-copilot-work.md b/rendered/tailspin-toys-dotnet/7-iterating-copilot-work.md new file mode 100644 index 00000000..4fb9bc17 --- /dev/null +++ b/rendered/tailspin-toys-dotnet/7-iterating-copilot-work.md @@ -0,0 +1,173 @@ +# Exercise 7: Iterating on GitHub Copilot's work + +| [← Previous lesson: Mission control][previous-lesson] | +|:--| + +Throughout this lab you've assigned several issues to GitHub Copilot coding agent. You asked it to add documentation to your code, generate endpoints for the design team to iterate on, and implement accessibility features including high-contrast and light mode toggles. Let's explore the code changes it suggested and, if necessary, provide feedback to Copilot to improve its work. + +## Scenario + +As has been highlighted numerous times, the fundamentals of software design and DevOps do not change with the addition of generative AI. We always want to review the code generated, and work through our normal DevOps process. With that in mind, let's review the suggestions from GitHub Copilot for creating the documentation, new endpoints, and accessibility features before we turn on review for the rest of our team. + +## Security and GitHub Copilot coding agent + +Because Copilot coding agent performs its tasks asynchronously and without supervision, certain security constraints have been put in place to ensure everything remains safe. These include: + +- Copilot only has read access to your repository and write access **only** to the branch it will use for its code. +- Coding agent runs inside of GitHub Actions, where it will create a separate, ephemeral environment in which to work. +- Any GitHub Actions workflows require approval from a human before they can be run. +- [Access to external resources is limited by default][agent-firewall], including MCP servers. + +## Reviewing the generated documentation + +Let's start by exploring the first pull request (PR) generated by GitHub Copilot coding agent - adding documentation to your code. You'll perform this task by utilizing the standard PR interface in GitHub.com. + +> [!NOTE] +> When you explore the PR you may notice a warning about GitHub Copilot being blocked by a firewall. This **is expected**, as Copilot has limited access to external resources by default, including calls to external MCP servers. If you wish, you can [customize or disable the firewall for Copilot coding agent][agent-firewall]. + +1. Return to your repository on github.com. +2. Select **Pull Requests** to open the list of pull requests. +3. Open issue titled something similar to **Add missing documentation** or something more robust. + +> [!NOTE] +> If Copilot is still working on the task, the issue will contain the **[WIP]** flag. If so, wait for Copilot to complete the work. This may take a few minutes, so feel free to take a break, or reflect on everything you've learned so far. + +4. Once the pull request is ready, select the **Files changed** tab and review the changes. + + ![Files changed tab](images/shared-pr-files-changed.png) + +5. Explore the newly updated code, which includes the newly created docstrings and other documentation. The exact changes will vary. +6. Once you've reviewed the updates and everything looks good, navigate back to the **Conversation** tab and scroll down. +7. You should see an indicator that some workflows are waiting for approval. +8. Click on the **Approve and run workflows** button to allow the workflows to run. + + ![Approve and run workflows](images/shared-approve-workflows.png) + +9. You should see the workflows get queued in the checks section of the pull request. All being well, you should see that the workflows pass for both the backend and frontend. This may take a few minutes to complete. + +## Requesting changes from GitHub Copilot + +Working with Copilot on a pull request is not just a one-way street. You can also tag Copilot in comments - like you would other members of your team - in the pull request, or inline comments of the code. Copilot will see these comments, and trigger another session to address them. Due to the non-deterministic results, we can't give prescriptive text of what to ask for. Some ideas of what to ask Copilot to update include: + +- Add comment headers to the top of each code file with a brief description of what they do. +- Add docstrings to TypeScript and Svelte files. +- Create a README in both the server and client folders with descriptions of the codebase of each. + +1. Add a comment requesting a change to the generated documentation, tagging **@copilot** like you would any user. Use one of the ideas above, or another suggestion for Copilot around documentation you'd like to see in the codebase. +2. Select **View Session** to watch Copilot perform its work. Notice how Copilot starts a new session to make the updates. +3. You can select **Back to pull request** to return to the pull request. + + ![Back to pull request](images/ex7-back-to-pr.png) + +4. Once Copilot has completed the changes, you should see a new commit in the pull request. +5. Select the **Files changed** tab to review the changes. + +Feel free to continue iterating until you are happy. Once happy, you can convert the PR to ready from a draft, and merge it into the main branch. + +![Convert PR to ready](images/ex7-ready-for-review.png) + +## Review the new endpoints + +Let's return to the PR Copilot generated for resolving our issue about adding endpoints to the games API for creating, updating and deleting games. + +1. Return to your repository in GitHub.com. +2. Select the **Pull Requests** tab. +3. Select the PR which has a title similar to **Add CRUD endpoints for games API** or something more robust. +4. Select the **Files changed** tab to review the code it generated. +5. Once you've reviewed the updates and everything looks good, navigate back to the **Conversation** tab and scroll down. +6. You should see an indicator that some workflows are waiting for approval. +7. Click on the **Approve and run workflows** button to allow the workflows to run. + + ![Approve and run workflows](images/shared-approve-workflows.png) + +8. You should see the workflows get queued in the checks section of the pull request. All being well, you should see that the workflows pass for both the backend and frontend. This may take a few minutes to complete. +9. **Optional:** You could even switch to this branch in your Codespace to perform a manual test of the new endpoints. Navigate to your Codespace, open the terminal, and run the following commands (replace **** with the name of the branch Copilot created, e.g. **copilot/fix-8**.): + + ```bash + git fetch origin + git checkout + ``` + +Copilot has created the new endpoints! Just as before, you can work iteratively with Copilot coding agent to request updates. For example, you might want to request Copilot centralizes the error handling to reduce duplication, or ensuring comments and docstrings are added (remember - this was assigned **before** you made the updates to your custom instructions!) Just like before, you can make these requests by adding a new comment on the **Conversation** tab, which Copilot will see and kickoff a new session. + +## Review the accessibility features + +Finally, let's review the accessibility features that were implemented using the custom accessibility agent. This PR should include both the high-contrast mode you assigned in Exercise 5, and the light mode that was requested in mission control in Exercise 6. + +1. Return to your repository in GitHub.com. +2. Select the **Pull Requests** tab. +3. Select the PR which has a title similar to **Add high contrast mode to website** or something more robust. + +> [!NOTE] +> If Copilot is still working on the task, the issue will contain the **[WIP]** flag. If so, wait for Copilot to complete the work. This may take a few minutes. + +4. Select the **Files changed** tab to review the code it generated. +5. Review the implementation, paying particular attention to: + - The toggle UI components for switching between modes + - The use of local storage to persist user preferences + - The CSS or styling changes for high-contrast and light modes + - The accessibility attributes (ARIA labels, keyboard navigation, etc.) + - Any JavaScript/TypeScript code that manages the mode switching + +6. Once you've reviewed the updates and everything looks good, navigate back to the **Conversation** tab and scroll down. +7. You should see an indicator that some workflows are waiting for approval. +8. Click on the **Approve and run workflows** button to allow the workflows to run. + + ![Approve and run workflows](images/shared-approve-workflows.png) + +9. You should see the workflows get queued in the checks section of the pull request. All being well, you should see that the workflows pass for both the backend and frontend. This may take a few minutes to complete. +10. **Optional:** You could switch to this branch in your Codespace to manually test the accessibility features. Navigate to your Codespace, open the terminal, and run the following commands (replace **** with the name of the branch Copilot created): + + ```bash + git fetch origin + git checkout + ``` + + Then start the application and test the high-contrast and light mode toggles in your browser to ensure they work as expected and persist across page reloads. + +Notice how the custom accessibility agent helped guide Copilot to implement these features following accessibility best practices. If you see any accessibility concerns or improvements, you can tag **@copilot** in a comment to request updates, just like you did with the previous PRs. + +## Optional Exercise - Explore the agent's capabilities with more issues + +Having access to a peer programmer who is able to explore our codebase and make changes asynchronously is powerful, allowing us to reach a first iteration across tasks quickly, allowing us to review and guide, or take over and continue coding in the editor. + +You have made great progress through the lab, and you're approaching the end. However, you're encouraged to create some additional issues in your GitHub repository and use Copilot to solve those. Some ideas include: + +- Create a backer interest form on the game details page +- Implement pagination on the game listing endpoint +- Add input validation and error handling to the API +- Something else? What else might you consider? + +## Summary + +Congratulations! You completed the lab! You worked through several features available to you with GitHub Copilot, from the IDE to the repository. In particular you: + +- **Learned how to use GitHub Copilot and the Model Context Protocol (MCP) to streamline software development**. You set up the GitHub MCP server to enable Copilot to interact with your repository, created a detailed backlog using Copilot Agent Mode. +- **Explored how custom instructions and prompt files can guide Copilot to follow your project's coding standards.** You created a custom instructions file to provide context for Copilot, ensuring it generates code that adheres to your project's guidelines and used prompt files to provide guidance for repetitive tasks and established practices. +- **Used Copilot Agent Mode to implement new features, coordinate changes across backend and frontend code, and automate repetitive tasks.** You used GitHub Copilot to implement a new category and publisher filter for the game listing page, making changes across the client, backend, and the resulting tests. +- **Experienced Copilot as a peer programmer, being assigned issues and working collaboratively on pull requests.** You assigned Copilot to issues in your backlog, allowing it to create a pull request, build a plan, implement changes, and iterate further as you provided feedback. + +This is just the beginning, and we can't wait to see how you use Copilot to help you with your own projects. We hope you enjoyed the lab, and we look forward to seeing you in the next one! Happy coding! + +## Resources + +- [GitHub Copilot][github-copilot] +- [About Copilot agents][copilot-agents] +- [Assigning GitHub issues to Copilot][assign-issue] +- [Copilot coding agent setup workflow best practices][coding-agent-best-practices] +- [Configuring Copilot coding agent firewall][agent-firewall] + +--- + +| [← Previous lesson: Managing agents][previous-lesson] | +|:--| + +[github-copilot]: https://github.com/features/copilot +[coding-agent-overview]: https://docs.github.com/copilot/using-github-copilot/coding-agent/about-assigning-tasks-to-copilot#overview-of-copilot-coding-agent +[assign-issue]: https://docs.github.com/copilot/using-github-copilot/coding-agent/using-copilot-to-work-on-an-issue +[setup-workflow]: https://docs.github.com/copilot/using-github-copilot/coding-agent/best-practices-for-using-copilot-to-work-on-tasks#pre-installing-dependencies-in-github-copilots-environment +[copilot-agents]: https://docs.github.com/copilot/using-github-copilot/coding-agent/about-assigning-tasks-to-copilot +[coding-agent-best-practices]: https://docs.github.com/copilot/using-github-copilot/coding-agent/best-practices-for-using-copilot-to-work-on-tasks +[agent-firewall]: https://docs.github.com/copilot/customizing-copilot/customizing-or-disabling-the-firewall-for-copilot-coding-agent + +[previous-lesson]: ./6-managing-agents.md diff --git a/rendered/tailspin-toys/0-prereqs.md b/rendered/tailspin-toys/0-prereqs.md new file mode 100644 index 00000000..0b76b958 --- /dev/null +++ b/rendered/tailspin-toys/0-prereqs.md @@ -0,0 +1,47 @@ +# Exercise 0: Prerequisites + +Before you get started on the lab, there's a few tasks you need to complete to get everything ready. You need to get a copy of the repository which includes the code, then spin up a [codespace][codespaces] to use to create your code. + +## Setting up the Lab Repository + +To create a copy of the repository for the code you'll create an instance from the [template][template-repository]. The new instance will contain all of the necessary files for the lab, and you'll use it as you work through the exercises. + +1. In a new browser window, navigate to the GitHub repository for this lab: `https://github.com/github-samples/agents-in-sdlc`. +2. Create your own copy of the repository by selecting the **Use this template** button on the lab repository page. Then select **Create a new repository**. + + ![Use this template button](images/ex0-use-template.png) + +3. If you are completing the workshop as part of an event being led by GitHub or Microsoft, follow the instructions provided by the mentors. Otherwise, you can create the new repository in an organization where you have access to Copilot coding agent and can assign issues to Copilot. + + ![Input the repository template settings](images/ex0-repository-settings.png) + +4. Make a note of the repository path you created (**organization-or-user-name/repository-name**), as you will be referring to this later in the lab. + +## Creating a codespace + +Next up, you'll be using a codespace to complete the lab exercises. [GitHub Codespaces][codespaces] are a cloud-based development environment that allows you to write, run, and debug code directly in your browser. It provides a fully-featured IDE with support for multiple programming languages, extensions, and tools. + +1. Navigate to your newly created repository. +2. Select the green **Code** button. + + ![Select the Code button](images/ex0-code-button.png) + +3. Select the **Codespaces** tab and select the **+** button to create a new Codespace. + + ![Create a new codespace](images/ex0-create-codespace.png) + +The creation of the codespace will take several minutes, although it's still far quicker than having to manually install all the services! That said, you can use this time to explore other features of GitHub Copilot, which we'll turn your attention to next! + +> [!IMPORTANT] +> You'll return to the codespace in a future exercise. For the time being, leave it open in a tab in your browser. + +## Summary + +Congratulations, you have created a copy of the lab repository! You also began the creation process of your codespace, which you'll use when you begin writing code. + +## Next step + +Let's explore how you can use Model Context Protocol (MCP) to interact with external services! You can do this by [setting up the backlog with Copilot agent mode and GitHub's MCP Server](./1-mcp.md). + +[codespaces]: https://github.com/features/codespaces +[template-repository]: https://docs.github.com/repositories/creating-and-managing-repositories/creating-a-template-repository diff --git a/rendered/tailspin-toys/1-mcp.md b/rendered/tailspin-toys/1-mcp.md new file mode 100644 index 00000000..1ad7d494 --- /dev/null +++ b/rendered/tailspin-toys/1-mcp.md @@ -0,0 +1,230 @@ +# Exercise 1 - Setting up the backlog with Copilot agent mode and GitHub's MCP Server + +| [← Prerequisites][previous-lesson] | [Next lesson: Custom instructions →][next-lesson] | +|:--|--:| + +There's more to writing code than just writing code. Issues need to be filed, external services need to be called, and information needs to be gathered. Typically this involves interacting with external tools, which can break a developer's flow. Through the power of Model Context Protocol (MCP), you can access all of this functionality right from Copilot! + +## Scenario + +You are a part-time developer for Tailspin Toys - a crowdfunding platform for board games with a developer theme. You've been assigned various tasks to introduce new functionality to the website. Being a good team member, you want to file issues to track your work. To help future you, you've decided to enlist the help of Copilot. You will set up your backlog of work for the rest of the lab, using GitHub Copilot Chat agent mode and the GitHub Model Context Protocol (MCP) server to create the issues for you. + +In this exercise, you will: + +- use Model Context Protocol (MCP), which provides access to external tools and capabilities. +- set up the GitHub MCP server in your repository. +- use GitHub Copilot Chat agent mode to create issues in your repository. + +By the end of this exercise, you will have created a backlog of GitHub issues for use throughout the remainder of the lab. + +## What is agent mode and Model Context Protocol (MCP)? + +Agent mode in GitHub Copilot Chat transforms Copilot into an AI agent that can perform actions on your behalf. This mode allows you to interact with Copilot in a more dynamic way, enabling it to use tools and execute tasks, like running tests or terminal commands, reading problems from the editor, and using those insights to update your code. This allows for a more interactive and collaborative workflow, enabling you to leverage the capabilities of AI in your development process. + +[Model Context Protocol (MCP)][mcp-blog-post] provides AI agents with a way to communicate with external tools and services. By using MCP, AI agents can communicate with external tools and services in real-time. This allows them to access up-to-date information (using resources) and perform actions on your behalf (using tools). + +These tools and resources are accessed through an MCP server, which acts as a bridge between the AI agent and the external tools and services. The MCP server is responsible for managing the communication between the AI agent and the external tools (such as existing APIs or local tools like NPM packages). Each MCP server represents a different set of tools and resources that the AI agent can access. + +![Diagram showing the inner works of agent mode and how it interacts with context, LLM and tools - including tools contributed by MCP servers and VS Code extensions](images/ex1-mcp-diagram.png) + +A couple of popular existing MCP servers are: + +- **[GitHub MCP Server][github-mcp-server]**: This server provides access to a set of APIs for managing your GitHub repositories. It allows the AI agent to perform actions such as creating new repositories, updating existing ones, and managing issues and pull requests. +- **[Playwright MCP Server][playwright-mcp-server]**: This server provides browser automation capabilities using Playwright. It allows the AI agent to perform actions such as navigating to web pages, filling out forms, and clicking buttons. + +There are many other MCP servers available that provide access to different tools and resources. GitHub hosts an [MCP registry][mcp-registry] to enhance discoverability and contributions to the ecosystem. + +> [!IMPORTANT] +> With regard to security, treat MCP servers as you would any other dependency in your project. Before using an MCP server, carefully review its source code, verify the publisher, and consider the security implications. Only use MCP servers that you trust and be cautious about granting access to sensitive resources or operations. + +## Ensure your codespace is ready + +In a [prior exercise][prereqs-lesson] you launched the codespace you'll use for the remainder of the coding exercises in this lab. Let's put the final touches on it before you begin using it. + +The setup process for the codespace installed and setup many [VS Code extensions][vscode-extensions]. As with any software, updates may be needed. When your codespace is created you'll need to ensure everything is up-to-date. + +1. Return to the tab where you started your codespace. If you closed the tab, return to your repository, select **Code** > **Codespaces** and then the name of the codespace. +2. Select **Extensions** on the workbench on the left side of your codespace. + + ![Screenshot of the extensions window with multiple extensions showing either Update or Reload Window buttons](images/ex1-extensions-updates.png) + +3. Select **Update** on any extensions with an **Update** button. Repeat as necessary. +4. Select **Reload Window** on any extensions with a **Reload Window** button to reload the codespace. +5. When prompted by a dialog, select **Reload** to reload the window. This will ensure the latest version is being used. + +## Using GitHub Copilot Chat and agent mode + +To access GitHub Copilot Chat agent mode, you need to have the GitHub Copilot Chat extension installed in your IDE, which should already be the case if you are using a GitHub Codespace. + +> [!TIP] +> If you do not have the GitHub Copilot Chat extension installed, you can [install it from the Visual Studio Code Marketplace][copilot-chat-extension]. Or open the Extensions view in Visual Studio Code, search for **GitHub Copilot Chat**, and select **Install**. + +Once you have the extension installed, you may need to authenticate with your GitHub account to enable it. + +1. Return to your codespace. +2. If you don't already see Copilot Chat on the right side of your editor, select the **Copilot Chat** icon at the top of your codespace. +3. Type a message like "Hello world" in the Copilot Chat window and press enter. This should activate Copilot Chat. +4. Alternatively, if you are not authenticated you will be prompted to sign in to your GitHub account. Follow the instructions to authenticate. + + ![Example of Copilot Chat authentication prompt](images/ex1-copilot-authentication.png) + +5. After authentication, you should see the Copilot Chat window appear. +6. Switch to agent mode by selecting the dropdown in the Copilot Chat window and selecting **Agent**. + + ![Example of switching to agent mode](images/shared-agent-mode-dropdown.png) + +7. Set the model to **Claude Sonnet 4.5**. + + ![Example of selecting the Claude Sonnet 4.5 model](images/ex1-select-model.png) + +> [!IMPORTANT] +> The authors of this workshop are not indicating a preference towards one model or another. When building this workshop, we used Claude Sonnet 4.5, and as such are including that in the instructions. The hope is the code suggestions you receive will be relatively consistent to ensure a good experience. However, because LLMs are probabilistic, you may notice the suggestions received differ from what is indicated in the workshop. This is perfectly normal and expected. + +8. The chat pane should update to indicate that you are now in agent mode. You should see a tools icon on the same line as the mode and model, which you utilized earlier, showing that you can configure tools for GitHub Copilot to use. + +Typically, the number of tools available will be set to 0 when setting up a new project, as you have not configured any MCP servers yet. But to help you get started, the project has a **.vscode/mcp.json** file with an example configuration for the [GitHub MCP server][github-mcp-server]. Let's go and explore that next. + +## Setting up the GitHub MCP server + +The **.vscode/mcp.json** file is used to configure the MCP servers that are available in this Visual Studio Code workspace. The MCP servers provide access to external tools and resources that GitHub Copilot can use to perform actions on your behalf. + +1. Open **.vscode/mcp.json** file in your repository. +2. You should see a JSON structure similar to the following: + + ```json + { + "servers": { + "github": { + "type": "http", + "url": "https://api.githubcopilot.com/mcp/" + } + } + } + ``` + +This configuration provides GitHub Copilot access to several additional tools so that it can interact with GitHub repositories, issues, pull requests, and more. This particular configuration uses the [remote GitHub MCP server][remote-github-mcp-server]. By using this approach, you don't need to worry about running the MCP server locally (and the associated management, like keeping it up to date), and you can authenticate to the remote server using OAuth 2.0 instead of a personal access token (PAT). + +The MCP server configuration is defined in the **servers** section of the **mcp.json** file. Each MCP server is defined by a unique name (in this case, github) and its type (in this case, **http**). When using local MCP servers, the type may be **stdio** and have a **command** and **args** field to specify how to start the MCP server. You can find out more about the configuration format in the [VS Code documentation][vscode-mcp-config]. In some configurations (not for the remote GitHub MCP server with OAuth), you may also see an **inputs** section. This defines any inputs (like sensitive tokens) that the MCP server may require. You can read more about the configuration properties in the [VS Code documentation][vscode-mcp-config] + +To utilize an MCP server it needs to be "started". This will allow GitHub Copilot to communicate with the server and perform the tasks you request. + +> [!NOTE] The exact authentication flow may vary a little bit. + +1. Inside VS Code, open **.vscode/mcp.json**. +2. To start the GitHub MCP server, select **Start** above the GitHub server. + + ![The start button above the GitHub MCP server entry](images/ex1-start-mcp-server.png) + +3. You should see a popup asking you to authenticate to GitHub. + + ![A popup showing that the GitHub MCP server wants to authenticate to GitHub](images/ex1-mcp-auth-popup.png) + +4. Select **Continue** on the user account that you're using for this lab. + + ![A popup showing the user account selection for GitHub authentication](images/ex1-mcp-select-account.png) + +5. If the page appears, select **Authorize visual-studio-code** to allow the GitHub MCP server to login as your selected user account. Once complete, the page should say "You can now close the window.". + + ![A popup showing the authorization for visual-studio-code app](images/ex1-mcp-authorize-vscode.png) + +6. After navigating back to the GitHub Codespace, you should see that the GitHub MCP server has started. You can check this in two places: + - The line in **.vscode/mcp.json** which previously said start should now present several options, and show a number of tools available. + - Select the tools icon in the Copilot Chat pane to see the tools available. Scroll down the list that appears at the top of the screen, and you should see a list of tools from the GitHub MCP server. + +That's it! You can now use Copilot Chat in agent mode to create issues, manage pull requests, and more. + +## Creating a backlog of tasks + +Now that you have set up the GitHub MCP server, you can use Copilot Agent mode to create a backlog of tasks for use in the rest of the lab. + +1. Return to the Copilot Chat pane. Ensure **Agent** is selected for the mode and **Claude Sonnet 4.5** is selected for the model. +2. Type or paste the following prompt to create the issues you'll be working on in the lab: + + ```markdown + In my GitHub repo, create GitHub issues for our Tailspin Toys backlog. Each issue should include: + - A clear title + - A brief description of the task and why it is important to the project + - A checkbox list of acceptance criteria + + From our recent planning meeting, the upcoming backlog includes the following tasks: + + 1. Allow users to filter games by category and publisher + 2. Update our repository coding standards (including rules about code formatting and documentation) in a custom instructions file + 3. Stretch Goal: Implement pagination on the game list page + ``` + +3. Press enter or select the **Send** button to send the prompt to Copilot. +4. GitHub Copilot should process the request and respond with a dialog box asking you to confirm the creation of the issues. + + ![Example of Copilot Chat dialog box asking for confirmation to run the create issue command](images/ex1-create-issue-dialog.png) + +> [!IMPORTANT] +> Remember, AI can make mistakes, so make sure to review the issues before confirming. + +5. Select **see more** in **Run open new issue** box to see the details of the issue that will be created. +6. Ensure the details in the **owner** and **repo**, **title** and **body** of the issue look correct. You can make any desired edits by double clicking the body and updating the content with the correct information. +7. After reviewing the generated content, select **Continue** to create the issue. + + ![Example of the expanded dialog box showing the GitHub Issue that will be created](images/ex1-create-issue-review.png) + +8. Repeat steps 4-6 for the remainder of the issues. Alternatively, if you are comfortable with Copilot automatically creating the issues you can select the down-arrow next to **Continue** and select **Allow in this session** to allow Copilot to create the issues for this session (the current chat). + + ![Example of allowing Copilot to automatically create issues](images/ex1-create-issue-allow.png) + +> [!IMPORTANT] +> Ensure you are comfortable with Copilot automatically performing tasks on your behalf before you selecting **Allow in this session** or a similar option. + +9. In a separate browser tab, navigate to your GitHub repository and select the issues tab. +10. You should see a list of issues that have been created by Copilot. Each issue should include a clear title and a checkbox list of acceptance criteria. + +You should notice that the issues are fairly detailed. This is where you benefit from the power of Large Language Models (LLMs) and Model Context Protocol (MCP), as it has been able to create a clear initial issue description. + +![Example of issues created in GitHub](images/ex1-github-issues-created.png) + +## Summary and next steps + +Congratulations, you have created issues on GitHub using Copilot Chat and MCP! + +To recap, in this exercise you: + +- used Model Context Protocol (MCP), which provides access to external tools and capabilities. +- set up the GitHub MCP server in your repository. +- used GitHub Copilot Chat agent mode to create issues in your repository. + +With the GitHub MCP server configured, you can now use GitHub Copilot Chat Agent Mode to perform additional actions on your behalf, like creating new repositories, managing pull requests, and searching for information across your repositories. + +You can now continue to the next exercise, where you will learn how to [provide Copilot guidance with custom instructions][next-lesson] to ensure code is generated following your organization's defined patterns and practices. + +### Optional exploration exercise – Set up the Microsoft Playwright MCP server + +If you are feeling adventurous, you can try installing and configuring another MCP server, such as the [Microsoft Playwright MCP server][playwright-mcp-server]. This will allow you to use GitHub Copilot Chat Agent Mode to perform browser automation tasks, such as navigating to web pages, filling out forms, and clicking buttons. + +You can find the instructions for installing and configuring the Playwright MCP server in the [Playwright MCP repository][playwright-mcp-server]. + +Notice that the setup process is similar to the GitHub MCP server, but you do not need to provide any credentials like the GitHub Personal Access Token. This is because the Playwright MCP server does not require authentication to access its capabilities. + +## Resources + +- [What the heck is MCP and why is everyone talking about it?][mcp-blog-post] +- [GitHub MCP Server][github-mcp-server] +- [Microsoft Playwright MCP Server][playwright-mcp-server] +- [GitHub MCP Registry][mcp-registry] +- [VS Code Extensions][vscode-extensions] +- [GitHub Copilot Chat Extension][copilot-chat-extension] + +--- + +| [← Prerequisites][previous-lesson] | [Next lesson: Custom instructions →][next-lesson] | +|:--|--:| + +[previous-lesson]: ./0-prereqs.md +[next-lesson]: ./2-custom-instructions.md +[prereqs-lesson]: ./0-prereqs.md +[mcp-blog-post]: https://github.blog/ai-and-ml/llms/what-the-heck-is-mcp-and-why-is-everyone-talking-about-it/ +[github-mcp-server]: https://github.com/github/github-mcp-server +[playwright-mcp-server]: https://github.com/microsoft/playwright-mcp +[mcp-registry]: https://github.com/mcp +[vscode-extensions]: https://code.visualstudio.com/docs/configure/extensions/extension-marketplace +[copilot-chat-extension]: https://marketplace.visualstudio.com/items?itemName=GitHub.copilot +[remote-github-mcp-server]: https://github.blog/changelog/2025-06-12-remote-github-mcp-server-is-now-available-in-public-preview/ +[vscode-mcp-config]: https://code.visualstudio.com/docs/copilot/chat/mcp-servers#_configuration-format diff --git a/rendered/tailspin-toys/2-custom-instructions.md b/rendered/tailspin-toys/2-custom-instructions.md new file mode 100644 index 00000000..48ce2101 --- /dev/null +++ b/rendered/tailspin-toys/2-custom-instructions.md @@ -0,0 +1,255 @@ +# Exercise 2 - Providing context to Copilot with instruction files + +| [← Previous lesson: Model Context Protocol (MCP)][previous-lesson] | [Next lesson: Copilot agent mode →][next-lesson] | +|:--|--:| + +Context is key across many aspects of life, and when working with generative AI. If you're performing a task which needs to be completed a particular way, or if a piece of background information is important, you want to ensure Copilot has access to that information. You can use [instruction files][instruction-files] to provide guidance so that Copilot not only understands what you want it to do but also how you want it to be done. + +In this exercise, you will learn how to: + +- provide Copilot with project-specific context, coding guidelines and documentation standards using [repository custom instructions][repository-custom-instructions] **.github/copilot-instructions.md**. +- provide path instruction files to guide Copilot for repetitive or templated tasks on specific types of files. +- implement both repository-wide instructions and task-specific instructions. + +> [!IMPORTANT] +> Note that the code generated may diverge from some of the standards you set. AI tools like Copilot are non-deterministic, and may not always provide the same result. The other files in the codebase do not contain documentation or comment headers, which could lead Copilot in another direction. Consistency is key, so making sure that your code follows the established patterns is important. You can always follow-up in chat and ask Copilot to follow your coding standards, which will help guide it in the right direction. + +## Scenario + +As any good dev shop, Tailspin Toys has a set of guidelines and requirements for development practices. These include: + +- API always needs unit tests. +- UI should be in dark mode and have a modern feel. +- Documentation should be added to code in the form of docstrings. +- A block of comments should be added to the head of each file describing what the file does. + +Through the use of instruction files you'll ensure Copilot has the right information to perform the tasks in alignment with the practices highlighted. + +## Before you begin + +You're going to be making some code changes, so you should follow the usual practice of creating a new branch to work in. This will allow you to make changes without affecting the main branch until you're ready. + +1. Return to your codespace from the previous exercise. +2. Open a new terminal window inside your codespace by selecting Ctl+\`. +3. Create and switch to a new branch by running the following command in the terminal: + + ```bash + git checkout -b add-filters + ``` + +## Custom instructions + +Custom instructions allow you to provide context and preferences to Copilot chat, so that it can better understand your coding style and requirements. This is a powerful feature that can help you steer Copilot to get more relevant suggestions and code snippets. You can specify your preferred coding conventions, libraries, and even the types of comments you like to include in your code. You can create instructions for your entire repository, or for specific types of files for task-level context. + +There are two types of instructions files: + +- **.github/copilot-instructions.md**, a single instruction file sent to Copilot for **every** chat prompt for the repository. This file should contain project-level information, context which is relevant for most chat requests sent to Copilot. This could include the tech stack being used, an overview of what's being built and best practices, and other global guidance for Copilot. +- **\*.instructions.md** files can be created for specific tasks or file types. You can use **\*.instructions.md** files to provide guidelines for particular languages (like Python or TypeScript), or for tasks like creating a Flask blueprint or a new set of unit tests. + +> [!NOTE] +> When working in your IDE, instructions files are only used for code generation in Copilot Chat, and not used for code completions or next edit suggestions. +> +> Copilot coding agent will utilize both repository level and \*.instructions with `applyTo` header matter when generating code. + +## Best practices for managing instructions files + +A full conversation about creating instructions files is beyond the scope of the workshop. However, the examples provided in the sample project provide a representative example of how to approach their management. At a high level: + +- Keep instructions in **copilot-instructions.md** focused on project-level guidance, such as a description of what's being built, the structure of the project, and global coding standards. +- Use **\*.instructions.md** files to provide specific instructions for file types (unit tests, Flask blueprints, API endpoints), or for specific tasks. +- Use natural language in your instructions files. Keep guidance clear. Provide examples of how code should (and shouldn't) look. + +There isn't one specific way to create instructions files, just as there isn't one specific way to use AI. You will find through experimentation what works best for your project. The guidance provided here and the [resources](#resources) below should help you get started. + +> [!TIP] +> Every project using GitHub Copilot should have a robust collection of instructions files to provide context and best guide code generation. As you explore the instructions files in the project, you may notice there are ones for numerous types of files and tasks, including [UI updates](../.github/instructions/ui.instructions.md) and [Astro](../.github/instructions/astro.instructions.md). The investment made in instructions files will greatly enhance the quality of code suggestion from Copilot, ensuring it better matches the style and requirements your organization has. +> +> You can even have Copilot aid in generating instructions files by selecting the gear icon for **Configure Chat** in Copilot chat and selecting **Generate Agent Instructions**. +> +> ![Screenshot of option in GitHub Copilot chat with configure chat highlighted and generate agent instructions highlighted](./images/ex2-generate-instructions.png) + +## Use GitHub Copilot Chat before updating custom instructions + +To see the impact of custom instructions, you'll start by sending a prompt with the current version of the files. You'll then make some updates, send the same prompt again, and note the difference. + +1. Return to your codespace. +2. Close any open files in your codespace from the previous exercises. This will ensure Copilot has the context you want it to have. +3. Open `server/routes/publishers.py`, an empty file. +4. If **Copilot chat** is not already open, open it by selecting the Copilot icon towards the top of your codespace. +5. Create a new chat session by typing `/clear` into the chat window and selecting Enter (or return on a Mac). +6. Select **Ask** from the modes dropdown. + + ![Chat mode selection dialog with Ask mode highlighted](./images/ex2-select-chat-mode.png) + +7. Send the following prompt to create a new endpoint to return all publishers: + + ```plaintext + Create a new endpoint to return a list of all publishers. It should return the name and id for all publishers. + ``` + +8. Copilot explores the project to learn how best to implement the code, and generates a list of suggestions, which may include code for `publishers.py`, `app.py`, and tests to ensure the new code runs correctly. +9. Explore the code, noticing the generated code includes [type hints][python-type-hints] because, as you'll see, the custom instructions includes the directive to include them. +10. Notice the generated code **is missing** either a docstring or a comment header - or both! + +> [!IMPORTANT] +> As highlighted previously, GitHub Copilot and LLM tools are probabilistic, not deterministic. As a result, the exact code generated may vary, and there's even a chance it'll abide by your rules without you spelling it out! But to aid consistency in code you should always document anything you want to ensure Copilot should understand about how you want your code generated. + +## Add new repository standards to copilot-instructions.md + +As highlighted previously, `copilot-instructions.md` is designed to provide project-level information to Copilot. Let's ensure repository coding standards are documented to improve code suggestions from Copilot chat. + +1. Return to your codespace. +2. Open `.github/copilot-instructions.md`. +3. Explore the file, noting the brief description of the project and sections for **Code standards**, **Scripts** and **GitHub Actions Workflows**. These are applicable to any interactions you'd have with Copilot, are robust, and provide clear guidance on what you're doing and how you want to accomplish it. +4. Locate the **Code formatting requirements** section, which should be near line 27. Note how it contains a note to use type hints. That's why you saw those in the code generated previously. +5. Add the following lines of markdown right below the note about type hints to instruct Copilot to add comment headers to files and docstrings (which should be near line 27): + + ```markdown + - Every function should have docstrings or the language equivalent. + - Before imports or any code, add a comment block to the file that explains its purpose. + ``` + +6. Close **copilot-instructions.md**. +7. Select **New Chat** in Copilot chat to clear the buffer and start a new conversation. +8. Return to **server/routes/publishers.py** to ensure focus is set correctly. +9. Send the same prompt as before to create the endpoint. + + ```plaintext + Create a new endpoint to return a list of all publishers. It should return the name and id for all publishers. + ``` + +10. Notice how the newly generated code includes a comment header at the top of the file which resembles the following: + + ```python + """ + Publisher API routes for the Tailspin Toys Crowd Funding platform. + This module provides endpoints to retrieve publisher information. + """ + ``` + +11. Notice how the newly generated code includes a docstring inside the function which resembles the following: + + ```python + """ + Returns a list of all publishers with their id and name. + + Returns: + Response: JSON response containing an array of publisher objects + """ + ``` + +12. Notice the generated code now includes a docstring as well as a comment block at the top! +13. Also note how the existing code isn't updated, but of course you could ask Copilot to perform that operation if you so desired! +14. **Don't implement the suggested changes**, as you'll be doing that in the next section. + +> [!NOTE] +> If you accepted the changes, you can always select the **Undo** button towards the top right of the Copilot chat window. + +From this section, you explored how the custom instructions file has provided Copilot with the context it needs to generate code that follows the established guidelines. + +## Instructions for specific tasks or files + +Coding is often repetitive, with developers performing similar tasks on a regular basis. Copilot is wonderful for allowing you to offload the mundane, like adding endpoints, generating tests, or building a new component. But all code has a set of requirements, and often require a particular template or structure to be followed. **\*.instructions.md** files allow you to provide tailored guidance for these types of tasks and files. They can be added manually when using Copilot Chat, or can have an `applyTo:` tag added to the top of the file to have Copilot automatically use them for specific files. + +## Explore a task-specific custom instructions file + +You want to create a new endpoint to list all publishers, and to follow the same pattern used for the existing [games endpoints][games-endpoints], and to create tests which follow the same pattern as the existing [games endpoints tests][games-tests]. An instruction file has already been created; let's explore it and see the difference in code it generates. + +1. Open `.github/instructions/python-tests.instructions.md`. +2. Note the `applyTo:` section at the top, which contains a filter for all files in the `server/tests` directory which start with `test_` and have a `.py` extension. Whenever Copilot Chat interacts with a file which matches this pattern it will automatically use the guidance provided in this file. +3. Note the file contains guidance about how tests should be created, and how to utilize SQLite when testing database functionality. +4. Open `.github/instructions/flask-endpoint.instructions.md`. +5. Review the following entries inside the instruction file, which includes: + + - an overview of requirements, including that tests must be created, and endpoints are created in Flask using blueprints. + - a link to another the previously mentioned `python-tests.instructions.md` file. + - links to two existing files which follow the patterns you want - both the games blueprint and tests. Notice how these are setup as normal markdown links, allowing an instruction file to incorporate additional files for context. + +6. Return to `server/routes/publishers.py` to ensure focus is set correctly. +7. Return to Copilot Chat and select **New Chat** to start a new session. +8. Select **Edit** from the mode dropdown, which will allow Copilot to update multiple files. + + ![Copilot Chat mode selector with Edit chosen and highlighted](./images/ex2-select-edit-mode.png) + +> [!NOTE] +> If you have any issues running the tests in this part of the exercise, please undo your changes and retry from the above step using **Agent** mode instead. + +9. Select the **Add Context** button to open the context dialog +10. If prompted to allow the codespace to see text and images copied to the clipboard, select **Allow**. +11. Select **Instructions** from the dropdown at the top of your codespace. + +> [!TIP] +> If the list of options is long, you can type **instructions** to filter to the Instructions option then select **Instructions**. + +12. Select **flask-endpoint .github/instructions** to add the instruction file to the context. + + ![Screenshot showing the instruction file being added into Copilot Chat](images/ex2-add-instructions-file.png) + +13. Send the same prompt as before to generate the desired endpoint: + + ```plaintext + Create a new endpoint to return a list of all publishers. It should return the name and id for all publishers. + ``` + +> [!NOTE] +> While the up-arrow shortcut to resend a prior command is handy, it will reset any context you might add as well. If you added in the instructions file as context, then use the up arrow, it will remove the instructions file. For this particular step, make sure you copy/paste (or type) the command to avoid accidentally removing context. + +14. Note the **References** section and how it uses the **flask-endpoint.instructions.md** file to provide context. If you use instructions files with Copilot agent mode, you will notice that Copilot explores and reads the files referenced in the instructions file. + + ![Screenshot of the references section, showing the included instructions file](./images/ex2-copilot-instructions-references.png) + +15. Copilot generates the files. Notice how it generates updates across multiple files, like **publishers.py** and **test_publishers.py** + +> [!NOTE] +> Note that the code generated may diverge from some of the standards we set. AI tools like Copilot are non-deterministic, and may not always provide the same result. The other files in our codebase do not contain docstrings or comment headers, which could lead Copilot in another direction. Consistency is key, so making sure that your code follows the established patterns is important. You can always follow-up in chat and ask Copilot to follow your coding standards, which will help guide it in the right direction. + +16. After reviewing the code, select **Keep** in Copilot Chat to accept the changes. +17. Open a terminal window by selecting Ctl+`. +18. Run the tests by running the script with the following command: + + ```sh + ./scripts/run-server-tests.sh + ``` + +19. Once the code is correct, and all tests pass, open the **Source Control** panel on the left of the Codespace and review the changes made by Copilot. +20. Stage the changes by selecting the **+** icon in the **Source Control** panel. +21. Generate a commit message using the **Sparkle** button. + + ![Screenshot of the Source Control panel showing the changes made](images/ex2-source-control-changes.png) + +22. Commit the changes to your repository by selecting **Commit**. + +## Summary and next steps + +Congratulations! You explored how to ensure Copilot has the right context to generate code following the practices your organization has set forth. This can be done at a repository level with the **.github/copilot-instructions.md** file, or on a task basis with instruction files. You explored how to: + +- provide Copilot with project-specific context, coding guidelines and documentation standards using custom instructions (.github/copilot-instructions.md). +- use instruction files to guide Copilot for repetitive or templated tasks. +- implement both repository-wide instructions and task-specific instructions. + +Next we'll use [agent mode to add functionality to the site][next-lesson]. + +## Resources + +- [Instruction files for GitHub Copilot customization][instruction-files] +- [5 tips for writing better custom instructions for Copilot][copilot-instructions-five-tips] +- [Best practices for creating custom instructions][instructions-best-practices] +- [Personal custom instructions for GitHub Copilot][personal-instructions] +- [Awesome Copilot - a collection of instructions files and other resources][awesome-copilot] + +--- + +| [← Previous lesson: Model Context Protocol (MCP)][previous-lesson] | [Next lesson: Copilot agent mode →][next-lesson] | +|:--|--:| + +[previous-lesson]: ./1-mcp.md +[next-lesson]: ./3-copilot-agent-mode-vscode.md +[instruction-files]: https://code.visualstudio.com/docs/copilot/copilot-customization +[python-type-hints]: https://docs.python.org/3/library/typing.html +[games-endpoints]: ../server/routes/games.py +[games-tests]: ../server/tests/test_games.py +[instructions-best-practices]: https://docs.github.com/enterprise-cloud@latest/copilot/using-github-copilot/coding-agent/best-practices-for-using-copilot-to-work-on-tasks#adding-custom-instructions-to-your-repository +[personal-instructions]: https://docs.github.com/copilot/customizing-copilot/adding-personal-custom-instructions-for-github-copilot +[copilot-instructions-five-tips]: https://github.blog/ai-and-ml/github-copilot/5-tips-for-writing-better-custom-instructions-for-copilot/ +[awesome-copilot]: https://github.com/github/awesome-copilot +[repository-custom-instructions]: https://docs.github.com/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot diff --git a/rendered/tailspin-toys/3-copilot-agent-mode-vscode.md b/rendered/tailspin-toys/3-copilot-agent-mode-vscode.md new file mode 100644 index 00000000..1e566103 --- /dev/null +++ b/rendered/tailspin-toys/3-copilot-agent-mode-vscode.md @@ -0,0 +1,223 @@ +# Exercise 3 - Adding new functionality with Copilot Agent Mode + +| [← Previous lesson: Custom instructions][previous-lesson] | [Next lesson: GitHub Copilot coding agent →][next-lesson] | +|:--|--:| + +Even the simplest of updates to an application typically require updates to multiple files and operations to be performed like running tests. As a developer your flow typically involves tracking down all the necessary files, making the changes, running the tests, debugging, figuring out which file was missed, making another update... The list goes on and on. + +This is where Copilot Agent Mode comes into play. + +Copilot Agent Mode is built to act more autonomously in your IDE. It behaves in a similar fashion to a developer, starting by exploring the existing project structure, performing the necessary updates, running tasks like tests, and automatically fixing any discovered mistakes. Let's explore how you can use Agent Mode to introduce new functionality to your site. + +> [!NOTE] +> While the names are similar, agent mode and coding agent are built for two different types of experiences. Agent mode performs its tasks in your IDE, allowing for quick feedback cycles and interaction. Coding agent is designed as a peer programmer, working asynchronously like a member of the team, interacting with you via issues and pull requests. + +In this exercise, you will learn how: + +- Copilot Agent Mode can explore your project, identify relevant files, and make coordinated changes. +- GitHub Copilot Agent Mode can implement new features across both backend and frontend codebases. +- to review changes and tests generated by Copilot Agent Mode before merging into your codebase. + +## Scenario + +As the list of games grows, Tailspin Toys wants to allow users to filter by publisher and category. This will require updating both the API and UI, and updating the tests for the API. With the help of Copilot Agent Mode you'll work with your AI pair programmer to add the new feature! + +## Running the application + +Before you make any changes, let's explore the Tailspin Toys website to understand its current functionality. + +The website is a crowdfunding platform for board games with a developer theme. It allows users to list games and display details about them. The website has two main components: the front-end (written in Svelte) and the backend (written in Python using Flask). + +### Starting the application + +To make running the website easier, a script has been provided that will start both the front-end and back-end servers. You can run this script in your GitHub Codespace with the following instructions: + +1. Return to your codespace. You'll continue working in your current branch. +2. Open a new terminal window inside your codespace by selecting Ctl + \`. +3. Run the following script to start the application: + + ```bash + scripts/start-app.sh + ``` + + Once the script is running, you should see output indicating that both the front-end and back-end servers are running, similar to the below: + + ```bash + Server (Flask) running at: http://localhost:5100 + Client (Astro) server running at: http://localhost:4321 + ``` + +> [!NOTE] +> If a dialog box opens prompting you to open a browser window for `http://localhost:5100` close it by selecting the **x**. + +4. Open the website by using Ctrl-**Click** (or Cmd-**Click** on a Mac) on the client address `http://localhost:4321` in the terminal. + +> [!NOTE] +> When using a codespace, selecting a link for the localhost URL from the Codespace terminal will automatically redirect you to `https://-4321.app.github.dev/`. This is a private tunnel to your codespace, which is now hosting your web server! + +### Exploring the application + +Once the application is running, you can explore its functionality. The main features of the website include: + +- **Home Page**: Displays a list of board games with their titles, images, and descriptions. +- **Game Details Page**: When you select a game, you'll be brought to a details page with more information about the game, including its title, description, publisher and category. +## Explore the backlog with Copilot + +The initial implementation of the application is functional, but we want to enhance it by adding new capabilities. Let's start off by reviewing the backlog. Ask GitHub Copilot to show you the backlog of items that we created in the previous exercise. + +1. Return to your codespace. +2. Open **Copilot Chat**. +3. Create a new chat session by selecting the **New Chat** button, which will remove any previous context. +4. Ensure **Agent** is selected from the list of modes. +5. Select **Claude Sonnet 4.5** from the list of available models. + +> [!IMPORTANT] +> The authors of this lab are not indicating a preference towards one model or another. When building this lab, we used Claude Sonnet 4.5, and as such are including that in the instructions. The hope is the code suggestions you receive will be relatively consistent to ensure a good experience. However, because LLMs are probabilistic, you may notice the suggestions received differ from what is indicated in the lab. This is perfectly normal and expected. + +6. Open the GitHub Copilot Chat, if it is not already open. +7. Switch to **Agent** mode, if you are not already in agent mode. +8. Select **Claude Sonnet 4.5** from the list of available models. + +> [!IMPORTANT] +> The authors of this lab are not indicating a preference towards one model or another. When building this lab, we used Claude Sonnet 4.5, and as such are including that in the instructions. The hope is the code suggestions you receive will be relatively consistent to ensure a good experience. However, because LLMs are probabilistic, you may notice the suggestions received differ from what is indicated in the lab. This is perfectly normal and expected. + +> [!NOTE] +> Because of the probabilistic nature of LLMs, Copilot may utilize a different MCP command, but should still be able to complete the task. + +8. Ask Copilot about the backlog of issues by sending the following prompt to Copilot: + + ```plaintext + Please show me the backlog of items from my GitHub repository. Help me prioritize them based on those which will be most useful to the user. + ``` +9. Select **Continue** to run the command to list all issues. +10. Review the generated list of issues. + +Notice how Copilot has even prioritized the items for you, based on the ones that it thinks will be most useful to the user. + +## Review instructions files + +Before kicking off the agent to generate the code, it's a good time to review the instructions file you'll use to provide Copilot context for its work. You're going to take advantage of the [user interface (UI)](../.github/instructions/ui.instructions.md) file, which contains context on how to approach adding functionality to the website. + +1. In your codespace, navigate to **.github/instructions/ui.instructions.md**. +2. Take note of the overall guidance on how to approach adding functionality. This includes: + - An overview of the architecture. + - Principles for component design, testability and accessibility. + - Links to specific instructions files for various file types, including: + - Astro + - Svelte + - Tailwind CSS + +> [!TIP] +> Instructions files allow you to reference both other instructions files and files in your project. The paths are relative to the location of the instructions file. This allows for reuse, breaking down complex instructions into smaller more manageable chunks, and providing examples and templates. + +## Implement the filtering functionality + +To implement filtering, no less than three separate updates will need to be made to the application: + +- A new endpoint added to the API +- A new set of tests for the new endpoint +- Updates to the UI to introduce the functionality + +In addition, the tests need to run (and pass) before you merge everything into your codebase. Copilot Agent Mode can perform these tasks for you! Let's add the functionality. + +1. You can continue in the current conversation with Copilot, or start a new one by selecting **New Chat**. +2. Select **Add Context**, **Instructions**, and **ui** as the instructions file. + + ![Screenshot showing an example of selecting the UI instructions file](images/ex3-select-instructions-file.png) + +3. Ensure **Agent** mode is still selected. + + ![Screenshot of Copilot Chat mode selection with Agent highlighted](./images/shared-agent-mode-dropdown.png) + +4. Ensure **Claude Sonnet 4.5** is still selected for the model. +5. Prompt Copilot to implement the functionality based on the issue you created earlier by using the following prompt: + + ```plaintext + Please update the site to include the filtering feature based on the requirements from the related GitHub issue in the backlog. Ensure all tests are passing before completion. The server is already running, so you do not need to start it up. + ``` + +6. Watch as Copilot begins by exploring the project, locating the files associated with the desired functionality. You should see it finding both the API and UI definitions, as well as the tests. It then begins modifying the files and running the tests. + + ![Screenshot showing Copilot exploring the project files](images/ex3-agent-mode-explores.png) + +> [!NOTE] +> You will notice that Copilot will perform several tasks, like exploring the project, modifying files, and running tests. It may take a few minutes depending on the complexity of the task and the codebase. During that process, you may notice **Keep** and **Undo** buttons appear in the code editor. When Copilot is finished, you will have a **Keep** or **Undo** for all of the changes, so you do not need to select them while work is in progress. + +7. As prompted by Copilot, select **Continue** to run the tests. + + ![Screenshot showing a dialog in the Copilot Chat pane asking the user to confirm they are happy to run tests](images/ex3-agent-mode-run-tests.png) + +8. You may experience some pauses and even see some tests fail throughout the process. That's okay! Copilot works back and forth between code generation and tests until it completes the task and doesn't detect any errors. + + ![Screenshot showing a complete Chat session with Copilot Agent Mode](images/ex3-agent-mode-proposed-changes.png) + +9. Explore the generated code for any potential issues. + +> [!IMPORTANT] +> Remember, it's always important to review the code that Copilot or any AI tools generate. + +10. Return to the browser with the website running. Explore the new functionality! +11. Once you've confirmed everything works and reviewed the code, select **Keep** in the Copilot Chat window. + +## Publish the branch and create a pull request + +With your changes created locally you're ready to create a pull request (PR) to allow for your team to review your suggested changes and work through your DevOps process. The first step in that process is to publish the branch. Let's take care of that first. + +1. Navigate to the **Source Control** panel in the Codespace and review the changes made by Copilot. +2. Stage the changes by selecting the **+** icon. +3. Generate a commit message using the **Sparkle** button. + + ![Screenshot of the Source Control panel showing the changes made](images/ex3-source-control-changes.png) + +4. Select **Publish** to push the branch to your repository. + +## Create the pull request + +There are several ways to create a pull request, including through github.com and the GitHub command-line interface (CLI). But since you're already working with GitHub Copilot, let's let it create the PR for you! You can have it find the relevant issue and create the PR with an association to the located issue. + +1. Navigate to the Copilot Chat panel and select **New Chat** to start a new session. +2. Ask Copilot to create a PR for you: + + ```plaintext + Find the issue in the repo related to the filtering feature. Create a new pull request for the current add-filters branch, and associate it with the correct issue. + ``` + +3. As needed, select **Continue** to allow Copilot to perform the tasks necessary to gather information and perform operations. +4. Notice how Copilot searches through the issues, finds the right one, and creates the PR. +5. Select the link generated by Copilot to review your pull request, but please **don't merge it yet**. + +## Summary and next steps + +Congratulations! In this exercise, we explored how to use GitHub Copilot Agent Mode to add new capabilities to the application. We learned how: + +- GitHub Copilot Agent Mode can implement new features across both backend and frontend codebases. +- Copilot Agent Mode can explore your project, identify relevant files, and make coordinated changes. +- to review changes and tests generated by Copilot Agent Mode before merging into your codebase. + +Now let's [return to our coding agent][next-lesson] to see how well it did with the issues we assigned to it. + +### Bonus exploration exercise – Implement paging + +As the list of games grows there will be a need for paging to be enabled. Using the skills you learned in this exercise, prompt Copilot to update the site to implement paging. Some considerations for the code include: + +- follow the existing best practices, including using the existing instructions files. +- consider how you want paging implemented, if you want to allow the user to select the page size or for it to be hard-coded. +- as you create the prompt ensure you provide Copilot with the necessary guidance to create the implementation as you desire. +- you may need to iterate with GitHub Copilot, asking for changes and providing context. This is the normal flow when working with Copilot! + +## Resources + +- [Coding agent 101][coding-agent-101] +- [Copilot ask, edit, and agent modes: What they do and when to use them][choose-mode] +- [Agent mode in VS Code][vs-code-agent-mode] + +--- + +| [← Previous lesson: Custom instructions][previous-lesson] | [Next lesson: GitHub Copilot coding agent →][next-lesson] | +|:--|--:| + +[previous-lesson]: ./2-custom-instructions.md +[next-lesson]: ./4-copilot-coding-agent.md +[coding-agent-101]: https://github.blog/ai-and-ml/github-copilot/agent-mode-101-all-about-github-copilots-powerful-mode/ +[choose-mode]: https://github.blog/ai-and-ml/github-copilot/copilot-ask-edit-and-agent-modes-what-they-do-and-when-to-use-them/ +[vs-code-agent-mode]: https://code.visualstudio.com/docs/copilot/chat/chat-agent-mode diff --git a/rendered/tailspin-toys/4-copilot-coding-agent.md b/rendered/tailspin-toys/4-copilot-coding-agent.md new file mode 100644 index 00000000..31868901 --- /dev/null +++ b/rendered/tailspin-toys/4-copilot-coding-agent.md @@ -0,0 +1,198 @@ +# Exercise 4 - GitHub Copilot coding agent + +| [← Previous lesson: Copilot agent mode][previous-lesson] | [Next lesson: Reviewing coding agent →][next-lesson] | +|:--|--:| + +There are likely very few, if any, organizations who don't struggle with tech debt. This could be unresolved security issues, legacy code requiring updates, or feature requests which have languished on the backlog because there just wasn't the time to implement them. GitHub Copilot's coding agent is built to perform tasks such as updating code and adding functionality, all in an autonomous fashion. Once the agent completes its work, it generates a draft PR ready for a human developer to review. This allows offloading of tedious tasks and an acceleration of the development process, and frees developers to focus on larger picture items. + +You'll explore the following with Copilot coding agent: + +- customizing the environment for generating code. +- ensuring operations are performed securely. +- the importance of clearly scoped issues. +- assigning issues to Copilot. + +## Scenario + +Tailspin Toys has some tech debt they'd like to address. The contractors initially hired to create the first version of the site left the documentation in an unideal state - and by that you'll notice it's completely lacking. As a first step, they'd like to see docstrings added to all functions in the application. + +Additionally, the design team is ready to get to work on building the UX for managing games. They don't need a full implementation yet, but they at least need some endpoints they can use for testing. Specifically, they need endpoints for the games API which will allow them to create, update and delete games. This is currently a blocker, but there are other issues which are of higher priority at the moment. + +These are both examples of tasks which can quickly find themselves deprioritized, and are great to assign to Copilot coding agent. Copilot coding agent can then work on them asynchronously, allowing the developer to focus on other tasks, then return to review Copilot's work and ensure everything is as expected. + +## Introducing GitHub Copilot coding agent + +[GitHub Copilot coding agent][coding-agent-overview] can perform tasks in the background, much in the same way a human developer would. And, just like with working with a human developer, this can be done in multiple ways, including [assigning a GitHub issue to Copilot][assign-issue]. Once assigned, Copilot will create a draft pull request to track its progress, setup an environment, and begin working on the task. You can dig into Copilot's session while it's still in flight or after its completed. Once its ready for you to review the proposed solution, it'll tag you in the pull request! + +## The importance of well-scoped instructions + +While it can often feel like it, there is no magic in GitHub Copilot. There are no magic solutions available, where you can with just a couple of sentences snap your fingers and let AI perform the entire task for you. In fact, even seemingly straight-forward operations can often have fair amount of complexity when you peel back the layers. + +As a result, you want to [be mindful about how you approach assigning tasks to Copilot coding agent][coding-agent-best-practices]. Working with Copilot as an AI pair programmer is typically the best approach. Approach tasks, big and small, following the same strategy you would without Copilot - work in stages, learn, experiment, and adapt accordingly. + +As always, the fundamentals of software development do not change with the addition of generative AI. + +## Setting up the dev environment for the Copilot coding agent + +Creating code, regardless of who's involved, typically requires a specific environment and some setup scripts to be run to ensure everything is in a good state. This holds true when assigning tasks to Copilot, which is performing tasks in a similar fashion to a SWE. + +Coding agent uses [GitHub Actions][github-actions] for its environment when doing its work. You can customize this environment by creating a [special setup workflow][setup-workflow], configured in the **.github/workflows/copilot-setup-steps.yml** file, to run before it gets to work. This enables it to have access to the required development tools and dependencies. This has been pre-configured ahead of the lab to help the lab flow and allow this learning opportunity. It makes sure that Copilot has access to Python, Node.JS, and the required dependencies for the client and server: + +```yaml +name: "Copilot Setup Steps" + +# Allows you to test the setup steps from your repository's "Actions" tab +on: workflow_dispatch + +jobs: + copilot-setup-steps: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Checkout code + uses: actions/checkout@v4 + + # Backend setup - Python + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install Python dependencies + working-directory: ./server + run: pip install -r requirements.txt + + # Frontend setup - Node.js + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + cache: "npm" + cache-dependency-path: "./client/package.json" + + - name: Install JavaScript dependencies + working-directory: ./client + run: npm ci +``` + +It looks like any other GitHub workflow file, but it has a few key points: + +- It contains a single job called **copilot-setup-steps**. This job is executed in GitHub Actions before Copilot starts working on the pull request. +- Notice the **workflow_dispatch** trigger, which allows you to run the workflow manually from the Actions tab of your repository. This is useful for testing that the workflow runs successfully instead of waiting for Copilot to run it. + +## Adding documentation + +While everyone understands the importance of documentation, most projects have either outdated information or lack it altogether. This is the type of tech debt which often goes unaddressed, slowing productivity and making it more difficult to maintain the codebase or bring new developers into the team. Fortunately, Copilot shines at creating documentation, and this is a perfect issue to assign to Copilot coding agent. It'll work in the background to generate the necessary documentation. In a future exercise you'll return to review its work. + +1. Navigate to your repository on github.com in a new browser tab. +2. Select the **Issues** tab. +3. Select **New issue** to open the new issue dialog. +4. Select **Blank issue** to create the new issue. +5. Set the **Title** to `Code lacks documentation`. +6. Set the **Description** to: + + ```plaintext + Our organization has a requirement that all functions have docstrings or the language equivalent. Unfortunately, recent updates haven't followed this standard. We need to update the existing code to ensure docstrings (or the equivalent) are included with every function or method. + ``` + +7. Select **Create** to create the issue. +8. On the right side, select **Assign to Copilot** to open the assignment dialog. + + ![Assigning Copilot to an issue](images/shared-assign-copilot.png) + +9. Select **Assign**. + + ![Copilot assignment details](images/ex4-assign-copilot-details.png) + +10. Select the **Pull Requests** tab. +11. Open the newly generated pull request (PR), which will be titled something similar to **[WIP]: Code lacks documentation**. If a new PR doesn't appear on the list, wait for a moment or two and refresh the browser window. +12. After a few minutes, you should see that Copilot has created a todo list. + +> [!NOTE] +> It make take several minutes for the todo list from Copilot to appear in the PR. Copilot is creating its environment (running the workflow highlighted previously), analyzing the project, and determining the best approach to tackling the problem. + +13. Review the list and the tasks it's going to complete. +14. Scroll down the pull request timeline, and you should see an update that Copilot has started working on the issue. +15. Select the **View session** button. + + ![Copilot session view](images/ex4-view-session.png) + +> [!IMPORTANT] +> You may need to refresh the window to see the updated indicator. + +16. Notice that you can scroll through the live session, and how Copilot is solving the problem. That includes exploring the code and understanding the state, how Copilot pauses to think and decide on the appropriate plan and also creating code. + +This will likely take several minutes. One of the primary goals of Copilot coding agent is to allow it to perform tasks asynchronously, freeing us to focus on other tasks. We're going to take advantage of that very feature by both assigning another task to Copilot coding agent, then turning our attention to writing some code to add features to our application. + +## Create new API endpoints + +As has been highlighted, one of the great advantages of GitHub Copilot coding agent is the ability to divide work, where you can focus on one set of tasks while it focuses on another. While creating the endpoints for modifying games for the design team might not necessarily take a long time, it's still time which could be used for other tasks. Let's assign it to Copilot coding agent! + +1. Return to your repository on github.com. +2. Select the **Issues** tab. +3. Select **New issue** to open the new issue dialogue. +4. Select **Blank issue** to use the blank template. +5. Set the **Title** to: `Add endpoints to create and edit games` +6. Set the **Description** to: + + ```markdown + We're going to be creating functionality in the future to allow for the submission (and editing) of games. For now we just want the endpoints so we can explore how we want to create the UX and do some acceptance testing. Our requirements are: + + - Add new endpoints to the Games API to support creating, updating and deleting games + - There should be appropriate error handling for all new endpoints + - There should be unit tests created for all new endpoints + - Before creating the PR, ensure all tests pass + ``` + +7. Select **Create** to create the issue. +8. On the right side, select **Assign to Copilot** to open the assignment dialog. + + ![Assigning Copilot to an issue](images/shared-assign-copilot.png) + +9. Select **Assign**. + +Shortly after, you should see a set of 👀 on the first comment in the issue, indicating Copilot is on the job! + +![Copilot uses the eyes emoji to indicate it's working on the issue](images/ex4-issue-eyes-emoji.png) + +9. Select **Assign** to assign the issue to Copilot coding agent. + +Copilot is now diligently working on your second request! Copilot coding agent works in a similar fashion to a SWE, so you don't need to actively monitor it, but instead review once it's completed. Let's turn your attention to writing code and adding other features. +## Summary and next steps + +With coding agent working diligently in the background, you can now turn your attention to your next lesson, [creating and using custom agents][next-lesson]. [Copilot coding agent can also use MCP servers][coding-agent-mcp], and has custom instructions available to it, which you explored in earlier modules. + +## Summary and next steps + +This lesson explored [GitHub Copilot coding agent][copilot-agents], your AI peer programmer. With coding agent you can assign issues to Copilot to perform asynchronously. You can use Copilot to address tech debt, create new features, or aid in migrating code from one framework to another. + +You explored these concepts: + +- customizing the environment for generating code. +- ensuring operations are performed securely. +- the importance of clearly scoped issues. +- assigning issues to Copilot. + +With coding agent working diligently in the background, we can now turn our attention to our next lesson, [creating and using custom agents][next-lesson]. [Copilot coding agent can also use MCP servers][coding-agent-mcp], and has custom instructions available to it, which we explored in earlier modules. + +## Resources + +- [About Copilot coding agent][copilot-agents] +- [Assigning GitHub issues to Copilot][assign-issue] +- [Copilot coding agent setup workflow best practices][coding-agent-best-practices] + +--- + +| [← Previous lesson: Copilot agent mode][previous-lesson] | [Next lesson: Custom agents →][next-lesson] | +|:--|--:| + +[coding-agent-overview]: https://docs.github.com/copilot/using-github-copilot/coding-agent/about-assigning-tasks-to-copilot#overview-of-copilot-coding-agent +[coding-agent-mcp]: https://docs.github.com/copilot/how-tos/agents/copilot-coding-agent/extending-copilot-coding-agent-with-mcp +[assign-issue]: https://docs.github.com/copilot/using-github-copilot/coding-agent/using-copilot-to-work-on-an-issue +[setup-workflow]: https://docs.github.com/copilot/using-github-copilot/coding-agent/best-practices-for-using-copilot-to-work-on-tasks#pre-installing-dependencies-in-github-copilots-environment +[copilot-agents]: https://docs.github.com/copilot/using-github-copilot/coding-agent/about-assigning-tasks-to-copilot +[coding-agent-best-practices]: https://docs.github.com/copilot/using-github-copilot/coding-agent/best-practices-for-using-copilot-to-work-on-tasks +[github-actions]: https://docs.github.com/actions +[next-lesson]: ./5-custom-agents.md +[previous-lesson]: ./3-copilot-agent-mode-vscode.md diff --git a/rendered/tailspin-toys/5-custom-agents.md b/rendered/tailspin-toys/5-custom-agents.md new file mode 100644 index 00000000..3256c9a8 --- /dev/null +++ b/rendered/tailspin-toys/5-custom-agents.md @@ -0,0 +1,93 @@ +# Exercise 5 - Custom agents + +| [← Previous lesson: GitHub Copilot coding agent][previous-lesson] | [Next lesson: Managing agents →][next-lesson] | +|:--|--:| + +[Custom agents][custom-agents] in GitHub Copilot allow you to create specialized AI assistants tailored to specific tasks or domains within your development workflow. By defining agents through markdown files in the `.github/agents` folder of your repository, you can provide Copilot with focused instructions, best practices, coding patterns, and domain-specific knowledge that guide it to perform particular types of work more effectively. This allows teams to codify their expertise and standards into reusable agents. You might create an accessibility agent that ensures [WCAG][wcag] compliance, a security agent that follows secure coding practices, or a testing agent that maintains consistent test patterns—enabling developers to leverage these specialized capabilities on-demand for faster, more consistent implementations. + +You'll explore the following with custom agents: + +- how to create a custom agent. +- assigning a task to a custom agent. + +## Scenario + +Tailspin Toys is committed to ensuring their crowdfunding platform is accessible to all users, regardless of their visual abilities or preferences. Recent user feedback has highlighted that some users find the current dark theme difficult to read due to insufficient contrast between text and background colors. To address this accessibility concern, the design team has requested the implementation of a high-contrast mode that users can toggle on and off. + +Because accessibility is critical, you want to ensure this is implemented as quickly as possible. You're going to utilize a custom agent to generate the functionality. +## Custom agents + +Custom agents are defined by markdown files in the **.github/agents** folder of your project. The markdown files will contain guidance for Copilot on how best to perform at task. + +## Reviewing the accessibility custom agent + +A custom agent has already been created for you for accessibility. Let's review the contents to understand how it will guide Copilot. + +1. Return to your codespace. +2. Open **.github/agents/accessibility.md**. +3. Note the header section with the name and description of the agent. + +> [!IMPORTANT] +> This section is required for custom agents. + +4. From there, scan and review the next sections which highlight: + - Core responsibilities when generating code for an accessible website. + - Best practices for accessibility. + - Code examples for HTML, CSS and JavaScript. + - A list of common pitfalls and mistakes. + +> [!NOTE] +> There is no "best markdown" for a custom agent. As with anything in AI, you will want to test and explore to determine what works best for your environments and scenarios. + +## Create and assign an issue + +Mission control is the central location for working with all agents for your environment. You can assign tasks to Copilot coding agent, monitor tasks, and even redirect and provide additional guidance. Let's start by assigning a task to create the high contrast mode to Copilot. + +1. Navigate to your repository. +2. Select the issues tab. +3. Select **New issue** to open the new issue dialog. +4. Select **Blank issue** to create the new issue. +5. Set the **Title** to `Add high contrast mode to website`. +6. Set the **Description** to: + + ```plaintext + We need a high contrast mode for the site. There should be a toggle for high contrast which the user can set. It should store the setting in local storage on the browser. + ``` + +7. Select **Create** to create the issue. +8. On the right side, select **Assign to Copilot** to open the assignment dialog. +9. Select **Accessibility agent** from the list of custom agents. + + ![Screenshot of coding agent assignment, with custom agent and accessibility highlighted](./images/ex5-select-custom-agent.png) + +10. Select **Assign**. +11. Copilot gets to work on the task in the background! + +## Summary and next steps + +This lesson explored [custom agents][custom-agents] in GitHub Copilot, specialized AI assistants tailored to specific tasks and domains. With custom agents you can codify your team's expertise and standards into reusable agents that guide Copilot to perform particular types of work more effectively. + +You explored these concepts: + +- how to create a custom agent. +- assigning a task to a custom agent. + +With Copilot working on implementing the high contrast mode, we can now turn our attention to our next lesson, [using Copilot HQ to monitor and guide agent sessions][next-lesson]. Custom agents help ensure that Copilot follows your organization's best practices and domain-specific requirements, enabling faster and more consistent implementations across your team. + +## Resources + +- [Custom agents][custom-agents] +- [Preparing to use custom agents in your organization][org-custom-agents] +- [Preparing to use custom agents in your enterprise][enterprise-custom-agents] + +--- + +| [← Previous lesson: GitHub Copilot coding agent][previous-lesson] | [Next lesson: Managing agents →][next-lesson] | +|:--|--:| + +[custom-agents]: https://docs.github.com/copilot/concepts/agents/coding-agent/about-custom-agents +[wcag]: https://www.w3.org/WAI/standards-guidelines/wcag/ +[org-custom-agents]: https://docs.github.com/copilot/how-tos/administer-copilot/manage-for-organization/prepare-for-custom-agents +[enterprise-custom-agents]: https://docs.github.com/copilot/how-tos/administer-copilot/manage-for-enterprise/manage-agents/prepare-for-custom-agents +[next-lesson]: ./6-managing-agents.md +[previous-lesson]: ./4-copilot-coding-agent.md diff --git a/rendered/tailspin-toys/6-managing-agents.md b/rendered/tailspin-toys/6-managing-agents.md new file mode 100644 index 00000000..7c00bf5a --- /dev/null +++ b/rendered/tailspin-toys/6-managing-agents.md @@ -0,0 +1,88 @@ +# Exercise 6 - Monitoring and managing agents + +| [← Previous lesson: Custom agents][previous-lesson] | [Next lesson: Iterating on Copilot's work →][next-lesson] | +|:--|--:| + +In the last couple of exercises you asked Copilot coding agent to take on three separate tasks focused on improving the user experience and adding functionality. While coding agent is built to operate asynchronously and autonomously, the ability to monitor these tasks is still important. + +There are numerous tools available to you to manage tasks assigned to coding agent, including [the agents page][agents-page] on GitHub.com. From this mission control you can see all agent tasks with open pull requests (PRs). You can explore the operations performed, and even steer an in-progress session to help guide it. + +In this lesson you will: + +- explore the agents page to monitor coding agent tasks. +- steer an in-flight session to request additional functionality. + +## Scenario + +After assigning the agent to create a high-contrast mode, the team realized it would be a good time to add a light mode as well. Since work was already being done to update the style of the site and add toggle functionality, it seemed logical to include this functionality. You want to steer the agent's work to ensure it adds a light mode as well as high contrast. + +## Review Copilot coding agent tasks + +Let's see the current status of all tasks assigned to Copilot coding agent. + +1. Navigate to agents page at [https://github.com/copilot/agents](https://github.com/copilot/agents). +2. Note the list of tasks, both on the main pane and on the left pane. You should see the list of the tasks you've assigned to Copilot, including: + - Updating documentation for your codebase. + - Generating new API endpoints for games. + - Adding a high contrast mode for the website. +3. Select one of the running tasks. Review the tasks which have been performed by Copilot. These can include: + - Checking out the code from the repository. + - Creating the environment for Copilot to work. + - Setting up MCP servers. + - Performing various steps to complete the assigned task. + +> [!NOTE] +> The exact steps listed will vary depending on the state of Copilot's work and the approach it took. + +4. Also note the pull request (PR) pane which appears on the right side. This allows you to see the PR and files changed for additional monitoring. +## Steering coding agent + +Now that you've seen the tasks which are active, let's request Copilot include the light mode toggle while it works on the high-contrast mode. + +1. Select the session which refers to adding a high contrast mode. The exact title will vary depending on the name Copilot uses and the current state of work. + + ![Accessibility session in mission control](images/ex6-accessibility-session.png) + +2. Watch the session for a few of minutes, until it indicates it's completed the setup and begun its work. You'll know this has happened when you start seeing messages similar to the ones below. +3. In the **Steer active session while Copilot is working** dialog, add the following prompt: + + ``` + While we are working on a high contrast mode, let's also add a light mode. There should be a switch for this mode as well where users can select their desired display mode. + ``` + + ![Screenshot of the coding agent task in the agents page with the steer active session while copilot is working dialogue highlighted](./images/ex6-steer-coding-agent-task.png) + +4. Press Enter to send the prompt. +5. Notice how Copilot acknowledges the prompt and includes it in its flow. + +## Let Copilot do its work + +Just like before, Copilot will get to work on the updated task! It will incorporate the new request into its flow after it completes the particular step it's working on when you sent the message. + +As before, this will take several minutes, so it's a good time to pause and reflect on everything you've learned and explored thus far. + +## Summary and next steps + +This lesson explored the Copilot agents page, your central hub for monitoring and guiding GitHub Copilot coding agent tasks. With this mission control you can track all active and completed tasks, review the work being performed, and even redirect in-flight tasks to adjust scope or provide additional guidance. + +You explored these concepts: + +- explored Copilot HQ and the agents page to monitor coding agent tasks. +- redirected an in-flight session to request additional functionality. + +With Copilot completing its work on the accessibility features, we can now turn our attention to our next lesson, [iterating on the pull requests Copilot created][next-lesson]. Mission control provides visibility into agent work and enables dynamic collaboration with coding agents as they work on tasks. + +## Resources + +- [Copilot HQ agents page][agents-page] +- [Custom agents][custom-agents] + +--- + +| [← Previous lesson: Custom agents][previous-lesson] | [Next lesson: Iterating on coding agent's work →][next-lesson] | +|:--|--:| + +[agents-page]: https://github.blog/changelog/2025-10-28-a-agents-page-to-assign-steer-and-track-copilot-coding-agent-tasks +[custom-agents]: https://docs.github.com/copilot/concepts/agents/coding-agent/about-custom-agents +[next-lesson]: ./7-iterating-copilot-work.md +[previous-lesson]: ./5-custom-agents.md diff --git a/rendered/tailspin-toys/7-iterating-copilot-work.md b/rendered/tailspin-toys/7-iterating-copilot-work.md new file mode 100644 index 00000000..4fb9bc17 --- /dev/null +++ b/rendered/tailspin-toys/7-iterating-copilot-work.md @@ -0,0 +1,173 @@ +# Exercise 7: Iterating on GitHub Copilot's work + +| [← Previous lesson: Mission control][previous-lesson] | +|:--| + +Throughout this lab you've assigned several issues to GitHub Copilot coding agent. You asked it to add documentation to your code, generate endpoints for the design team to iterate on, and implement accessibility features including high-contrast and light mode toggles. Let's explore the code changes it suggested and, if necessary, provide feedback to Copilot to improve its work. + +## Scenario + +As has been highlighted numerous times, the fundamentals of software design and DevOps do not change with the addition of generative AI. We always want to review the code generated, and work through our normal DevOps process. With that in mind, let's review the suggestions from GitHub Copilot for creating the documentation, new endpoints, and accessibility features before we turn on review for the rest of our team. + +## Security and GitHub Copilot coding agent + +Because Copilot coding agent performs its tasks asynchronously and without supervision, certain security constraints have been put in place to ensure everything remains safe. These include: + +- Copilot only has read access to your repository and write access **only** to the branch it will use for its code. +- Coding agent runs inside of GitHub Actions, where it will create a separate, ephemeral environment in which to work. +- Any GitHub Actions workflows require approval from a human before they can be run. +- [Access to external resources is limited by default][agent-firewall], including MCP servers. + +## Reviewing the generated documentation + +Let's start by exploring the first pull request (PR) generated by GitHub Copilot coding agent - adding documentation to your code. You'll perform this task by utilizing the standard PR interface in GitHub.com. + +> [!NOTE] +> When you explore the PR you may notice a warning about GitHub Copilot being blocked by a firewall. This **is expected**, as Copilot has limited access to external resources by default, including calls to external MCP servers. If you wish, you can [customize or disable the firewall for Copilot coding agent][agent-firewall]. + +1. Return to your repository on github.com. +2. Select **Pull Requests** to open the list of pull requests. +3. Open issue titled something similar to **Add missing documentation** or something more robust. + +> [!NOTE] +> If Copilot is still working on the task, the issue will contain the **[WIP]** flag. If so, wait for Copilot to complete the work. This may take a few minutes, so feel free to take a break, or reflect on everything you've learned so far. + +4. Once the pull request is ready, select the **Files changed** tab and review the changes. + + ![Files changed tab](images/shared-pr-files-changed.png) + +5. Explore the newly updated code, which includes the newly created docstrings and other documentation. The exact changes will vary. +6. Once you've reviewed the updates and everything looks good, navigate back to the **Conversation** tab and scroll down. +7. You should see an indicator that some workflows are waiting for approval. +8. Click on the **Approve and run workflows** button to allow the workflows to run. + + ![Approve and run workflows](images/shared-approve-workflows.png) + +9. You should see the workflows get queued in the checks section of the pull request. All being well, you should see that the workflows pass for both the backend and frontend. This may take a few minutes to complete. + +## Requesting changes from GitHub Copilot + +Working with Copilot on a pull request is not just a one-way street. You can also tag Copilot in comments - like you would other members of your team - in the pull request, or inline comments of the code. Copilot will see these comments, and trigger another session to address them. Due to the non-deterministic results, we can't give prescriptive text of what to ask for. Some ideas of what to ask Copilot to update include: + +- Add comment headers to the top of each code file with a brief description of what they do. +- Add docstrings to TypeScript and Svelte files. +- Create a README in both the server and client folders with descriptions of the codebase of each. + +1. Add a comment requesting a change to the generated documentation, tagging **@copilot** like you would any user. Use one of the ideas above, or another suggestion for Copilot around documentation you'd like to see in the codebase. +2. Select **View Session** to watch Copilot perform its work. Notice how Copilot starts a new session to make the updates. +3. You can select **Back to pull request** to return to the pull request. + + ![Back to pull request](images/ex7-back-to-pr.png) + +4. Once Copilot has completed the changes, you should see a new commit in the pull request. +5. Select the **Files changed** tab to review the changes. + +Feel free to continue iterating until you are happy. Once happy, you can convert the PR to ready from a draft, and merge it into the main branch. + +![Convert PR to ready](images/ex7-ready-for-review.png) + +## Review the new endpoints + +Let's return to the PR Copilot generated for resolving our issue about adding endpoints to the games API for creating, updating and deleting games. + +1. Return to your repository in GitHub.com. +2. Select the **Pull Requests** tab. +3. Select the PR which has a title similar to **Add CRUD endpoints for games API** or something more robust. +4. Select the **Files changed** tab to review the code it generated. +5. Once you've reviewed the updates and everything looks good, navigate back to the **Conversation** tab and scroll down. +6. You should see an indicator that some workflows are waiting for approval. +7. Click on the **Approve and run workflows** button to allow the workflows to run. + + ![Approve and run workflows](images/shared-approve-workflows.png) + +8. You should see the workflows get queued in the checks section of the pull request. All being well, you should see that the workflows pass for both the backend and frontend. This may take a few minutes to complete. +9. **Optional:** You could even switch to this branch in your Codespace to perform a manual test of the new endpoints. Navigate to your Codespace, open the terminal, and run the following commands (replace **** with the name of the branch Copilot created, e.g. **copilot/fix-8**.): + + ```bash + git fetch origin + git checkout + ``` + +Copilot has created the new endpoints! Just as before, you can work iteratively with Copilot coding agent to request updates. For example, you might want to request Copilot centralizes the error handling to reduce duplication, or ensuring comments and docstrings are added (remember - this was assigned **before** you made the updates to your custom instructions!) Just like before, you can make these requests by adding a new comment on the **Conversation** tab, which Copilot will see and kickoff a new session. + +## Review the accessibility features + +Finally, let's review the accessibility features that were implemented using the custom accessibility agent. This PR should include both the high-contrast mode you assigned in Exercise 5, and the light mode that was requested in mission control in Exercise 6. + +1. Return to your repository in GitHub.com. +2. Select the **Pull Requests** tab. +3. Select the PR which has a title similar to **Add high contrast mode to website** or something more robust. + +> [!NOTE] +> If Copilot is still working on the task, the issue will contain the **[WIP]** flag. If so, wait for Copilot to complete the work. This may take a few minutes. + +4. Select the **Files changed** tab to review the code it generated. +5. Review the implementation, paying particular attention to: + - The toggle UI components for switching between modes + - The use of local storage to persist user preferences + - The CSS or styling changes for high-contrast and light modes + - The accessibility attributes (ARIA labels, keyboard navigation, etc.) + - Any JavaScript/TypeScript code that manages the mode switching + +6. Once you've reviewed the updates and everything looks good, navigate back to the **Conversation** tab and scroll down. +7. You should see an indicator that some workflows are waiting for approval. +8. Click on the **Approve and run workflows** button to allow the workflows to run. + + ![Approve and run workflows](images/shared-approve-workflows.png) + +9. You should see the workflows get queued in the checks section of the pull request. All being well, you should see that the workflows pass for both the backend and frontend. This may take a few minutes to complete. +10. **Optional:** You could switch to this branch in your Codespace to manually test the accessibility features. Navigate to your Codespace, open the terminal, and run the following commands (replace **** with the name of the branch Copilot created): + + ```bash + git fetch origin + git checkout + ``` + + Then start the application and test the high-contrast and light mode toggles in your browser to ensure they work as expected and persist across page reloads. + +Notice how the custom accessibility agent helped guide Copilot to implement these features following accessibility best practices. If you see any accessibility concerns or improvements, you can tag **@copilot** in a comment to request updates, just like you did with the previous PRs. + +## Optional Exercise - Explore the agent's capabilities with more issues + +Having access to a peer programmer who is able to explore our codebase and make changes asynchronously is powerful, allowing us to reach a first iteration across tasks quickly, allowing us to review and guide, or take over and continue coding in the editor. + +You have made great progress through the lab, and you're approaching the end. However, you're encouraged to create some additional issues in your GitHub repository and use Copilot to solve those. Some ideas include: + +- Create a backer interest form on the game details page +- Implement pagination on the game listing endpoint +- Add input validation and error handling to the API +- Something else? What else might you consider? + +## Summary + +Congratulations! You completed the lab! You worked through several features available to you with GitHub Copilot, from the IDE to the repository. In particular you: + +- **Learned how to use GitHub Copilot and the Model Context Protocol (MCP) to streamline software development**. You set up the GitHub MCP server to enable Copilot to interact with your repository, created a detailed backlog using Copilot Agent Mode. +- **Explored how custom instructions and prompt files can guide Copilot to follow your project's coding standards.** You created a custom instructions file to provide context for Copilot, ensuring it generates code that adheres to your project's guidelines and used prompt files to provide guidance for repetitive tasks and established practices. +- **Used Copilot Agent Mode to implement new features, coordinate changes across backend and frontend code, and automate repetitive tasks.** You used GitHub Copilot to implement a new category and publisher filter for the game listing page, making changes across the client, backend, and the resulting tests. +- **Experienced Copilot as a peer programmer, being assigned issues and working collaboratively on pull requests.** You assigned Copilot to issues in your backlog, allowing it to create a pull request, build a plan, implement changes, and iterate further as you provided feedback. + +This is just the beginning, and we can't wait to see how you use Copilot to help you with your own projects. We hope you enjoyed the lab, and we look forward to seeing you in the next one! Happy coding! + +## Resources + +- [GitHub Copilot][github-copilot] +- [About Copilot agents][copilot-agents] +- [Assigning GitHub issues to Copilot][assign-issue] +- [Copilot coding agent setup workflow best practices][coding-agent-best-practices] +- [Configuring Copilot coding agent firewall][agent-firewall] + +--- + +| [← Previous lesson: Managing agents][previous-lesson] | +|:--| + +[github-copilot]: https://github.com/features/copilot +[coding-agent-overview]: https://docs.github.com/copilot/using-github-copilot/coding-agent/about-assigning-tasks-to-copilot#overview-of-copilot-coding-agent +[assign-issue]: https://docs.github.com/copilot/using-github-copilot/coding-agent/using-copilot-to-work-on-an-issue +[setup-workflow]: https://docs.github.com/copilot/using-github-copilot/coding-agent/best-practices-for-using-copilot-to-work-on-tasks#pre-installing-dependencies-in-github-copilots-environment +[copilot-agents]: https://docs.github.com/copilot/using-github-copilot/coding-agent/about-assigning-tasks-to-copilot +[coding-agent-best-practices]: https://docs.github.com/copilot/using-github-copilot/coding-agent/best-practices-for-using-copilot-to-work-on-tasks +[agent-firewall]: https://docs.github.com/copilot/customizing-copilot/customizing-or-disabling-the-firewall-for-copilot-coding-agent + +[previous-lesson]: ./6-managing-agents.md diff --git a/scenarios/README.md b/scenarios/README.md new file mode 100644 index 00000000..af8e99b0 --- /dev/null +++ b/scenarios/README.md @@ -0,0 +1,60 @@ +# Scenarios + +This directory contains **scenario packs** — self-contained bundles of configuration and content that let authors swap the sample application used in the "Agents in the SDLC" workshop without rewriting the core exercises. + +## What is a scenario? + +A scenario is a specific sample application (e.g. Tailspin Toys, a Java e-commerce store, a Node.js blog platform) that learners interact with as they work through the workshop exercises. The exercises themselves teach the same Copilot concepts regardless of the scenario; the scenario just provides the concrete codebase and context. + +## Directory structure + +``` +scenarios/ + / + scenario.yml # Required: metadata, variables, skip list + steps/ # Optional: scenario-specific exercise sections + .md # Injects sections into the named core exercise + README.md # Optional: notes for maintainers +``` + +### `scenario.yml` — required fields + +| Field | Type | Description | +|---|---|---| +| `name` | string | Human-readable scenario name | +| `description` | string | Short description of the sample app | +| `repository` | string | GitHub repo in `org/repo` format | +| `tech_stack` | map | Frontend, backend, and database details | +| `variables` | map | Content variables (company name, features, etc.) | +| `skip` | list | Exercise filenames (without `.md`) to omit from this scenario | + +### `steps/` — optional + +The core exercises in `workshop-content/` are generic templates. When your scenario needs to inject application-specific content (company name, tech-stack details, feature descriptions), create a steps file in `steps/` with the same filename as the exercise. A steps file contains only the `## ` sections that differ from the core — each matching section replaces its counterpart in the core exercise when exercises are rendered for this scenario. + +See [docs/authoring/new-scenario-guide.md](../docs/authoring/new-scenario-guide.md) for step-by-step instructions. + +## Available scenarios + +| Scenario ID | Application | Tech stack | Status | +|---|---|---|---| +| `tailspin-toys` | Tailspin Toys (crowdfunding for board games) | Python/Flask · Astro/Svelte | ✅ Default | +| `tailspin-toys-dotnet` | Tailspin Toys .NET (crowdfunding for board games) | ASP.NET Core · Astro/Svelte | ✅ Available | + +## Adding a new scenario + +Use the scaffolding script to get started: + +```bash +python scripts/new-scenario.py +``` + +This creates the directory structure, a pre-filled `scenario.yml`, and placeholder override files. See the [authoring guide](../docs/authoring/new-scenario-guide.md) for full instructions. + +## Validating a scenario + +Before submitting a new scenario, run the validation script to catch common issues: + +```bash +python scripts/validate-scenario.py +``` diff --git a/scenarios/tailspin-toys-dotnet/scenario.yml b/scenarios/tailspin-toys-dotnet/scenario.yml new file mode 100644 index 00000000..f48a0ba3 --- /dev/null +++ b/scenarios/tailspin-toys-dotnet/scenario.yml @@ -0,0 +1,56 @@ +# tailspin-toys-dotnet — scenario configuration +# See docs/authoring/new-scenario-guide.md for full documentation. + +# Human-readable name displayed in the workshop +name: Tailspin Toys (.NET) + +# Short description of the application used in this scenario +description: > + A crowdfunding platform for board games with a developer theme. + The app uses an ASP.NET Core Web API, a SQLite database, and an + Astro/Svelte frontend with Tailwind CSS. + +# GitHub repository for the sample application (org/repo) +# The app is stored as a subfolder in this repository. +repository: github-samples/agents-in-sdlc + +# Technology stack — used when generating scenario-specific content +tech_stack: + frontend: + name: Astro + Svelte + language: TypeScript / JavaScript + notes: > + Astro handles routing and static rendering. + Svelte components (with runes-based reactivity) handle interactivity. + The frontend proxies all /api/* requests to the ASP.NET Core backend. + backend: + name: ASP.NET Core Web API + language: C# + notes: > + RESTful API using ASP.NET Core controllers and Entity Framework Core ORM. + C# nullable reference types are enabled on all files. + XML documentation comments are required on all public types and members. + database: SQLite (via Entity Framework Core) + +# Content variables — substituted into workshop content and prompts +variables: + company_name: Tailspin Toys + company_description: a crowdfunding platform for board games with a developer theme + product_type: crowdfunding platform + primary_entities: games, publishers, categories + filter_feature: filter games by category and publisher + new_endpoints_feature: endpoints to create, update, and delete games + accessibility_feature: high-contrast mode toggle + documentation_feature: XML documentation comments for all public types and methods + +# Exercises to skip for this scenario. +# List exercise filenames (without the .md extension) from workshop-content/ +# that are NOT applicable to this scenario. +skip: [] + +# Notes for workshop authors or maintainers (not shown to participants) +author_notes: > + This scenario uses an ASP.NET Core Web API backend instead of Flask/Python. + The frontend (Astro + Svelte) is identical to the canonical tailspin-toys scenario. + The app lives in the tailspin-toys-dotnet/ subfolder of this repository. + Steps files in steps/ inject .NET-specific content into exercises 2, 3, 4, 5, and 6. diff --git a/scenarios/tailspin-toys-dotnet/steps/2-custom-instructions.md b/scenarios/tailspin-toys-dotnet/steps/2-custom-instructions.md new file mode 100644 index 00000000..cd3e3914 --- /dev/null +++ b/scenarios/tailspin-toys-dotnet/steps/2-custom-instructions.md @@ -0,0 +1,209 @@ +## Scenario + +As any good dev shop, Tailspin Toys has a set of guidelines and requirements for development practices. These include: + +- API always needs unit tests. +- UI should be in dark mode and have a modern feel. +- Documentation should be added to code in the form of XML documentation comments. +- A block of comments should be added to the head of each file describing what the file does. + +Through the use of instruction files you'll ensure Copilot has the right information to perform the tasks in alignment with the practices highlighted. + +## Custom instructions + +Custom instructions allow you to provide context and preferences to Copilot chat, so that it can better understand your coding style and requirements. This is a powerful feature that can help you steer Copilot to get more relevant suggestions and code snippets. You can specify your preferred coding conventions, libraries, and even the types of comments you like to include in your code. You can create instructions for your entire repository, or for specific types of files for task-level context. + +There are two types of instructions files: + +- **.github/copilot-instructions.md**, a single instruction file sent to Copilot for **every** chat prompt for the repository. This file should contain project-level information, context which is relevant for most chat requests sent to Copilot. This could include the tech stack being used, an overview of what's being built and best practices, and other global guidance for Copilot. +- **\*.instructions.md** files can be created for specific tasks or file types. You can use **\*.instructions.md** files to provide guidelines for particular languages (like C# or TypeScript), or for tasks like creating an ASP.NET Core controller or a new set of unit tests. + +> [!NOTE] +> When working in your IDE, instructions files are only used for code generation in Copilot Chat, and not used for code completions or next edit suggestions. +> +> Copilot coding agent will utilize both repository level and \*.instructions with `applyTo` header matter when generating code. + +## Best practices for managing instructions files + +A full conversation about creating instructions files is beyond the scope of the workshop. However, the examples provided in the sample project provide a representative example of how to approach their management. At a high level: + +- Keep instructions in **copilot-instructions.md** focused on project-level guidance, such as a description of what's being built, the structure of the project, and global coding standards. +- Use **\*.instructions.md** files to provide specific instructions for file types (unit tests, API controllers, frontend components), or for specific tasks. +- Use natural language in your instructions files. Keep guidance clear. Provide examples of how code should (and shouldn't) look. + +There isn't one specific way to create instructions files, just as there isn't one specific way to use AI. You will find through experimentation what works best for your project. The guidance provided here and the [resources](#resources) below should help you get started. + +> [!TIP] +> Every project using GitHub Copilot should have a robust collection of instructions files to provide context and best guide code generation. As you explore the instructions files in the project, you may notice there are ones for numerous types of files and tasks, including [UI updates](../.github/instructions/ui.instructions.md) and [Astro](../.github/instructions/astro.instructions.md). The investment made in instructions files will greatly enhance the quality of code suggestion from Copilot, ensuring it better matches the style and requirements your organization has. +> +> You can even have Copilot aid in generating instructions files by selecting the gear icon for **Configure Chat** in Copilot chat and selecting **Generate Agent Instructions**. +> +> ![Screenshot of option in GitHub Copilot chat with configure chat highlighted and generate agent instructions highlighted](./images/ex2-generate-instructions.png) + +## Use GitHub Copilot Chat before updating custom instructions + +To see the impact of custom instructions, you'll start by sending a prompt with the current version of the files. You'll then make some updates, send the same prompt again, and note the difference. + +1. Return to your codespace. +2. Close any open files in your codespace from the previous exercises. This will ensure Copilot has the context you want it to have. +3. Open `server/TailspinToys.Api/Controllers/PublishersController.cs`, an empty controller file. +4. If **Copilot chat** is not already open, open it by selecting the Copilot icon towards the top of your codespace. +5. Create a new chat session by typing `/clear` into the chat window and selecting Enter (or return on a Mac). +6. Select **Ask** from the modes dropdown. + + ![Chat mode selection dialog with Ask mode highlighted](./images/ex2-select-chat-mode.png) + +7. Send the following prompt to create a new endpoint to return all publishers: + + ```plaintext + Create a new endpoint to return a list of all publishers. It should return the name and id for all publishers. + ``` + +8. Copilot explores the project to learn how best to implement the code, and generates a list of suggestions, which may include code for `PublishersController.cs` and tests to ensure the new code runs correctly. +9. Explore the code, noticing the generated code uses C# types and nullable reference types because, as you'll see, the custom instructions includes the directive to include them. +10. Notice the generated code **is missing** XML documentation comments or a file header comment - or both! + +> [!IMPORTANT] +> As highlighted previously, GitHub Copilot and LLM tools are probabilistic, not deterministic. As a result, the exact code generated may vary, and there's even a chance it'll abide by your rules without you spelling it out! But to aid consistency in code you should always document anything you want to ensure Copilot should understand about how you want your code generated. + +## Add new repository standards to copilot-instructions.md + +As highlighted previously, `copilot-instructions.md` is designed to provide project-level information to Copilot. Let's ensure repository coding standards are documented to improve code suggestions from Copilot chat. + +1. Return to your codespace. +2. Open `.github/copilot-instructions.md`. +3. Explore the file, noting the brief description of the project and sections for **Code standards**, **Scripts** and **GitHub Actions Workflows**. These are applicable to any interactions you'd have with Copilot, are robust, and provide clear guidance on what you're doing and how you want to accomplish it. +4. Locate the **Code formatting requirements** section. Note how it contains a note to use C# nullable reference types and standard C# naming conventions. That's why you saw those in the code generated previously. +5. Add the following lines of markdown right below the note about nullable reference types to instruct Copilot to add XML documentation comments and file headers: + + ```markdown + - Every public type, method, and property should have XML documentation comments (``, ``, ``). + - Before the namespace declaration, add a comment block to the file that explains its purpose. + ``` + +6. Close **copilot-instructions.md**. +7. Select **New Chat** in Copilot chat to clear the buffer and start a new conversation. +8. Return to **server/TailspinToys.Api/Controllers/PublishersController.cs** to ensure focus is set correctly. +9. Send the same prompt as before to create the endpoint. + + ```plaintext + Create a new endpoint to return a list of all publishers. It should return the name and id for all publishers. + ``` + +10. Notice how the newly generated code includes a file header comment at the top which resembles the following: + + ```csharp + // PublishersController.cs + // Provides API endpoints for retrieving publisher information + // for the Tailspin Toys crowdfunding platform. + ``` + +11. Notice how the newly generated code includes XML documentation comments inside the action method which resemble the following: + + ```csharp + /// + /// Returns a list of all publishers with their id and name. + /// + /// A JSON array of publisher objects containing id and name. + ``` + +12. Notice the generated code now includes XML documentation as well as a comment block at the top! +13. Also note how the existing code isn't updated, but of course you could ask Copilot to perform that operation if you so desired! +14. **Don't implement the suggested changes**, as you'll be doing that in the next section. + +> [!NOTE] +> If you accepted the changes, you can always select the **Undo** button towards the top right of the Copilot chat window. + +From this section, you explored how the custom instructions file has provided Copilot with the context it needs to generate code that follows the established guidelines. + +## Explore a task-specific custom instructions file + +You want to create a new endpoint to list all publishers, following the same pattern used for the existing [games controller][games-controller], and to create tests which follow the same pattern as the existing [games controller tests][games-tests]. An instruction file has already been created; let's explore it and see the difference in code it generates. + +1. Open `.github/instructions/csharp-tests.instructions.md`. +2. Note the `applyTo:` section at the top, which contains a filter for all test files in the `server/TailspinToys.Tests` directory ending in `Tests.cs`. Whenever Copilot Chat interacts with a file which matches this pattern it will automatically use the guidance provided in this file. +3. Note the file contains guidance about how xUnit tests should be created, and how to use the EF Core in-memory provider for testing database functionality. +4. Open `.github/instructions/csharp-api.instructions.md`. +5. Review the following entries inside the instruction file, which includes: + + - an overview of requirements, including that tests must be created, and controllers inherit from `ControllerBase` with `[ApiController]`. + - a link to the previously mentioned `csharp-tests.instructions.md` file. + - links to two existing files which follow the patterns you want — both the games controller and its tests. Notice how these are set up as normal markdown links, allowing an instruction file to incorporate additional files for context. + +6. Return to `server/TailspinToys.Api/Controllers/PublishersController.cs` to ensure focus is set correctly. +7. Return to Copilot Chat and select **New Chat** to start a new session. +8. Select **Edit** from the mode dropdown, which will allow Copilot to update multiple files. + + ![Copilot Chat mode selector with Edit chosen and highlighted](./images/ex2-select-edit-mode.png) + +> [!NOTE] +> If you have any issues running the tests in this part of the exercise, please undo your changes and retry from the above step using **Agent** mode instead. + +9. Select the **Add Context** button to open the context dialog +10. If prompted to allow the codespace to see text and images copied to the clipboard, select **Allow**. +11. Select **Instructions** from the dropdown at the top of your codespace. + +> [!TIP] +> If the list of options is long, you can type **instructions** to filter to the Instructions option then select **Instructions**. + +12. Select **csharp-api .github/instructions** to add the instruction file to the context. + + ![Screenshot showing the instruction file being added into Copilot Chat](images/ex2-add-instructions-file.png) + +13. Send the same prompt as before to generate the desired endpoint: + + ```plaintext + Create a new endpoint to return a list of all publishers. It should return the name and id for all publishers. + ``` + +> [!NOTE] +> While the up-arrow shortcut to resend a prior command is handy, it will reset any context you might add as well. If you added in the instructions file as context, then use the up arrow, it will remove the instructions file. For this particular step, make sure you copy/paste (or type) the command to avoid accidentally removing context. + +14. Note the **References** section and how it uses the **csharp-api.instructions.md** file to provide context. If you use instructions files with Copilot agent mode, you will notice that Copilot explores and reads the files referenced in the instructions file. + + ![Screenshot of the references section, showing the included instructions file](./images/ex2-copilot-instructions-references.png) + +15. Copilot generates the files. Notice how it generates updates across multiple files, like **PublishersController.cs** and **PublishersControllerTests.cs** + +> [!NOTE] +> Note that the code generated may diverge from some of the standards we set. AI tools like Copilot are non-deterministic, and may not always provide the same result. The other files in our codebase do not contain XML documentation comments or comment headers, which could lead Copilot in another direction. Consistency is key, so making sure that your code follows the established patterns is important. You can always follow-up in chat and ask Copilot to follow your coding standards, which will help guide it in the right direction. + +16. After reviewing the code, select **Keep** in Copilot Chat to accept the changes. +17. Open a terminal window by selecting Ctl+\`. +18. Run the tests by running the script with the following command: + + ```sh + ./scripts/run-server-tests.sh + ``` + +19. Once the code is correct, and all tests pass, open the **Source Control** panel on the left of the Codespace and review the changes made by Copilot. +20. Stage the changes by selecting the **+** icon in the **Source Control** panel. +21. Generate a commit message using the **Sparkle** button. + + ![Screenshot of the Source Control panel showing the changes made](images/ex2-source-control-changes.png) + +22. Commit the changes to your repository by selecting **Commit**. + +## Resources + +- [Instruction files for GitHub Copilot customization][instruction-files] +- [5 tips for writing better custom instructions for Copilot][copilot-instructions-five-tips] +- [Best practices for creating custom instructions][instructions-best-practices] +- [Personal custom instructions for GitHub Copilot][personal-instructions] +- [Awesome Copilot - a collection of instructions files and other resources][awesome-copilot] + +--- + +| [← Previous lesson: Model Context Protocol (MCP)][previous-lesson] | [Next lesson: Copilot agent mode →][next-lesson] | +|:--|--:| + +[previous-lesson]: ./1-mcp.md +[next-lesson]: ./3-copilot-agent-mode-vscode.md +[instruction-files]: https://code.visualstudio.com/docs/copilot/copilot-customization +[games-controller]: ../server/TailspinToys.Api/Controllers/GamesController.cs +[games-tests]: ../server/TailspinToys.Tests/GamesControllerTests.cs +[instructions-best-practices]: https://docs.github.com/enterprise-cloud@latest/copilot/using-github-copilot/coding-agent/best-practices-for-using-copilot-to-work-on-tasks#adding-custom-instructions-to-your-repository +[personal-instructions]: https://docs.github.com/copilot/customizing-copilot/adding-personal-custom-instructions-for-github-copilot +[copilot-instructions-five-tips]: https://github.blog/ai-and-ml/github-copilot/5-tips-for-writing-better-custom-instructions-for-copilot/ +[awesome-copilot]: https://github.com/github/awesome-copilot +[repository-custom-instructions]: https://docs.github.com/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot diff --git a/scenarios/tailspin-toys-dotnet/steps/3-copilot-agent-mode-vscode.md b/scenarios/tailspin-toys-dotnet/steps/3-copilot-agent-mode-vscode.md new file mode 100644 index 00000000..2fed400e --- /dev/null +++ b/scenarios/tailspin-toys-dotnet/steps/3-copilot-agent-mode-vscode.md @@ -0,0 +1,43 @@ +## Scenario + +As the list of games grows, you want to allow users to filter by category. This will require updating both the API and UI, and updating the tests for the API. With the help of Copilot Agent Mode you'll work with your AI pair programmer to add the new feature! + +## Running the application + +Before you make any changes, let's explore the Tailspin Toys website to understand its current functionality. + +The website is a crowdfunding platform for board games with a developer theme. It allows users to list games and display details about them. The website has two main components: the front-end (written in Svelte) and the backend (written in C#). + +### Starting the application + +To make running the website easier, a script has been provided that will start both the front-end and back-end servers. You can run this script in your GitHub Codespace with the following instructions: + +1. Return to your codespace. You'll continue working in your current branch. +2. Open a new terminal window inside your codespace by selecting Ctl + \`. +3. Run the following script to start the application: + + ```bash + scripts/start-app.sh + ``` + + Once the script is running, you should see output indicating that both the front-end and back-end servers are running, similar to the below: + + ```bash + Server (ASP.NET Core) running at: http://localhost:5100 + Client (Astro) server running at: http://localhost:4321 + ``` + +> [!NOTE] +> If a dialog box opens prompting you to open a browser window for `http://localhost:5100` close it by selecting the **x**. + +4. Open the website by using Ctrl-**Click** (or Cmd-**Click** on a Mac) on the client address `http://localhost:4321` in the terminal. + +> [!NOTE] +> When using a codespace, selecting a link for the localhost URL from the Codespace terminal will automatically redirect you to `https://-4321.app.github.dev/`. This is a private tunnel to your codespace, which is now hosting your web server! + +### Exploring the application + +Once the application is running, you can explore its functionality. The main features of the website include: + +- **Home Page**: Displays a list of board games with their titles, images, and descriptions. +- **Game Details Page**: When you select a game, you'll be brought to a details page with more information about the game, including its title, description, publisher and category. diff --git a/scenarios/tailspin-toys-dotnet/steps/4-copilot-coding-agent.md b/scenarios/tailspin-toys-dotnet/steps/4-copilot-coding-agent.md new file mode 100644 index 00000000..4bb28028 --- /dev/null +++ b/scenarios/tailspin-toys-dotnet/steps/4-copilot-coding-agent.md @@ -0,0 +1,137 @@ +## Scenario + +Tailspin Toys has some tech debt they'd like to address. The contractors initially hired to create the first version of the site left the documentation in an unideal state - and by that you'll notice it's completely lacking. As a first step, they'd like to see XML documentation comments added to all public types, methods and properties in the application. + +Additionally, the design team is ready to get to work on building the UX for managing games. They don't need a full implementation yet, but they at least need some endpoints they can use for testing. Specifically, they need endpoints for the games API which will allow them to create, update and delete games. This is currently a blocker, but there are other issues which are of higher priority at the moment. + +These are both examples of tasks which can quickly find themselves deprioritized, and are great to assign to Copilot coding agent. Copilot coding agent can then work on them asynchronously, allowing the developer to focus on other tasks, then return to review Copilot's work and ensure everything is as expected. + +## Setting up the dev environment for the Copilot coding agent + +Creating code, regardless of who's involved, typically requires a specific environment and some setup scripts to be run to ensure everything is in a good state. This holds true when assigning tasks to Copilot, which is performing tasks in a similar fashion to a SWE. + +Coding agent uses [GitHub Actions][github-actions] for its environment when doing its work. You can customize this environment by creating a [special setup workflow][setup-workflow], configured in the **.github/workflows/copilot-setup-steps.yml** file, to run before it gets to work. This enables it to have access to the required development tools and dependencies. This has been pre-configured ahead of the lab to help the lab flow and allow this learning opportunity. It makes sure that Copilot has access to .NET, Node.JS, and the required dependencies for the client and server: + +```yaml +name: "Copilot Setup Steps" + +# Allows you to test the setup steps from your repository's "Actions" tab +on: workflow_dispatch + +jobs: + copilot-setup-steps: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Checkout code + uses: actions/checkout@v4 + + # Backend setup - .NET + - name: Set up .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: "8.0" + + - name: Restore .NET dependencies + run: dotnet restore server/TailspinToys.sln + + - name: Build .NET project + run: dotnet build server/TailspinToys.sln --no-restore + + # Frontend setup - Node.js + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + cache: "npm" + cache-dependency-path: "./client/package.json" + + - name: Install JavaScript dependencies + working-directory: ./client + run: npm ci +``` + +It looks like any other GitHub workflow file, but it has a few key points: + +- It contains a single job called **copilot-setup-steps**. This job is executed in GitHub Actions before Copilot starts working on the pull request. +- Notice the **workflow_dispatch** trigger, which allows you to run the workflow manually from the Actions tab of your repository. This is useful for testing that the workflow runs successfully instead of waiting for Copilot to run it. + +## Adding documentation + +While everyone understands the importance of documentation, most projects have either outdated information or lack it altogether. This is the type of tech debt which often goes unaddressed, slowing productivity and making it more difficult to maintain the codebase or bring new developers into the team. Fortunately, Copilot shines at creating documentation, and this is a perfect issue to assign to Copilot coding agent. It'll work in the background to generate the necessary documentation. In a future exercise you'll return to review its work. + +1. Navigate to your repository on github.com in a new browser tab. +2. Select the **Issues** tab. +3. Select **New issue** to open the new issue dialog. +4. Select **Blank issue** to create the new issue. +5. Set the **Title** to `Code lacks documentation`. +6. Set the **Description** to: + + ```plaintext + Our organization has a requirement that all functions have XML documentation comments (or the language equivalent). Unfortunately, recent updates haven't followed this standard. We need to update the existing code to ensure XML documentation comments (or the equivalent) are included with every public type, method, and property. + ``` + +7. Select **Create** to create the issue. +8. On the right side, select **Assign to Copilot** to open the assignment dialog. + + ![Assigning Copilot to an issue](images/shared-assign-copilot.png) + +9. Select **Assign**. + + ![Copilot assignment details](images/ex4-assign-copilot-details.png) + +10. Select the **Pull Requests** tab. +11. Open the newly generated pull request (PR), which will be titled something similar to **[WIP]: Code lacks documentation**. If a new PR doesn't appear on the list, wait for a moment or two and refresh the browser window. +12. After a few minutes, you should see that Copilot has created a todo list. + +> [!NOTE] +> It make take several minutes for the todo list from Copilot to appear in the PR. Copilot is creating its environment (running the workflow highlighted previously), analyzing the project, and determining the best approach to tackling the problem. + +13. Review the list and the tasks it's going to complete. +14. Scroll down the pull request timeline, and you should see an update that Copilot has started working on the issue. +15. Select the **View session** button. + + ![Copilot session view](images/ex4-view-session.png) + +> [!IMPORTANT] +> You may need to refresh the window to see the updated indicator. + +16. Notice that you can scroll through the live session, and how Copilot is solving the problem. That includes exploring the code and understanding the state, how Copilot pauses to think and decide on the appropriate plan and also creating code. + +This will likely take several minutes. One of the primary goals of Copilot coding agent is to allow it to perform tasks asynchronously, freeing us to focus on other tasks. We're going to take advantage of that very feature by both assigning another task to Copilot coding agent, then turning our attention to writing some code to add features to our application. + +## Create new API endpoints + +As has been highlighted, one of the great advantages of GitHub Copilot coding agent is the ability to divide work, where you can focus on one set of tasks while it focuses on another. While creating the endpoints for modifying games for the design team might not necessarily take a long time, it's still time which could be used for other tasks. Let's assign it to Copilot coding agent! + +1. Return to your repository on github.com. +2. Select the **Issues** tab. +3. Select **New issue** to open the new issue dialogue. +4. Select **Blank issue** to use the blank template. +5. Set the **Title** to: `Add endpoints to create and edit games` +6. Set the **Description** to: + + ```markdown + We're going to be creating functionality in the future to allow for the submission (and editing) of games. For now we just want the endpoints so we can explore how we want to create the UX and do some acceptance testing. Our requirements are: + + - Add new endpoints to the Games API to support creating, updating and deleting games + - There should be appropriate error handling for all new endpoints + - There should be unit tests created for all new endpoints + - Before creating the PR, ensure all tests pass + ``` + +7. Select **Create** to create the issue. +8. On the right side, select **Assign to Copilot** to open the assignment dialog. + + ![Assigning Copilot to an issue](images/shared-assign-copilot.png) + +9. Select **Assign**. + +Shortly after, you should see a set of 👀 on the first comment in the issue, indicating Copilot is on the job! + +![Copilot uses the eyes emoji to indicate it's working on the issue](images/ex4-issue-eyes-emoji.png) + +9. Select **Assign** to assign the issue to Copilot coding agent. + +Copilot is now diligently working on your second request! Copilot coding agent works in a similar fashion to a SWE, so you don't need to actively monitor it, but instead review once it's completed. Let's turn your attention to writing code and adding other features. diff --git a/scenarios/tailspin-toys-dotnet/steps/5-custom-agents.md b/scenarios/tailspin-toys-dotnet/steps/5-custom-agents.md new file mode 100644 index 00000000..852dc20b --- /dev/null +++ b/scenarios/tailspin-toys-dotnet/steps/5-custom-agents.md @@ -0,0 +1,5 @@ +## Scenario + +Tailspin Toys is committed to ensuring their crowdfunding platform is accessible to all users, regardless of their visual abilities or preferences. Recent user feedback has highlighted that some users find the current dark theme difficult to read due to insufficient contrast between text and background colors. To address this accessibility concern, the design team has requested the implementation of a high-contrast mode that users can toggle on and off. + +Because accessibility is critical, you want to ensure this is implemented as quickly as possible. You're going to utilize a custom agent to generate the functionality. diff --git a/scenarios/tailspin-toys-dotnet/steps/6-managing-agents.md b/scenarios/tailspin-toys-dotnet/steps/6-managing-agents.md new file mode 100644 index 00000000..5f2440b7 --- /dev/null +++ b/scenarios/tailspin-toys-dotnet/steps/6-managing-agents.md @@ -0,0 +1,23 @@ +## Scenario + +After assigning the agent to create a high-contrast mode, the team realized it would be a good time to add a light mode as well. Since work was already being done to update the style of the site and add toggle functionality, it seemed logical to include this functionality. You want to steer the agent's work to ensure it adds a light mode as well as high contrast. + +## Review Copilot coding agent tasks + +Let's see the current status of all tasks assigned to Copilot coding agent. + +1. Navigate to agents page at [https://github.com/copilot/agents](https://github.com/copilot/agents). +2. Note the list of tasks, both on the main pane and on the left pane. You should see the list of the tasks you've assigned to Copilot, including: + - Updating documentation for your codebase. + - Generating new API endpoints for games. + - Adding a high contrast mode for the website. +3. Select one of the running tasks. Review the tasks which have been performed by Copilot. These can include: + - Checking out the code from the repository. + - Creating the environment for Copilot to work. + - Setting up MCP servers. + - Performing various steps to complete the assigned task. + +> [!NOTE] +> The exact steps listed will vary depending on the state of Copilot's work and the approach it took. + +4. Also note the pull request (PR) pane which appears on the right side. This allows you to see the PR and files changed for additional monitoring. diff --git a/scenarios/tailspin-toys/scenario.yml b/scenarios/tailspin-toys/scenario.yml new file mode 100644 index 00000000..25fdb92f --- /dev/null +++ b/scenarios/tailspin-toys/scenario.yml @@ -0,0 +1,56 @@ +# Tailspin Toys Scenario +# This is the default scenario for the "Agents in the SDLC" workshop. +# See scenarios/README.md for full documentation on the scenario format. + +# Human-readable name displayed in the workshop +name: Tailspin Toys + +# Short description of the application used in this scenario +description: > + A crowdfunding platform for board games with a developer theme. + The app uses a Python/Flask REST API, a SQLite database, and an + Astro/Svelte frontend with Tailwind CSS. + +# GitHub repository for the sample application (org/repo) +repository: github-samples/tailspin-toys + +# Technology stack — used when generating scenario-specific content +tech_stack: + frontend: + name: Astro + Svelte + language: TypeScript / JavaScript + notes: > + Astro handles routing and static rendering. + Svelte components (with runes-based reactivity) handle interactivity. + backend: + name: Flask + language: Python + notes: > + RESTful API using Flask blueprints and SQLAlchemy ORM. + Python type hints are required on all function signatures. + database: SQLite (via SQLAlchemy) + +# Content variables — these values are substituted into workshop content +# and override prompts when rendering scenario-specific materials. +variables: + company_name: Tailspin Toys + company_description: a crowdfunding platform for board games with a developer theme + product_type: crowdfunding platform + primary_entities: games, publishers, categories + filter_feature: filter games by category and publisher + new_endpoints_feature: endpoints to create, update, and delete games + accessibility_feature: high-contrast mode toggle + documentation_feature: docstrings for all functions + +# Exercises to skip for this scenario. +# List exercise filenames (without the .md extension) from workshop-content/ +# that are NOT applicable to this scenario. +# Leave empty (or omit) if all exercises apply. +skip: [] + +# Notes for workshop authors or maintainers (not shown to participants) +author_notes: > + This is the canonical scenario. The core workshop-content/ exercises are written + as generic templates. Steps files in steps/ inject Tailspin-specific content + (Flask/Python details, Tailspin Toys narrative) into the rendered exercises. + When creating a new scenario, use this file as a reference. diff --git a/scenarios/tailspin-toys/steps/2-custom-instructions.md b/scenarios/tailspin-toys/steps/2-custom-instructions.md new file mode 100644 index 00000000..6639357d --- /dev/null +++ b/scenarios/tailspin-toys/steps/2-custom-instructions.md @@ -0,0 +1,213 @@ +## Scenario + +As any good dev shop, Tailspin Toys has a set of guidelines and requirements for development practices. These include: + +- API always needs unit tests. +- UI should be in dark mode and have a modern feel. +- Documentation should be added to code in the form of docstrings. +- A block of comments should be added to the head of each file describing what the file does. + +Through the use of instruction files you'll ensure Copilot has the right information to perform the tasks in alignment with the practices highlighted. + +## Custom instructions + +Custom instructions allow you to provide context and preferences to Copilot chat, so that it can better understand your coding style and requirements. This is a powerful feature that can help you steer Copilot to get more relevant suggestions and code snippets. You can specify your preferred coding conventions, libraries, and even the types of comments you like to include in your code. You can create instructions for your entire repository, or for specific types of files for task-level context. + +There are two types of instructions files: + +- **.github/copilot-instructions.md**, a single instruction file sent to Copilot for **every** chat prompt for the repository. This file should contain project-level information, context which is relevant for most chat requests sent to Copilot. This could include the tech stack being used, an overview of what's being built and best practices, and other global guidance for Copilot. +- **\*.instructions.md** files can be created for specific tasks or file types. You can use **\*.instructions.md** files to provide guidelines for particular languages (like Python or TypeScript), or for tasks like creating a Flask blueprint or a new set of unit tests. + +> [!NOTE] +> When working in your IDE, instructions files are only used for code generation in Copilot Chat, and not used for code completions or next edit suggestions. +> +> Copilot coding agent will utilize both repository level and \*.instructions with `applyTo` header matter when generating code. + +## Best practices for managing instructions files + +A full conversation about creating instructions files is beyond the scope of the workshop. However, the examples provided in the sample project provide a representative example of how to approach their management. At a high level: + +- Keep instructions in **copilot-instructions.md** focused on project-level guidance, such as a description of what's being built, the structure of the project, and global coding standards. +- Use **\*.instructions.md** files to provide specific instructions for file types (unit tests, Flask blueprints, API endpoints), or for specific tasks. +- Use natural language in your instructions files. Keep guidance clear. Provide examples of how code should (and shouldn't) look. + +There isn't one specific way to create instructions files, just as there isn't one specific way to use AI. You will find through experimentation what works best for your project. The guidance provided here and the [resources](#resources) below should help you get started. + +> [!TIP] +> Every project using GitHub Copilot should have a robust collection of instructions files to provide context and best guide code generation. As you explore the instructions files in the project, you may notice there are ones for numerous types of files and tasks, including [UI updates](../.github/instructions/ui.instructions.md) and [Astro](../.github/instructions/astro.instructions.md). The investment made in instructions files will greatly enhance the quality of code suggestion from Copilot, ensuring it better matches the style and requirements your organization has. +> +> You can even have Copilot aid in generating instructions files by selecting the gear icon for **Configure Chat** in Copilot chat and selecting **Generate Agent Instructions**. +> +> ![Screenshot of option in GitHub Copilot chat with configure chat highlighted and generate agent instructions highlighted](./images/ex2-generate-instructions.png) + +## Use GitHub Copilot Chat before updating custom instructions + +To see the impact of custom instructions, you'll start by sending a prompt with the current version of the files. You'll then make some updates, send the same prompt again, and note the difference. + +1. Return to your codespace. +2. Close any open files in your codespace from the previous exercises. This will ensure Copilot has the context you want it to have. +3. Open `server/routes/publishers.py`, an empty file. +4. If **Copilot chat** is not already open, open it by selecting the Copilot icon towards the top of your codespace. +5. Create a new chat session by typing `/clear` into the chat window and selecting Enter (or return on a Mac). +6. Select **Ask** from the modes dropdown. + + ![Chat mode selection dialog with Ask mode highlighted](./images/ex2-select-chat-mode.png) + +7. Send the following prompt to create a new endpoint to return all publishers: + + ```plaintext + Create a new endpoint to return a list of all publishers. It should return the name and id for all publishers. + ``` + +8. Copilot explores the project to learn how best to implement the code, and generates a list of suggestions, which may include code for `publishers.py`, `app.py`, and tests to ensure the new code runs correctly. +9. Explore the code, noticing the generated code includes [type hints][python-type-hints] because, as you'll see, the custom instructions includes the directive to include them. +10. Notice the generated code **is missing** either a docstring or a comment header - or both! + +> [!IMPORTANT] +> As highlighted previously, GitHub Copilot and LLM tools are probabilistic, not deterministic. As a result, the exact code generated may vary, and there's even a chance it'll abide by your rules without you spelling it out! But to aid consistency in code you should always document anything you want to ensure Copilot should understand about how you want your code generated. + +## Add new repository standards to copilot-instructions.md + +As highlighted previously, `copilot-instructions.md` is designed to provide project-level information to Copilot. Let's ensure repository coding standards are documented to improve code suggestions from Copilot chat. + +1. Return to your codespace. +2. Open `.github/copilot-instructions.md`. +3. Explore the file, noting the brief description of the project and sections for **Code standards**, **Scripts** and **GitHub Actions Workflows**. These are applicable to any interactions you'd have with Copilot, are robust, and provide clear guidance on what you're doing and how you want to accomplish it. +4. Locate the **Code formatting requirements** section, which should be near line 27. Note how it contains a note to use type hints. That's why you saw those in the code generated previously. +5. Add the following lines of markdown right below the note about type hints to instruct Copilot to add comment headers to files and docstrings (which should be near line 27): + + ```markdown + - Every function should have docstrings or the language equivalent. + - Before imports or any code, add a comment block to the file that explains its purpose. + ``` + +6. Close **copilot-instructions.md**. +7. Select **New Chat** in Copilot chat to clear the buffer and start a new conversation. +8. Return to **server/routes/publishers.py** to ensure focus is set correctly. +9. Send the same prompt as before to create the endpoint. + + ```plaintext + Create a new endpoint to return a list of all publishers. It should return the name and id for all publishers. + ``` + +10. Notice how the newly generated code includes a comment header at the top of the file which resembles the following: + + ```python + """ + Publisher API routes for the Tailspin Toys Crowd Funding platform. + This module provides endpoints to retrieve publisher information. + """ + ``` + +11. Notice how the newly generated code includes a docstring inside the function which resembles the following: + + ```python + """ + Returns a list of all publishers with their id and name. + + Returns: + Response: JSON response containing an array of publisher objects + """ + ``` + +12. Notice the generated code now includes a docstring as well as a comment block at the top! +13. Also note how the existing code isn't updated, but of course you could ask Copilot to perform that operation if you so desired! +14. **Don't implement the suggested changes**, as you'll be doing that in the next section. + +> [!NOTE] +> If you accepted the changes, you can always select the **Undo** button towards the top right of the Copilot chat window. + +From this section, you explored how the custom instructions file has provided Copilot with the context it needs to generate code that follows the established guidelines. + +## Explore a task-specific custom instructions file + +You want to create a new endpoint to list all publishers, and to follow the same pattern used for the existing [games endpoints][games-endpoints], and to create tests which follow the same pattern as the existing [games endpoints tests][games-tests]. An instruction file has already been created; let's explore it and see the difference in code it generates. + +1. Open `.github/instructions/python-tests.instructions.md`. +2. Note the `applyTo:` section at the top, which contains a filter for all files in the `server/tests` directory which start with `test_` and have a `.py` extension. Whenever Copilot Chat interacts with a file which matches this pattern it will automatically use the guidance provided in this file. +3. Note the file contains guidance about how tests should be created, and how to utilize SQLite when testing database functionality. +4. Open `.github/instructions/flask-endpoint.instructions.md`. +5. Review the following entries inside the instruction file, which includes: + + - an overview of requirements, including that tests must be created, and endpoints are created in Flask using blueprints. + - a link to another the previously mentioned `python-tests.instructions.md` file. + - links to two existing files which follow the patterns you want - both the games blueprint and tests. Notice how these are setup as normal markdown links, allowing an instruction file to incorporate additional files for context. + +6. Return to `server/routes/publishers.py` to ensure focus is set correctly. +7. Return to Copilot Chat and select **New Chat** to start a new session. +8. Select **Edit** from the mode dropdown, which will allow Copilot to update multiple files. + + ![Copilot Chat mode selector with Edit chosen and highlighted](./images/ex2-select-edit-mode.png) + +> [!NOTE] +> If you have any issues running the tests in this part of the exercise, please undo your changes and retry from the above step using **Agent** mode instead. + +9. Select the **Add Context** button to open the context dialog +10. If prompted to allow the codespace to see text and images copied to the clipboard, select **Allow**. +11. Select **Instructions** from the dropdown at the top of your codespace. + +> [!TIP] +> If the list of options is long, you can type **instructions** to filter to the Instructions option then select **Instructions**. + +12. Select **flask-endpoint .github/instructions** to add the instruction file to the context. + + ![Screenshot showing the instruction file being added into Copilot Chat](images/ex2-add-instructions-file.png) + +13. Send the same prompt as before to generate the desired endpoint: + + ```plaintext + Create a new endpoint to return a list of all publishers. It should return the name and id for all publishers. + ``` + +> [!NOTE] +> While the up-arrow shortcut to resend a prior command is handy, it will reset any context you might add as well. If you added in the instructions file as context, then use the up arrow, it will remove the instructions file. For this particular step, make sure you copy/paste (or type) the command to avoid accidentally removing context. + +14. Note the **References** section and how it uses the **flask-endpoint.instructions.md** file to provide context. If you use instructions files with Copilot agent mode, you will notice that Copilot explores and reads the files referenced in the instructions file. + + ![Screenshot of the references section, showing the included instructions file](./images/ex2-copilot-instructions-references.png) + +15. Copilot generates the files. Notice how it generates updates across multiple files, like **publishers.py** and **test_publishers.py** + +> [!NOTE] +> Note that the code generated may diverge from some of the standards we set. AI tools like Copilot are non-deterministic, and may not always provide the same result. The other files in our codebase do not contain docstrings or comment headers, which could lead Copilot in another direction. Consistency is key, so making sure that your code follows the established patterns is important. You can always follow-up in chat and ask Copilot to follow your coding standards, which will help guide it in the right direction. + +16. After reviewing the code, select **Keep** in Copilot Chat to accept the changes. +17. Open a terminal window by selecting Ctl+`. +18. Run the tests by running the script with the following command: + + ```sh + ./scripts/run-server-tests.sh + ``` + +19. Once the code is correct, and all tests pass, open the **Source Control** panel on the left of the Codespace and review the changes made by Copilot. +20. Stage the changes by selecting the **+** icon in the **Source Control** panel. +21. Generate a commit message using the **Sparkle** button. + + ![Screenshot of the Source Control panel showing the changes made](images/ex2-source-control-changes.png) + +22. Commit the changes to your repository by selecting **Commit**. + +## Resources + +- [Instruction files for GitHub Copilot customization][instruction-files] +- [5 tips for writing better custom instructions for Copilot][copilot-instructions-five-tips] +- [Best practices for creating custom instructions][instructions-best-practices] +- [Personal custom instructions for GitHub Copilot][personal-instructions] +- [Awesome Copilot - a collection of instructions files and other resources][awesome-copilot] + +--- + +| [← Previous lesson: Model Context Protocol (MCP)][previous-lesson] | [Next lesson: Copilot agent mode →][next-lesson] | +|:--|--:| + +[previous-lesson]: ./1-mcp.md +[next-lesson]: ./3-copilot-agent-mode-vscode.md +[instruction-files]: https://code.visualstudio.com/docs/copilot/copilot-customization +[python-type-hints]: https://docs.python.org/3/library/typing.html +[games-endpoints]: ../server/routes/games.py +[games-tests]: ../server/tests/test_games.py +[instructions-best-practices]: https://docs.github.com/enterprise-cloud@latest/copilot/using-github-copilot/coding-agent/best-practices-for-using-copilot-to-work-on-tasks#adding-custom-instructions-to-your-repository +[personal-instructions]: https://docs.github.com/copilot/customizing-copilot/adding-personal-custom-instructions-for-github-copilot +[copilot-instructions-five-tips]: https://github.blog/ai-and-ml/github-copilot/5-tips-for-writing-better-custom-instructions-for-copilot/ +[awesome-copilot]: https://github.com/github/awesome-copilot +[repository-custom-instructions]: https://docs.github.com/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot diff --git a/scenarios/tailspin-toys/steps/3-copilot-agent-mode-vscode.md b/scenarios/tailspin-toys/steps/3-copilot-agent-mode-vscode.md new file mode 100644 index 00000000..9585ecd3 --- /dev/null +++ b/scenarios/tailspin-toys/steps/3-copilot-agent-mode-vscode.md @@ -0,0 +1,43 @@ +## Scenario + +As the list of games grows, Tailspin Toys wants to allow users to filter by publisher and category. This will require updating both the API and UI, and updating the tests for the API. With the help of Copilot Agent Mode you'll work with your AI pair programmer to add the new feature! + +## Running the application + +Before you make any changes, let's explore the Tailspin Toys website to understand its current functionality. + +The website is a crowdfunding platform for board games with a developer theme. It allows users to list games and display details about them. The website has two main components: the front-end (written in Svelte) and the backend (written in Python using Flask). + +### Starting the application + +To make running the website easier, a script has been provided that will start both the front-end and back-end servers. You can run this script in your GitHub Codespace with the following instructions: + +1. Return to your codespace. You'll continue working in your current branch. +2. Open a new terminal window inside your codespace by selecting Ctl + \`. +3. Run the following script to start the application: + + ```bash + scripts/start-app.sh + ``` + + Once the script is running, you should see output indicating that both the front-end and back-end servers are running, similar to the below: + + ```bash + Server (Flask) running at: http://localhost:5100 + Client (Astro) server running at: http://localhost:4321 + ``` + +> [!NOTE] +> If a dialog box opens prompting you to open a browser window for `http://localhost:5100` close it by selecting the **x**. + +4. Open the website by using Ctrl-**Click** (or Cmd-**Click** on a Mac) on the client address `http://localhost:4321` in the terminal. + +> [!NOTE] +> When using a codespace, selecting a link for the localhost URL from the Codespace terminal will automatically redirect you to `https://-4321.app.github.dev/`. This is a private tunnel to your codespace, which is now hosting your web server! + +### Exploring the application + +Once the application is running, you can explore its functionality. The main features of the website include: + +- **Home Page**: Displays a list of board games with their titles, images, and descriptions. +- **Game Details Page**: When you select a game, you'll be brought to a details page with more information about the game, including its title, description, publisher and category. diff --git a/scenarios/tailspin-toys/steps/4-copilot-coding-agent.md b/scenarios/tailspin-toys/steps/4-copilot-coding-agent.md new file mode 100644 index 00000000..b3a4afdd --- /dev/null +++ b/scenarios/tailspin-toys/steps/4-copilot-coding-agent.md @@ -0,0 +1,135 @@ +## Scenario + +Tailspin Toys has some tech debt they'd like to address. The contractors initially hired to create the first version of the site left the documentation in an unideal state - and by that you'll notice it's completely lacking. As a first step, they'd like to see docstrings added to all functions in the application. + +Additionally, the design team is ready to get to work on building the UX for managing games. They don't need a full implementation yet, but they at least need some endpoints they can use for testing. Specifically, they need endpoints for the games API which will allow them to create, update and delete games. This is currently a blocker, but there are other issues which are of higher priority at the moment. + +These are both examples of tasks which can quickly find themselves deprioritized, and are great to assign to Copilot coding agent. Copilot coding agent can then work on them asynchronously, allowing the developer to focus on other tasks, then return to review Copilot's work and ensure everything is as expected. + +## Setting up the dev environment for the Copilot coding agent + +Creating code, regardless of who's involved, typically requires a specific environment and some setup scripts to be run to ensure everything is in a good state. This holds true when assigning tasks to Copilot, which is performing tasks in a similar fashion to a SWE. + +Coding agent uses [GitHub Actions][github-actions] for its environment when doing its work. You can customize this environment by creating a [special setup workflow][setup-workflow], configured in the **.github/workflows/copilot-setup-steps.yml** file, to run before it gets to work. This enables it to have access to the required development tools and dependencies. This has been pre-configured ahead of the lab to help the lab flow and allow this learning opportunity. It makes sure that Copilot has access to Python, Node.JS, and the required dependencies for the client and server: + +```yaml +name: "Copilot Setup Steps" + +# Allows you to test the setup steps from your repository's "Actions" tab +on: workflow_dispatch + +jobs: + copilot-setup-steps: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Checkout code + uses: actions/checkout@v4 + + # Backend setup - Python + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install Python dependencies + working-directory: ./server + run: pip install -r requirements.txt + + # Frontend setup - Node.js + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + cache: "npm" + cache-dependency-path: "./client/package.json" + + - name: Install JavaScript dependencies + working-directory: ./client + run: npm ci +``` + +It looks like any other GitHub workflow file, but it has a few key points: + +- It contains a single job called **copilot-setup-steps**. This job is executed in GitHub Actions before Copilot starts working on the pull request. +- Notice the **workflow_dispatch** trigger, which allows you to run the workflow manually from the Actions tab of your repository. This is useful for testing that the workflow runs successfully instead of waiting for Copilot to run it. + +## Adding documentation + +While everyone understands the importance of documentation, most projects have either outdated information or lack it altogether. This is the type of tech debt which often goes unaddressed, slowing productivity and making it more difficult to maintain the codebase or bring new developers into the team. Fortunately, Copilot shines at creating documentation, and this is a perfect issue to assign to Copilot coding agent. It'll work in the background to generate the necessary documentation. In a future exercise you'll return to review its work. + +1. Navigate to your repository on github.com in a new browser tab. +2. Select the **Issues** tab. +3. Select **New issue** to open the new issue dialog. +4. Select **Blank issue** to create the new issue. +5. Set the **Title** to `Code lacks documentation`. +6. Set the **Description** to: + + ```plaintext + Our organization has a requirement that all functions have docstrings or the language equivalent. Unfortunately, recent updates haven't followed this standard. We need to update the existing code to ensure docstrings (or the equivalent) are included with every function or method. + ``` + +7. Select **Create** to create the issue. +8. On the right side, select **Assign to Copilot** to open the assignment dialog. + + ![Assigning Copilot to an issue](images/shared-assign-copilot.png) + +9. Select **Assign**. + + ![Copilot assignment details](images/ex4-assign-copilot-details.png) + +10. Select the **Pull Requests** tab. +11. Open the newly generated pull request (PR), which will be titled something similar to **[WIP]: Code lacks documentation**. If a new PR doesn't appear on the list, wait for a moment or two and refresh the browser window. +12. After a few minutes, you should see that Copilot has created a todo list. + +> [!NOTE] +> It make take several minutes for the todo list from Copilot to appear in the PR. Copilot is creating its environment (running the workflow highlighted previously), analyzing the project, and determining the best approach to tackling the problem. + +13. Review the list and the tasks it's going to complete. +14. Scroll down the pull request timeline, and you should see an update that Copilot has started working on the issue. +15. Select the **View session** button. + + ![Copilot session view](images/ex4-view-session.png) + +> [!IMPORTANT] +> You may need to refresh the window to see the updated indicator. + +16. Notice that you can scroll through the live session, and how Copilot is solving the problem. That includes exploring the code and understanding the state, how Copilot pauses to think and decide on the appropriate plan and also creating code. + +This will likely take several minutes. One of the primary goals of Copilot coding agent is to allow it to perform tasks asynchronously, freeing us to focus on other tasks. We're going to take advantage of that very feature by both assigning another task to Copilot coding agent, then turning our attention to writing some code to add features to our application. + +## Create new API endpoints + +As has been highlighted, one of the great advantages of GitHub Copilot coding agent is the ability to divide work, where you can focus on one set of tasks while it focuses on another. While creating the endpoints for modifying games for the design team might not necessarily take a long time, it's still time which could be used for other tasks. Let's assign it to Copilot coding agent! + +1. Return to your repository on github.com. +2. Select the **Issues** tab. +3. Select **New issue** to open the new issue dialogue. +4. Select **Blank issue** to use the blank template. +5. Set the **Title** to: `Add endpoints to create and edit games` +6. Set the **Description** to: + + ```markdown + We're going to be creating functionality in the future to allow for the submission (and editing) of games. For now we just want the endpoints so we can explore how we want to create the UX and do some acceptance testing. Our requirements are: + + - Add new endpoints to the Games API to support creating, updating and deleting games + - There should be appropriate error handling for all new endpoints + - There should be unit tests created for all new endpoints + - Before creating the PR, ensure all tests pass + ``` + +7. Select **Create** to create the issue. +8. On the right side, select **Assign to Copilot** to open the assignment dialog. + + ![Assigning Copilot to an issue](images/shared-assign-copilot.png) + +9. Select **Assign**. + +Shortly after, you should see a set of 👀 on the first comment in the issue, indicating Copilot is on the job! + +![Copilot uses the eyes emoji to indicate it's working on the issue](images/ex4-issue-eyes-emoji.png) + +9. Select **Assign** to assign the issue to Copilot coding agent. + +Copilot is now diligently working on your second request! Copilot coding agent works in a similar fashion to a SWE, so you don't need to actively monitor it, but instead review once it's completed. Let's turn your attention to writing code and adding other features. diff --git a/scenarios/tailspin-toys/steps/5-custom-agents.md b/scenarios/tailspin-toys/steps/5-custom-agents.md new file mode 100644 index 00000000..852dc20b --- /dev/null +++ b/scenarios/tailspin-toys/steps/5-custom-agents.md @@ -0,0 +1,5 @@ +## Scenario + +Tailspin Toys is committed to ensuring their crowdfunding platform is accessible to all users, regardless of their visual abilities or preferences. Recent user feedback has highlighted that some users find the current dark theme difficult to read due to insufficient contrast between text and background colors. To address this accessibility concern, the design team has requested the implementation of a high-contrast mode that users can toggle on and off. + +Because accessibility is critical, you want to ensure this is implemented as quickly as possible. You're going to utilize a custom agent to generate the functionality. diff --git a/scenarios/tailspin-toys/steps/6-managing-agents.md b/scenarios/tailspin-toys/steps/6-managing-agents.md new file mode 100644 index 00000000..5f2440b7 --- /dev/null +++ b/scenarios/tailspin-toys/steps/6-managing-agents.md @@ -0,0 +1,23 @@ +## Scenario + +After assigning the agent to create a high-contrast mode, the team realized it would be a good time to add a light mode as well. Since work was already being done to update the style of the site and add toggle functionality, it seemed logical to include this functionality. You want to steer the agent's work to ensure it adds a light mode as well as high contrast. + +## Review Copilot coding agent tasks + +Let's see the current status of all tasks assigned to Copilot coding agent. + +1. Navigate to agents page at [https://github.com/copilot/agents](https://github.com/copilot/agents). +2. Note the list of tasks, both on the main pane and on the left pane. You should see the list of the tasks you've assigned to Copilot, including: + - Updating documentation for your codebase. + - Generating new API endpoints for games. + - Adding a high contrast mode for the website. +3. Select one of the running tasks. Review the tasks which have been performed by Copilot. These can include: + - Checking out the code from the repository. + - Creating the environment for Copilot to work. + - Setting up MCP servers. + - Performing various steps to complete the assigned task. + +> [!NOTE] +> The exact steps listed will vary depending on the state of Copilot's work and the approach it took. + +4. Also note the pull request (PR) pane which appears on the right side. This allows you to see the PR and files changed for additional monitoring. diff --git a/scripts/new-scenario.py b/scripts/new-scenario.py new file mode 100644 index 00000000..df3ff459 --- /dev/null +++ b/scripts/new-scenario.py @@ -0,0 +1,218 @@ +#!/usr/bin/env python3 +""" +new-scenario.py — Scaffold a new workshop scenario. + +Usage: + python scripts/new-scenario.py + +Creates the directory structure and starter files for a new scenario under +scenarios//. After running this script, follow the instructions +in docs/authoring/new-scenario-guide.md to complete the scenario. +""" + +import sys +import os +import re +import textwrap +from pathlib import Path + + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + +def fail(message: str) -> None: + """Print an error message and exit with a non-zero status.""" + print(f"Error: {message}", file=sys.stderr) + sys.exit(1) + + +def validate_scenario_id(scenario_id: str) -> None: + """Enforce a simple naming convention: lowercase letters, digits, hyphens.""" + if not re.fullmatch(r"[a-z][a-z0-9-]*", scenario_id): + fail( + f"'{scenario_id}' is not a valid scenario ID. " + "Use only lowercase letters, digits, and hyphens (must start with a letter)." + ) + + +def repo_root() -> Path: + """Return the repository root (the directory that contains scripts/).""" + scripts_dir = Path(__file__).resolve().parent + return scripts_dir.parent + + +# --------------------------------------------------------------------------- +# File content templates +# --------------------------------------------------------------------------- + +SCENARIO_YML_TEMPLATE = """\ +# {scenario_id} — scenario configuration +# Edit every field below before opening a pull request. +# See docs/authoring/new-scenario-guide.md for full documentation. + +# Human-readable name displayed in the workshop +name: {display_name} + +# Short description of the application used in this scenario +description: > + TODO: Describe the sample application in one or two sentences. + What does it do? Who is the fictional company? + +# GitHub repository for the sample application (org/repo) +repository: TODO/TODO + +# Technology stack — used when generating scenario-specific content +tech_stack: + frontend: + name: TODO + language: TODO + notes: > + TODO: Describe the frontend framework and any notes relevant to the exercises. + backend: + name: TODO + language: TODO + notes: > + TODO: Describe the backend framework and any notes relevant to the exercises. + database: TODO + +# Content variables — substituted into workshop content and prompts +variables: + company_name: TODO + company_description: TODO # one-line description, e.g. "a crowdfunding platform for board games" + product_type: TODO # e.g. "e-commerce store", "blog platform" + primary_entities: TODO # e.g. "products, orders, customers" + filter_feature: TODO # what learners build in exercise 3 + new_endpoints_feature: TODO # what the coding agent builds in exercise 4 + accessibility_feature: TODO # what the custom agent builds in exercise 5 + documentation_feature: TODO # what is documented in exercise 4's first task + +# Exercises to skip for this scenario. +# List exercise filenames (without the .md extension) from workshop-content/ +# that are NOT applicable to this scenario. +skip: [] + # Examples: + # - 3-copilot-agent-mode-vscode # skip if the app has no frontend + # - 5-custom-agents # skip if accessibility task doesn't apply + +# Notes for workshop authors or maintainers (not shown to participants) +author_notes: > + TODO: Add any notes for future maintainers about this scenario. +""" + +STEPS_README_TEMPLATE = """\ +# {display_name} — Exercise Steps + +This directory contains scenario-specific step content for the **{display_name}** scenario. + +## How steps work + +Place a Markdown file here with the **same filename** as an exercise in `workshop-content/` to inject +scenario-specific sections into that exercise. A steps file contains only the `## ` sections that differ +from the generic core exercise — each matching section replaces the corresponding section in the core +file when exercises are rendered for this scenario. + +For example, to customise only the `## Scenario` and `## Running the application` sections of exercise 3: + +```markdown +## Scenario + +Your application-specific scenario description here. + +## Running the application + +Your application-specific startup instructions here. +``` + +Steps files must NOT be created for exercises listed in the `skip` field of `scenario.yml`. + +See [docs/authoring/new-scenario-guide.md](../../../docs/authoring/new-scenario-guide.md) for full instructions. + +## Files in this directory + +*(None yet — add steps files as needed.)* +""" + + +# --------------------------------------------------------------------------- +# Scaffolding logic +# --------------------------------------------------------------------------- + +def scenario_id_to_display_name(scenario_id: str) -> str: + """Convert 'my-scenario-id' to 'My Scenario Id' as a placeholder name.""" + return " ".join(word.capitalize() for word in scenario_id.split("-")) + + +def create_scenario(scenario_id: str) -> None: + root = repo_root() + scenario_dir = root / "scenarios" / scenario_id + steps_dir = scenario_dir / "steps" + + # Guard against overwriting an existing scenario + if scenario_dir.exists(): + fail( + f"scenarios/{scenario_id}/ already exists. " + "Remove it first or choose a different scenario ID." + ) + + display_name = scenario_id_to_display_name(scenario_id) + + # Create directories + steps_dir.mkdir(parents=True) + print(f"Created: scenarios/{scenario_id}/") + print(f"Created: scenarios/{scenario_id}/steps/") + + # Write scenario.yml + yml_content = SCENARIO_YML_TEMPLATE.format( + scenario_id=scenario_id, + display_name=display_name, + ) + (scenario_dir / "scenario.yml").write_text(yml_content, encoding="utf-8") + print(f"Created: scenarios/{scenario_id}/scenario.yml") + + # Write steps/README.md + steps_readme = STEPS_README_TEMPLATE.format(display_name=display_name) + (steps_dir / "README.md").write_text(steps_readme, encoding="utf-8") + print(f"Created: scenarios/{scenario_id}/steps/README.md") + + # Summary + print() + print("Scaffolding complete!") + print() + print("Next steps:") + print(f" 1. Edit scenarios/{scenario_id}/scenario.yml — fill in every TODO field.") + print(f" 2. Add exercise steps files to scenarios/{scenario_id}/steps/ as needed.") + print(f" 3. Run: python scripts/validate-scenario.py {scenario_id}") + print(f" 4. Update the scenario table in scenarios/README.md.") + print() + print("Full instructions: docs/authoring/new-scenario-guide.md") + + +# --------------------------------------------------------------------------- +# Entry point +# --------------------------------------------------------------------------- + +def main() -> None: + if len(sys.argv) != 2: + print( + textwrap.dedent( + """\ + Usage: + python scripts/new-scenario.py + + Example: + python scripts/new-scenario.py java-bookstore + + The scenario ID must be lowercase letters, digits, and hyphens. + """ + ) + ) + sys.exit(1) + + scenario_id = sys.argv[1].strip() + validate_scenario_id(scenario_id) + create_scenario(scenario_id) + + +if __name__ == "__main__": + main() diff --git a/scripts/render-scenario.py b/scripts/render-scenario.py new file mode 100644 index 00000000..7b81c395 --- /dev/null +++ b/scripts/render-scenario.py @@ -0,0 +1,194 @@ +#!/usr/bin/env python3 +""" +render-scenario.py — Render workshop exercises for a specific scenario. + +Usage: + python scripts/render-scenario.py [] + python scripts/render-scenario.py --all [] + +For each exercise in workshop-content/, the script: + 1. Reads the core exercise. + 2. If the scenario has a matching steps file in scenarios//steps/, + injects its ## sections into the core exercise, replacing any section + in the core that shares the same heading. + 3. Writes the rendered file to // (default: + rendered//). + +The steps file need only contain the sections that differ from the core. +Sections not present in the steps file are kept verbatim from the core. + +Exit codes: + 0 All exercises rendered successfully. + 1 One or more errors occurred. +""" + +import sys +import textwrap +from pathlib import Path + + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + +def repo_root() -> Path: + """Return the repository root (the directory containing scripts/).""" + return Path(__file__).resolve().parent.parent + + +def parse_sections(content: str) -> "dict[str, str]": + """ + Split markdown content into level-2 sections keyed by heading text. + + Each value includes the '## heading\\n' line plus all subsequent lines + up to (but not including) the next level-2 heading. Content that + appears before the first '## ' heading is ignored for injection + purposes (it is preserved verbatim from the core exercise). + """ + sections: dict[str, str] = {} + lines = content.splitlines(keepends=True) + i = 0 + while i < len(lines): + line = lines[i] + if line.startswith("## "): + header = line[3:].rstrip("\n").rstrip() + section_lines: list[str] = [line] + i += 1 + while i < len(lines) and not lines[i].startswith("## "): + section_lines.append(lines[i]) + i += 1 + sections[header] = "".join(section_lines) + else: + i += 1 + return sections + + +def inject_sections(core: str, steps: str) -> str: + """ + Return a copy of *core* where each level-2 section whose heading + matches a heading in *steps* has been replaced by the steps version. + + Content before the first '## ' heading and any sections not present + in *steps* are kept exactly as they appear in *core*. + """ + step_sections = parse_sections(steps) + if not step_sections: + return core + + lines = core.splitlines(keepends=True) + result: list[str] = [] + in_replaced_section = False + + for line in lines: + if line.startswith("## "): + header = line[3:].rstrip("\n").rstrip() + if header in step_sections: + # Emit the replacement section (includes the ## heading line) + result.append(step_sections[header]) + in_replaced_section = True + else: + in_replaced_section = False + result.append(line) + elif not in_replaced_section: + result.append(line) + + return "".join(result) + + +# --------------------------------------------------------------------------- +# Rendering +# --------------------------------------------------------------------------- + +def render_scenario(scenario_id: str, output_dir: Path) -> bool: + """ + Render all exercises for *scenario_id* into *output_dir*//. + Returns True if everything succeeded. + """ + root = repo_root() + workshop_dir = root / "workshop-content" + steps_dir = root / "scenarios" / scenario_id / "steps" + scenario_dir = root / "scenarios" / scenario_id + out_dir = output_dir / scenario_id + + if not scenario_dir.is_dir(): + print( + f" ✗ scenarios/{scenario_id}/ does not exist.", + file=sys.stderr, + ) + return False + + out_dir.mkdir(parents=True, exist_ok=True) + + exercises = sorted(p for p in workshop_dir.glob("*.md") if p.name != "README.md") + for ex_path in exercises: + core = ex_path.read_text(encoding="utf-8") + steps_path = steps_dir / ex_path.name + if steps_path.exists(): + steps = steps_path.read_text(encoding="utf-8") + rendered = inject_sections(core, steps) + label = "(with scenario steps)" + else: + rendered = core + label = "" + out_path = out_dir / ex_path.name + out_path.write_text(rendered, encoding="utf-8") + print(f" ✓ {ex_path.name} {label}".rstrip()) + + return True + + +# --------------------------------------------------------------------------- +# Entry point +# --------------------------------------------------------------------------- + +def main() -> None: + root = repo_root() + scenarios_dir = root / "scenarios" + default_output = root / "rendered" + + if len(sys.argv) < 2: + print( + textwrap.dedent( + """\ + Usage: + python scripts/render-scenario.py [] + python scripts/render-scenario.py --all [] + + Example: + python scripts/render-scenario.py tailspin-toys + python scripts/render-scenario.py --all rendered/ + """ + ) + ) + sys.exit(1) + + arg = sys.argv[1].strip() + output_dir = Path(sys.argv[2]) if len(sys.argv) > 2 else default_output + + if arg == "--all": + if not scenarios_dir.is_dir(): + print("No scenarios/ directory found.", file=sys.stderr) + sys.exit(1) + scenario_ids = [ + d.name + for d in sorted(scenarios_dir.iterdir()) + if d.is_dir() and not d.name.startswith(".") + ] + if not scenario_ids: + print("No scenarios found in scenarios/.") + sys.exit(0) + all_ok = True + for sid in scenario_ids: + print(f"Rendering scenario: {sid}") + if not render_scenario(sid, output_dir): + all_ok = False + print() + sys.exit(0 if all_ok else 1) + else: + print(f"Rendering scenario: {arg}") + ok = render_scenario(arg, output_dir) + sys.exit(0 if ok else 1) + + +if __name__ == "__main__": + main() diff --git a/scripts/validate-scenario.py b/scripts/validate-scenario.py new file mode 100644 index 00000000..1d10c78f --- /dev/null +++ b/scripts/validate-scenario.py @@ -0,0 +1,383 @@ +#!/usr/bin/env python3 +""" +validate-scenario.py — Validate a workshop scenario's structure and configuration. + +Usage: + python scripts/validate-scenario.py + python scripts/validate-scenario.py --all # validate every scenario + +Exit codes: + 0 All checks passed. + 1 One or more errors found. +""" + +import sys +from pathlib import Path +from typing import Any + + +# Sentinel used by the minimal YAML parser to indicate that a field was +# detected in the file but its value is a block scalar or nested map that +# the parser did not fully deserialise (e.g. `description: >`). +_PRESENT_MARKER = "__present__" + + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + +def repo_root() -> Path: + """Return the repository root (the directory that contains scripts/).""" + return Path(__file__).resolve().parent.parent + + +def load_yaml(path: Path) -> dict[str, Any]: + """Load a YAML file, returning a dict. Requires PyYAML.""" + try: + import yaml # type: ignore[import] + except ImportError: + # Fall back to a minimal parser for simple flat YAML structures + # so the script works without installing extra dependencies. + return _minimal_yaml_parse(path) + + with open(path, encoding="utf-8") as fh: + return yaml.safe_load(fh) or {} + + +def _minimal_yaml_parse(path: Path) -> dict[str, Any]: + """ + Minimal YAML parser that handles the subset of YAML used in scenario.yml: + - Top-level key: value pairs (strings, empty, block scalars) + - Nested maps at two levels of indentation + - Lists (inline [] or block - items) + Comments and blank lines are ignored. + """ + lines = path.read_text(encoding="utf-8").splitlines() + return _parse_block(lines, 0, 0)[0] + + +def _skip_to_next_indent(lines: list[str], start: int, base_indent: int) -> int: + """Advance past all lines that are more indented than base_indent.""" + i = start + while i < len(lines): + raw = lines[i] + stripped = raw.strip() + if not stripped or stripped.startswith("#"): + i += 1 + continue + indent = len(raw) - len(raw.lstrip()) + if indent <= base_indent: + break + i += 1 + return i + + +def _parse_block( + lines: list[str], start: int, base_indent: int +) -> "tuple[dict[str, Any], int]": + """ + Parse a YAML mapping block starting at `start`, where all keys are + indented exactly `base_indent` spaces. Returns (mapping_dict, next_line_index). + """ + result: dict[str, Any] = {} + i = start + + while i < len(lines): + raw = lines[i] + stripped = raw.strip() + + # Skip blank lines and comments + if not stripped or stripped.startswith("#"): + i += 1 + continue + + indent = len(raw) - len(raw.lstrip()) + + # If we've de-dented below our base, we're done with this block + if indent < base_indent: + break + + # If we're deeper than expected, skip (handled by recursive calls) + if indent > base_indent: + i += 1 + continue + + # Expect a mapping key at this indent level + if ":" not in stripped: + i += 1 + continue + + key, _, rest = stripped.partition(":") + key = key.strip() + rest = rest.strip() + + i += 1 # advance past this key line + + if rest in (">", "|"): + # Block scalar: consume its content lines and mark as present + i = _skip_to_next_indent(lines, i, base_indent) + result[key] = _PRESENT_MARKER + elif rest == "": + # Could be a nested map or an empty value; peek ahead + j = i + while j < len(lines) and (not lines[j].strip() or lines[j].strip().startswith("#")): + j += 1 + + if j < len(lines): + next_indent = len(lines[j]) - len(lines[j].lstrip()) + next_stripped = lines[j].strip() + + if next_indent > base_indent: + if next_stripped.startswith("- "): + items, i = _parse_list(lines, j, next_indent) + result[key] = items + else: + nested, i = _parse_block(lines, j, next_indent) + result[key] = nested + else: + result[key] = _PRESENT_MARKER + else: + result[key] = _PRESENT_MARKER + elif rest == "[]": + result[key] = [] + else: + result[key] = rest.strip("'\"") + + return result, i + + +def _parse_list(lines: list[str], start: int, base_indent: int) -> "tuple[list[str], int]": + """Parse a YAML sequence (list of '- item' lines) at `base_indent`.""" + items: list[str] = [] + i = start + + while i < len(lines): + raw = lines[i] + stripped = raw.strip() + + if not stripped or stripped.startswith("#"): + i += 1 + continue + + indent = len(raw) - len(raw.lstrip()) + + if indent < base_indent: + break + + if stripped.startswith("- "): + item = stripped[2:].strip().strip("'\"") + # Skip commented-out items + if not item.startswith("#"): + items.append(item) + + i += 1 + + return items, i + + +# --------------------------------------------------------------------------- +# Validation checks +# --------------------------------------------------------------------------- + +REQUIRED_TOP_LEVEL_FIELDS = ["name", "description", "repository", "tech_stack", "variables", "skip"] +REQUIRED_VARIABLES = [ + "company_name", + "company_description", + "product_type", + "primary_entities", + "filter_feature", + "new_endpoints_feature", + "accessibility_feature", + "documentation_feature", +] + + +class Validator: + def __init__(self, scenario_id: str) -> None: + self.scenario_id = scenario_id + self.root = repo_root() + self.scenario_dir = self.root / "scenarios" / scenario_id + self.workshop_dir = self.root / "workshop-content" + self.errors: list[str] = [] + self.warnings: list[str] = [] + + def err(self, msg: str) -> None: + self.errors.append(msg) + + def warn(self, msg: str) -> None: + self.warnings.append(msg) + + def exercises(self) -> list[str]: + """Return all exercise filenames (without .md) from workshop-content/.""" + if not self.workshop_dir.exists(): + return [] + return [ + p.stem + for p in sorted(self.workshop_dir.glob("*.md")) + if p.name != "README.md" + ] + + def run(self) -> bool: + """Run all checks. Return True if no errors were found.""" + self._check_directory_exists() + if self.errors: + return False # Cannot continue without the directory + + config = self._check_scenario_yml() + if config is not None: + self._check_required_fields(config) + self._check_variables(config) + skip_list = self._check_skip_list(config) + self._check_steps(skip_list) + else: + # scenario.yml missing — steps check may still be useful + self._check_steps([]) + + return len(self.errors) == 0 + + def _check_directory_exists(self) -> None: + if not self.scenario_dir.is_dir(): + self.err( + f"scenarios/{self.scenario_id}/ does not exist. " + f"Run: python scripts/new-scenario.py {self.scenario_id}" + ) + + def _check_scenario_yml(self) -> "dict[str, Any] | None": + yml_path = self.scenario_dir / "scenario.yml" + if not yml_path.exists(): + self.err(f"scenarios/{self.scenario_id}/scenario.yml is missing.") + return None + try: + config = load_yaml(yml_path) + except Exception as exc: + self.err(f"scenarios/{self.scenario_id}/scenario.yml cannot be parsed: {exc}") + return None + return config + + def _check_required_fields(self, config: dict[str, Any]) -> None: + for field in REQUIRED_TOP_LEVEL_FIELDS: + val = config.get(field) + if val is None: + self.err(f"scenario.yml: required field '{field}' is missing or empty.") + # skip: [] is an empty list — that is valid (means "no exercises skipped") + + def _check_variables(self, config: dict[str, Any]) -> None: + variables = config.get("variables") or {} + if not isinstance(variables, dict): + self.err("scenario.yml: 'variables' must be a mapping.") + return + for var in REQUIRED_VARIABLES: + val = variables.get(var) + if val is None: + self.err(f"scenario.yml: variables.{var} is missing.") + elif isinstance(val, str) and (val.upper().startswith("TODO") or val == _PRESENT_MARKER): + self.warn(f"scenario.yml: variables.{var} still contains a TODO placeholder.") + + # Check top-level fields for TODOs + for field in ["name", "description", "repository"]: + val = config.get(field) + if isinstance(val, str) and val.upper().startswith("TODO"): + self.warn(f"scenario.yml: field '{field}' still contains a TODO placeholder.") + + def _check_skip_list(self, config: dict[str, Any]) -> list[str]: + skip = config.get("skip") or [] + if not isinstance(skip, list): + self.err("scenario.yml: 'skip' must be a list.") + return [] + + valid_exercises = self.exercises() + for entry in skip: + if not isinstance(entry, str): + self.err(f"scenario.yml: skip entry {entry!r} is not a string.") + elif entry not in valid_exercises: + self.err( + f"scenario.yml: skip entry '{entry}' does not match any exercise " + f"in workshop-content/ (valid: {', '.join(valid_exercises)})." + ) + return [s for s in skip if isinstance(s, str)] + + def _check_steps(self, skip_list: list[str]) -> None: + steps_dir = self.scenario_dir / "steps" + if not steps_dir.is_dir(): + self.warn( + f"scenarios/{self.scenario_id}/steps/ does not exist. " + "Create it (even empty) to hold exercise steps files." + ) + return + + valid_exercises = set(self.exercises()) + for steps_file in steps_dir.glob("*.md"): + if steps_file.name == "README.md": + continue + stem = steps_file.stem + if stem not in valid_exercises: + self.err( + f"steps/{steps_file.name}: does not correspond to any exercise " + f"in workshop-content/." + ) + elif stem in skip_list: + self.err( + f"steps/{steps_file.name}: exercise '{stem}' is in the skip " + "list but also has a steps file — remove one or the other." + ) + + +# --------------------------------------------------------------------------- +# Entry point +# --------------------------------------------------------------------------- + +def validate_one(scenario_id: str) -> bool: + print(f"Validating scenario: {scenario_id}") + v = Validator(scenario_id) + passed = v.run() + + for warning in v.warnings: + print(f" ⚠ {warning}") + for error in v.errors: + print(f" ✗ {error}") + + if passed and not v.warnings: + print(f" ✓ All checks passed.") + elif passed: + print(f" ✓ No errors (but see warnings above).") + else: + print(f" ✗ {len(v.errors)} error(s) found.") + + print() + return passed + + +def main() -> None: + root = repo_root() + scenarios_dir = root / "scenarios" + + if len(sys.argv) < 2: + print(__doc__) + sys.exit(1) + + arg = sys.argv[1] + + if arg == "--all": + if not scenarios_dir.is_dir(): + print("No scenarios/ directory found.", file=sys.stderr) + sys.exit(1) + scenario_ids = [ + d.name + for d in sorted(scenarios_dir.iterdir()) + if d.is_dir() and not d.name.startswith(".") + ] + if not scenario_ids: + print("No scenarios found in scenarios/.") + sys.exit(0) + all_passed = True + for sid in scenario_ids: + if not validate_one(sid): + all_passed = False + sys.exit(0 if all_passed else 1) + else: + passed = validate_one(arg) + sys.exit(0 if passed else 1) + + +if __name__ == "__main__": + main() diff --git a/tailspin-toys-dotnet/.devcontainer/devcontainer.json b/tailspin-toys-dotnet/.devcontainer/devcontainer.json new file mode 100644 index 00000000..47ba13f7 --- /dev/null +++ b/tailspin-toys-dotnet/.devcontainer/devcontainer.json @@ -0,0 +1,28 @@ +{ + "name": "Tailspin Toys .NET", + "image": "mcr.microsoft.com/devcontainers/base:bookworm", + "features": { + "ghcr.io/devcontainers/features/dotnet:2": { + "version": "8.0" + }, + "ghcr.io/devcontainers/features/node:1": {}, + "ghcr.io/warrenbuckley/codespace-features/sqlite:1": {} + }, + "postCreateCommand": "./scripts/setup-env.sh", + "forwardPorts": [ + 4321, + 5100 + ], + "customizations": { + "vscode": { + "extensions": [ + "github.copilot", + "github.copilot-chat", + "ms-dotnettools.csdevkit", + "ms-dotnettools.csharp", + "svelte.svelte-vscode", + "astro-build.astro-vscode" + ] + } + } +} diff --git a/tailspin-toys-dotnet/.github/agents/accessibility.md b/tailspin-toys-dotnet/.github/agents/accessibility.md new file mode 100644 index 00000000..3de98a2e --- /dev/null +++ b/tailspin-toys-dotnet/.github/agents/accessibility.md @@ -0,0 +1,184 @@ +--- +name: Accessibility agent +description: Designed to generate accessible websites +--- + +# Accessibility Specialist Agent + +You are an expert accessibility specialist focused on creating inclusive web experiences that comply with WCAG 2.1 Level AA standards. + +## Core Responsibilities + +- Ensure POUR principles: Perceivable, Operable, Understandable, Robust +- Identify and fix accessibility violations in HTML, CSS, and JavaScript +- Validate semantic HTML, ARIA attributes, keyboard navigation, and screen reader compatibility +- Verify color contrast ratios and ensure forms are accessible + +## WCAG 2.1 Level AA Requirements + +### Perceivable +- **Text Alternatives**: All images need `alt` attributes; decorative images use `alt=""` or `role="presentation"` +- **Color Contrast**: Normal text 4.5:1, large text 3:1; don't rely on color alone +- **Semantic Structure**: Use `