Building Effective Agent Architectures with GitHub Copilot
GitHub Copilot's customization system separates into four distinct layers: custom agents, instructions, skills, and MCP servers. Each handles a different concern, and they compose together while remaining independently upgradeable.
The key insight: separating "who" (agent workflow), "rules" (project standards), and "how" (capabilities) means you can change one without touching the others. Update standards without rewriting agents. Upgrade skills without modifying instructions. Change agent behavior while keeping conventions intact.
Everything lives in git. Changes go through pull requests. You can review, approve, and roll back AI behavior like infrastructure.
> **Honest disclaimer:** The thoughts here are mine — the prose, structure, and general readability are courtesy of AI. I handed it a brain-dump and it handed back something you'd actually want to read.
```mermaid
graph TB
subgraph "GitHub Copilot Architecture"
A[Custom Agents
Who orchestrates?] --> Core[Copilot] I[Instructions
What rules apply?] --> Core S[Skills
What capabilities exist?] --> Core M[MCP Servers
What external data?] --> Core end Core --> Output[AI Response] style A fill:#e1f5ff style I fill:#fff4e1 style S fill:#f0e1ff style M fill:#e1ffe1 style Core fill:#ffd6d6 ``` ## Project Structure A typical setup: ``` .github/ ├─ agents/ # Custom workflow agents ├─ instructions/ # Context-specific standards ├─ skills/ # Reusable capabilities (SKILL.md files) └─ copilot-instructions.md # Global standards .vscode/ └─ mcp.json # MCP server configs ``` All version controlled in your repo. Skills are SKILL.md files that define specific operations agents can invoke. All reviewable through PRs. Quick example: Want all API errors to follow a consistent format? ```markdown # .github/instructions/api.instructions.md --- applyTo: 'src/api/**' --- Return errors as: { "error": { "code": "...", "message": "..." } } ``` Copilot applies this automatically when working on API files. Standard enforced through the tool, not documentation. --- ## The Four Layers ### 1. Custom Agents Custom agents define workflow orchestration. They specify which tools are available, coordinate multi-step processes, and delegate to specialist agents. ```markdown # .github/agents/feature-builder.agent.md --- name: Feature Builder tools: ['agent'] agents: ['Researcher', 'Implementer'] --- Coordinate feature development by delegating research to Researcher (read-only) and implementation to Implementer (write-access). ``` When custom agents work well: - Multi-phase workflows with distinct tool needs - Tool restrictions prevent accidents (researcher can't modify code) - Specialized expertise per domain Keep workflow logic here, not coding standards. ### 2. Instructions Instructions define project standards that apply automatically based on file context. ```markdown # .github/instructions/api.instructions.md --- applyTo: 'src/api/**' --- - Validate input with Joi schemas - Return errors as: { "error": { "code": "...", "message": "..." } } - Include tests ``` Global instructions (`.github/copilot-instructions.md`) apply everywhere. Targeted instructions use `applyTo` patterns for file-specific rules. When instructions work well: - Team-wide conventions that always apply - File-specific standards (API patterns, component conventions) - Replacing documentation with enforcement Keep global instructions under 50 lines. Use targeted files for context-specific rules. ### 3. Skills Skills extend what agents can do by providing specific, invokable capabilities. You define them as SKILL.md files in `.github/skills/`, and agents gain new operations they can perform. ```markdown # .github/skills/github-pr-analyzer.SKILL.md --- name: GitHub PR Analyzer --- Analyze pull requests for code quality issues, suggest improvements, and summarize changes for review. ``` Skills are executable capabilities. When an agent needs to analyze a PR, it invokes the skill. The skill handles the complex logic; the agent uses the result. Skills load automatically when relevant. Any agent can invoke any skill in your `.github/skills/` directory, making capabilities instantly reusable across workflows. When skills make sense: - Complex operations requiring specialized logic - Reusable capabilities across multiple agents - Domain-specific workflows you want to standardize ### 4. MCP Servers MCP servers connect Copilot to external systems—databases, APIs, cloud services. ```json // .vscode/mcp.json { "mcpServers": { "postgres": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-postgres"], "env": { "POSTGRES_CONNECTION": "${env:DATABASE_URL}" } } } } ``` When MCP works well: - Agents need runtime data (database schemas, API state) - External system information affects decisions - Data lives outside your codebase Use environment variables for credentials. Start with read-only operations. --- ## Why Separation Matters Independent layers mean independent updates. Four examples: ### Adding Capabilities ```mermaid flowchart LR SK["✅ .github/skills/
NEW: pr-analyzer.SKILL.md"] AG["✓ .github/agents/
(unchanged)"] IN["✓ .github/instructions/
(unchanged)"] MC["✓ .vscode/mcp.json
(unchanged)"] SK --> Result["All agents gain
PR analysis capability"] style SK fill:#f0e1ff,stroke:#9333ea,stroke-width:3px style AG fill:#f5f5f5,stroke:#d1d5db style IN fill:#f5f5f5,stroke:#d1d5db style MC fill:#f5f5f5,stroke:#d1d5db style Result fill:#d6ffd6 ``` **Adding capabilities**: Add a new skill file to `.github/skills/`, and all agents can immediately invoke it. For example, add a PR analyzer skill and all agents gain PR analysis capabilities. ### Enforcing Standards ```mermaid flowchart LR IN["✅ .github/instructions/
NEW: api.instructions.md"] AG["✓ .github/agents/
(unchanged)"] SK["✓ .github/skills/
(unchanged)"] MC["✓ .vscode/mcp.json
(unchanged)"] IN --> Result["All API work follows
validation rules"] style IN fill:#fff4e1,stroke:#f59e0b,stroke-width:3px style AG fill:#f5f5f5,stroke:#d1d5db style SK fill:#f5f5f5,stroke:#d1d5db style MC fill:#f5f5f5,stroke:#d1d5db style Result fill:#d6ffd6 ``` **Enforcing standards**: Add API validation requirement to instructions file. Copilot applies it automatically when working on APIs. No reminders needed. ### Changing Workflows ```mermaid flowchart LR AG["✅ .github/agents/
MODIFIED: feature-builder.agent.md"] IN["✓ .github/instructions/
(unchanged)"] SK["✓ .github/skills/
(unchanged)"] MC["✓ .vscode/mcp.json
(unchanged)"] AG --> Result["More thorough
planning phase"] style AG fill:#e1f5ff,stroke:#3b82f6,stroke-width:3px style IN fill:#f5f5f5,stroke:#d1d5db style SK fill:#f5f5f5,stroke:#d1d5db style MC fill:#f5f5f5,stroke:#d1d5db style Result fill:#d6ffd6 ``` **Changing workflows**: Update feature-builder agent to be more thorough during planning. Standards stay unchanged in separate instruction files. ### Switching Data Sources ```mermaid flowchart LR MC["✅ .vscode/mcp.json
MODIFIED: postgres connection"] AG["✓ .github/agents/
(unchanged)"] IN["✓ .github/instructions/
(unchanged)"] SK["✓ .github/skills/
(unchanged)"] MC --> Result["Now connects to
cloud database"] style MC fill:#e1ffe1,stroke:#22c55e,stroke-width:3px style AG fill:#f5f5f5,stroke:#d1d5db style IN fill:#f5f5f5,stroke:#d1d5db style SK fill:#f5f5f5,stroke:#d1d5db style Result fill:#d6ffd6 ``` **Switching data sources**: Move from local Postgres to cloud database by updating MCP server config. Agents and instructions stay the same—only connection details change. Shared standards across projects: Create a shared repository of instruction files. Reference them in multiple services via git submodules or sync scripts. Update once, all services benefit. --- ## When to Use Each Layer ```mermaid flowchart TD Start([What do you need?]) --> Q1{Always applies
to files?} Q1 -->|Yes| Instructions[Instructions
File-based rules] Q1 -->|No| Q2{Multi-step
workflow?} Q2 -->|Yes| Agent[Custom Agent
Orchestration] Q2 -->|No| Q3{Reusable
operation?} Q3 -->|Yes| Skill[Skill
Invokable capability] Q3 -->|No| Q4{External
data?} Q4 -->|Yes| MCP[MCP Server
Runtime access] Q4 -->|No| None[Not needed] style Instructions fill:#fff4e1 style Agent fill:#e1f5ff style Skill fill:#f0e1ff style MCP fill:#e1ffe1 ``` Static rule that always applies → Instructions Multi-step workflow → Custom Agent Reusable specialized operations → Skills Runtime data access → MCP Examples: - "All API errors use format X" → Instructions - "Check if users table has email column" → MCP - "Use TypeScript strict mode" → Instructions - "Coordinate research then implementation" → Custom Agent - "Summarize this GitHub PR" → Skills --- ## Version Control as Governance These files live in git. Changes go through pull requests: ```bash git checkout -b add-api-validation # Edit .github/instructions/api.instructions.md git commit -m "Add email validation requirement" # Team reviews in PR, merges when approved ``` All four layers live in your repository as version-controlled files. For regulated teams: - Compliance requirements live as code - Git provides audit trail (who changed what, when) - Review gates enforce governance through workflows - Rollback works like any infrastructure change You can require security team approval for compliance instruction changes, just like production deployments. --- ## Start Simple ```mermaid graph TD Start([Start Here]) --> Step1["1. Global Instructions
.github/copilot-instructions.md"] Step1 --> Step2["2. Add Skills
.github/skills/*.SKILL.md"] Step2 --> Step3["3. Add Agents
.github/agents/*.agent.md"] Step3 --> Step4["4. Split Instructions
.github/instructions/*.instructions.md"] Step4 --> Step5["5. Add Orchestration
Multiple specialized agents"] Step5 --> Step6["6. Integrate MCP
.vscode/mcp.json"] Step1 -.->|"20-30 lines of
core standards"| Start Step2 -.->|"When you need
reusable capabilities"| Step1 Step3 -.->|"When workflows
repeat"| Step2 Step4 -.->|"When global file
grows large"| Step3 Step5 -.->|"When multi-phase
patterns emerge"| Step4 Step6 -.->|"When external
data needed"| Step5 style Start fill:#d6ffd6 style Step1 fill:#fff4e1 style Step2 fill:#f0e1ff style Step3 fill:#e1f5ff style Step4 fill:#fff4e1 style Step5 fill:#e1f5ff style Step6 fill:#e1ffe1 ``` Begin with global instructions: ``` .github/copilot-instructions.md (20-30 lines covering core standards) ``` Add skills when you need reusable capabilities: ``` .github/skills/ └─ github-pr-analyzer.SKILL.md ``` Add agents when repetitive workflows appear: ``` .github/agents/ └─ feature-builder.agent.md ``` Split instructions by context when global file grows: ``` .github/instructions/ ├─ api.instructions.md └─ components.instructions.md ``` Add orchestration when multi-phase workflows become common: ``` .github/agents/ ├─ feature-builder.agent.md (orchestrator) ├─ researcher.agent.md (specialist) └─ implementer.agent.md (specialist) ``` Integrate external systems when runtime data is needed: ``` .vscode/mcp.json (MCP servers) ``` Each stage solves a real problem. Build complexity incrementally. --- ## Common Pitfalls **Mixing standards into agents**: Keep workflow in agents, standards in instructions. If it applies to all work in a directory, it's an instruction. **Monolithic instructions**: Don't put everything in one 3000-line file. Split by context using `applyTo` patterns. **Over-engineering early**: Don't create 25 hyper-specific agents before you know what you need. Start with instructions, add agents as workflows emerge. **Duplicating skills unnecessarily**: Check existing skills before creating new ones. Don't create five variations of the same operation. **Hardcoding credentials in MCP configs**: Use environment variables (`${env:VAR_NAME}`) for sensitive data. Never commit credentials to version control. --- ## Wrapping Up - The layered approach gives you separation of concerns, independent upgrades, and version-controlled governance. - Agents define workflow. Instructions enforce standards. Skills provide reusable capabilities. MCP accesses external data. - When these work independently, you can upgrade skills without rewriting agents, update standards without touching workflows, and change agent behavior while keeping rules intact. - Version control makes this infrastructure. Changes go through PRs. Git provides audit trails. Everything is reviewable and rollback-able. - For regulated teams, compliance lives as code with traceable changes and enforced review gates. - Start with instructions. Add agents when workflows repeat. Add MCP when external data is needed. Build incrementally. - The value comes from composability, not complexity. --- ## References **Official Documentation**: - [Custom Agents](https://code.visualstudio.com/docs/copilot/customization/custom-agents) - [Copilot Instructions](https://code.visualstudio.com/docs/copilot/copilot-customization) - [MCP in VS Code](https://code.visualstudio.com/docs/copilot/copilot-mcp) - [MCP Protocol](https://modelcontextprotocol.io/introduction)
Who orchestrates?] --> Core[Copilot] I[Instructions
What rules apply?] --> Core S[Skills
What capabilities exist?] --> Core M[MCP Servers
What external data?] --> Core end Core --> Output[AI Response] style A fill:#e1f5ff style I fill:#fff4e1 style S fill:#f0e1ff style M fill:#e1ffe1 style Core fill:#ffd6d6 ``` ## Project Structure A typical setup: ``` .github/ ├─ agents/ # Custom workflow agents ├─ instructions/ # Context-specific standards ├─ skills/ # Reusable capabilities (SKILL.md files) └─ copilot-instructions.md # Global standards .vscode/ └─ mcp.json # MCP server configs ``` All version controlled in your repo. Skills are SKILL.md files that define specific operations agents can invoke. All reviewable through PRs. Quick example: Want all API errors to follow a consistent format? ```markdown # .github/instructions/api.instructions.md --- applyTo: 'src/api/**' --- Return errors as: { "error": { "code": "...", "message": "..." } } ``` Copilot applies this automatically when working on API files. Standard enforced through the tool, not documentation. --- ## The Four Layers ### 1. Custom Agents Custom agents define workflow orchestration. They specify which tools are available, coordinate multi-step processes, and delegate to specialist agents. ```markdown # .github/agents/feature-builder.agent.md --- name: Feature Builder tools: ['agent'] agents: ['Researcher', 'Implementer'] --- Coordinate feature development by delegating research to Researcher (read-only) and implementation to Implementer (write-access). ``` When custom agents work well: - Multi-phase workflows with distinct tool needs - Tool restrictions prevent accidents (researcher can't modify code) - Specialized expertise per domain Keep workflow logic here, not coding standards. ### 2. Instructions Instructions define project standards that apply automatically based on file context. ```markdown # .github/instructions/api.instructions.md --- applyTo: 'src/api/**' --- - Validate input with Joi schemas - Return errors as: { "error": { "code": "...", "message": "..." } } - Include tests ``` Global instructions (`.github/copilot-instructions.md`) apply everywhere. Targeted instructions use `applyTo` patterns for file-specific rules. When instructions work well: - Team-wide conventions that always apply - File-specific standards (API patterns, component conventions) - Replacing documentation with enforcement Keep global instructions under 50 lines. Use targeted files for context-specific rules. ### 3. Skills Skills extend what agents can do by providing specific, invokable capabilities. You define them as SKILL.md files in `.github/skills/`, and agents gain new operations they can perform. ```markdown # .github/skills/github-pr-analyzer.SKILL.md --- name: GitHub PR Analyzer --- Analyze pull requests for code quality issues, suggest improvements, and summarize changes for review. ``` Skills are executable capabilities. When an agent needs to analyze a PR, it invokes the skill. The skill handles the complex logic; the agent uses the result. Skills load automatically when relevant. Any agent can invoke any skill in your `.github/skills/` directory, making capabilities instantly reusable across workflows. When skills make sense: - Complex operations requiring specialized logic - Reusable capabilities across multiple agents - Domain-specific workflows you want to standardize ### 4. MCP Servers MCP servers connect Copilot to external systems—databases, APIs, cloud services. ```json // .vscode/mcp.json { "mcpServers": { "postgres": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-postgres"], "env": { "POSTGRES_CONNECTION": "${env:DATABASE_URL}" } } } } ``` When MCP works well: - Agents need runtime data (database schemas, API state) - External system information affects decisions - Data lives outside your codebase Use environment variables for credentials. Start with read-only operations. --- ## Why Separation Matters Independent layers mean independent updates. Four examples: ### Adding Capabilities ```mermaid flowchart LR SK["✅ .github/skills/
NEW: pr-analyzer.SKILL.md"] AG["✓ .github/agents/
(unchanged)"] IN["✓ .github/instructions/
(unchanged)"] MC["✓ .vscode/mcp.json
(unchanged)"] SK --> Result["All agents gain
PR analysis capability"] style SK fill:#f0e1ff,stroke:#9333ea,stroke-width:3px style AG fill:#f5f5f5,stroke:#d1d5db style IN fill:#f5f5f5,stroke:#d1d5db style MC fill:#f5f5f5,stroke:#d1d5db style Result fill:#d6ffd6 ``` **Adding capabilities**: Add a new skill file to `.github/skills/`, and all agents can immediately invoke it. For example, add a PR analyzer skill and all agents gain PR analysis capabilities. ### Enforcing Standards ```mermaid flowchart LR IN["✅ .github/instructions/
NEW: api.instructions.md"] AG["✓ .github/agents/
(unchanged)"] SK["✓ .github/skills/
(unchanged)"] MC["✓ .vscode/mcp.json
(unchanged)"] IN --> Result["All API work follows
validation rules"] style IN fill:#fff4e1,stroke:#f59e0b,stroke-width:3px style AG fill:#f5f5f5,stroke:#d1d5db style SK fill:#f5f5f5,stroke:#d1d5db style MC fill:#f5f5f5,stroke:#d1d5db style Result fill:#d6ffd6 ``` **Enforcing standards**: Add API validation requirement to instructions file. Copilot applies it automatically when working on APIs. No reminders needed. ### Changing Workflows ```mermaid flowchart LR AG["✅ .github/agents/
MODIFIED: feature-builder.agent.md"] IN["✓ .github/instructions/
(unchanged)"] SK["✓ .github/skills/
(unchanged)"] MC["✓ .vscode/mcp.json
(unchanged)"] AG --> Result["More thorough
planning phase"] style AG fill:#e1f5ff,stroke:#3b82f6,stroke-width:3px style IN fill:#f5f5f5,stroke:#d1d5db style SK fill:#f5f5f5,stroke:#d1d5db style MC fill:#f5f5f5,stroke:#d1d5db style Result fill:#d6ffd6 ``` **Changing workflows**: Update feature-builder agent to be more thorough during planning. Standards stay unchanged in separate instruction files. ### Switching Data Sources ```mermaid flowchart LR MC["✅ .vscode/mcp.json
MODIFIED: postgres connection"] AG["✓ .github/agents/
(unchanged)"] IN["✓ .github/instructions/
(unchanged)"] SK["✓ .github/skills/
(unchanged)"] MC --> Result["Now connects to
cloud database"] style MC fill:#e1ffe1,stroke:#22c55e,stroke-width:3px style AG fill:#f5f5f5,stroke:#d1d5db style IN fill:#f5f5f5,stroke:#d1d5db style SK fill:#f5f5f5,stroke:#d1d5db style Result fill:#d6ffd6 ``` **Switching data sources**: Move from local Postgres to cloud database by updating MCP server config. Agents and instructions stay the same—only connection details change. Shared standards across projects: Create a shared repository of instruction files. Reference them in multiple services via git submodules or sync scripts. Update once, all services benefit. --- ## When to Use Each Layer ```mermaid flowchart TD Start([What do you need?]) --> Q1{Always applies
to files?} Q1 -->|Yes| Instructions[Instructions
File-based rules] Q1 -->|No| Q2{Multi-step
workflow?} Q2 -->|Yes| Agent[Custom Agent
Orchestration] Q2 -->|No| Q3{Reusable
operation?} Q3 -->|Yes| Skill[Skill
Invokable capability] Q3 -->|No| Q4{External
data?} Q4 -->|Yes| MCP[MCP Server
Runtime access] Q4 -->|No| None[Not needed] style Instructions fill:#fff4e1 style Agent fill:#e1f5ff style Skill fill:#f0e1ff style MCP fill:#e1ffe1 ``` Static rule that always applies → Instructions Multi-step workflow → Custom Agent Reusable specialized operations → Skills Runtime data access → MCP Examples: - "All API errors use format X" → Instructions - "Check if users table has email column" → MCP - "Use TypeScript strict mode" → Instructions - "Coordinate research then implementation" → Custom Agent - "Summarize this GitHub PR" → Skills --- ## Version Control as Governance These files live in git. Changes go through pull requests: ```bash git checkout -b add-api-validation # Edit .github/instructions/api.instructions.md git commit -m "Add email validation requirement" # Team reviews in PR, merges when approved ``` All four layers live in your repository as version-controlled files. For regulated teams: - Compliance requirements live as code - Git provides audit trail (who changed what, when) - Review gates enforce governance through workflows - Rollback works like any infrastructure change You can require security team approval for compliance instruction changes, just like production deployments. --- ## Start Simple ```mermaid graph TD Start([Start Here]) --> Step1["1. Global Instructions
.github/copilot-instructions.md"] Step1 --> Step2["2. Add Skills
.github/skills/*.SKILL.md"] Step2 --> Step3["3. Add Agents
.github/agents/*.agent.md"] Step3 --> Step4["4. Split Instructions
.github/instructions/*.instructions.md"] Step4 --> Step5["5. Add Orchestration
Multiple specialized agents"] Step5 --> Step6["6. Integrate MCP
.vscode/mcp.json"] Step1 -.->|"20-30 lines of
core standards"| Start Step2 -.->|"When you need
reusable capabilities"| Step1 Step3 -.->|"When workflows
repeat"| Step2 Step4 -.->|"When global file
grows large"| Step3 Step5 -.->|"When multi-phase
patterns emerge"| Step4 Step6 -.->|"When external
data needed"| Step5 style Start fill:#d6ffd6 style Step1 fill:#fff4e1 style Step2 fill:#f0e1ff style Step3 fill:#e1f5ff style Step4 fill:#fff4e1 style Step5 fill:#e1f5ff style Step6 fill:#e1ffe1 ``` Begin with global instructions: ``` .github/copilot-instructions.md (20-30 lines covering core standards) ``` Add skills when you need reusable capabilities: ``` .github/skills/ └─ github-pr-analyzer.SKILL.md ``` Add agents when repetitive workflows appear: ``` .github/agents/ └─ feature-builder.agent.md ``` Split instructions by context when global file grows: ``` .github/instructions/ ├─ api.instructions.md └─ components.instructions.md ``` Add orchestration when multi-phase workflows become common: ``` .github/agents/ ├─ feature-builder.agent.md (orchestrator) ├─ researcher.agent.md (specialist) └─ implementer.agent.md (specialist) ``` Integrate external systems when runtime data is needed: ``` .vscode/mcp.json (MCP servers) ``` Each stage solves a real problem. Build complexity incrementally. --- ## Common Pitfalls **Mixing standards into agents**: Keep workflow in agents, standards in instructions. If it applies to all work in a directory, it's an instruction. **Monolithic instructions**: Don't put everything in one 3000-line file. Split by context using `applyTo` patterns. **Over-engineering early**: Don't create 25 hyper-specific agents before you know what you need. Start with instructions, add agents as workflows emerge. **Duplicating skills unnecessarily**: Check existing skills before creating new ones. Don't create five variations of the same operation. **Hardcoding credentials in MCP configs**: Use environment variables (`${env:VAR_NAME}`) for sensitive data. Never commit credentials to version control. --- ## Wrapping Up - The layered approach gives you separation of concerns, independent upgrades, and version-controlled governance. - Agents define workflow. Instructions enforce standards. Skills provide reusable capabilities. MCP accesses external data. - When these work independently, you can upgrade skills without rewriting agents, update standards without touching workflows, and change agent behavior while keeping rules intact. - Version control makes this infrastructure. Changes go through PRs. Git provides audit trails. Everything is reviewable and rollback-able. - For regulated teams, compliance lives as code with traceable changes and enforced review gates. - Start with instructions. Add agents when workflows repeat. Add MCP when external data is needed. Build incrementally. - The value comes from composability, not complexity. --- ## References **Official Documentation**: - [Custom Agents](https://code.visualstudio.com/docs/copilot/customization/custom-agents) - [Copilot Instructions](https://code.visualstudio.com/docs/copilot/copilot-customization) - [MCP in VS Code](https://code.visualstudio.com/docs/copilot/copilot-mcp) - [MCP Protocol](https://modelcontextprotocol.io/introduction)
Comments
Post a Comment