Thursday, September 3, 2026

Enhancing C# Development with GitHub Copilot CLI and VS Code

GitHub Copilot is transforming how developers work by turning AI from a simple code generator into a practical development partner. In this article, we explore how to use GitHub Copilot CLI and Visual Studio Code together with the Awesome Copilot ecosystem to build better .NET applications, customize AI behavior, and bring domain-specific guidance directly into the development workflow. From designing models and applying best practices to installing reusable agents, instructions, and skills, this walkthrough shows how to make Copilot feel deeply integrated with the way you code.

Using GitHub Copilot CLI

Create a sample .NET Console app

From within a termnal window in a working directory, type the following commands:

dotnet new console -o AwesomeAthlete
cd AwesomeAthlete

Install GitHub Copilot CLI

Follow instructions at Installing GitHub Copilot CLI to install the GitGub Copilot CLI.

Start the copilot app by typing the following command inside the same folder as the .NET app created earlier:

copilot

Explore online plugins repo

Visit: https://github.com/github/awesome-copilot and review the plugins/csharp-dotnet-development plugin.

Install the plugin by entering this command in GitHub Copilot CLI:

/plugin install csharp-dotnet-development@awesome-copilot

To view a list of plugins, enter this command:

/plugin list

Let's get the plugin to do something useful. For example, ask the plugin to help you design some domain models by entering this command:

@csharp-dotnet-development help me design a class model for Athlete

Thereafter, you can enter this command to add the required C# classes:

add the class models to my app and put code in Program.cs that calls those classes and prints sample data to the console

Among others, the plugin contains a command named /csharp-dotnet-development:dotnet-best-practices. We can use this command by entering this instruction:

/csharp-dotnet-development:dotnet-best-practices

Since we have a very simple C# application, the only suggestion made by AI is to add documentation to the domain classes.

Exit GitHub Copilot CLI by typing in the /exit command.

/exit

Using Visual Studio Code (VS Code)

If you do not already have VS Code installed on your computer, you can get it from https://code.visualstudio.com/. Make sure to install the GitHub Copilot Chat extension before proceeding.

Open the AwesomeAthlete folder in VS Code. You ca do that by simply typing in the following from a termninal window from inside the AwesomeAthlete folder:

code .

Customize or Extend the Plugin

You can modify plugin components to suit your needs.

In plugin folder: ~/.copilot/installed-plugins/awesome-copilot/<plugin-name>/

  • Edit com.github.copilot/agents/*.md to change agent behavior
  • Edit skills/*/SKILL.md to add new skills

Restart VS Code to reload changes

Installing Awesome Copilot artifacts

Point your browser to Awesome GitHub Copilot. Let's try installing the Caveman Mode instruction that optimizes token interaction with AI. Click on Instructions.

Find the Caveman Mode instruction. Click on VS Code Install.

Click Yes on this dialog.

Choose to install the instructions in the current workspace under folder .github, instead of globally.

Accept the default name caveman-mode for the instructions.

The caveman-mode-instructions.md file is saved in your workspace under .github.

Here is an example on how to use this instruction. Enter the following into the VS Code chat window:

caveman-mode how many years did it take to build the empire state building in new york

The prompt is distilled to the essential keywords: Empire State Building construction duration. The response stays concise and focused, avoiding unnecessary wording. This keeps token usage low and saves you money.

Awesome Copilot

The Awesome Copilot (By Tim Heuer) extension for VS Code allows you to browse and download instructions, prompts, chat modes, and agents from the Awesome Copilot community.

Install the above extension into your VS Code. You wiill find Awesome Copilot in your explorer.

You will find folders Instructions, Agents, and Skills.

For example, expand the Agents node, then select CSharpExpert.agent.md.

If you decide to download this agent, click on the download tool beside it.

You can change the same of the agent .md file. Simply hit Enter to accept the default name.

The agent gets installed in your local workspace under .github/agents.

You can also modify any of these AI artifacts after you install them locally.

💡 TIP: There are new AI artifacts being added regularly. Click on refresh to load the latest.

@agentPlugins

There are multiple ways of installing AI plugins into VS Code. In your VS Code Extensions tab enter the keywoord @agentPlugins.

There are many plugins that you can choose from. You can narrow down the list by adding a filter. For example, I entered the csharp filter and received a short list of the plugings that fit that keyword:

Click on the csharp-dotnet-development plugin. You will see more information about the plugin. In this example, the plugin consists of a number of slash (/) commands and one agent.

I you are in a C# application, you can use the /csharp-dotnet-development:csharp-xunit slash command to generate test cases with this prompt:

/csharp-dotnet-development:csharp-xunit generate test cases

Plugins consist of plugin.json file, skills, agents, hooks, and MCP. Below is an illustration of the plugin architecture:

Any agents that are installed in your environment can be invoked from the chat window. For example, in the below illustration, I installed the CSharpExpert.agent.md agent locally and it is appears in the chat window ready to be invoked:

You can, at any time, disable or uninstall any plugin by right-clicking on it in the extensions tab and choosing disable or uninstall.

Conclusion

GitHub Copilot plugins extend AI-assisted development beyond simple code generation. With GitHub Copilot CLI, VS Code, and the Awesome Copilot ecosystem, you can add specialized agents, instructions, skills, hooks, and commands to your C# workflow.

These tools help you design .NET applications, apply best practices, generate tests, and customize Copilot to match your development style. Explore the available artifacts, install the ones that fit your needs, and adapt them to make GitHub Copilot a more effective development partner.

References

Manage Agents, Instructions, Prompts, & Skills in Seconds with this VS Code Extension

Get Awesome-Copilot custom chat modes and prompt files - right from within GitHub Copilot Chat.

GitHub Copilot Agent Plugins: Package & Distribute Skills, MCP, Hooks & Custom Agents

Thursday, August 27, 2026

AI Instructions, Agent Skills and Prompt Files in VS Code

In this tutorial we will use a very simple C# console application to reinforce some of the concepts pertaining to coding with AI in VS Code.

Pre-requisites

You will need .NET and VS Code in order to proceed with this walkthrough.

Getting Started

Create a new console app and open it in VS Code with the following terminal window commands:

dotnet new console -o Toons.Net
cd Toons.Net
code .

Replace contents of Program.cs with:

Toon[] toons = {
    new() {
        ID = 1,
        First = "Barney",
        Last = "Rubble",
        Gender = Gender.Male,
        Occupation = "Mining Assistant"
    },
    new() {
        ID = 2,
        First = "Betty",
        Last = "Rubble",
        Gender = Gender.Female,
        Occupation = "Nurse" },
    new() {
        ID = 3,
        First = "Fred",
        Last = "Flintstone",
        Gender = Gender.Male,
        Occupation = "Mining Manager" },
    new() {
        ID = 4,
        First = "Wilma",
        Last = "Flintstone",
        Gender = Gender.Female,
        Occupation = "Teacher" },
    new() {
        ID = 5,
        First = "Pebbles",
        Last = "Flintstone",
        Gender = Gender.Female,
        Occupation = "Toddler" },
};

foreach (var item in toons) {
    Console.Write($"ID: {item.ID}, ");
    Console.Write($"First: {item.First}, ");
    Console.Write($"Last: {item.Last}, ");
    Console.Write($"Gender: {item.Gender}, ");
    Console.WriteLine($"Occupation: {item.Occupation}");
}

public class Toon {
    public int ID { get; set; }
    public string? First { get; set; }
    public string? Last { get; set; }
    public Gender Gender { get; set; }
    public string? Occupation { get; set; }
}

public enum Gender {
    Male,
    Female
}

To see what it does, run the application by entering the following command in a terminal window inside the Toons.Net folder:

dotnet run

Custom Instructions

Custom instructions enable you to define common guidelines and rules that automatically influence how AI generates code and handles other development tasks. Instead of manually including context in every chat prompt, specify custom instructions in a Markdown file to ensure consistent AI responses that align with your coding practices and project requirements.

In a ./github folder, add a file named copilot-instructions.md with this text that provides some coding principles and the manner by which AI will refer to you as Sensei:

# Please call me Sensei and speak with the calm discipline of a samurai.

## Naming Conventions
- Use PascalCase for component names, interfaces, and type aliases
- Use camelCase for variables, functions, and methods
- Prefix private class members with underscore (_)
- Use ALL_CAPS for constants

# Project-specific guidelines
- Use async/await for asynchronous operations
- When creating sample Toon data, ensure names are diverse and culturally inclusive
- When creating sample Toon data, use Occupations that represent a wide range of disciplines and regions

Note this interaction when you prompt the AI chat with "Hello":

You should put your team coding standards in the copilot-instructions.md file. You may also wish to put this file at a workspace level, rather than a project level.

Skills

Agent skills are folders of instructions, scripts, and resources that GitHub Copilot can load when relevant to perform specialized tasks.

You can think of agents skills as the micro-services of AI.

Agent skills are an open standard that work across multiple AI agents, including GitHub Copilot and VS Code, Copilot CLI, and Copilot Cloud Agent.

In folder ./github/skills/hello-world, add a file named SKILL.md with this text:

---
name: hello-world
description: "Use when: you want a simple Hello World response in ASCII text."
---
# Hello World

When invoked, output exactly this line:

 _   _      _ _                             _     _ _
| | | | ___| | | ___    __      _____  _ __| | __| | |
| |_| |/ _ \ | |/ _ \   \ \ /\ / / _ \| '__| |/ _` | |
|  _  |  __/ | | (_) |   \ V  V / (_) | |  | | (_| |_|
|_| |_|\___|_|_|\___( )   \_/\_/ \___/|_|  |_|\__,_(_)
⚠️ The name of the skill must exactly match the folder name.
⚠️  It is mandatory to provide name and description.

Enter this prompt in the chat window:

add a simple Hello World response in ASCII text to Program.cs

It will add this code to Program.cs:

Console.WriteLine("""
 _   _      _ _                             _     _ _
| | | | ___| | | ___    __      _____  _ __| | __| | |
| |_| |/ _ \ | |/ _ \   \ \ /\ / / _ \| '__| |/ _` | |
|  _  |  __/ | | (_) |   \ V  V / (_) | |  | | (_| |_|
|_| |_|\___|_|_|\___( )   \_/\_/ \___/|_|  |_\__,_(_)
                    |/
""");

A good site to visit to get skills, instructions, plugins, and agents for VS Code is https://github.com/github/awesome-copilot. Point your browser to that site then navigate to /skills/dotnet-best-practices. Copy the content of the SKILL.md file from the code tab:

Visiting https://github.com/github/awesome-copilot is a good starting point for creating these .md files which will make you very efficient in your journey developing software with AI. 

Create a folder ./github/skills/dotnet-best-practices and add to it the contents of SKILL.md file that you copied. You can edit it as you see fit.

Add this prompt to the chat window:

Apply /dotnet-best-practices to this project

This results in best practices being applied to your project. I noticed extensive documentation being added to Program.cs:

Console.WriteLine("""
 _   _      _ _                             _     _ _
| | | | ___| | | ___    __      _____  _ __| | __| | |
| |_| |/ _ \ | |/ _ \   \ \ /\ / / _ \| '__| |/ _` | |
|  _  |  __/ | | (_) |   \ V  V / (_) | |  | | (_| |_|
|_| |_|\___|_|_|\___( )   \_/\_/ \___/|_|  |_|\__,_(_)
""");

Toon[] toons = {
    new() {
        ID = 1,
        First = "Barney",
        Last = "Rubble",
        Gender = Gender.Male,
        Occupation = "Mining Assistant"
    },
    new() {
        ID = 2,
        First = "Betty",
        Last = "Rubble",
        Gender = Gender.Female,
        Occupation = "Nurse" },
    new() {
        ID = 3,
        First = "Fred",
        Last = "Flintstone",
        Gender = Gender.Male,
        Occupation = "Mining Manager" },
    new() {
        ID = 4,
        First = "Wilma",
        Last = "Flintstone",
        Gender = Gender.Female,
        Occupation = "Teacher" },
    new() {
        ID = 5,
        First = "Pebbles",
        Last = "Flintstone",
        Gender = Gender.Female,
        Occupation = "Toddler" },
};

foreach (var item in toons)
{
    Console.Write($"ID: {item.ID}, ");
    Console.Write($"First: {item.First}, ");
    Console.Write($"Last: {item.Last}, ");
    Console.Write($"Gender: {item.Gender}, ");
    Console.WriteLine($"Occupation: {item.Occupation}");
}

/// <summary>
/// Represents a character in the sample toon collection.
/// </summary>
public class Toon
{
    /// <summary>
    /// Gets the unique identifier for the toon.
    /// </summary>
    public int ID { get; init; }

    /// <summary>
    /// Gets the toon&apos;s first name.
    /// </summary>
    public required string First { get; init; }

    /// <summary>
    /// Gets the toon&apos;s last name.
    /// </summary>
    public required string Last { get; init; }

    /// <summary>
    /// Gets the toon&apos;s gender classification.
    /// </summary>
    public required Gender Gender { get; init; }

    /// <summary>
    /// Gets the toon&apos;s occupation.
    /// </summary>
    public required string Occupation { get; init; }
}

/// <summary>
/// Defines the gender classifications used by the sample data.
/// </summary>
public enum Gender
{
    /// <summary>
    /// Identifies a male toon.
    /// </summary>
    Male,

    /// <summary>
    /// Identifies a female toon.
    /// </summary>
    Female
}

Built-in skills and agents in VS Code

Let's ask copilot chat to add a README.md file to our project with this prompt:

Add a README.md file with relevant information about the current project.

View the built-in skills in VS Code by clicking the gear icon in the chat window:

Find the create-skill under Built-in.

Click on create-skill to view details of the agent skill. This opens the relevant SKILL.md file.

Let’s use create-skill in our software project. In the chat window, enter this prompt:

/create-skill that will update the README.md file whenever a feature is added to the project.

A new SKILL.md file is added to your project under ./github/skills folder:

⚠️ The added feature can be given a different name than "update-readme-on-feature".

Let us add a feature to test it out. Add this prompt in the chat window:

Add a new feature that allows the list of toons to be sorted by id, first, last, gender, or occupation.

After the feature is added, you will notice that the README.md file gets updated accordingly:

Prompt files

Prompt files, also known as slash commands, let you simplify prompting for common tasks by encoding them as standalone Markdown files that you can invoke directly in chat. Each prompt file includes task-specific context and guidelines about how the task should be performed.

In folder ./github/prompts, add a file named code-review-analyzer.md with this text:

---
name: Researcher
description: Research codebase patterns and gather context
tools: ['read', 'search']
model: Claude Sonnet 4.5 (copilot)
user-invocable: true
---
Research the existing codebase for relevant files, functions, and patterns.
Return a concise summary of your findings, including links to relevant code sections.
Report on any insights that may help in implementing new features.

If you like, you can get AI to write these instructions for you.

Invoke the analyser instructions by entering the /Researcher prompt in the chat window.

Conclusion

In this tutorial, we have learned the significance of AI Instructions, Agent Skills and Prompt Files in VS Code. The sky is the limit as to how far you can go with these concepts to make your coding experience much more efficient.

Friday, July 17, 2026

Coding with Microsoft Foundry Local

Coding with Microsoft Foundry Local

In this article we will explore the Microsoft Foundry Local CLI application. We will then write a simple C# program that interacts with a local model that is served by Foundry Local.

Copanion Video: https://youtu.be/YD5QKDcb8T8

What is Microsoft Foundry Local?

Foundry Local is an AI solution that runs entirely on the user's device. It also provides an SDK (C#, JavaScript, Rust, and Python) that helps you build apps that interact with Foundry Local.

Installation

To install Foundry Local, follow these steps:

Windows

winget install Microsoft.FoundryLocal


macOS (only on silicon chips)

brew tap microsoft/foundrylocal
brew trust microsoft/foundrylocal
brew install foundrylocal


Exporing CLI commands

Try the following Foundry Local CLI commands:

Detect the CLI version:

foundry --version

Expected output:

0.8.119

View the list of CLI commands:

foundry --help

Expected output:

Description:
Foundry Local CLI: Run AI models on your device.
 ðŸš€ Getting started:
 1. To view available models: foundry model list
 2. To run a model: foundry model run <model>

 EXAMPLES:
foundry model run phi-3-mini-4k

 Usage:
foundry [command] [options]

 Options:
-?, -h, --help Show help and usage information
--version Show version information
--license Display foundry license information

Commands:
model Discover, run and manage models
cache Manage the local cache
service Manage the local model inference service

Download a model into local cache:

foundry model download qwen2.5-0.5b

Expected output:

Downloading qwen2.5-0.5b-instruct-generic-gpu:4... 
 . . . T R U N C A T E D . . . 
 [################################## ] 94.85 % [Time remaining: about 1s]
[################################## ] 95.22 % [Time remaining: about 1s]
[################################## ] 95.59 % [Time remaining: about 1s]
[################################## ] 95.96 % [Time remaining: about 1s]
[################################## ] 96.33 % [Time remaining: about 1s]
[################################## ] 96.69 % [Time remaining: about 1s]
[################################## ] 97.06 % [Time remaining: about 1s]
[################################### ] 97.43 % [Time remaining: about 1s]
[################################### ] 97.79 % [Time remaining: about 1s]
[################################### ] 98.16 % [Time remaining: about 1s]
[################################### ] 98.53 % [Time remaining: about 1s]
[################################### ] 98.90 % [Time remaining: about 1s]
[################################### ] 99.27 % [Time remaining: about 1s]
[################################### ] 99.63 % [Time remaining: about 1s]
[####################################] 100.00 % [Time remaining: about 0s]
[####################################] 100.00 % [Time remaining: about 0s] 85.9 MB/s

Tips:
- To find model cache location use: foundry cache location
- To find models already downloaded use: foundry cache ls

List models in local cache:

foundry cache list

Expected output:

💾 qwen2.5-0.5b              qwen2.5-0.5b-instruct-generic-gpu:4

Remove a model from local cache:

foundry cache remove qwen2.5-0.5b

Expected output:

⚠️ This will delete model 'qwen2.5-0.5b (qwen2.5-0.5b-instruct-generic-gpu:4)' from cache.
⚠️ Are you sure you want to delete this model from the local cache? (y/n)
y
Deleted model qwen2.5-0.5b-instruct-generic-gpu:4 from the cache.

Download and run a model:

foundry model run qwen2.5-0.5b

Expected output:

Downloading qwen2.5-0.5b-instruct-generic-gpu:4...
[####################################] 100.00 % [Time remaining: about 0s]  105.2 MB/s
🕛 Loading model...
🟢 Model qwen2.5-0.5b-instruct-generic-gpu:4 loaded successfully

Interactive Chat. Enter /? or /help for help.
Press Ctrl+C to cancel generation. Type /exit to leave the chat.

Interactive mode, please enter your prompt
>

💡 TIP

If you get an error when running a model, it may mean that your hardware is incompatible with the specific model that was downloaded. You can try looking ar variants of that model for different processor configurations. To view the variants for a model (Example: qwen2.5-0.5b), type the following command: 

foundry model info qwen2.5-0.5b

You can then try one of the variants like qwen2.5-0.5b-instruct-generic-cpu with: 
foundry model run qwen2.5-0.5b-instruct-generic-cpu

The above puts the user in a CLI interactive mode. You can then send prompt to the model. Let's ask the model to create for us a C# program that does temperature conversion. Type in the following prompt:

Write a C# console app that converts temperature from C to F and also from F to C.

Expected output:

🧠 Thinking...
🤖 Certainly! Below is a simple console application written in C# that takes user input for Celsius temperature and converts it to either Fahrenheit or vice versa.


using System;
using System.Windows.Forms;

namespace TemperatureConverterApp
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Console.WriteLine("Enter the Temperature (in Celcius): ");
                int celsius = Convert.ToInt32(Console.ReadLine());

                bool convertToFahrenheit = false;
                string result;

                if (Convert.ToBoolean(calculateCtoF(celsius)) == true)
                    result = "Celsius to Fahrenheit: ";
                else
                    result = "Temperature not converted";

                result += $"Celsius {result}";

                if (convertToFahrenheit) 
                {
                    Console.WriteLine($"Result: Fahrenheits");
                    return;
                }

                Console.WriteLine(result);
            }
            catch
            {
                Console.WriteLine("Invalid Input");
            }
        }

        public static bool calculateCtoF(int celsius)
        {
            double fahrenheit = 9/5 * celsius + 32;
            double result = Math.Round(fahrenheit, 1);

            // Round down to the nearest integer since temperatures must be whole numbers
            if (fahrenheit.ToString() != "0")
                return true;
            else
                return false;
        }

        public static bool calculateFtoc(double fahrenheit)
        {
            double celsius = fahrenheit - 32 * 5 / 9;
            double result = Math.Round(celsius, 1);

            // Round down to the nearest integer since temperatures must be whole numbers
            if (celsius.ToString() != "0")
                return true;
            else
                return false;
        }
    }
}

Explanation: 

1. Imports: The code starts with importing necessary namespaces (System and System.Windows.Forms). It's assumed you have this namespace available. 

2. Program Class
    - This contains the main program logic. 

3. calculateCtoF Function
    - Calculates the temperature in Fahrenheit given Celsius temperature. 
    - If successful, calculates the equivalent number of degrees Celsius based on the provided value and rounds it to the closest integer.  
    - Outputs the result along with any additional information like "Celsius" or "Temperature not converted". 

4. calculateFtoc Function
    - Calculates the equivalent temperature in Celcius given the equivalent degrees Fahrenheit. 
    - Same as calculateCtoF, but used for converting degrees Fahrenheit back to Celsius. 

Example Usage: 

If you run the program, pressing the keyboard will take an input to calculate the correct conversion type and output results accordingly. 

Example Input: 25 
    - If calculated using Celsius, it will print: "Celsius", then "25". 
    - If converted to Fahrenheit, it will print: "Temperature not converted", then "25". 

This example only demonstrates basic conversions between the two temperature scales and does not handle invalid inputs like non-numerical characters which would throw exceptions during parsing.

Exit CLI mode, type:

/exit

Stop the Foundry service:

foundry service stop

Expected output:

🔴 Service is stopped.

Start the Foundry service:

foundry service start

Expected output:

🟢 Service is Started on http://127.0.0.1:64398/, PID 9459!

Develop a C# app using Foundry Local SDK

The Foundry Local SDK enables you to ship AI features in your applications that are capable of using local AI models through a simple and intuitive API. The SDK abstracts away the complexities of managing AI models and provides a seamless experience for integrating local AI capabilities into your applications.

dotnet new console -o FoundryLocalConsoleApp
cd FoundryLocalConsoleApp
dotnet add package Microsoft.AI.Foundry.Local
dotnet add package Microsoft.Extensions.Logging
dotnet add package Betalgo.Ranul.OpenAI -v  9.1.0

Add this to the .csproj file right above </PropertyGroup>:

<RuntimeIdentifiers>osx-arm64;osx-x64;win-x64;linux-x64</RuntimeIdentifiers>

Replace Program.cs with this code that asks the qwen2.5-0.5b local AI model the question: Where did coffee come from?:

using Betalgo.Ranul.OpenAI.ObjectModels.RequestModels;
using Microsoft.AI.Foundry.Local;
using Microsoft.Extensions.Logging;

CancellationToken ct = new();

var config = new Configuration {
    AppName = "foundry_local_samples",
    LogLevel = Microsoft.AI.Foundry.Local.LogLevel.Information
};

using var loggerFactory = LoggerFactory.Create(builder => {
    // Intentionally no providers configured; this still yields a valid ILogger instance.
});
ILogger logger = loggerFactory.CreateLogger("FoundryLocalConsoleApp");

// Initialize the singleton instance.
await FoundryLocalManager.CreateAsync(config, logger);
var mgr = FoundryLocalManager.Instance;


// Discover available execution providers and their registration status.
var eps = mgr.DiscoverEps();
int maxNameLen = 30;
Console.WriteLine("Available execution providers:");
Console.WriteLine($"  {"Name".PadRight(maxNameLen)}  Registered");
Console.WriteLine($"  {new string('─', maxNameLen)}  {"──────────"}");
foreach (var ep in eps) {
    Console.WriteLine($"  {ep.Name.PadRight(maxNameLen)}  {ep.IsRegistered}");
}

// Download and register all execution providers with per-EP progress.
// EP packages include dependencies and may be large.
// Download is only required again if a new version of the EP is released.
// For cross platform builds there is no dynamic EP download and this will return immediately.
Console.WriteLine("\nDownloading execution providers:");
if (eps.Length > 0) {
    string currentEp = "";
    await mgr.DownloadAndRegisterEpsAsync((epName, percent) => {
        if (epName != currentEp) {
            if (currentEp != "") {
                Console.WriteLine();
            }
            currentEp = epName;
        }
        Console.Write($"\r  {epName.PadRight(maxNameLen)}  {percent,6:F1}%");
    });
    Console.WriteLine();
} else {
    Console.WriteLine("No execution providers to download.");
}


// Get the model catalog
var catalog = await mgr.GetCatalogAsync();


// Get a model using an alias.
var model = await catalog.GetModelAsync("qwen2.5-0.5b") ?? throw new Exception("Model not found");

// Download the model (the method skips download if already cached)
await model.DownloadAsync(progress =>{
    Console.Write($"\rDownloading model: {progress:F2}%");
    if (progress >= 100f)
    {
        Console.WriteLine();
    }
});

// Load the model
Console.Write($"Loading model {model.Id}...");
await model.LoadAsync();
Console.WriteLine("done.");

// Get a chat client
var chatClient = await model.GetChatClientAsync();

// Create a chat message
List<ChatMessage> messages = new() {
    new ChatMessage { Role = "user", Content = "Where did coffee come from?" }
};

// Get a streaming chat completion response
Console.WriteLine("Chat completion response:");
var streamingResponse = chatClient.CompleteChatStreamingAsync(messages, ct);
await foreach (var chunk in streamingResponse) {
    Console.Write(chunk.Choices[0].Message.Content);
    Console.Out.Flush();
}
Console.WriteLine();

// Tidy up - unload the model
await model.UnloadAsync();

ℹ️ NOTE - Notice model qwen2.5-0.5b in the above code (around line 59). Change this to any other model or variant of your choice.

Expected output:


  Available execution providers:
  Name                            Registered
  ──────────────────────────────  ──────────
  WebGpuExecutionProvider         False

Downloading execution providers:
  WebGpuExecutionProvider          100.0%
Loading model qwen2.5-0.5b-instruct-generic-gpu:4...done.
Chat completion response:
Coffee originated in the Ethiopian Highlands and later spread to other regions due to various factors such as trade, migration, and disease. It''s believed that people first brought coffee from Ethiopia with them when they migrated to other parts of the world. The earliest known records suggest that the first drink made from coffee was consumed by the Shas people in West Africa.

As the demand for coffee grew, more people began to experiment with making their own beverages. By 1750, coffee had been developed into its current form in the Middle East and Asia. It wasn''t until 1826 that an American named Robert Brown invented espresso, which has since become one of the most popular beverages worldwide.

The history of coffee is a story of innovation, trade, and cultural exchange over centuries. Coffee has played a significant role in many societies around the world and continues to be enjoyed today through different methods and traditions.
 

For more information, see the Foundry Local SDK reference.

Saturday, May 16, 2026

Squad with GitHub Copilot CLI: Human-led AI agent teams

What is Squad?

Squad is a team of agents that work on your behalf to conduct specializations like: DevOps, Testing, DB optimization, etc. Squad works with GitHub Copilot CLI. In this article, we will explore Squad by getting it to create ASP.NET Blazor application, then enhance it with more features.

ⓘ NOTE: 

  • This is an experimental project and may change over time.
  • Using Squad can result in the consumption of a sizable amount of AI tokens.

Pre-requisites

In order to proceed with this tutorial, you will need to have the following software installed on your computer:

  1. .NET 10.0 or later
  2. SQLite 
  3. GitHub Copilot CLI
  4. Node.js and npm (version 5.2.0 or higher) 

The GitHub repo for the Squad project is at https://github.com/bradygaster/squad

ⓘ NOTE the following about Squad:

  1. Squad works with GitHub Copilot
  2. You need to have Node.js and npm (version 5.2.0 or higher) installed on your computer in order to setup Squad.
  3. Using Squad can result in the consumption of a sizable amount of AI tokens.

Connect to a SQLite Database

Let's use GitHub Copilot CLI to connect to and explore the Chinook database (a sample database that represents a digital music store).

What is the Chinook Database?

The Chinook database models a digital media store, similar to an old iTunes store. It contains real music data and includes 11 tables:

Table Description
Artist Music artists
Album Albums released by artists
Track Individual songs, including price and duration
Genre Music genres (Rock, Jazz, Pop, etc.)
MediaType Format of the track (MP3, AAC, etc.)
Playlist Named playlists
PlaylistTrack Tracks belonging to each playlist
Customer Store customers
Employee Store employees and their reporting structure
Invoice Customer purchases
InvoiceLine Individual line items on each invoice

Connecting to the Database

  1. Download the Chinook.sqlite database file here 👉Click to download

  2. Create a folder named Chinook and place the downloaded Chinook.sqlite file inside it.

  3. Open your terminal, navigate to the Chinook folder, and launch GitHub Copilot CLI, by typing in:

copilot
        
  1. Wait for the Copilot CLI interface to load. You should see the prompt ready for input.

  2. Once inside Copilot CLI, type the following prompt and press ENTER to establish a connection to the Chinook database. This tells Copilot which database file to use and how to access it.

    Connect to the Chinook.sqlite database using the connection string DataSource=Chinook.sqlite;Cache=Shared;
            
  3. You should see Copilot confirm the connection. If you are asked to trust files in the current folder or asked to run commands, press ENTER to confirm Yes.

Exploring the Database

Once connected, try the following prompts one at a time. After each one, take a moment to look at the results before moving on.

List all tables in the database:

List all the tables in a table format
        

See what is inside a table:

Display data in the Genre table.
        

Ask for insights:

Analyse the data in the database and provide me with some interesting insights.
        

Use SQLite database with ASP.NET app

Let's use GitHub Copilot CLI to build a simple ASP.NET Razor Pages web application that reads and manages data from the Chinook database. You will do this step by step, one prompt at a time.

💡TIP: If you want GitHub Copilot to run commands without always asking for confirmation, enter the command /yolo, which stands for "You Only Live Once".1


Prompt 1 — Create the Project

Type the following prompt inside Copilot CLI and press ENTER:

Create a simple ASP.NET Razor Pages web application using .NET 10 in a folder named Chinook.Web. Do not add any database or authentication yet. 
💡TIP: Wait for Copilot to finish completely before moving on to the next prompt. Rushing to the next step before Copilot is done is the most common cause of errors in this tutorial.

Prompt 2 — Connect the Database

⚠️WARNING: The following prompt connects to your existing Chinook.sqlite database. Do not modify or delete the database file while Copilot is running, as this may cause your data to be lost.

Add Entity Framework Core SQLite to Chinook.Web. Connect it to the existing Chinook.sqlite in the parent folder using connection string "DataSource=../Chinook.sqlite;Cache=Shared;" in appsettings.Development.json. Do not overwrite or delete any existing data.

💡TIP: To verify the app is running correctly, open a new terminal window, navigate to the Chinook.Web folder, and run:

dotnet watch

Your browser should open automatically.


Prompt 3 — Scaffold CRUD Pages

Create a Genre model that matches the existing Genre table in Chinook.sqlite. The SQLite database uses singular table names (e.g. Genre, not Genres), so the model must include a [Table("Genre")] attribute from System.ComponentModel.DataAnnotations.Schema to prevent Entity Framework Core from pluralizing the table name. Scaffold full CRUD Razor Pages for Genre. Add a Genre link to the main navigation menu. 
💡TIP: Go back to the terminal running dotnet watch. Your app should reload automatically. Navigate to the /Genres page in your browser. You should see a list of genres loaded from the Chinook database.

Prompt 4 — Apply the Theme

Replace the default Bootstrap CSS in _Layout.cshtml with the Bootswatch Sketchy theme CDN link from https://bootswatch.com/sketchy/

Your app should now look noticeably different (hand-drawn style buttons and a unique font). Refresh http://localhost:5000/Genres to see the new theme applied.


Prompt 5 — Run the app 

Run the app 

If everything is OK, you should see the Genre list page populated with data from the Chinook database. Try adding, editing, and deleting a genre to confirm that full CRUD functionality is working.

Let's use Squad

Install Squad globally on your computer by typing the follwoing terminal window command:

npm install -g @bradygaster/squad-cli
        

In the Chinook.Web folder created in tutorial number 2 (CRUD App), initialize Squad with:

squad init
        

Start a GitHub Copilot CLI session by typing the following terminal window command:

copilot
        

You must be logged into GitHub in order to use Squad. Type the following command in the input field to login into GitHub:

login

Select GitHub.com by hitting ENTER on 1.

GitHub.com

A message is displayed that a code will be placed in the clipboard and your browser will be used for authentication once you press any key.

authenticate

Your default browser will open to the Device Activation page.

device-activation

Choose your preferred GitHub account then click on Continue.

one-time-code

Enter the one-time code that was given to you in the GitHub Copilot CLI, then click on Continue. Note that it will be different from the code in the image above.

authorize

Click on Authorize github.

mfa

You might be required to go through the multi-function authentication process. Once you are fully authenticated, you should received the below message in your browser:

congrats

We will choose the Squad agent to help us improve the Chinook.Web app. In the input field, type the following command to select an agent:

Choose the Squad agent.

squad-agent

It would be exhausing for the developer to approve every action that agents will be attempting to make. Autopilot mode is a behavioral state where Copilot executes multi-step tasks autonomously until completion. We will set the CLI to work in autopilot mode. Cycle through all the various modes with SHIFT TAB and select autopilot.

autopilot

Enter this prompt:

I like the disney universe of cartoon characters and would like to assign a squad to work on the Chinook.Web project.  
        Review the current state, propose new features, and discuss next steps. 
        

Accept the request for elevated permissions.

permission

💡TIP: If you enter command /tasks, you can observe the individual agents at work.

A long process of autonomous work will commence. Sit back, relax, and watch what is happening. Once everything settles down, you will receive a message that looks like this:

Next steps you requested:
        
           - Review current state: Try "Mickey, review the current project 
          architecture"
           - Propose features: Try "Team, what should we build next?" or "Mickey, 
          propose features for the Chinook database"
           - Discuss next steps: Ask "What features would make the most impact?" or 
          have Mickey analyze the Chinook schema and suggest CRUD pages for other 
          entities (Artists, Albums, Tracks, etc.)
        
          Quick commands to try:
        
           - "Mickey, review the project" — architecture analysis
           - "Team, add CRUD pages for Artists" — parallel fan-out to build a feature
           - "What's in the Chinook database?" — I can answer directly (no spawn 
          needed)
           - "Ralph, status" — check for any work in progress
        
          The team is fully configured, state files are in place, and .gitattributes
          is set up for clean cross-branch merges. Ready to work!
        

Look at the source code, you will notice that much has happened.

  1. A number of skills were added to the .copilot/skills folder:

skills

  1. Workflows were added to the .github/workflows folder:

workflows

  1. Under the .squad folder, in addition to other folders and files, there is an agents folder with our Disney workers:

workers

Read the charter for each of these workers. For example, Mickey's charter in the charter.md file is:

# Mickey — Lead
        
        > Architecture, scope, and quality — the one who sees the whole picture
        
        ## Identity
        
        - **Name:** Mickey
        - **Role:** Lead & Architect
        - **Expertise:** System design, code review, architectural patterns, .NET best practices
        - **Style:** Direct and decisive. Thinks big picture first, details second.
        
        ## What I Own
        
        - Overall project architecture and design decisions
        - Code review and quality gates
        - Technical scope definition and feature planning
        - Cross-module integration and consistency
        
        ## How I Work
        
        - Start with the why, then the what, then the how
        - Push back on scope creep and unnecessary complexity
        - Review others' work with an architectural lens
        - Document key decisions in the team knowledge base
        
        ## Boundaries
        
        **I handle:** Architecture, design reviews, scope decisions, technical leadership
        
        **I don't handle:** Deep implementation details (that's for the specialists), day-to-day bug fixes
        
        **When I'm unsure:** I consult with the appropriate specialist (Donald for backend, Minnie for frontend, Goofy for testing strategy)
        
        **If I review others' work:** On rejection, I may require a different agent to revise (not the original author) or request a new specialist be spawned. The Coordinator enforces this.
        
        ## Model
        
        - **Preferred:** auto
        - **Rationale:** Coordinator selects the best model based on task type — cost first unless writing code
        - **Fallback:** Standard chain — the coordinator handles fallback automatically
        
        ## Collaboration
        
        Before starting work, use the `TEAM ROOT` provided in the spawn prompt. All `.squad/` paths must be resolved relative to this root.
        
        Before starting work, read `.squad/decisions.md` for team decisions that affect me.
        After making a decision others should know, write it to `.squad/decisions/inbox/mickey-{brief-slug}.md` — the Scribe will merge it.
        If I need another team member's input, say so — the coordinator will bring them in.
        
        ## Voice
        
        Opinionated about clean architecture. Will push back on technical debt. Prefers simplicity over cleverness. Thinks in systems, not just features. Not afraid to say "we shouldn't build that."
        

Go ahead and ask for more features. I asked for the following enhancements:

  1. add CRUD pages for Artists
  2. add Sales Dashboard & Reporting
  3. recruit a GitHub DevOps engineer to configure some github actions for CI
  4. add web designer to help make the UI of the entire web app more colorful and compelling
ⓘ NOTE that agents get to choose different models for theie assigned tasks. For example: Mickey is using claude-sonnet-4.6, and Daisy is using claude-opus-4.5, etc.

models

There are instances when one agent waits for other agents to complete their assigned tasks.

wait

The end result is that we now have a web app that is colorful, has artists crud, and a dashboard.

end-result

Here's what the dashboard looks like:

dashboard

To find out token usage, you can type the /usage command. I used 7.5 million tokens. Most were used in understanding the entireity of the code base.

usage

Squad is a very interesting tool and provides us with an insight into the future world of software development.