Estimated time: 120 minutes (7 exercises)
Difficulty: intermediate — this workshop walks you through the full customization of GitHub Copilot in VS Code. You will start from always-on instructions and progress all the way to configuring custom agents, skills, hooks, and plugins. Each exercise corresponds to one of the customization options available in the platform.
AI-Assisted Development — Module 3
This training package is proprietary and confidential and is intended solely for the uses described in the training materials. Copying or disclosing all or part of the content and/or software included in such packages is prohibited. The contents of this package are for informational and training purposes only and are provided "as is" without warranties of any kind, express or implied, including, but not limited to, the implied warranties of merchantability, fitness for a particular purpose, and non-infringement. The content of the training package, including URLs and other references to Internet websites, is subject to change without notice. Unless otherwise noted, the companies, organizations, products, domain names, email addresses, logos, people, places, and events depicted herein are fictitious and no association with any real company, organization, product, domain name, email address, logo, person, place, or event is intended or should be inferred.
GitHub Copilot is not just a generic assistant: it is a composable system you can tailor to your project, your team, and your workflows. In this workshop we will explore all the customization options available in Visual Studio Code, each with a dedicated hands-on exercise.
The following table summarizes the seven customization types we will cover:
| # | Goal | Customization | When it activates |
|---|---|---|---|
| 1 | Apply coding standards everywhere | Always-on Instructions | Automatically included in every request |
| 2 | Different rules for different file types | File-based Instructions | When files match a pattern or description |
| 3 | Reusable tasks to run repeatedly | Prompt Files | When you invoke a slash command |
| 4 | Package multi-step workflows with scripts | Agent Skills | When the task matches the skill description |
| 5 | Specialized AI persona with tool restrictions | Custom Agents | When you select it or another agent delegates to it |
| 6 | Automate tasks at agent lifecycle points | Hooks | When the agent reaches a matching lifecycle event |
| 7 | Connect to external APIs or databases | MCP | When the task matches a tool description |
Each exercise is self-contained, but the order is designed to progressively build your understanding of the customization system.
This exercise teaches you how to create a copilot-instructions.md file that is automatically applied to every Copilot Chat interaction in your workspace. It is the starting point for ensuring that all generated code follows your project conventions.
Before you begin, make sure you have:
- Visual Studio Code installed (version 1.100+)
- The GitHub Copilot extension active with a valid plan (Free, Pro, Business, or Enterprise)
- A Node.js/TypeScript project open in VS Code (or create an empty one with
npm init -y && npx tsc --init)
- Create the
.github/copilot-instructions.mdfile at the workspace root - Write style instructions and project conventions in Markdown format
- Verify that Copilot automatically applies the instructions in every response
Step 1 — Create the folder and file
- Open the VS Code integrated terminal (
Ctrl+``) - Run the following commands:
mkdir -p .github touch .github/copilot-instructions.md
- Open the newly created file in the editor
Step 2 — Write the always-on instructions
- Paste the following example instructions into the file (adapt them to your actual project):
# Project Standards ## General Conventions - Use TypeScript for all new JavaScript code - Prefer functional patterns and immutability when possible - Write JSDoc comments for all public APIs - Use 2 spaces for indentation, never tabs ## Naming - Variables and functions: camelCase - Classes and interfaces: PascalCase - Constants: UPPER_SNAKE_CASE - Files: kebab-case.ts ## Error Handling - Always handle errors with try-catch in async blocks - Return meaningful error messages, never generic strings - Log errors with a structured logger (not console.log) ## Testing - Include unit tests for all business logic - Use Jest as the testing framework - Aim for at least 80% code coverage
Step 3 — Verify it works
- Open Copilot Chat (
Ctrl+Alt+I) - Ask: "Create a function that reads a JSON file and returns the parsed data"
- Observe that Copilot uses TypeScript, camelCase, error handling with try-catch, and JSDoc comments — without you having to specify any of this in the prompt
Step 4 — Verify via Diagnostics
- Right-click in the Chat view and select Diagnostics
- Verify that the
copilot-instructions.mdfile appears among the loaded instructions - If it does not appear, check that the file is in the correct location:
.github/copilot-instructions.md
- The
.github/copilot-instructions.mdfile exists at the workspace root - Copilot generates code that follows the conventions written in the file (TypeScript, camelCase, JSDoc, try-catch)
- The Diagnostics view shows the file among the active instructions
This exercise teaches you how to create instruction files scoped to specific file patterns, such as .tsx, .test.ts, or .css. Unlike always-on instructions, these activate only when you are working on files that match the specified pattern.
Before you begin, make sure you have:
- Completed Exercise 1
- A
.github/instructionsfolder in the workspace (or thechat.instructionsFilesLocationssetting configured)
- Create a
*.instructions.mdfile with theapplyToproperty in the YAML frontmatter - Define specific rules for React
.tsxfiles - Verify that the instructions only activate on files matching the pattern
Step 1 — Create the folder structure
- Run in the terminal:
mkdir -p .github/instructions
Step 2 — Create instructions for React components
- Create the file
.github/instructions/react-components.instructions.md:--- applyTo: "**/*.tsx" description: "Conventions for React components in TypeScript" --- # Rules for React Components (.tsx) - Always use functional components with arrow functions and named exports - Define props with a dedicated TypeScript interface (Props suffix) - Use React.FC only when necessary for children - Prefer useState and useReducer for local state - Extract complex logic into separate custom hooks - Each component must have its own file — one file = one component - Use Tailwind CSS for styling, no CSS-in-JS
Step 3 — Create instructions for test files
- Create the file
.github/instructions/testing.instructions.md:--- applyTo: "**/*.test.ts" description: "Conventions for test files" --- # Rules for Tests - Use the AAA pattern (Arrange, Act, Assert) in every test - Name tests following the pattern: "should [expected behavior] when [condition]" - Mock external dependencies, never internal modules - Each test file tests a single module - Include at least one test for the error case
Step 4 — Verify conditional activation
- Open a
.tsxfile and ask Copilot Chat: "Create a Card component with title and description" - Verify it follows the React rules (functional component, Props interface, Tailwind)
- Now open a
.tsfile (not.tsx) and make the same request: the React rules should not activate - Open a
.test.tsfile and ask: "Write tests for an add(a, b) function" - Verify it uses the AAA pattern and the correct naming convention
- At least two
*.instructions.mdfiles exist withapplyToin the frontmatter - React rules apply only when working on
.tsxfiles - Testing rules apply only when working on
.test.tsfiles - The Diagnostics view confirms which instructions are active for each context
This exercise teaches you how to create reusable prompt files that you can invoke as slash commands in Copilot Chat. They are ideal for repetitive tasks such as scaffolding components, generating documentation, or preparing pull requests.
Before you begin, make sure you have:
- Completed Exercises 1 and 2
- The
.github/promptsfolder in the workspace
- Create a
.prompt.mdfile with YAML frontmatter - Use input variables (
${input:...}) to parameterize the prompt - Invoke the prompt as a slash command and verify the result
Step 1 — Create the prompts folder
- Run in the terminal:
mkdir -p .github/prompts
Step 2 — Create a component scaffolding prompt
- Create the file
.github/prompts/create-component.prompt.md:--- agent: 'agent' description: 'Generate a new React component with tests and storybook' --- Create a new complete React component with the following specifications: Component name: ${input:componentName:Enter the component name} Type: ${input:componentType:Component type (ui, layout, form, page)} For each component, generate: 1. The component file (.tsx) following the instructions in [react-components](../instructions/react-components.instructions.md) 2. The test file (.test.tsx) following the instructions in [testing](../instructions/testing.instructions.md) 3. An index.ts file for the export Folder structure: src/components/${input:componentName}/ ├── ${input:componentName}.tsx ├── ${input:componentName}.test.tsx └── index.ts
Step 3 — Create a code review prompt
- Create the file
.github/prompts/code-review.prompt.md:--- agent: 'ask' description: 'Perform a structured review of the selected code' --- Perform a code review of the provided code. Structure your feedback into the following sections: ## Analysis - Code quality and adherence to project standards - Potential bugs or security issues - Performance and possible optimizations ## Suggestions For each issue found, indicate: - Severity (high / medium / low) - Affected line or code block - Concrete suggestion for the fix ## Verdict Indicate whether the code is ready for merge or needs changes.
Step 4 — Use the prompt files
- Open Copilot Chat
- Type
/create-componentin the input bar: the prompt will appear among the available commands - Copilot will ask you for the parameter values (component name, type)
- Verify that the result generates the complete structure with all files
Step 5 — Generate a prompt with AI (optional)
- In the chat, type
/create-promptand describe the task you want to automate, for example: "a prompt to generate unit tests from a source file" - Copilot will generate the
.prompt.mdfile for you - Review the result and save the file in the
.github/promptsfolder
- At least two
.prompt.mdfiles exist in the.github/promptsfolder - The
/create-componentprompt is visible as a slash command in Copilot Chat - When invoked, Copilot asks for input parameters and generates the expected result
- The prompt references existing instruction files via Markdown links
This exercise teaches you how to create an Agent Skill — a folder containing instructions, scripts, and resources that Copilot automatically loads when the task matches the skill description. Skills are portable and also work with Copilot CLI and the Copilot coding agent.
Before you begin, make sure you have:
- Visual Studio Code version 1.108+ (Agent Skills were introduced in December 2025)
- Completed the previous exercises
- Node.js installed (for the example scripts)
- Create a skill folder structure with a
SKILL.mdfile and resources - Define the description in the frontmatter for automatic activation
- Verify that Copilot loads the skill when the task is relevant
Step 1 — Create the skill folder structure
- Run in the terminal:
mkdir -p .github/skills/api-endpoint
Step 2 — Create the SKILL.md file
- Create the file
.github/skills/api-endpoint/SKILL.md:--- name: api-endpoint description: > Generate a complete REST API endpoint with controller, service, validation, and tests. Use this skill when asked to create a new API, a new endpoint, or a new route. --- # REST API Endpoint Creation This skill generates a complete API endpoint following the project architecture. ## When to use this skill - Creating a new REST endpoint - Adding a route to an existing controller - Generating boilerplate for a complete CRUD ## Structure to generate For each endpoint, create the following files: 1. Controller: `src/controllers/{name}.controller.ts` 2. Service: `src/services/{name}.service.ts` 3. Validation: `src/validators/{name}.validator.ts` 4. Tests: `src/controllers/{name}.controller.test.ts` ## Controller template Follow the template in [controller-template](./controller-template.ts) ## Conventions - Use decorators for input validation - Handle errors with centralized middleware - Every endpoint must have inline OpenAPI documentation - Tests must cover the cases: success, validation error, not found, server error
Step 3 — Add a reference template
- Create the file
.github/skills/api-endpoint/controller-template.ts:import { Request, Response, NextFunction } from 'express'; import { validateRequest } from '../middleware/validation'; /** * @openapi * /api/{resource}: * get: * summary: Retrieve the list of resources * responses: * 200: * description: List retrieved successfully */ export const getAll = async ( req: Request, res: Response, next: NextFunction ): Promise<void> => { try { // TODO: implement service logic res.json({ data: [] }); } catch (error) { next(error); } };
Step 4 — Verify automatic activation
- Open Copilot Chat in agent mode
- Ask: "Create an API endpoint for managing users with full CRUD"
- Copilot should recognize the
api-endpointskill and follow the defined structure - Alternatively, type
/api-endpointin the chat to manually activate the skill - Check the Diagnostics view to confirm the skill was loaded
- The
.github/skills/api-endpoint/folder containsSKILL.mdand at least one resource file - The
SKILL.mdhas a frontmatter withnameanddescription - Copilot automatically loads the skill when you ask to create an API endpoint
- The generated code follows the structure and conventions defined in the skill
This exercise teaches you how to create a custom agent — a specialized "persona" with its own set of instructions, available tools, and preferred model. Custom agents are ideal for roles such as security reviewer, database admin, or planner.
Before you begin, make sure you have:
- Visual Studio Code version 1.108+
- Completed the previous exercises
- Create an
.agent.mdfile with frontmatter defining tools, model, and handoffs - Select the custom agent from the agent picker in the Chat view
- Verify that the agent operates with the defined restrictions and behavior
Step 1 — Create the agents folder
- Run in the terminal:
mkdir -p .github/agents
Step 2 — Create a "Security Reviewer" agent
- Create the file
.github/agents/security-reviewer.agent.md:--- name: Security Reviewer description: > Reviews code from a security perspective, identifying vulnerabilities, authentication issues, injection flaws, and data exposure. tools: ['search/codebase', 'search/web'] model: 'Claude Sonnet 4.6' --- # Security Reviewer Instructions You are an application security expert. Your role is to review code without making direct changes. ## Analysis Focus - OWASP Top 10 vulnerabilities (injection, broken auth, XSS, CSRF, etc.) - Secure handling of credentials and secrets - Input validation and sanitization - Sensitive data exposure in API responses - Security configurations (CORS, headers, rate limiting) ## Report Format For each issue found, report: - **Severity**: Critical / High / Medium / Low / Info - **OWASP Category**: which Top 10 category applies - **Location**: affected file and line (or block) - **Description**: what is wrong and why it is a risk - **Remediation**: how to fix the issue ## Important Guidelines - DO NOT write or suggest code directly - Ask clarifying questions about design decisions when needed - Consider the project context by reading the [global instructions](../copilot-instructions.md)
Step 3 — Create a "Planner" agent with handoff
- Create the file
.github/agents/planner.agent.md:--- name: Planner description: > Generates a detailed implementation plan for new features or refactoring. Does not modify code directly. tools: ['search/codebase', 'fetch'] model: 'Claude Sonnet 4.6' handoffs: - label: Implement the plan agent: agent prompt: Implement the plan outlined above. send: false --- # Planner Instructions You are in planning mode. Your task is to generate an implementation plan, never to modify code. ## Plan Structure Every plan must include: - **Overview**: brief description of the feature or refactoring task - **Files involved**: list of files to create, modify, or delete - **Dependencies**: required libraries or modules - **Implementation steps**: ordered steps with complexity estimate - **Risks and mitigations**: potential problems and how to prevent them - **Acceptance criteria**: how to verify the implementation is correct
Step 4 — Select and test the agent
- Open Copilot Chat
- Click the agent picker (dropdown at the top of the Chat view)
- Select Security Reviewer from the list
- Paste or select a block of code and ask: "Review this code"
- Verify that the agent follows the defined report format and does not generate code
Step 5 — Test the handoff
- Select the Planner agent from the agent picker
- Ask: "Plan the addition of a JWT authentication system"
- At the end of the plan, the "Implement the plan" button should appear
- Clicking the button switches the conversation to the standard agent with the plan as context
- At least two
.agent.mdfiles exist in the.github/agentsfolder - The custom agents appear in the agent picker of the Chat view
- The Security Reviewer produces reports without generating code
- The Planner offers a handoff to the implementation agent
This exercise teaches you how to configure hooks — shell commands that run automatically in response to specific events during an agent session. Hooks are deterministic: unlike instructions, they execute every time the condition is met.
Before you begin, make sure you have:
- Visual Studio Code version 1.109+ (hooks are in Preview)
- Node.js and npm installed
- Prettier installed in the project (
npm install --save-dev prettier)
- Create a hook configuration file in JSON format
- Configure a
PostToolUsehook to automatically format files after every edit - Configure a
PreToolUsehook to block dangerous commands - Verify hook execution in the output channel
Step 1 — Create the hooks folder
- Run in the terminal:
mkdir -p .github/hooks
Step 2 — Create an auto-formatting hook
- Create the file
.github/hooks/auto-format.json:{ "hooks": { "PostToolUse": [ { "type": "command", "command": "npx prettier --write \"$TOOL_INPUT_FILE_PATH\"", "timeout": 15 } ] } } - This hook runs Prettier on every file modified by the agent
Step 3 — Create a security hook
- Create the file
.github/hooks/security-gates.json:{ "hooks": { "PreToolUse": [ { "type": "command", "command": ".github/hooks/scripts/validate-command.sh", "timeout": 10 } ] } } - Create the scripts folder and the validation script:
mkdir -p .github/hooks/scripts
- Create the file
.github/hooks/scripts/validate-command.sh:#!/bin/bash # Read the JSON input from stdin INPUT=$(cat) TOOL_NAME=$(echo "$INPUT" | jq -r '.toolName // empty') COMMAND=$(echo "$INPUT" | jq -r '.toolArgs.command // empty') # Block dangerous commands if [[ "$TOOL_NAME" == "bash" ]]; then if echo "$COMMAND" | grep -qE '(rm\s+-rf\s+/|DROP\s+TABLE|DROP\s+DATABASE)'; then echo '{"decision": "deny", "reason": "Dangerous command blocked by security policy"}' exit 1 fi fi # Approve everything else exit 0
- Make the script executable:
chmod +x .github/hooks/scripts/validate-command.sh
Step 4 — Verify hook execution
- Open Copilot Chat in agent mode
- Ask the agent to create or modify a TypeScript file
- After the edit, verify that the file was automatically formatted by Prettier
- Open the output channel: View > Output, then select GitHub Copilot Chat Hooks from the dropdown
- Verify that the log shows the PostToolUse hook execution
Step 5 — Test command blocking
- Ask the agent: "Delete all files in the project root folder"
- The PreToolUse hook should block the command and return the error message
- Verify in the output channel that the hook intercepted and denied the command
- At least two
.jsonfiles exist in the.github/hooksfolder - After every file edit by the agent, Prettier runs automatically
- Dangerous commands are blocked by the PreToolUse hook
- The "GitHub Copilot Chat Hooks" output channel shows execution logs
This exercise teaches you how to configure an MCP (Model Context Protocol) server in VS Code to give Copilot access to external tools such as databases, APIs, and services. MCP is the open standard for connecting AI agents to external data sources.
Before you begin, make sure you have:
- Visual Studio Code version 1.100+
- Docker installed (for the PostgreSQL MCP server example) or Node.js
- Basic familiarity with REST APIs
- Configure an MCP server in the workspace settings
- Verify that MCP tools are available in Copilot Chat
- Use an MCP tool to query an external data source
Step 1 — Understand MCP configuration
- MCP servers are configured in the
.vscode/settings.jsonworkspace file or via the Command Palette - Open the Command Palette (
Ctrl+Shift+P) and search for "MCP: Add Server" - VS Code will guide you through the configuration
Step 2 — Configure an example MCP server (filesystem)
- Open or create the
.vscode/settings.jsonfile and add the configuration:{ "mcp": { "servers": { "filesystem": { "command": "npx", "args": [ "-y", "@modelcontextprotocol/server-filesystem", "${workspaceFolder}" ] } } } } - This MCP server provides Copilot with tools to read, write, and search files in the filesystem
Step 3 — Configure a PostgreSQL MCP server (optional)
- If you have Docker, start a test PostgreSQL container:
docker run --name pg-demo -e POSTGRES_PASSWORD=demo123 -p 5432:5432 -d postgres:16
- Add the PostgreSQL MCP server to the configuration:
{ "mcp": { "servers": { "postgres": { "command": "npx", "args": [ "-y", "@modelcontextprotocol/server-postgres", "postgresql://postgres:demo123@localhost:5432/postgres" ] } } } }
Step 4 — Verify tool availability
- Open Copilot Chat in agent mode
- Click the Tools icon (gear/wrench icon) in the chat bar
- Verify that the configured MCP server's tools appear in the list
- Tools will be prefixed with the server name (e.g.,
filesystem,postgres)
Step 5 — Use MCP tools in a conversation
- Ask Copilot: "List all TypeScript files in the project"
- Copilot should use the
filesystemtool to search for files - If you configured PostgreSQL, ask: "Show me the tables in the database"
- Copilot should use the
postgrestool to execute the query
Step 6 — Combine MCP with a custom agent (optional)
- Create an agent that specifically uses MCP tools:
--- name: Database Admin description: Manages and queries the project's PostgreSQL database tools: ['postgres', 'search/codebase'] --- You are an expert DBA. You help write queries, optimize schemas, and troubleshoot PostgreSQL database performance issues. Always use the postgres tool to execute queries.
- At least one MCP server is configured in
.vscode/settings.json - The MCP server's tools appear in the Copilot Chat tool list
- Copilot uses MCP tools to answer relevant questions
- (Optional) A custom agent is configured to work specifically with MCP tools
