The VS Code Insiders + GitHub Copilot Context Engineering Playbook
A hands-on guide to structuring your VS Code repository so GitHub Copilot agent mode actually works. Covers the six-layer context stack, custom agents, skills, MCP servers, tool sets, and self-improving workflows—with every file you need to create.
The VS Code Insiders + GitHub Copilot Context Engineering Playbook
VS Code Insiders has quietly become the most capable AI agent development environment available. With agent mode, custom agents, skills, MCP servers, instruction files, prompt files, and tool sets, Copilot now has a full context engineering stack—but almost nobody is using it correctly.
The problem isn’t capability. It’s context management. Most developers either dump everything into copilot-instructions.md (bloating every interaction) or use none of these features at all (leaving performance on the table).
This guide shows you how to structure a repository so Copilot agent mode gets the right context at the right time—and nothing more.
Why Context Engineering Matters for Copilot
Every time you open Copilot chat or trigger agent mode, the system builds a prompt behind the scenes. That prompt includes:
- Your
copilot-instructions.mdandAGENTS.md(always loaded) - Any matching
.instructions.mdfiles (loaded byapplyTopattern) - Tool definitions from connected MCP servers (always loaded)
- The active agent’s persona and tool restrictions
- Skill instructions (loaded when the description matches)
- Your conversation history
All of this competes for the same context window. Connect five MCP servers with 20 tools each, write a 500-line copilot-instructions.md, and you’ve consumed most of Copilot’s working memory before you’ve even asked a question.
The fix is progressive disclosure: Copilot starts with a minimal context and reaches for more only when needed.
The Six-Layer Context Stack
VS Code Insiders implements context engineering through six distinct layers, each with a different loading behavior:
┌─────────────────────────────────────────────────┐
│ Custom Agents (.agent.md) ← Personas │
│ Loaded when you @mention the agent │
├─────────────────────────────────────────────────┤
│ Always-On Instructions ← Identity │
│ copilot-instructions.md + AGENTS.md │
│ Loaded on EVERY interaction │
├─────────────────────────────────────────────────┤
│ File-Based Instructions (.instructions.md) │
│ Loaded when applyTo pattern matches │
├─────────────────────────────────────────────────┤
│ Agent Skills (SKILL.md) ← On-demand │
│ Loaded when description matches task │
├─────────────────────────────────────────────────┤
│ MCP Servers (mcp.json) ← External │
│ Tool definitions loaded at startup │
├─────────────────────────────────────────────────┤
│ Prompt Files (.prompt.md) ← Workflows │
│ Loaded only when explicitly invoked │
└─────────────────────────────────────────────────┘
The key insight: only the top two layers are always-on. Everything else loads conditionally. Your job is to keep the always-on layers tiny and push heavy content into the conditional layers.
Step-by-Step: Building the Repository
1. Create the Directory Structure
# PowerShell (Windows)
New-Item -ItemType Directory -Force -Path `
.github/instructions, `
.github/agents, `
.github/skills, `
.github/prompts, `
.vscode, `
.learnings, `
docs
# Bash (macOS/Linux)
mkdir -p .github/{instructions,agents,skills,prompts} .vscode .learnings docs
2. Write copilot-instructions.md (≤100 Lines)
This is the most important file. It loads on every single Copilot interaction—chat, inline suggestions, agent mode, everything. Every unnecessary line wastes tokens on every turn.
Create .github/copilot-instructions.md:
# Project Instructions
## Build & Dev Commands
npm install # Install dependencies
npm run dev # Start dev server
npm run build # Production build
npm run test # Run tests
npm run lint # Lint check
## Architecture
[2-3 sentences describing your project, stack, and deployment target]
Key directories: src/ (application), tests/ (test suite), docs/ (reference)
## Conventions
- TypeScript strict mode
- Prettier with tabs, single quotes
- CSS custom properties for all styling values
- No hardcoded colors, spacing, or typography values
## Self-Improvement
Log learnings to `.learnings/` for continuous improvement.
| Situation | Log to |
|-----------|--------|
| Command fails | .learnings/ERRORS.md |
| User corrects you | .learnings/LEARNINGS.md |
| Better approach found | .learnings/LEARNINGS.md |
| Missing feature | .learnings/FEATURE_REQUESTS.md |
See docs/ for detailed architecture and patterns.
That’s it. ~30 lines. It tells Copilot how to build, what the project is, what conventions to follow, and where to find more detail. It does not contain the detail itself.
3. Write AGENTS.md as a Map
Create AGENTS.md at the repo root:
# Agent Guide
## Agents
- **reviewer** (.github/agents/reviewer.agent.md) — Code review and security
- **writer** (.github/agents/writer.agent.md) — Docs and blog posts
- **deployer** (.github/agents/deployer.agent.md) — Build and deploy
## Skills
- **seo-audit** (.github/skills/seo-audit/) — SEO analysis
- **test-coverage** (.github/skills/test-coverage/) — Coverage reports
## Reference Docs
- Architecture: docs/architecture.md
- Conventions: docs/conventions.md
- API Patterns: docs/api-patterns.md
## Critical Rules
1. Run `npm run build` before pushing — CI will reject broken builds
2. All new features need tests
3. Never commit secrets — use environment variables
This is a table of contents. Copilot reads it, knows what agents and skills exist, and navigates to the right file when needed.
4. Create Scoped Instructions
These load only when Copilot is working with files that match the applyTo glob. Zero cost otherwise.
.github/instructions/typescript.instructions.md:
---
applyTo: "**/*.ts,**/*.tsx"
---
# TypeScript Rules
- Explicit return types on all exported functions
- Prefer `interface` over `type` for object shapes
- Use `readonly` for immutable properties
- Custom error classes — never `throw 'string'`
- Use `satisfies` for type-safe object literals
.github/instructions/css.instructions.md:
---
applyTo: "**/*.css,**/*.astro"
---
# CSS Rules
- Use CSS custom properties from vars.css — no hardcoded values
- Dark theme uses `[data-theme="dark"]` selector
- Component-scoped styles in `<style>` blocks
- Mobile-first responsive design
.github/instructions/testing.instructions.md:
---
applyTo: "tests/**,**/*.test.*,**/*.spec.*"
---
# Testing Conventions
- Use Vitest for all tests
- Arrange-Act-Assert pattern
- Mock external dependencies, not internal modules
- Test file mirrors source path: src/utils/foo.ts → tests/utils/foo.test.ts
Each file is 5–10 lines. They inject precisely the right conventions when Copilot touches the relevant files.
5. Create Custom Agents
Agents are specialized personas that Copilot switches into when you @mention them. Each agent gets its own system prompt, tool restrictions, and behavioral rules.
.github/agents/reviewer.agent.md:
---
description: Reviews code for security, quality, and convention compliance
tools:
- codebase
- terminal
---
# Code Reviewer
You review code changes for:
1. Security vulnerabilities (OWASP Top 10)
2. Convention compliance (check docs/conventions.md)
3. Test coverage — every new function needs a test
4. Performance: unnecessary re-renders, N+1 queries, unbounded loops
Be specific. Reference file names and line numbers.
Skip style issues that Prettier handles.
Never suggest changes outside the scope of what was modified.
.github/agents/writer.agent.md:
---
description: Creates and edits documentation and blog posts
tools:
- codebase
---
# Technical Writer
You write documentation and blog content.
- Tone: knowledgeable but approachable
- Use fenced code blocks with language identifiers
- Keep paragraphs short — 2-4 sentences max
- Lead with the practical takeaway, then explain why
For blog posts, always include frontmatter with title, description, pubDate, and tags.
The tools field is critical. The reviewer needs terminal to run lints and tests. The writer doesn’t—removing it means fewer tool definitions consuming context.
6. Create Skills for Heavy Content
Skills are the workhorse for content that’s too large for always-on instructions but too important to leave undiscovered. They load only when Copilot determines the description matches the current task.
.github/skills/deploy/SKILL.md:
---
description: "Deployment workflow: build verification, staging, and production release"
---
# Deploy Skill
## Pre-deployment
1. `npm run lint` — fix all errors
2. `npm run test` — all tests green
3. `npm run build` — clean build with no warnings
4. Verify no uncommitted changes: `git status`
## Staging
1. Push to `staging` branch
2. Verify preview deployment at [staging URL]
3. Run smoke tests
## Production
1. Merge to `main` via PR
2. CI/CD handles deployment automatically
3. Verify production site within 5 minutes
4. Check Application Insights for errors
.github/skills/seo-audit/SKILL.md:
---
description: "Audit pages for SEO: meta tags, Open Graph, structured data, performance"
---
# SEO Audit Skill
## Checklist
- [ ] Title tag present and under 60 characters
- [ ] Meta description present and under 160 characters
- [ ] Open Graph tags: og:title, og:description, og:image, og:url
- [ ] Twitter card tags: twitter:card, twitter:title, twitter:description
- [ ] JSON-LD structured data (Article, WebSite, BreadcrumbList)
- [ ] Canonical URL set correctly
- [ ] All images have alt text
- [ ] Heading hierarchy: single h1, logical h2/h3 nesting
- [ ] Internal links use relative paths
- [ ] No broken links (run link checker)
The description field is what Copilot uses to decide whether to load the skill. Write it like a search query — what would someone ask when they need this?
7. Configure Tool Sets
Tool sets let you pre-configure which tools are available, reducing startup context when full capabilities aren’t needed.
Create .vscode/tool-sets.jsonc:
{
// Quick questions — no terminal or network access
"reading": {
"codebase": true,
"fetch": false,
"terminal": false
},
// Full development — all tools available
"development": {
"codebase": true,
"terminal": true,
"fetch": true
},
// Research — web access, no file modification
"research": {
"codebase": true,
"fetch": true,
"terminal": false
}
}
Switch between tool sets based on what you’re doing. Reading code? Use reading. Building features? Use development. Researching a library? Use research.
8. Configure MCP Servers
MCP servers give Copilot access to external tools — documentation lookups, web search, database queries. But every server’s tool definitions load at startup.
Create .vscode/mcp.json:
{
"servers": {
"context7": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@upstash/context7-mcp"]
}
}
}
Start with one. Add more only when you have a concrete need. Common useful servers:
| Server | Purpose | When to Add |
|---|---|---|
| context7 | Library documentation lookup | When you frequently ask about library APIs |
| exa | Web search | When you need current information during development |
| github | GitHub API (issues, PRs) | When you manage issues/PRs from Copilot |
Each server you add increases startup token cost on every interaction. Three focused servers beats ten general-purpose ones.
9. Create Prompt Files for Repetitive Workflows
Prompt files are reusable templates you invoke explicitly — they never load automatically.
.github/prompts/pr-review.prompt.md:
---
description: "Review the current changes for a pull request"
---
Review the staged/uncommitted changes in this repository:
1. Run `git diff --staged` to see what's changed
2. Check each file for:
- Security issues (injection, auth bypass, secrets)
- Missing tests for new functionality
- Convention violations
- Performance concerns
3. Summarize findings as a PR review comment
.github/prompts/new-component.prompt.md:
---
description: "Scaffold a new component with tests"
---
Create a new component named "${input:componentName}":
1. Create `src/components/${input:componentName}.astro`
2. Add component-scoped styles using CSS custom properties
3. Create `tests/${input:componentName}.test.ts` with basic tests
4. Export typed Props interface
Invoke these with /pr-review or /new-component in Copilot chat.
10. Set Up the Self-Improvement Loop
This is what makes the system compound over time. Create three tracking files:
.learnings/ERRORS.md:
# Error Log
<!-- Agent logs command failures and error resolutions here -->
| Date | Error | Resolution | Status |
|------|-------|------------|--------|
.learnings/LEARNINGS.md:
# Learnings
<!-- Agent logs corrections, knowledge gaps, and better approaches -->
| Date | Category | Learning | Status |
|------|----------|----------|--------|
.learnings/FEATURE_REQUESTS.md:
# Feature Requests
<!-- Agent logs capability gaps discovered during work -->
| Date | Request | Priority | Status |
|------|---------|----------|--------|
The self-improvement instructions in copilot-instructions.md (Step 2) tell Copilot to log here. Over time, patterns emerge — you review the logs, promote the best learnings to permanent instructions, and delete the noise.
The promotion pipeline: .learnings/ → manual review → promote to copilot-instructions.md or a skill.
The Complete Structure
project-root/
├── AGENTS.md # ≤100 lines — map to everything
├── .github/
│ ├── copilot-instructions.md # ≤100 lines — always-on identity
│ ├── instructions/
│ │ ├── typescript.instructions.md # Scoped to *.ts, *.tsx
│ │ ├── css.instructions.md # Scoped to *.css, *.astro
│ │ └── testing.instructions.md # Scoped to tests/**
│ ├── agents/
│ │ ├── reviewer.agent.md # @reviewer — restricted tools
│ │ └── writer.agent.md # @writer — no terminal
│ ├── skills/
│ │ ├── deploy/SKILL.md # Loaded when deploying
│ │ └── seo-audit/SKILL.md # Loaded for SEO tasks
│ └── prompts/
│ ├── pr-review.prompt.md # /pr-review
│ └── new-component.prompt.md # /new-component
├── .vscode/
│ ├── mcp.json # 1-3 MCP servers max
│ └── tool-sets.jsonc # reading / development / research
├── .learnings/
│ ├── ERRORS.md # Self-improvement: errors
│ ├── LEARNINGS.md # Self-improvement: corrections
│ └── FEATURE_REQUESTS.md # Self-improvement: gaps
├── docs/
│ ├── architecture.md # Deep reference (agent navigates here)
│ ├── conventions.md # Detailed conventions
│ └── patterns.md # Reusable patterns
└── src/ # Your code
VS Code Settings to Enable Everything
Add these to your .vscode/settings.json to ensure Copilot discovers all layers:
{
"chat.promptFilesLocations": {
".github/prompts": true
},
"chat.instructionsFilesLocations": {
".github/instructions": true
},
"chat.agentFilesLocations": {
".github/agents": true
},
"chat.agentSkillsLocations": {
".github/skills": true
}
}
Important: These settings use object format ({ "path": true }), not arrays. Array format is silently ignored — a common gotcha.
Common Mistakes to Avoid
1. Monolithic instructions file. If copilot-instructions.md is over 100 lines, you’re paying for that context on every interaction. Move the detail to skills or docs.
2. Too many MCP servers. Each one adds tool definitions at startup. If you have 5+ servers connected, you may be consuming a third of the context window before asking a question. Audit with: how many tools am I actually using?
3. Skills with vague descriptions. The description field determines when a skill loads. “Helpful utilities” matches nothing useful. “Deployment workflow: build verification, staging, and production release” matches exactly when needed.
4. Agents without tool restrictions. An agent with all tools available gets the full tool definition set in its context. Restrict to what the agent actually needs.
5. Instructions that duplicate what Copilot can infer. Don’t tell Copilot “use TypeScript” in a TypeScript project — it can see that. Focus on non-obvious conventions: “use satisfies for type-safe literals” or “error classes live in src/errors/.”
6. Array format for settings. "chat.promptFilesLocations": [".github/prompts"] is silently ignored. Use object format: { ".github/prompts": true }.
Measuring the Impact
After setting this up, you’ll notice:
- Faster responses — less context to process means quicker completions
- More relevant answers — Copilot sees the right conventions for the file type you’re editing, not every convention for every language
- Fewer corrections — scoped instructions and the self-improvement loop reduce repeated mistakes
- Better agent performance — restricted tool sets mean agents pick the right tool more often
The investment is about 30 minutes of setup. The payoff compounds on every interaction.
This guide is part of a broader research synthesis on context engineering. For the full picture—including Google ADK’s tiered architecture, OpenAI’s Harness Engineering case study, agent handoff protocols, and the MCP vs A2A protocol landscape—see Context Engineering > Prompt Engineering.