Skip to main content

Lab 7: Custom Instructions, Agents & Spaces

๐ŸŽฏ Learning Objectives
  • Create and test repository-level custom instructions (copilot-instructions.md)
  • Create path-scoped instructions that apply to specific directories
  • Build reusable prompt templates (.prompt.md files)
  • Set up a Copilot Space with curated knowledge for your team
  • Create a custom agent profile in .github/agents/NAME.md

Custom Instructions Hierarchy

Personal โ†’ Path-specific โ†’ Repository-wide โ†’ Agent instructions โ†’ Organization

Shown highest to lowest precedence. Enterprise and organization policies are guardrails, not something repo files can override.

Prerequisites

  • A code project in VS Code (the lab3-api project works well, or any TypeScript project)
  • GitHub Copilot extension active
  • A GitHub repository (for Spaces โ€” available on all Copilot plans including Free)

Exercises

Step 1

Create Repository-Level Custom Instructions

The .github/copilot-instructions.md file applies to everyone who uses Copilot in this repository. It's the most important customization file.

Instructions

  1. Create the directory structure if it doesn't exist:
    mkdir -p .github
  2. Create the file .github/copilot-instructions.md with the following content:
    # Copilot Instructions for This Project
    
    

    Architecture
    #

    • This is a TypeScript monorepo with api/ and frontend/ directories
    • The API uses Express.js with SQLite and follows the repository pattern
    • The frontend uses React with TypeScript

    Coding Standards
    #

    • Always use TypeScript strict mode โ€” no any types
    • Use const by default; use let only when reassignment is necessary
    • Never use var
    • All functions must have explicit return types
    • Use async/await โ€” never raw Promises with .then() or callbacks

    Database
    #

    • Use parameterized SQL queries ONLY โ€” never string concatenation
    • All database access goes through repository classes, never direct queries in routes
    • Use transactions for multi-step database operations

    Error Handling
    #

    • Use custom error classes that extend Error (see src/errors/)
    • Never catch and silently ignore errors
    • API endpoints must return consistent JSON error responses:
      { "error": { "code": "ERROR_CODE", "message": "Human readable message" } }
    • Never expose stack traces or internal details in API responses

    Testing
    #

    • Use Jest for all tests
    • Follow the Arrange-Act-Assert (AAA) pattern
    • Every new function needs at least: happy path, error case, edge case tests
    • Minimum 80% code coverage for new code

    Documentation
    #

    • All exported functions must have JSDoc with @param, @returns, and @throws
    • Complex business logic must include a “Why” comment explaining the rationale
    • README.md must be updated when new features are added
  3. Save the file.
  4. Test it. Open Copilot Chat and ask:
  5. Write a function that fetches a user from the database by their email address.
    </li>
    <li>Verify the generated code follows your instructions:
      <ul>
        <li>Does it use TypeScript with explicit types?</li>
        <li>Does it use parameterized queries?</li>
        <li>Does it go through a repository class?</li>
        <li>Does it have JSDoc?</li>
        <li>Does it use async/await?</li>
        <li>Does it return consistent error format?</li>
      </ul>
    </li>
    <li>Try a second test โ€” ask for something that might violate the rules:
    
    Write a quick function that queries the database for all users, 
    using db.exec() directly in the route handler.
    </li>
    <li>Copilot should still follow your instructions and use the repository pattern with parameterized queries, even though you asked for a shortcut.</li>
    
๐Ÿ’ก Exam Tip: The exam will ask: "Where do you place repository-level custom instructions?" Answer: .github/copilot-instructions.md. This file applies to all contributors automatically โ€” no IDE setup required.
Step 2

Create Path-Scoped Instructions

Path-scoped instructions apply different rules to different parts of your codebase. The API backend and React frontend may need very different coding standards.

Instructions

  1. Create the instructions directory:
    mkdir -p .github/instructions
  2. Create .github/instructions/api.instructions.md:
    ---
    applyTo: "api/**"
    ---
    
    

    API-Specific Instructions
    #

    Framework
    #

    • Use Express.js with TypeScript
    • All routes must use async request handlers with try/catch
    • Use express-validator for input validation on all endpoints

    Database
    #

    • Use better-sqlite3 for database access
    • All queries must be parameterized (use ? placeholders)
    • Use repository pattern โ€” no direct database access in route handlers

    HTTP Conventions
    #

    • POST returns 201 with created resource
    • PUT returns 200 with updated resource
    • DELETE returns 204 with no body
    • GET returns 200 with resource or array
    • Not found returns 404 with error object
    • Validation errors return 400 with field-level error details

    Security
    #

    • Validate and sanitize all request body inputs
    • Rate limit all endpoints
    • Use helmet middleware for security headers
    • Never expose internal error details in responses
  3. Create .github/instructions/frontend.instructions.md:
  4. ---
    applyTo: "frontend/**"
    ---
    
    # Frontend-Specific Instructions
    
    ## Framework
    - Use React 18+ with TypeScript
    - Use functional components only โ€” no class components
    - Use React hooks (useState, useEffect, useCallback, useMemo)
    
    ## Styling
    - Use CSS Modules for component-specific styles
    - Follow BEM naming convention for CSS classes
    - Mobile-first responsive design
    
    ## State Management
    - Use React Context for global state (no Redux)
    - Keep component state local when possible
    - Use custom hooks to encapsulate complex state logic
    
    ## Testing
    - Use React Testing Library (not Enzyme)
    - Test behavior, not implementation details
    - Use data-testid attributes for test selectors
    
    ## Accessibility
    - All interactive elements must have ARIA labels
    - Images must have alt text
    - Form inputs must have associated labels
    - Color should not be the sole means of conveying information
    </li>
    <li><strong>Test the path scoping.</strong> Create a file at <code>api/test-route.ts</code>. Open Chat and ask:
    
    #file:api/test-route.ts Write an endpoint that creates a new blog post with title and content fields.
    </li>
    <li>The generated code should follow the API-specific rules (Express, parameterized queries, 201 status, etc.).</li>
    <li>Now create a file at <code>frontend/test-component.tsx</code>. Ask:
    
    #file:frontend/test-component.tsx Write a form component for creating a new blog post with title and content fields.
    </li>
    <li>The generated code should follow the frontend-specific rules (React functional component, CSS Modules, ARIA labels, etc.).</li>
    
๐Ÿ’ก Key Concept: The applyTo YAML frontmatter in path-scoped instruction files uses glob patterns. "api/**" matches all files under the api/ directory. You can use any glob pattern: "**/*.test.ts", "src/components/**", etc.
Step 3

Create a Reusable Prompt Template

Prompt templates (.prompt.md files) are reusable prompts that your team can invoke by name. They standardize common tasks like creating new features, writing reviews, or generating documentation.

Instructions

  1. Create the prompts directory:
    mkdir -p .github/prompts
  2. Create .github/prompts/new-feature.prompt.md:
    ---
    description: "Scaffold a new feature with route, repository, types, and tests"
    ---
    
    

    New Feature Scaffolding
    #

    Create a complete feature implementation for: {{ feature_description }}

    Files to Create
    #

    1. Types (api/src/types/{{ feature_name }}.ts):

      • Define the main entity interface
      • Define Create and Update input interfaces
      • Define the repository interface
    2. Repository (api/src/repositories/{{ feature_name }}-repository.ts):

      • Implement the repository interface
      • Use parameterized SQL queries
      • Include all CRUD operations
    3. Routes (api/src/routes/{{ feature_name }}-routes.ts):

      • RESTful CRUD endpoints
      • Input validation with express-validator
      • Consistent error responses
      • JSDoc on every endpoint
    4. Tests (api/src/tests/{{ feature_name }}.test.ts):

      • Happy path tests for all endpoints
      • Validation error tests
      • Not-found tests
      • Use supertest for HTTP testing

    Requirements
    #

    • Follow the project’s coding standards in .github/copilot-instructions.md
    • Use TypeScript strict mode
    • Parameterized queries only
    • 80%+ test coverage
  3. Create another template โ€” .github/prompts/code-review.prompt.md:
  4. ---
    description: "Perform a thorough code review on the selected code"
    ---
    
    # Code Review
    
    Review the provided code for:
    
    ## Correctness
    - Logic errors or bugs
    - Off-by-one errors
    - Null/undefined handling
    - Race conditions in async code
    
    ## Security
    - SQL injection vulnerabilities
    - XSS vulnerabilities
    - Authentication/authorization issues
    - Hardcoded secrets or credentials
    - Input validation gaps
    
    ## Performance
    - N+1 query patterns
    - Unnecessary re-renders (React)
    - Missing memoization opportunities
    - Large array operations that could be optimized
    
    ## Maintainability
    - Code duplication
    - Overly complex functions (cyclomatic complexity)
    - Missing error handling
    - Poor variable/function names
    - Missing or outdated documentation
    
    ## Testing
    - Is this code testable?
    - What test cases are missing?
    - Are edge cases covered?
    
    Format each finding as:
    **[SEVERITY]** Category: Description โ†’ Suggested fix
    </li>
    <li><strong>Use the template.</strong> In Copilot Chat, you can reference prompt files using the <code>#prompt</code> syntax or by invoking them from the command palette. Try:
    
    Use the new-feature prompt template to create a "comments" feature 
    where users can add comments to tasks. Feature name: comments.
    </li>
    
๐Ÿ’ก Team Value: Prompt templates are version-controlled with your repo. Every team member gets the same standardized prompts. This ensures consistent code quality across the team โ€” no more "it depends on who wrote the prompt."
Step 4

Create a Copilot Space

Copilot Spaces let you curate a collection of repositories, code, pull requests, issues, notes, images, and uploaded files that Copilot can use as context when answering questions in GitHub. GitHub-based sources stay in sync as the project changes.

Instructions

  1. Go to github.com/copilot/spaces.
  2. Click "Create Space".
  3. Name it: Task API Architecture
  4. Add the following types of content to your Space:
    • Architecture docs: Add your README, any architecture decision records (ADRs), or design documents
    • Coding standards: Add your .github/copilot-instructions.md
    • API reference: Add your route files, OpenAPI spec, issues, or relevant pull requests
    • Type definitions: Add your TypeScript type files
    • Example code: Add well-written example files that demonstrate your patterns
  5. After creating the Space, use it in Copilot Chat on GitHub by selecting the Space as context:
    What is our error handling pattern? Show me 
    an example of a route handler that follows our standards.
  6. Compare the response to asking the same question without the Space selected. The Space provides richer, more project-specific context.
๐Ÿ’ก Plan Availability: Spaces are available on all Copilot plans, including Free. Anyone with a Copilot license can create and use Spaces.
๐Ÿ’ก Exam Tip: Spaces are the current curated-context feature. They are available to anyone with a Copilot license, including Copilot Free, and viewers only see sources they already have permission to access.
Step 5

Test Everything Together

Verify that custom instructions, path-scoped instructions, and Spaces all work together.

Instructions

  1. With all your customization files in place, run a comprehensive test. Open Copilot Chat in Agent Mode and type:
    Add a "tags" feature to the task API. Each task can have multiple 
    tags (strings). Include:
    - Updated Task type with optional tags array
    - New endpoints: POST /tasks/:id/tags and DELETE /tasks/:id/tags/:tag
    - Updated GET /tasks to support filtering by tag (?tag=urgent)
    - Tests for all new functionality
  2. Review the generated code against your instruction files:
    • โœ… TypeScript strict mode, no any types?
    • โœ… Parameterized SQL queries?
    • โœ… Repository pattern?
    • โœ… Express-validator on inputs?
    • โœ… Correct HTTP status codes (201 for POST, 204 for DELETE)?
    • โœ… JSDoc comments?
    • โœ… AAA pattern in tests?
  3. If Copilot violates any of your instructions, note it down. Refine your instructions to be more explicit on that point.
Step 6

Bonus: Create a Custom Agent

Custom agent profiles (.github/agents/NAME.md) let you create specialized personas with explicit instructions, model preferences, and tool access.

Instructions

  1. Create .github/agents/security-reviewer.md:
    ---
    description: "Security-focused code reviewer that checks for OWASP Top 10 vulnerabilities"
    tools:
      - codebase
    ---
    
    

    Security Reviewer Agent
    #

    You are a senior security engineer reviewing code for vulnerabilities.

    Your Role
    #

    • Review all code changes for security issues before they ship
    • Focus on OWASP Top 10 vulnerabilities
    • Be thorough but practical โ€” prioritize critical and high severity issues

    Review Checklist (Always Check)
    #

    1. Injection (A03): SQL injection, command injection, LDAP injection
    2. Broken Auth (A07): Weak passwords, missing MFA, session fixation
    3. Sensitive Data (A02): Hardcoded secrets, unencrypted PII, verbose errors
    4. XSS (A03): Reflected, stored, and DOM-based XSS
    5. Access Control (A01): Missing authorization checks, IDOR vulnerabilities
    6. Security Misconfiguration (A05): Default credentials, unnecessary features enabled
    7. Insecure Dependencies (A06): Known CVEs in dependencies

    Output Format
    #

    For each finding:

    • Severity: Critical / High / Medium / Low
    • OWASP Category: A01-A10 reference
    • Location: File and line number
    • Description: What’s wrong
    • Exploitation: How could this be exploited
    • Fix: Specific code fix recommendation

    Tone
    #

    Be direct and technical. Don’t sugarcoat security issues. Every finding should have an actionable fix.



  2. To use the custom agent, select the agent persona from the available agents list when supported by your Copilot surface.

  3. Test it:

    @security-reviewer Review the code in lab6-security.ts for any 
    remaining security concerns.
    </li>
    
๐Ÿ’ก Key Concept: Custom agent profiles are different from repository custom instructions. Instructions shape normal Copilot responses; custom agent profiles define a selectable agent with its own behavior and tool scope.

โœ… Completion Checklist

  • Created .github/copilot-instructions.md with comprehensive team standards
  • Created path-scoped instructions for api/ and frontend/ with different rules
  • Verified that Copilot follows both repo-level and path-scoped instructions
  • Created reusable prompt templates (.prompt.md) for new features and code reviews
  • Created a Copilot Space with architecture docs and coding standards (available on all plans)
  • Tested all customizations working together on a real feature request

๐Ÿง  Practice after the lab

Turn what you just built into recall practice.

  1. Work through the question bank for Domain 2 and Domain 4 without notes.
  2. Take the free official practice assessment on Microsoft Learn.
  3. Review every miss and tag it by domain.
  4. Write one flash card per missed concept: Spaces, instructions, custom agents, MCP, or policies.

๐ŸŽฏ Key Takeaways for the Exam

  • Instruction precedence: Personal โ†’ Path-specific โ†’ Repository-wide โ†’ Agent instructions โ†’ Organization
  • Repository instructions: .github/copilot-instructions.md โ€” applies to all contributors
  • Path-scoped instructions: .github/instructions/*.instructions.md with applyTo glob
  • Prompt templates: .github/prompts/*.prompt.md โ€” reusable, version-controlled prompts
  • Copilot Spaces are curated context collections for licensed Copilot users; organization policy and source permissions still apply
  • Custom agent profiles: .github/agents/NAME.md files create specialized personas
  • All customization files are version-controlled in the repository
  • More specific instructions take precedence over less specific ones