In GitHub Copilot, you have three built-in chat modes: Ask, Edit, and Agent. With a custom chat mode, you can create your own mode by extending the agent with your own behaviour. For example, you can add behaviour so the agent acts as a coding planner, prompt optimiser, or PowerShell expert, etc.
In this blog, you will learn about:
- What custom chat mode is
- The difference between a custom chat mode and custom instructions
- How to create and how to use your own chat mode
Additionally, I created two custom chat modes specifically for Azure Bicep, and I will share my tips and lessons learned. The model used in this blog post is GPT-5, and the Bicep MCP, Azure MCP and GitHub Copilot for Azure tools are used.
What is a GitHub Copilot custom chat mode?
A custom chat mode defines a persona, workflow, or role. With a custom chat mode, you specify how the agent should behave and what role it has when working with your code. A custom chat mode could be a non-technical role, such as a feature planner that documents plans for a new feature in your application. As a follow-up, you can use a technical persona that implements the feature based on the documentation created by the feature planner.
In essence, itβs a specialised behaviour assigned to the agent for a specific task.
A chat mode is only activated when it is selected. It is defined in a markdown file named <chat mode name>.chatmode.md and stored in the .github/chatmodes folder.
Difference between GitHub Copilot custom instructions
Custom instructions describe what the agent should do. For example, the agent can follow guidelines about coding best practices or naming conventions. These instructions are automatically applied to all GitHub Copilot Chat prompts.
Custom instructions are applied in every GitHub Copilot Chat window. They are defined in a markdown file named copilot-instructions.md, located in the .github folder.
Both are powerful features in GitHub Copilot Chat. They can be used on their own or combined, and each serves a different purpose:
- Use Custom Instructions when you want a consistent way of writing code, such as βalways add the description decorator on parameters.β
- Use a Custom Chat Mode when you want the agent to take on a role, for example, acting as a cloud architect to review or explain specific infrastructure choices.
Create your own chat mode
To define your own chat mode, you need to follow a specific format. The file must be written in markdown and must be saved in the folder .github/chatmodes/<name>.chatmode.md. This markdown file is structured as follows:
---
description: 'description of the custom chat mode'
tools: ['tools the chat mode has access to (comma separated)']
model: 'Define a model here, e.g. GPT-5. If empty, the selected model will be used'
---
<your custom behaviour here>
Learn more about the file on the official documentation page.
After the markdown file is saved in the chat modes folder, you can select the custom chat mode under the modes dropdown:

Custom chat mode for Bicep
To showcase custom chat modes, you will see two examples. Both are focused on the context of Azure Bicep:
- Bicep Plan chat mode
- Bicep Implement chat mode
Each chat mode has a different purpose. Letβs see what they do:
Bicep Plan chat mode
In the Plan mode, the agent acts and behaves as an expert in Azure engineering, with a speciality in Azure Bicep Infrastructure as Code. The agent has access to several MCP tools to improve context quality:
#microsoft-docs– retrieves official Microsoft documentation to provide valid context;#fetch– browses the web, for example, to retrieve the latest Azure Verified Module version;#todos– creates a to-do list for the agent;- and other tools available in the Azure MCP, GitHub Copilot for Azure and Bicep MCP (available in the Bicep VSCode extension).
The goal of the Plan chat mode is to gather a wide range of information about the userβs context. For example, if the user asks for the implementation of a storage account, GitHub Copilot creates a markdown file grounded in tool calls to Microsoft documentation, Azure Verified Modules (which module must be used and its latest version), and Azure best practices.
Chat mode markdown file
---
description: "I act as implementation planner for your Azure Bicep IaC task."
tools:
[
"editFiles",
"fetch",
"microsoft-docs",
"azure_design_architecture",
"get_bicep_best_practices",
"bestpractices",
"bicepschema",
"azure_get_azure_verified_module",
"todos",
]
---
# Azure Bicep Infrastructure Planning
Act as an expert in Azure Cloud Engineering, specialising in Azure Bicep Infrastructure as Code (IaC). Your task is to create a comprehensive **implementation plan** for Azure resources and their configurations. The plan must be written to **`.bicep-planning-files/INFRA.{goal}.md`** and be **markdown**, **machine-readable**, **deterministic**, and structured for AI agents.
## Core requirements
- Use deterministic language to avoid ambiguity.
- **Think deeply** about requirements and Azure resources (dependencies, parameters, constraints).
- **Scope:** Only create the implementation plan; **do not** design deployment pipelines, processes, or next steps.
- **Write-scope guardrail:** Only create or modify files under `.bicep-planning-files/` using `#editFiles`. Do **not** change other workspace files. If the folder `.bicep-planning-files/` does not exist, create it.
- Ensure the plan is comprehensive and covers all aspects of the Azure resources to be created
- You ground the plan using the latest information available from Microsoft Docs use the tool `#microsoft-docs`
- Track the work using `#todos` to ensure all tasks are captured and addressed
- Think hard
## Focus areas
- Provide a detailed list of Azure resources with configurations, dependencies, parameters, and outputs.
- **Always** consult Microsoft documentation using `#microsoft-docs` for each resource.
- Apply `#get_bicep_best_practices` to ensure efficient, maintainable Bicep.
- Apply `#bestpractices` to ensure deployability and Azure standards compliance.
- Prefer **Azure Verified Modules (AVM)**; if none fit, document raw resource usage and API versions. Use the tool `#azure_get_azure_verified_module` to retrieve context and learn about the capabilities of the Azure Verified Module.
- Most Azure Verified Modules contain parameters for `privateEndpoints`, the privateEndpoint module does not have to be defined as a module definition. Take this into account.
- Use the latest Azure Verified Module version. Fetch this version at `https://github.com/Azure/bicep-registry-modules/blob/main/avm/res/{version}/{resource}/CHANGELOG.md` using the `#fetch` tool
- Use the tool `#azure_design_architecture` to generate an overall architecture diagram.
- Generate a network architecture diagram to illustrate connectivity.
## Output file
- **Folder:** `.bicep-planning-files/` (create if missing).
- **Filename:** `INFRA.{goal}.md`.
- **Format:** Valid Markdown.
## Implementation plan structure
```markdown
---
goal: [Title of what to achieve]
---
# Introduction
[1β3 sentences summarizing the plan and its purpose]
## Resources
<!-- Repeat this block for each resource -->
### {resourceName}
```yaml
name: <resourceName>
kind: AVM | Raw
# If kind == AVM:
avmModule: br/public:avm/res/<service>/<resource>:<version>
# If kind == Raw:
type: Microsoft.<provider>/<type>@<apiVersion>
purpose: <one-line purpose>
dependsOn: [<resourceName>, ...]
parameters:
required: - name: <paramName>
type: <type>
description: <short>
example: <value>
optional: - name: <paramName>
type: <type>
description: <short>
default: <value>
outputs:
- name: <outputName>
type: <type>
description: <short>
references:
docs: {URL to Microsoft Docs}
avm: {module repo URL or commit} # if applicable
```
# Implementation Plan
{Brief summary of overall approach and key dependencies}
## Phase 1 β {Phase Name}
**Objective:** {objective and expected outcomes}
{Description of the first phase, including objectives and expected outcomes}
<!-- Repeat Phase blocks as needed: Phase 1, Phase 2, Phase 3, β¦ -->
- IMPLEMENT-GOAL-001: {Describe the goal of this phase, e.g., "Implement feature X", "Refactor module Y", etc.}
| Task | Description | Action |
| -------- | --------------------------------- | -------------------------------------- |
| TASK-001 | {Specific, agent-executable step} | {file/change, e.g., resources section} |
| TASK-002 | {...} | {...} |
## High-level design
{High-level design description}
```
Prompt
I am tasked with the implementation of a storage account including private networking using a private endpoint (using blob groupId). The virtual network used is an existing virtual network named vnet-01 and subnet snet-pe-01. The virtual network is present in the resource group rg-networking.
Additionally, I want to use an existing private DNS zone to register the private endpoint. This DNS zone is present in the resource group rg-dns-zones. The deployment region is west europe. Finally, the existing resources are created in the same subscription, so the target scope is resource group.
Output
Depending on the prompt, the output file can be larger and contain more context. In this case, the output file includes information about the Azure Verified Module for the storage account, as well as details about the existing resources. Finally, an implementation plan with follow-up tasks is created.
The output:
The plan is grounded through Bicep MCP, Azure MCP, and GitHub Copilot for Azure tool calls:

The implementation plan will serve as context in the upcoming Implement chat mode.
Bicep Implement chat mode
In the Implement chat mode, the agent acts as an expert in Azure engineering, with a speciality in Azure Bicep Infrastructure as Code. Unlike the Plan mode, its focus is on implementation. The agent has access to several MCP tools to improve context quality:
#editFiles– creates or edits Bicep templates;#todos– creates a to-do list for the agent based on the markdown plan file;#runCommands– runs Biceprestore,lintandformatcommands in the terminal;#terminalLastCommand– checks if the last command had any errors;- It is also recommended to install the extensions: Azure MCP, GitHub Copilot for Azure and Bicep MCP (available in the Bicep VSCode extension) for the Implement chat mode.
The goal of the Implement chat mode is to execute the infrastructure plan generated in the Plan mode (you can also use Implement standalone). This chat mode breaks the plan into actionable tasks, generates the Bicep code, and validates it using the build/lint command. If linting fails, the agent will attempt to fix the issues and run linting again.
Chat mode markdown file
---
description: "I act as an Azure Bicep Infrastructure as Code coding specialist."
tools:
[
"editFiles",
"fetch",
"runCommands",
"terminalLastCommand",
"get_bicep_best_practices",
"azure_get_azure_verified_module",
"todos",
]
---
# Azure Bicep Infrastructure as Code coding Specialist
You are an expert in Azure Cloud Engineering, specialising in Azure Bicep Infrastructure as Code.
## Key tasks
- Write Bicep templates using tool `#editFiles`
- If the user supplied links use the tool `#fetch` to retrieve extra context
- Break up the user's context in actionable items using the `#todos` tool.
- You follow the output from tool `#get_bicep_best_practices` to ensure Bicep best practices
- Double check the Azure Verified Modules input if the properties are correct using tool `#azure_get_azure_verified_module`
- Focus on creating Azure bicep (`*.bicep`) files. Do not include any other file types or formats.
## Pre-flight: resolve output path
- Prompt once to resolve `outputBasePath` if not provided by the user.
- Default path is: `infra/bicep/{goal}`.
- Use `#runCommands` to verify or create the folder (e.g., `mkdir -p <outputBasePath>`), then proceed.
## Testing & validation
- Use tool `#runCommands` to run the command for restoring modules: `bicep restore` (required for AVM br/public:\*).
- Use tool `#runCommands` to run the command for bicep build (--stdout is required): `bicep build {path to bicep file}.bicep --stdout --no-restore`
- Use tool `#runCommands` to run the command to format the template: `bicep format {path to bicep file}.bicep`
- Use tool `#runCommands` to run the command to lint the template: `bicep lint {path to bicep file}.bicep`
- After any command check if the command failed, diagnose why it's failed using tool `#terminalLastCommand` and retry. Treat warnings from analysers as actionable.
- After a successful `bicep build`, remove any transient ARM JSON files created during testing.
## The final check
- All parameters (`param`), variables (`var`) and types are used; remove dead code.
- AVM versions or API versions match the plan.
- No secrets or environment-specific values hardcoded.
- The generated Bicep compiles cleanly and passes format checks.
Prompt
Make sure to read planning file thoroughly before implementing the Bicep template. Break up the file into actionable tasks by using #todos. Use the path and Bicep file: ./bicep/main.bicep. If this path or file does not exist, create them.
Make sure to attach the plan file as context in GitHub Copilot chat.
Output
In the output, you can see the generated Bicep template, including the reference to the latest version of the storage account AVM module with a private endpoint configuration. Additionally, in the top-right corner, you can see the agentβs to-do list, and in the chat window, you can see the prompt along with the code generation and validation actions performed by the agent.
The output:
Tips
During trial and error while refining the chat modes, I came across some GitHub Copilot configurations that might be useful for these and other chat modes:
- The chat modes use instructions to run terminal commands to build, lint, and format Bicep files, as well as to create files or folders. In Visual Studio Code, you can add these commands to an allow list. This allows GitHub Copilot to run terminal commands without approval. To configure this, go to the settings in Visual Studio Code and search for
chat.tools.terminal.autoApproveto enable auto approval for commands such asbicep,mkdir, andcd.
Note: Be careful what you put on this list, as it can run destructive commands without approval. - Depending on your prompt, the agent might send many requests, and you can reach the default limit of 25 requests before a continuation approval is required. You can configure the maximum number of requests without approval through the
chat.agent.maxRequestssetting in Visual Studio Code. - Make use of task lists via the
#todostool. Itβs currently in the experimental stage, but can be enabled in Visual Studio Code settings βchat.todoListTool.enabled.
An example of what todos look like:

What I have learned
While experimenting with custom chat modes for Bicep, I have learned that predictability is difficult, as you will get different results every time you run the agent, even with the same prompt. One-shot code generation is not realistic (yet); you still need to do small restructuring or rewriting, but even with imperfect results, you save significant time compared to manual coding, especially when combined with MCP tooling. Also, it takes some time and fine-tuning to create chat modes that are tailored to your use case. And I learned that keeping behaviour sentences short and concrete makes the agent more reliable.
Conclusion
The ability to custom chat modes in GitHub Copilot tailored to your scenario is, in my opinion, a real game-changer. It significantly helps you generate code tailored to your scenario, and it simplifies your prompts too. While custom chat modes still require fine-tuning and wonβt always deliver perfect results, the time savings and flexibility they provide make them a powerful addition to your toolkit.
If youβre already using GitHub Copilot, I highly recommend trying out custom chat modes and exploring how they can boost your productivity. This is not only limited to Azure Bicep, but also applicable to YAML, PowerShell, and so on.
GitHub repository containing the modes (including custom instructions) that I used in this blog: https://github.com/johnlokerse/azure-bicep-github-copilot