A starter template for building AI-powered agents with the GitHub Copilot SDK deployed to Azure Container Apps.
Copilot SDK Agent is a full-stack TypeScript application that demonstrates how to build a conversational AI agent using the GitHub Copilot SDK. It pairs an Express API backend with a React frontend to deliver a chat interface that streams responses from a Copilot-powered agent with custom tool support.
- Backend (
src/api/) — Express server that creates a Copilot SDK session, registers custom tools, and streams responses over Server-Sent Events (SSE). - Frontend (
src/web/) — React + Vite single-page app with a chat window, message input, and dark/light mode support.
- Streaming SSE chat — Real-time token-by-token responses via the Copilot SDK
- Custom tool support — Extensible tool system using
defineTool()(seesrc/api/tools/) - React frontend — Modern chat UI with dark/light mode and responsive design
- One-command local dev — Run all services with
azd app runviaazd app - One-command Azure deployment — Deploy to Azure Container Apps with
azd up - Foundry AI agent — Optional Foundry-hosted agent via the
azd ai agentextension with BYOM (Bring Your Own Model) support - Docker-based containerization — Multi-stage Dockerfile for optimized production builds
- Automatic GitHub token provisioning — Preprovision hook retrieves your token via
ghCLI
| Tool | Version | Purpose |
|---|---|---|
| pnpm | 10+ | Fast, disk-efficient package manager |
| Node.js | 24+ | Runtime for the API and build tooling |
GitHub CLI (gh) |
Latest | Provides the GITHUB_TOKEN for the Copilot SDK |
Azure Developer CLI (azd) |
Latest | Provisions and deploys Azure resources |
| Docker | Latest | (Optional) Local container testing |
GitHub CLI setup:
gh auth login
gh auth refresh --scopes copilot1. Install Azure Developer CLI (azd)
2. Install the azd app extension
azd config set alpha.extensions on
azd extension source add -n jongio -t url -l https://jongio.github.io/azd-extensions/registry.json
azd extension install jongio.azd.appazd init -t jongio/copilot-sdk-agent
azd app runThe prerun hook automatically retrieves your GITHUB_TOKEN from the gh CLI via scripts/get-github-token.mjs (the same script also runs as a preprovision hook during azd up). azd app installs dependencies, starts both services, and provides a real-time dashboard. Open the URL shown in the dashboard output to start chatting.
This repo includes a devcontainer configuration for one-click setup:
The devcontainer automatically installs Node.js 24, pnpm, Azure Developer CLI (azd), Azure CLI, GitHub CLI, Docker, and all recommended VS Code extensions. After opening, authenticate the GitHub CLI with the copilot scope, then run:
gh auth login
gh auth refresh --scopes copilot
azd app runRun services manually (without azd app)
# Set your GitHub token
export GITHUB_TOKEN=$(gh auth token)
# Install dependencies
cd src/api && pnpm install && cd ../web && pnpm install && cd ../..
# Start the API server (in one terminal)
cd src/api && pnpm dev
# Start the web dev server (in another terminal)
cd src/web && pnpm devcopilot-sdk-agent/
├── src/
│ ├── agent/ # Foundry hosted agent
│ │ ├── agent.yaml # Agent definition (model, instructions, tools)
│ │ ├── app.py # Agent entry point
│ │ ├── Dockerfile # Agent container (Python 3.12)
│ │ └── requirements.txt # Python dependencies
│ ├── api/ # Express backend
│ │ ├── index.ts # App entry point — Express setup, CORS, SPA fallback
│ │ ├── routes/
│ │ │ ├── chat.ts # POST /chat — Copilot SDK session & SSE streaming
│ │ │ └── health.ts # GET /health — Health check endpoint
│ │ ├── tools/
│ │ │ └── greet.ts # Example custom tool using defineTool()
│ │ ├── Dockerfile # API container (Node.js + pnpm)
│ │ ├── package.json # API dependencies
│ │ └── tsconfig.json # TypeScript config (server)
│ └── web/ # React frontend
│ ├── App.tsx # Root component
│ ├── App.css # App styles with dark/light mode
│ ├── main.tsx # React entry point
│ ├── index.html # HTML shell
│ ├── index.css # Global styles & CSS custom properties
│ ├── types.ts # Shared TypeScript types
│ ├── components/
│ │ ├── ChatWindow.tsx # Message display with streaming indicator
│ │ ├── MessageInput.tsx# Input field with submit handling
│ │ └── ThemeToggle.tsx # Dark/light mode toggle
│ ├── hooks/
│ │ ├── useChat.ts # Chat state management & SSE consumption
│ │ └── useTheme.ts # Theme preference with localStorage
│ ├── Dockerfile # Web container (Vite build + nginx)
│ ├── package.json # Web dependencies
│ └── vite.config.ts # Vite configuration
├── infra/ # Azure infrastructure (Bicep)
│ ├── main.bicep # Subscription-scoped deployment
│ ├── main.parameters.json # Parameter mappings for azd
│ ├── resources.bicep # All Azure resources (ACR, Container Apps, Key Vault, etc.)
│ └── ...
├── scripts/ # Automation scripts
│ └── get-github-token.mjs # Hook: injects GITHUB_TOKEN from gh CLI (runs on prerun and preprovision)
├── azure.yaml # Azure Developer CLI service definition
├── LICENSE # MIT License
├── CONTRIBUTING.md # Contribution guidelines
└── README.md
Tools let the Copilot agent call your own functions. To add a new tool:
1. Create a tool file in src/api/tools/:
// src/api/tools/weather.ts
import { defineTool } from "@github/copilot-sdk";
export const weather = defineTool("weather", {
description: "Get the current weather for a city",
parameters: {
type: "object",
properties: {
city: { type: "string", description: "City name" },
},
required: ["city"],
},
handler: async (args: { city: string }) => {
// Replace with a real API call
return { temperature: "72°F", condition: "Sunny", city: args.city };
},
});2. Register the tool in src/api/routes/chat.ts:
import { greet } from "../tools/greet.js";
import { weather } from "../tools/weather.js";
// In createSession():
const session = await client.createSession({
model: "gpt-4o",
systemMessage: { mode: "append", content: "..." },
tools: [greet, weather],
});The agent will automatically discover and use the new tool based on its description and parameter schema.
This template includes a Foundry-hosted agent (src/agent/) deployed via the azd ai agent extension. When the AZURE_AI_FOUNDRY_PROJECT_ENDPOINT environment variable is set, the API backend automatically uses BYOM (Bring Your Own Model) to route requests through your Foundry-deployed model instead of the default Copilot model.
The Foundry agent is defined in src/agent/agent.yaml and deployed as a CopilotAgent service. Infrastructure provisioning creates an Azure AI Services account and project in infra/resources.bicep.
azd upThis single command handles the entire deployment pipeline:
- Preprovision hook — Retrieves your
GITHUB_TOKENfrom theghCLI and stores it in theazdenvironment - Provisions infrastructure — Creates Azure Container Registry, Container Apps Environment, Key Vault, Application Insights, and a managed identity (using Azure Verified Modules)
- Builds and pushes — Builds the Docker image and pushes it to the provisioned ACR
- Deploys — Deploys the container to Azure Container Apps with the
GITHUB_TOKENsecurely referenced from Key Vault
To initialize from the template without cloning:
azd init --template jongio/copilot-sdk-agent
azd upThe easiest way to run locally is with azd app, which starts all services, installs dependencies, and provides a real-time dashboard:
azd app runYou can also run services individually:
| Command | Directory | Description |
|---|---|---|
azd app run |
repo root | Start all services with auto-dependency install and dashboard |
pnpm dev |
src/api |
Start the Express server with hot reload (via tsx --watch) |
pnpm dev |
src/web |
Start the Vite dev server with HMR for the React frontend |
pnpm build |
src/api |
Compile the Express server |
pnpm build |
src/web |
Bundle the React frontend |
graph LR
User -->|SSE streaming| ReactUI["React UI<br/>(Vite SPA)"]
ReactUI -->|SSE streaming| API["Express API<br/>POST /chat"]
API -->|Tool execution| Tools["Custom Tools<br/>(defineTool)"]
API --> SDK["Copilot SDK<br/>createSession"]
SDK --> Copilot["GitHub Copilot<br/>Service"]
Azure deployment topology:
graph TB
subgraph Azure Resource Group
subgraph Container Apps Environment
Agent["Agent App"]
end
ACR["Container Registry<br/>(ACR)"]
KV["Azure Key Vault<br/>(GITHUB_TOKEN)"]
MI["Managed Identity"]
AI["App Insights"]
end
Agent -->|pulls images| ACR
Agent -->|reads secrets| KV
MI -->|authenticates| Agent
Agent -->|sends telemetry| AI
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
This project is licensed under the MIT License — see the LICENSE file for details.