Squad.Agents.AI 1.0.0 is the stable package version and multi-targets net8.0, net9.0, and net10.0. It uses Microsoft Agent Framework 1.23.0 and GitHub Copilot SDK 1.0.14. Source versioning does not confirm NuGet publication; use the local package instructions below until 1.0.0 is published.
Squad.Agents.AI exposes a Squad team as a Microsoft Agent Framework AIAgent. SquadAgent composes the Squad CLI through the GitHub Copilot SDK, delegates MAF sessions/runs/streaming to the inner Copilot agent, and gives .NET consumers a DI-friendly wrapper instead of hand-rolling CLI process setup.
Public surface:
SquadAgent— sealedAIAgentwrapper over the Copilot-backed inner agent. Supports both non-streaming and streaming viaRunStreamingAsync.SquadAgentOptions— team root, CLI path/args, environment, token, logging, instruction settings, and aConfigureCopilotClientdelegate for advanced SDK customization.SquadConnectionFactory— parses PATH orsquad://connection strings into options.SquadServiceCollectionExtensions— registersSquadAgentand baseAIAgentin DI, with standard and keyed overloads.
Repository: https://github.com/github/squad
dotnet add package Squad.Agents.AI --version 1.0.0If you are consuming the PR before publish, pack it locally and add the generated package source:
dotnet pack src/Squad.Agents.AI/Squad.Agents.AI.csproj -c Release -o nupkgs
dotnet add package Squad.Agents.AI --version 1.0.0 --source ./nupkgs- .NET 8, 9, or 10 for consumers; .NET 10 SDK to build this repository and run the sample.
- GitHub Copilot CLI available on
PATH(copilot --version). - Squad CLI and an initialized Squad team root; see the Squad CLI repo.
- GitHub Copilot authentication through the signed-in user. The quickstart below does not require an app key or environment variable.
For a bounded sample check without authentication, CLI startup, or model calls:
dotnet run --project src\Squad.Agents.AI\samples\Squad.Agents.AI.Sample -- --smokeThis checks default and keyed DI resolution and the client configuration callback. The five live sample flows still require Copilot authentication and may consume credits; the smoke check does not validate live responses or streaming.
using Microsoft.Agents.AI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Squad.Agents.AI;
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddSquadAgent(o =>
{
o.SquadFolderPath = @"C:\path\to\your\team-root";
});
using var host = builder.Build();
var squad = host.Services.GetRequiredService<AIAgent>();
var session = await squad.CreateSessionAsync();
var response = await squad.RunAsync("What can this Squad team do?", session);
Console.WriteLine(response.Text);SquadAgent supports streaming via the MAF RunStreamingAsync method. The inner Copilot-backed agent streams response updates as they arrive from the CLI process:
var squad = host.Services.GetRequiredService<SquadAgent>();
var session = await squad.CreateSessionAsync();
await foreach (var update in squad.RunStreamingAsync("Summarize the team.", session))
{
Console.Write(update.Text);
}Register multiple Squad teams in the same DI container using .NET 8+ keyed services:
builder.Services.AddKeyedSquadAgent("research", o =>
{
o.SquadFolderPath = @"C:\research-team";
});
builder.Services.AddKeyedSquadAgent("platform", o =>
{
o.SquadFolderPath = @"C:\platform-team";
});
// Resolve in a minimal API endpoint:
app.MapGet("/ask-research", async ([FromKeyedServices("research")] SquadAgent agent) =>
{
var session = await agent.CreateSessionAsync();
var response = await agent.RunAsync("What's the latest?", session);
return response.Text;
});Keyed registrations include AddKeyedSquadAgent overloads for service key, optional connection-string name, and lifetime. Keyed and non-keyed registrations can coexist.
Use ConfigureCopilotClient to customize the underlying CopilotClientOptions after Squad applies its standard values. This is the extension point for injecting custom environment variables, providing a BYOK token, or tuning SDK settings:
builder.Services.AddSquadAgent(o =>
{
o.SquadFolderPath = @"C:\team";
o.ConfigureCopilotClient = clientOpts =>
{
// Inject a BYOK token from your own credential store
clientOpts.GitHubToken = myVault.GetSecret("copilot-token");
// Add custom environment variables for the CLI process
clientOpts.Environment = new Dictionary<string, string>
{
["MY_CUSTOM_VAR"] = "value"
};
};
});Routing guard: Squad enforces a hard routing gate — if the delegate changes
Cwd,CliPath, orCliArgs, the original values are restored and a warning is logged. Configure these viaSquadAgentOptionsinstead.
The default path mirrors the base GitHub Copilot SDK examples: leave GitHubToken and GitHubTokenProvider unset, then run with a locally signed-in GitHub Copilot user. For local development, sign in before running the app, for example with gh auth login, the Copilot CLI sign-in flow, or a Copilot-supported local sign-in that the SDK runtime can access.
The SDK documents the credential priority order in Authenticate Copilot SDK and the broader authentication overview. Explicit tokens and environment variables are supported by the SDK, but they are not required for the minimal happy path.
Use GitHubTokenProvider only when the host owns token retrieval, such as Key Vault, managed identity, or CI secret flow scenarios. Use GitHubToken only when you already have a Copilot-supported token in process and cannot use a provider callback. Use ConfigureCopilotClient when you need full control over the SDK's CopilotClientOptions, including BYOK token injection.
AddSquadAgent() reads ConnectionStrings:squad through IConfiguration.GetConnectionString("squad"). In environment variables, use ConnectionStrings__squad.
Named registrations support both connection-string conventions:
| Style | Example | Looks up |
|---|---|---|
| Aspire-style direct (tried first) | AddSquadAgent("research-squad") |
ConnectionStrings:research-squad |
| Legacy prefixed fallback | AddSquadAgent("research") |
ConnectionStrings:squad-research |
So when an Aspire AppHost registers a Squad resource via builder.AddSquad("research-squad", ...) and a downstream project does .WithReference(researchSquad), the consumer can resolve the agent with a single builder.Services.AddKeyedSquadAgent("research-squad") call — the SDK finds the Aspire-injected connection string automatically. Existing consumers using the prefixed form continue to work; the SDK tries the literal name first and falls back to squad-{name} if the direct lookup is empty.
Supported connection string forms:
C:\path\to\team-root
squad://localhost?teamRoot=C%3A%5Cteam&cliPath=C%3A%5Ctools%5Ccopilot.exe&cliArgs=--yolo&env=KEY=value
Parsed URI query keys: teamRoot, cliPath, cwd, cliArgs (semicolon-separated), and env (key=value;key2=value2). Unknown URI host/protocol values are reserved for future use.
SquadAgent exists to wrap a Squad coordinator team, so it passes --agent squad to the underlying copilot.exe child process by default. That tells the CLI to load .github/agents/squad.agent.md as the agent definition — which is what teaches the coordinator to eager-execute, fan out, and dispatch through the task tool. Without it, the CLI uses its built-in generic agent and the coordinator role-plays responses inline instead of spawning real subagents — producing SDK behavior that does NOT match running copilot --agent squad interactively against the same team root.
| Scenario | What the SDK does |
|---|---|
Default — squad.agent.md exists |
Auto-adds --agent squad |
squad.agent.md not found at .github/agents/ |
Silently skips --agent (graceful degradation for not-yet-initialized teams; logs a Debug message) |
Consumer sets AgentFileName = "data" (and file exists) |
Auto-adds --agent data |
Consumer sets AgentFileName = null |
Skips --agent entirely |
Consumer already supplied --agent X in CliArgs |
Respects the explicit value; does not add a second --agent |
CliPath not set (SDK bundled runtime) |
Skips --agent; see below |
When CliPath is not set, the Copilot SDK launches its bundled copilot-runtime embedded host instead of a full interactive Copilot CLI. That host accepts only SDK host flags and exits with copilot-runtime: unsupported argument '--allow-all' for interactive-CLI flags, so SquadAgent does not inject --allow-all or --agent in this mode:
- The coordinator is still selected: the session sets
EnableConfigDiscovery = trueandAgent = "Squad", which resolves.github/agents/squad.agent.mdfrom the team root. - Tool permissions flow through
OnPermissionRequest = PermissionHandler.ApproveAll. RequestExtensionsis set tofalse, because the bundled runtime otherwise fails session creation withextensionSdkPath is required when standalone extensions are requested. Override it viaConfigureSessionif you supply an extension SDK.- Host-supplied
CliArgsare still passed through verbatim, so only use flags the bundled runtime supports.
Set CliPath to a full Copilot CLI to get the --allow-all / --agent defaults described above.
Squad.Agents.AI emits one OpenTelemetry Activity per subagent dispatch out of the box. Hosts that subscribe to the activity source see one squad.subagent {Name} span per spawn, with the subagent name as a tag and timeline annotations (squad.subagent.start, squad.subagent.message, squad.subagent.completed, squad.subagent.failed) marking every state transition.
Two-line wiring is all that is required — no manual callback plumbing:
using OpenTelemetry.Trace;
using Squad.Agents.AI;
builder.Services.AddOpenTelemetry()
.WithTracing(t => t.AddSource(SquadAgentDiagnostics.ActivitySourceName));
builder.Services.AddSquadAgent(o => o.SquadFolderPath = @"C:\team");When the coordinator's task tool spawns specialists, the host's tracer (Jaeger, Zipkin, Application Insights, or the Aspire dashboard's Traces view) shows one squad.subagent span per spawn, each tagged with squad.subagent.name, squad.subagent.display_name, squad.subagent.sdk_agent_id, and squad.subagent.reply_preview — plus timeline events for every lifecycle transition.
Turning telemetry off. Set EmitSubagentActivities = false to suppress Squad's built-in spans (for example, when you want to drive observability entirely from your own callback or avoid double-counting). The OnSubagentTrace callback continues to fire either way — it is the customization seam, independent of telemetry.
builder.Services.AddSquadAgent(o =>
{
o.SquadFolderPath = @"C:\team";
o.EmitSubagentActivities = false; // disable built-in OTel emission
o.OnSubagentTrace = trace => // handle telemetry yourself
{
if (trace.Kind == SquadAgentTraceEventKind.SubagentStarted)
MyMetrics.IncrementSpawn(trace.SubagentName!);
};
});| Option | Purpose |
|---|---|
SquadFolderPath |
Squad team root; PATH connection strings set this and Cwd. |
CliPath / CliArgs |
Override the Copilot CLI executable and add extra CLI flags. When CliPath is unset, the SDK's bundled runtime is used and SquadAgent does not inject --allow-all / --agent (see Bundled runtime). |
Cwd |
Working directory for the Copilot CLI process; defaults to SquadFolderPath. |
Environment |
Additional environment variables for the CLI process. Excluded from JSON serialization; token-pattern keys are redacted in ToString(). |
GitHubToken |
Advanced direct token escape hatch; excluded from JSON serialization and redacted by ToString(). |
GitHubTokenProvider |
Advanced callback for secure token retrieval; wins over GitHubToken. |
ConfigureCopilotClient |
Advanced delegate for customizing CopilotClientOptions. Routing properties are guarded; see BYOK section. |
TraceEvents |
Enables verbose SDK logging and emits a startup warning when enabled. |
AgentName |
Display name for the resulting AIAgent; defaults to Squad. |
AgentFileName |
Name of the agent definition under .github/agents/{name}.agent.md to load via the CLI's --agent flag. Defaults to "squad". Set to null to skip auto-injection; the file-existence check makes this safe to leave on for not-yet-initialized teams. |
Instructions |
Optional system instructions passed to the inner Copilot agent. |
EmitSubagentActivities |
Whether the SDK opens an OpenTelemetry Activity per subagent dispatch and annotates lifecycle events. Defaults to true. Set to false to handle telemetry from your own OnSubagentTrace callback. |
OnSubagentTrace |
Optional callback invoked for every typed SquadAgentTraceEvent. Independent of EmitSubagentActivities — both can be on simultaneously. |
- Credential redaction:
GitHubTokenandEnvironmentvalues whose keys match*TOKEN*,*KEY*,*SECRET*,*HMAC*,*PASSWORD*, or*CREDENTIAL*are always redacted inToString()output. - JSON safety:
GitHubToken,GitHubTokenProvider,Environment, andConfigureCopilotClientare marked[JsonIgnore]and will not appear in JSON serialization output. - Routing guard: The
ConfigureCopilotClientdelegate cannot changeCwd,CliPath, orCliArgs— changes are silently restored to prevent routing the agent to an unintended CLI process. - TraceEvents warning: Enabling
TraceEventslogs a startup warning because verbose SDK traces may include sensitive operational details. - Avoid hardcoded tokens: Never embed tokens in source code. Use
GitHubTokenProviderfor production token retrieval from Key Vault, managed identity, or similar secure stores.
- Default DI lifetime is scoped. An overload accepts any
ServiceLifetime. - DI registers both
SquadAgentand baseAIAgent(non-keyed). Keyed DI registers bothSquadAgentandAIAgentunder the same key. - The package targets .NET 8, 9, and 10 and includes OpenTelemetry activity support.
- The package does not validate that
SquadFolderPathexists; consumers should validate their deployment paths. TraceEventscan log sensitive operational details. Keep it off unless debugging.
lib/net8.0/,lib/net9.0/, andlib/net10.0/, each containingSquad.Agents.AI.dlland XML IntelliSense / API docsbuildTransitive/Squad.Agents.AI.propsfor the pinned Copilot SDK native runtime bridgeREADME.mdfor NuGet.org rendering.nuspecmetadata with authors, tags, repository, and readme pointerLICENSEcopied from the repository root
A runnable console application is included at
src/Squad.Agents.AI/samples/Squad.Agents.AI.Sample/. It demonstrates the five
core integration patterns in one place: basic DI, keyed DI with multiple agents,
the ConfigureCopilotClient delegate, streaming via RunStreamingAsync, and subagent OpenTelemetry observability.
| Prerequisite | Notes |
|---|---|
| .NET 10 SDK | dotnet --version should print 10.x.x |
GitHub Copilot CLI on PATH |
Install from github.com/github/copilot-cli; verify with copilot --version |
| Squad CLI installed | Follow the install guide in the Squad repository README |
| Initialized Squad team root | Run squad init in a directory; this becomes your team root |
| GitHub Copilot authentication | Run gh auth login or copilot auth login once before running the sample |
Set the team root path before running:
# Linux / macOS
export SQUAD_TEAM_ROOT=/path/to/your/team-root
# Windows PowerShell
$env:SQUAD_TEAM_ROOT = "C:\path\to\your\team-root"Run all five flows in sequence:
dotnet run --project src/Squad.Agents.AI/samples/Squad.Agents.AI.Sample/Run a single flow (1–5):
dotnet run --project src/Squad.Agents.AI/samples/Squad.Agents.AI.Sample/ -- --flow=1
dotnet run --project src/Squad.Agents.AI/samples/Squad.Agents.AI.Sample/ -- --flow=2
dotnet run --project src/Squad.Agents.AI/samples/Squad.Agents.AI.Sample/ -- --flow=3
dotnet run --project src/Squad.Agents.AI/samples/Squad.Agents.AI.Sample/ -- --flow=4
dotnet run --project src/Squad.Agents.AI/samples/Squad.Agents.AI.Sample/ -- --flow=5Flow 1 — Basic DI registration — AddSquadAgent registers SquadAgent and the
base AIAgent interface. Resolves the agent from DI, creates a session, calls
RunAsync, and prints AgentResponse.Text.
Flow 2 — Keyed DI (multiple agents) — AddKeyedSquadAgent registers two agents
under keys "alpha" and "beta". Resolution uses
GetRequiredKeyedService<SquadAgent>("alpha").
Flow 3 — BYOK / ConfigureCopilotClient delegate — the delegate receives
CopilotClientOptions after Squad has applied its defaults. The sample merges a custom
environment variable without overriding authentication, model, or session configuration.
Hosts can additionally inject a token from their credential store. The routing gate prevents accidental redirection of
Cwd, CliPath, or CliArgs — configure those on SquadAgentOptions directly.
Flow 4 — Streaming — RunStreamingAsync returns
IAsyncEnumerable<AgentResponseUpdate>. Each update.Text fragment is written to
Console.Write without a newline for live token-by-token output.
Flow 5 — Subagent observability — requests two specialist introductions and prints dispatch callbacks and OpenTelemetry span counts. A response alone does not prove that subagents were dispatched; inspect the captured events and spans.
| Error | Cause | Fix |
|---|---|---|
GitHub Copilot CLI was not found on PATH |
copilot binary is missing or not on PATH |
Install from github.com/github/copilot-cli; verify with copilot --version |
Authentication failed / 401 |
Copilot CLI is not signed in | Run gh auth login or copilot auth login |
SquadFolderPath does not exist |
SQUAD_TEAM_ROOT points to a non-existent path |
Set SQUAD_TEAM_ROOT to an initialized Squad team directory |
The system cannot find the file specified (Win32Exception) |
Copilot CLI not found | Same as first row above |
Build error: Package Squad.Agents.AI not found |
Sample uses a project reference; ensure you run from the repo root | Run dotnet build from the repository root or pass --project src/Squad.Agents.AI/samples/Squad.Agents.AI.Sample/ |
- Root repo: https://github.com/github/squad
- Microsoft Agent Framework: https://github.com/microsoft/agents
- GitHub Copilot SDK authentication: https://github.com/github/copilot-sdk/blob/main/docs/auth/authenticate.md
- GitHub Copilot CLI: https://github.com/github/copilot-cli
- Changelog: https://github.com/github/squad/blob/main/CHANGELOG.md
License: MIT.