A practical guide to configuration, scoped instructions, and AI-assisted workflows for .NET projects
Table of Contents
- Introduction
- The
.github/Configuration Ecosystem - Scoped Instructions with
.instructions.mdFiles - Using a High-Reasoning Model to Bootstrap Your Configuration
- Prerequisites and Environment Setup
- Working with Copilot in C#
- Conclusion
Introduction
In this guide, we will:
- Explain how to use
.github/copilot-instructions.mdand scoped.instructions.mdfiles to guide Copilot's behavior. - Show how to use a high-reasoning model like Claude Opus to help you design your Copilot configuration.
- Walk through the environment setup for GitHub Copilot in Visual Studio Code for C# development.
- Provide a workflow template tailored to .NET projects.
- Share practical advice for using Copilot effectively in a C# environment.
GitHub Copilot can dramatically accelerate your .NET development workflow when paired with the right project structure and clear instructions. This guide shows you exactly how to get started and how to shape Copilot's output to match your standards.
The most impactful thing you can do isn't installing extensions or learning shortcuts - it's giving Copilot explicit, scoped instructions about your architecture. We start there.
2. The .github/ Configuration Ecosystem
2.1 What is .github/copilot-instructions.md?
The .github/copilot-instructions.md file is a project-level configuration file that tells GitHub Copilot how to behave in your repository. It acts as a style and architecture guide that Copilot uses to generate code aligned with your standards. This file is automatically loaded into every Copilot interaction within your repo.
2.2 The full .github/ file hierarchy
your-repo/
.github/
copilot-instructions.md # Global rules (always active)
instructions/
api-controllers.instructions.md # Scoped: controller layer
application-handlers.instructions.md # Scoped: CQRS/MediatR
domain-entities.instructions.md # Scoped: domain model
infrastructure-data.instructions.md # Scoped: data access
testing.instructions.md # Scoped: test projects
agents/
generate-entity.agent.md # Custom agent profiles
review-pr.agent.md
AGENTS.md # Open standard for coding agents
src/
tests/
| File | Scope | Purpose |
|---|---|---|
copilot-instructions.md |
Global | Architecture, conventions, libraries - applies everywhere |
instructions/*.instructions.md |
Targeted via glob | Layer-specific rules activated by file path |
agents/*.agent.md |
On-demand | Custom agent profiles with specialized tools and prompts |
AGENTS.md |
Global | Open standard, works with Copilot, Claude Code, and others |
2.3 What to include in global instructions
Your copilot-instructions.md should cover these areas:
- Project overview - Architecture pattern, layers, key libraries
- Coding standards - Naming, async/await rules, formatting preferences
- Architecture guidelines - Where logic lives, dependency direction, patterns like CQRS
- Libraries and patterns - Which packages to use (and which to avoid)
- Security and performance - What not to log, async anti-patterns, injection prevention
- Documentation - XML doc expectations, comment style
Here is a complete example:
# Copilot Instructions for This Repository
## Project Overview
- This is a C#/.NET 8 REST API for managing customer orders.
- We follow Clean Architecture with separate layers: API, Application, Domain, Infrastructure.
- We use Entity Framework Core, MediatR, FluentValidation, and AutoMapper.
## Coding Standards
- Use async/await for I/O-bound operations.
- Prefer dependency injection over static classes.
- Use PascalCase for classes, methods, and public properties.
- Use camelCase for local variables and method parameters.
- Use expression-bodied members for simple properties and methods when it improves readability.
## Architecture Guidelines
- Controllers should be thin and delegate work to Application layer handlers.
- Use MediatR for commands and queries.
- Domain entities should not depend on infrastructure or external services.
- Repositories live in the Infrastructure layer and implement domain interfaces.
- Avoid placing business logic in controllers or DbContext.
## Libraries and Patterns
- Use Entity Framework Core for data access.
- Use FluentValidation for input validation.
- Use AutoMapper for mapping between DTOs and domain models.
- Prefer LINQ over manual loops when querying collections.
- Use ILogger<T> for logging.
## Security and Performance
- Do not log sensitive information (passwords, tokens, PII).
- Avoid synchronous blocking calls in async code (no .Result or .Wait()).
- Use parameterized queries or EF Core to avoid SQL injection.
- Use CancellationToken in async methods where appropriate.
## Documentation
- Use XML documentation comments for public classes and methods.
- Include <summary>, <param>, and <returns> tags.
- Keep comments concise and focused on intent.
2.4 How global instructions improve Copilot's output
- Produces code aligned with your architecture (e.g., MediatR handlers instead of controller logic).
- Reduces irrelevant suggestions and random library usage.
- Helps new contributors follow project conventions.
- Encourages consistent patterns across the codebase.
2.5 Maintaining global instructions
- Update them when your architecture evolves.
- Add new conventions as your team adopts them.
- Remove outdated guidance to avoid confusion.
3. Scoped Instructions with .instructions.md Files
3.1 Why scoped instructions matter
The global copilot-instructions.md file applies everywhere, but real projects have different rules for different layers. Your Domain layer operates under different conventions than Infrastructure. Test projects follow distinct patterns from production code. Scoped instructions let you target specific directories and file types with tailored guidance.
3.2 How scoped instructions work
Create .instructions.md files under .github/instructions/. Each file uses YAML frontmatter with an applyTo glob pattern that tells Copilot when to activate those instructions.
your-repo/
.github/
copilot-instructions.md # Global rules
instructions/
api-controllers.instructions.md # Controller layer rules
application-handlers.instructions.md # CQRS/MediatR rules
domain-entities.instructions.md # Domain model rules
infrastructure-data.instructions.md # Data access rules
testing.instructions.md # Test project rules
3.3 Example: Controller layer instructions
---
applyTo: "**/Controllers/**/*.cs"
---
## Controller Guidelines
- Controllers must be thin. No business logic - delegate to MediatR handlers.
- Every action method must return `ActionResult<T>` or `IActionResult`.
- Use `[ApiController]` and `[Route("api/[controller]")]` attributes.
- Apply rate limiting via `[EnableRateLimiting("PolicyName")]`.
- Validate input at the handler level using FluentValidation, not in controllers.
- Use constructor injection for dependencies. Maximum 3 injected services per controller.
- Return appropriate HTTP status codes: 200 for success, 201 for creation, 204 for delete, 400 for validation errors, 404 for not found.
- Async all the way - every action method should be async and return a Task.
3.4 Example: Domain entity instructions
---
applyTo: "**/Domain/**/*.cs"
---
## Domain Layer Guidelines
- Domain entities must have ZERO dependencies on Infrastructure, Application, or external packages.
- Use private setters on entity properties. Expose behavior through methods.
- Value objects should override Equals and GetHashCode.
- Enums belong in the Domain layer, adjacent to the entities that use them.
- No EF Core attributes on domain entities - use fluent configuration in Infrastructure.
- Domain exceptions should inherit from a base DomainException class.
3.5 Example: Data access instructions
---
applyTo: "**/Infrastructure/**/*.cs"
---
## Infrastructure Layer Guidelines
- Use Entity Framework Core for writes and complex queries.
- Use Dapper for read-optimized queries (reports, list endpoints, dashboards).
- Repository interfaces are defined in Domain. Implementations live here.
- EF entity configurations go in separate `EntityNameConfiguration.cs` files using `IEntityTypeConfiguration<T>`.
- Connection strings come from IConfiguration, never hardcoded.
- Always use async methods: `ToListAsync()`, `FirstOrDefaultAsync()`, `SaveChangesAsync()`.
- Use `CancellationToken` in all async data access methods.
3.6 Example: Test project instructions
---
applyTo: "**/*Tests*/**/*.cs"
---
## Testing Guidelines
- Use xUnit for all tests.
- Name test methods: `MethodName_Scenario_ExpectedResult` (e.g., `Create_ValidOrder_ReturnsSuccess`).
- Use Arrange-Act-Assert pattern with clear section comments.
- Use Moq for mocking interfaces.
- Integration tests should use WebApplicationFactory and a real test database.
- Do not mock the database in integration tests - use an in-memory PostgreSQL or SQLite provider.
- One assertion per test method when possible.
- Test class names should match the class under test: `OrderServiceTests` for `OrderService`.
3.7 Example: Application/handler instructions
---
applyTo: "**/Application/**/*.cs"
---
## Application Layer Guidelines
- Use MediatR for all commands and queries. No direct service calls from controllers.
- Commands mutate state. Queries read state. Never mix them.
- Every command/query gets its own handler class in its own file.
- Use FluentValidation validators for input validation. One validator per command/query.
- Return Result<T> from handlers, not exceptions, for expected failure cases.
- DTOs live in the Application layer. Map from domain entities using explicit mapping methods.
- Handler naming: `CreateOrderCommandHandler`, `GetOrderByIdQueryHandler`.
3.8 How scoped instructions layer together
When you edit a file in src/Infrastructure/Repositories/OrderRepository.cs, Copilot loads:
-
Global -
copilot-instructions.md(always active) -
Scoped -
infrastructure-data.instructions.md(matches the**/Infrastructure/**glob)
The scoped instructions add specificity without contradicting the global rules. Think of it like CSS specificity: global sets the baseline, scoped overrides for context.
4. Using a High-Reasoning Model to Bootstrap Your Configuration
4.1 The bootstrapping problem
Setting up copilot-instructions.md, scoped .instructions.md files, and custom agents for a real project is a significant amount of work. You need to articulate your architecture, conventions, patterns, and edge cases in a way that's clear enough for an AI to follow. Most developers either skip this step or write something too vague to be useful.
This is where a high-reasoning model like Claude Opus shines. Rather than writing all these configuration files by hand, you can use a powerful reasoning model to analyze your codebase and generate them for you.
4.2 The workflow: AI configures AI
The idea is simple: use a smarter, more expensive model for the one-time setup work, then let the faster, cheaper model execute day-to-day using the configuration the reasoning model created.
Step 1: Let the reasoning model explore your codebase
Open your project in a tool like Claude Code (or any CLI that uses a high-reasoning model) and ask it to analyze your architecture:
Analyze this codebase. Identify:
- The architecture pattern (Clean Architecture, layers, dependencies)
- Naming conventions actually used (not aspirational)
- Libraries and frameworks in use
- Testing patterns and frameworks
- Data access patterns
- Authentication approach
- Any inconsistencies or anti-patterns
The reasoning model reads your actual code - not what you think your code looks like, but what it actually is. It will catch inconsistencies you've forgotten about.
Step 2: Generate the Copilot configuration files
Based on your analysis, generate:
1. A .github/copilot-instructions.md file with global project rules
2. Scoped .instructions.md files for each architectural layer
3. Target the glob patterns to match our actual directory structure
The instructions should reflect what we actually do, not theoretical best practices.
Make them specific enough that Copilot produces code consistent with the existing codebase.
Step 3: Review, refine, iterate
The reasoning model gives you a complete first draft. Review it, push back on anything that doesn't match your intent, and ask it to revise. This conversation is the valuable part - the model helps you articulate decisions you've made implicitly but never documented.
The infrastructure instructions mention Dapper, but we only use Dapper for reporting queries.
Regular reads still go through EF Core. Update the instructions to reflect that distinction.
4.3 Why this works
A reasoning model excels at the meta-work. Writing instructions for another AI is fundamentally a reasoning and articulation task - exactly what models like Claude Opus are built for. You're not asking it to write production code (where Copilot is fine). You're asking it to:
- Understand architectural decisions and their implications
- Identify patterns across hundreds of files
- Express conventions precisely enough for another AI to follow
- Anticipate edge cases and ambiguities
Copilot excels at the execution. Once the configuration files exist, Copilot's inline suggestions, chat, and agent mode all benefit from the precise, scoped instructions. You get the reasoning model's understanding embedded in every Copilot suggestion, without paying for the reasoning model on every keystroke.
4.4 Practical example
Here's what this looks like end-to-end. You have a .NET Clean Architecture project. You open it in Claude Code:
You: "I need to set up Copilot instructions for this repo. Analyze the codebase and generate the .github/copilot-instructions.md and scoped instruction files."
Claude Opus: Reads your solution structure, scans your controllers, handlers, entities, repositories, tests. Identifies that you use MediatR but not AutoMapper (you use manual mapping). Notices your tests use xUnit with FluentAssertions but not Moq - you use NSubstitute. Sees that your domain entities use private constructors with factory methods.
It generates instruction files that reflect your actual codebase, not a generic template. The domain-entities.instructions.md says "use private constructors with static factory methods" because that's what your code actually does.
You push the files to your repo. Now every developer on the team, and Copilot, operates with the same understanding of your architecture.
4.5 Maintaining instructions over time
Architectures evolve. When you make significant changes:
- Open the project in your reasoning model
- Ask it to diff the current instructions against the actual codebase
- Update the instructions to reflect the new reality
Compare our .github/copilot-instructions.md and scoped instructions against the current codebase.
Flag any instructions that are outdated, contradicted by actual code, or missing.
Generate updated versions.
This keeps your Copilot configuration honest. Dead instructions are worse than no instructions - they cause Copilot to generate code that fights your actual patterns.
4.6 Cost perspective
Using a reasoning model for setup is a one-time (or occasional) cost. You might spend $5-10 in API calls to fully analyze a large codebase and generate all your instruction files. Those files then improve every Copilot interaction for every developer on the team, indefinitely. The ROI is asymmetric: a small upfront investment in reasoning creates compounding returns in daily productivity.
5. Prerequisites and Environment Setup
Before diving in, make sure your environment is ready.
5.1 Required tools
- .NET 8 SDK (or later) installed and on your PATH
-
Visual Studio Code with these extensions:
- GitHub Copilot
- C# Dev Kit
- C# (ms-dotnettools.csharp)
- .NET Install Tool
5.2 Authenticating Copilot
After installing the GitHub Copilot extension, VS Code prompts you to sign in with GitHub. Approve the authorization in your browser. Once authenticated, test it with a quick comment in any .cs file:
// create a method that calculates compound interest
If Copilot suggests a full method implementation, you're good to go.
5.3 Code style configuration
If you don't already have an .editorconfig, generate one:
- Open the Command Palette (
Ctrl+Shift+P/Cmd+Shift+P) - Search for Generate .editorconfig
- Select C#
Example .editorconfig:
[*.cs]
indent_style = space
indent_size = 4
dotnet_style_prefer_auto_properties = true:suggestion
dotnet_style_qualification_for_field = true:suggestion
csharp_new_line_before_open_brace = all
Copilot follows these conventions when generating code, especially as your codebase grows.
6. Working with Copilot in C
6.1 A practical development loop
When working with Copilot on C# code, a simple loop keeps you productive:
- Plan - Write a comment describing what you need
- Generate - Accept or tab through Copilot's suggestion
- Review - Check correctness, naming, and edge cases
- Test - Run the project or unit tests
- Refine - If the output is off, rephrase your comment and try again
The key insight: your comment quality drives the output quality. Be specific about patterns you want.
// Create an ICustomerRepository interface and CustomerRepository class
// using constructor injection for DbContext, with async CRUD methods
A vague comment like // customer stuff gives you vague code. A precise comment like the above gives you something close to production-ready.
6.2 Using comments and documentation to steer output
Guide Copilot with intent comments:
// validate user input and return a list of error messages if invalid
XML documentation comments give Copilot even more to work with:
/// <summary>
/// Calculates the total price including tax.
/// </summary>
/// <param name="amount">Base amount.</param>
/// <param name="taxRate">Tax rate as a decimal.</param>
/// <returns>Total price including tax.</returns>
public decimal CalculateTotal(decimal amount, decimal taxRate)
{
}
Copilot uses these to infer intent and generate more accurate method bodies.
6.3 Useful shortcuts
| Action | Windows | Mac |
|---|---|---|
| Accept suggestion | Tab |
Tab |
| Trigger suggestion | Alt+\ |
Option+\ |
| Open Copilot Chat | Ctrl+Shift+I |
Cmd+Shift+I |
6.4 Where Copilot shines in C
- Boilerplate - DTOs, interfaces, repository stubs, controller actions. Copilot handles repetitive structure well.
- Test scaffolding - Write one test method, Copilot suggests the rest following your pattern.
- LINQ expressions - Describe the transformation in a comment, get a working query back.
- EF Core configurations - Entity type configurations, migrations setup, DbContext registration.
6.5 Where to watch out
- Outdated APIs - Copilot may suggest deprecated .NET methods. Check the target framework.
-
Async anti-patterns - Watch for
.Result,.Wait(), or missingawaitin generated code. - Security-sensitive code - Never trust Copilot output for authentication, authorization, or raw SQL without careful review.
- Over-engineering - Copilot sometimes adds abstractions you didn't ask for. Keep it simple.
Use Roslyn analyzers, run your tests, and treat every suggestion as a draft - not a final answer.
Conclusion
GitHub Copilot becomes significantly more powerful when paired with:
- A well-structured
.github/copilot-instructions.mdfile -
Scoped
.instructions.mdfiles that give Copilot layer-specific guidance - A high-reasoning model to bootstrap and maintain your configuration
- Clear C# coding standards and a deliberate workflow
The key insight is that AI tools work best when they work together. Use a reasoning model like Claude Opus to do the hard thinking - analyzing your architecture, articulating your conventions, and generating precise instructions. Then let Copilot execute against those instructions thousands of times a day. The reasoning model is the architect; Copilot is the builder. Together, they're far more effective than either one alone.
By defining your standards and giving Copilot explicit, scoped instructions, you transform it from a generic autocomplete tool into a project-aware assistant that genuinely understands your .NET ecosystem.
United States
NORTH AMERICA
Related News
CBS News Shutters Radio Service After Nearly a Century
3h ago
Officer Leaks Location of French Aircraft Carrier With Strava Run
3h ago
White House Unveils National AI Policy Framework To Limit State Power
3h ago
Microsoft Says It Is Fixing Windows 11
3h ago
Can Private Space Companies Replace the ISS Before 2030?
3h ago