A cartoon person holding hands with a robot both with multiple speech bubbles

Building Your First Extension

Brian A. Randell
Brian A. Randell // Staff Developer Advocate // GitHub

In this module, you will learn how to build your first extension. When building your extension today, you can choose two core scenarios. One build a GitHub App and it will work in GitHub.com, Visual Studio Code, and Visual Studio 2022 on Windows seamlessly and out of the box. Or two, you can build a GitHub Copilot Extension for Visual Studio Code if you need deep, in client experiences and possibly, you already have a native VS Code extension.

Building a production ready extension requires you consider security, availability, and more. Please visit https://github.com/copilot-extensions for more samples including samples on custom function calling, OAuth flows, and more. In addition, check back here for updates to this Learning Pathway once the GitHub Copilot Extension program leaves beta.

Build an Extension as a GitHub App

Creating a private GitHub Copilot extension involves setting up a GitHub App that interacts with Copilot through the provided APIs. The first step is to define the functionality of your extension—whether it’s fetching data from an internal API, automating a repetitive task, or providing custom suggestions based on your company’s codebase. Once you’ve defined your goals, you can create the app, configure permissions, and test it in your environment. Building a private extension allows you to tailor Copilot to you and your team’s specific needs without making the extension available to the broader public.

Building in a User Account

In this walkthrough you’ll build your first GitHub Copilot Extension as a GitHub App using a GitHub Codespace. You’ll create an ASP.NET Core 8.0 minimal web API using C# for this particular example where your extension will return its responses as if it were a pirate.

Note this provided code sample is written to get you running as quickly as possible and may make sacrifices for production readiness to keep it simple.

1. The first thing you’ll want to decide is your App’s name. You will be putting the name inside your code and using it later when you define your GitHub App on github.com.

Note: The name cannot be longer than 34 characters.

Your app's name will be shown in the user interface when your app takes an action. Uppercase letters will be converted to lowercase, with spaces replaced by -, and accents ignored. For example, My APp Näme would display as my-app-name.

The name must be unique across GitHub. You cannot use the same name as an existing GitHub account, unless it is your own user or organization name.

2. Using your web browser, log into your GitHub account.

3. Navigate to your profile’s home page (https://github.com/yourhandle)

4. Create a new Git repo in your account:

  • Choose your account as the owner

  • Provide a name and description

  • You can make the repo public or private—your choice

  • Place a check next to Add a README file

  • From the Add .gitignore list choose Visual Studio

  • Choose a license that works for you

5. Once the repository is ready, click the down arrow on the right of the <> Code button.

6. Select the Codespaces tab, and then click theto open the menu.

New Codespace dropdown

7. From the menu, select New with options.

8. Here you can adjust the options like pick more cores or change the region. The defaults should be good enough but feel free to adjust based on your needs.

9. Click Create codespace. Wait for the Codespace to be created.

You’ll be using the Codespace environment “as-is” with no customizations or optimizations. You can however add any number of extensions to have a custom experience like Github Copilot, GitHub Copilot Chat, and the Microsoft C# Dev Kit.

10. Once the Codespace is running, access the Terminal window.

11. You should be in a folder like /workspaces/reponame on the main branch. Create a new folder called src by typing the following and pressing Enter:

mkdir src

12. Next change into the directory by typing the following and pressing Enter:

cd src

13. In the Terminal window, create a web service project, replacing extensionname with the name of your extension that you defined earlier in step 1.

dotnet new web -o extensionname

14. Next, change into the directory where your source lives (which will be the name of your extension, NOT the word extensionname) by typing the following and pressing Enter:

cd extensionname

You’ll now add a reference to the GitHub Octokit library which makes it easier to work with the GitHub API from C#.

15. Type the following and press Enter:

dotnet add package Octokit --version 13.0.1

There are additional Octokit libraries for JavaScript, Ruby, Go, and more. Visit https://github.com/octokit for more information.

16. Open Program.cs from the Explorer.

17. Modify the existing code in line 4 to say “Hello Copilot!” instead of the existing message. The new line should look like as follows:

app.MapGet("/", () => "Hello Copilot!");

18. Create a new record file called Message.cs with the following body:

public record Message
{
    public required string Role { get; set; }
    public required string Content { get; set; }
}

Copilot will provide data containing the role (system, assitant, or user) and the message data.

19. Create a new record file called Request.cs with the following body:

public record Request
{
    public bool Stream { get; set; }
    public List<Message> Messages { get; set; } = [];
}

20. Back in Program.cs, add the following using directives to the top of the file:

using Microsoft.AspNetCore.Mvc;
using Octokit;
using System.Net.Http.Headers;

21. Still in Program.cs, add variables with their default values, making sure to replace extensionname with the real name of your extension. You will want this code to be above the line of code that shows app.Run();:

string yourGitHubAppName = "extensionname";
string githubCopilotCompletionsUrl = 
    "https://api.githubcopilot.com/chat/completions";

22. Still in Program.cs, add the following code to expose an agent endpoint for Copilot to access. You will want this code to be above the line of code that shows app.Run();:

app.MapPost("/agent", async (
    [FromHeader(Name = "X-GitHub-Token")] string githubToken, 
    [FromBody] Request userRequest) =>
{



}

Note: you can call the endpoint any valid name of your liking.

At this point, your Program.cs source file should look like this:

using Microsoft.AspNetCore.Mvc;
using Octokit;
using System.Net.Http.Headers;



var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();



app.MapGet("/", () => "Hello Copilot!");


// make sure you change the App Name below
string yourGitHubAppName = " extensionname ";
string githubCopilotCompletionsUrl = 
    "https://api.githubcopilot.com/chat/completions";



app.MapPost("/agent", async (
    [FromHeader(Name = "X-GitHub-Token")] string githubToken, 
    [FromBody] Request userRequest) =>
{



});

app.Run();

23. You can make sure you don’t have any typos or errors by going to the Terminal and running the following command:

dotnet build

Note, as you complete the rest of the steps, you will use this command to make sure you’ve not made any mistakes.

24. Identify the user using the GitHub API token provided in the request headers.

var octokitClient = 
    new GitHubClient(
        new Octokit.ProductHeaderValue(yourGitHubAppName))
{
    Credentials = new Credentials(githubToken)
};
var user = await octokitClient.User.Current();

25. Now it’s time to insert special  system messages.The first is to acknowledge the user using their GitHub login handle. The second is to have make the extension ‘talk like Blackbeard the Pirate’. You’ll add them in the message list.

userRequest.Messages.Insert(0, new Message
{
    Role = "system",
    Content = 
        "Start every response with the user's name, " + 
        $"which is @{user.Login}"
});
userRequest.Messages.Insert(0, new Message
{
    Role = "system",
    Content = 
        "You are a helpful assistant that replies to " +
        "user messages as if you were Blackbeard the Pirate."
});

26. Use the HttpClient class to communicate back to Copilot. To keep the example simple, the code constructs one on every request. This is not optimal for production situations..

var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = 
    new AuthenticationHeaderValue("Bearer", githubToken);
userRequest.Stream = true;

27. Use Copilot's LLM to generate a response to the user's messages.

var copilotLLMResponse = await httpClient.PostAsJsonAsync(
    githubCopilotCompletionsUrl, userRequest);

28. The last bit of code needed is to stream the response straight back to the user.

var responseStream = 
    await copilotLLMResponse.Content.ReadAsStreamAsync();
return Results.Stream(responseStream, "application/json");

29. In order for a user to install your extension as a GitHub app, you need to provide a callback endpoint. Add the following code for the callback endpoint. You will want this code to be above the line of code that shows app.Run();:

app.MapGet("/callback", () => "You may close this tab and " + 
    "return to GitHub.com (where you should refresh the page " +
    "and start a fresh chat). If you're using VS Code or " +
    "Visual Studio, return there.");

30. Return to the Terminal window, and run the following command:

dotnet build

You should have 0 Warnings and 0 Errors. If you want, you can commit your changes, and optionally push them.

It’s now time to test your web app to make sure it runs. You still have more work to call the agent from Copilot Chat. This will just be a quick test.

31. In the Terminal run the following command:

dotnet run

You will see a message pop up telling you that your application is running. You’ll see two choices. The first is Open in Browser. The second is Make Public.

Message "Your application running on port 5010 is available" with buttons "Open in Brower" and "Make public"

32. Choose Open in Browser. A new tab will open and you should see your message “Hello Copilot!”

This lets you quickly see that your service works. But, you need to do a bit more configuration before you can test the actual Copilot related code.

33. Before you close the tab showing the message, copy the full URL and save it somewhere like a text file. Once you’ve saved it, close the tab and return to your Codespace.

34. In the Terminal, press Ctrl+C to stop the app from running.

You now need to create a GitHub App for your extension.

35. Open a new browser tab and navigate to your GitHub account at https://github.com.

36. In the upper-right corner of any page on GitHub, click your profile photo.

37. You are configuring this for a personal account, so click Settings.

38. In the left sidebar, click Developer settings.

39. In the left sidebar, click GitHub Apps.

40. Click New GitHub App.

41. Under GitHub App name, enter a name for your app. This should be the name you chose in step 1 above.

Reminder: The name cannot be longer than 34 characters.

Your app's name will be shown in the user interface when your app takes an action. Uppercase letters will be converted to lowercase, with spaces replaced by -, and accents ignored. For example, My APp Näme would display as my-app-name.

The name must be unique across GitHub. You cannot use the same name as an existing GitHub account, unless it is your own user or organization name.

42. Optionally, under Description, type a description of your app. Users and organizations will see this description when they install your app.

43. Under Homepage URL, enter a URL for your app.

You can use:

  • Your app's website URL.

  • The URL of the person that owns the app (like their public GitHub page).

  • The URL of the repository where your app's code is stored, if it is a public repository.

44. Under Callback URL, which will be your server's hostname (aka forwarding endpoint) that you copied from your browser earlier. Because you’re using Codespaces, It will look something like this with callback at the end:

https://funny-name-5abcde6zyxwvu7a-1111.app.github.dev/callback

Naturally, this is only for development and testing. You’ll want a proper hosting environment for real use.

45. Under Webhook deselect Active.

Webhooks let your app subscribe to events happening in a software system and automatically receive a delivery of data to your server whenever those events occur. Webhooks are used to receive data as it happens, as opposed to polling an API (calling an API intermittently) to see if data is available. Your extension will not use them which is why you’re unchecking this option.

46. Finally, click Create GitHub App.

Now that you’ve created the app, you need to adjust its Permissions.

47. In the left sidebar, click Permissions & events.

48. Expand the Account permissions option.

You only need one permission for your extension to be usable by a user via GitHub Copilot. If however, you want to access additional data on behalf of the user on GitHub, you’ll need to adjust the permissions accordingly. This should be part of your extension design and planning process.

49. In the dropdown menu, to the right of GitHub Copilot Chat item, select Read-only.

50. Scroll down and click Save changes.

The last step before you can install and test requires you configure settings for Copilot to find access extension.

51. In the left sidebar, click Copilot.

52. Under URL enter your server's hostname (aka forwarding endpoint) that you copied from your browser earlier. Because you’re using Codespaces, It will look something like. You need to add agent at the end like the following:

https://funny-name-5abcde6zyxwvu7a-1111.app.github.dev/agent

53. In the Inference description, provide a string that you want the user to see if they access your extension from Visual Studio Code or Visual Studio 2022. 

For example: I talk like a pirate

Note: In the future, this will be used for a machine-ready description, used to infer your App's capabilities.

54. Click Save.

55. In your GitHub App settings, in the left sidebar, click Install App.

56. Click the Install button next to your account (you account should be the only one visible at this time).

57. Leave this tab open.

58. Switch back to your Codespace.

59. In the Terminal and running the following command:

dotnet run

You will see a message pop up telling you that your application is running. You’ll see two choices again. The first is Open in Browser. The second is Make Public.

Message "Your application running on port 5010 is available" with buttons "Open in Brower" and "Make public"

60. Choose Make Public.

You can now test your extension from Copilot!

61. Follow along below.

  • If you have access to GitHub Copilot Enterprise, on any page on GitHub.com, click the GitHub Copilot icon on the page. The Copilot Chat panel is displayed.

  • If you don’t have a GitHub Copilot Enterprise license, or if you prefer to test from a client IDE, open the Copilot Chat panel in VS Code or Visual Studio 2022. This assumes you have either a GitHub Copilot Individual or GitHub Copilot Business license or trial.

62. Invoke your extension from the Copilot Chat panel by typing @EXTENSIONNAME, replacing any spaces in the extension name with -, then press Enter.

63. If this is your first time using the extension, you will be prompted to authenticate. Follow the steps on screen to authenticate your extension.

Because you’re using a Codespace, you’ll get a warning from GitHub:

You are about to access a development port served by someone’s codespace.

This is your Codespace so it’s OK.

64. Click Continue.

65. Ask your extension a question in the chat window.

For example, What is the software development lifecycle?

You should get a very nice answer written in a “pirate voice”.

66. Ask your extension a non-programming question in the chat window. For example, Tell me a pirate dad joke.

You will most likely be told “The response was filtered due to the prompt not being programming related. Please modify your prompt and retry.” This is expected as GitHub Copilot is focused on software development workflows and not general Q&A.

67. When you’re done testing, stop your running app.

68. Close your Codespace.

69. Go to https://github.com/codespaces and stop your codespace.

And there you have it. Your first GitHub Copilot Extension running as a GitHub App!


Building for GitHub using Your Organization’s Account

Building an extension for your organization is almost entirely the same. The biggest difference is how you configure your GitHub app. Look at the example on creating your first extension or visit https://github.com/copilot-extensions for more samples.

Once you have a testable extension, you’ll need to do the following.

1. Open a new tab and navigate to your GitHub account at https://github.com.

2. In the upper-right corner of any page on GitHub, click your profile photo.

3. You are configuring this for an organization, so click Your organizations.

4. To the right of the organization name you want to use, click Settings.

5. In the left sidebar, click Developer settings.

6. In the left sidebar, click GitHub Apps.

7. Click New GitHub App.

8. Under GitHub App name, enter a name for your app.

Reminder: The name cannot be longer than 34 characters.

Your app's name will be shown in the user interface when your app takes an action. Uppercase letters will be converted to lowercase, with spaces replaced by -, and accents ignored. For example, My APp Näme would display as my-app-name.

The name must be unique across GitHub. You cannot use the same name as an existing GitHub account, unless it is your own user or organization name.

9. Optionally, under Description, type a description of your app. Users and organizations will see this description when they install your app.

10. Under Homepage URL, enter a URL for your app.

You can use:

  • Your app's website URL.

  • The URL of the organization that owns the app (such as your public GitHub page or your company’s home page).

  • The URL of the repository where your app's code is stored, if it is a public repository.

11. Under Callback URL, put your server's fully qualified HTTPS-enabled hostname and callback endpoint.

12. Under Webhook deselect Active.

Webhooks let your app subscribe to events happening in a software system and automatically receive a delivery of data to your server whenever those events occur. Webhooks are used to receive data as it happens, as opposed to polling an API (calling an API intermittently) to see if data is available. Your extension will not use them which is why you’re unchecking this option.

13. Finally, click Create GitHub App.

Now that you’ve created the app, you need to adjust its Permissions.

14. In the left sidebar, click Permissions & events.

15. Expand the Account permissions option.

You only need one permission for your extension to be usable by a user via GitHub Copilot. If however, you want to access additional data on behalf of the user on GitHub, you’ll need to adjust the permissions accordingly. This should be part of your extension design and planning process.

16. In the dropdown menu, to the right of GitHub Copilot Chat item, select Read-only.

17. Scroll down and click Save changes.

The last step before you can install and test requires you configure settings for Copilot to find your extension.

18. In the left sidebar, click Copilot.

19. Under URL enter your server's hostname and extension endpoint.

20. In the Inference description, provide a string that you want the user to see if they access your extension from Visual Studio Code or Visual Studio 2022. 

21. Click Save.

22. In your GitHub App settings, in the left sidebar, click Install App.

23. Click the Install button next to your organization name (you organization should be the only one visible at this time). However, you can publish the extension to the marketplace or the public once you’ve got it working and tested.

At this point, anyone in your organization who has a valid GitHub Copilot license can access and test your extension.


Building for VS Code

If you build your extension as a GitHub App, it will automatically show up in the Copilot Chat window for users when they type @ and the extension name. It just works. Your app just needs to be configured for the right level of visibility and optionally published if it’s meant for someone besides the developer or organization who built it.

However, for developers building extensions for Visual Studio Code who want to create deep integration, you can program the VS Code APIs which provide access to native extensions to interact with the Copilot Chat interface and more. The process begins with setting up a VS Code extension using the official extension development tools. From there, developers can use the Chat and Language Model APIs to create interactive features that respond to user inputs in real time. Whether it’s generating code snippets, providing documentation, or suggesting improvements, the key is to make the extension context-aware so that it enhances the developer’s experience within VS Code.

Visit https://code.visualstudio.com/api/extension-guides/chat for details.


Building for Visual Studio

To develop a GitHub Copilot extension that functions within Visual Studio2022, you can create a GitHub App using the instructions in the “Build an Extension as a GitHub App” section above. GitHub Apps that have been approved by the user or organization will appear in Visual Studio's Copilot Chat allowing users to interact with the extension using the chat window or inline chat in Visual Studio.

ide showing code

Extension authors can leverage the robust features and integrations provided by GitHub, ensuring that their extension can interact efficiently with the Copilot ecosystem.


Sharing and Publishing

Once your extension is ready, you need to determine with whom you will share it (if at all).

Manual Publishing

In the section “Build an Extension as a GitHub App”, you can find the instructions for creating a GitHub App which controls your extensions basic visibility.

Anyone can install GitHub Apps on their personal account.

Organization owners can install GitHub Apps on their organization.

Admins of repositories that are owned by an organization can also install GitHub Apps on the organization if they only grant the app access to repositories that they are an admin of and if the app does not request any organization permissions or the "repository administration" permission. Organization owners can prevent outside collaborators who are repository admins from installing GitHub Apps.

Organization members who are not organization owners or repository admins can still select the organization during the install process. Instead of installing the app, GitHub will send a notification to the organization owner to request the organization owner to install the app.

The "app manager" role in an organization does not give a person the ability to install a GitHub App in the organization.

If your GitHub App is private, you can make it public by going to your app’s settings, and in the Advanced section, click the Make Public button.

Marketplace Publishing

Once you have a working extension, it’s up to you if you want to publish your extension to the world. Depending on the type of GitHub Copilot Extension you’ve built, this could be the GitHub Marketplace or the Visual Studio Code Marketplace. This section will focus on the GitHub Marketplace for Copilot Extensions built as GitHub Apps. 

For Visual Studio Code, you can find more information about that marketplace and publishing at https://code.visualstudio.com/api/working-with-extensions/publishing-extension.

The publishing process for the GitHub Marketplace involves packaging your extension, submitting it for review, and adhering to GitHub’s guidelines for Marketplace apps. Publishing to the Marketplace makes your extension available to the broader GitHub community, allowing others to benefit from your work. Additionally, you can choose to offer your extension for free or as a paid product, depending on your goals.

Please see https://docs.github.com/en/copilot/building-copilot-extensions/managing-the-availability-of-your-copilot-extension for more information.

Up next: Partnering with GitHub on your Extension

Get started with GitHub Copilot