Getting Started with the GitHub Copilot SDK — Part 1: Client Lifecycle & Connection

I've been spending a lot of time with the GitHub Copilot SDK for .NET lately, and I
want to walk through it the way I actually learned it:
One small, self-contained concept at a time.
This is Part 1 of a series. The companion code lives on GitHub at
egarim/GettingStartedWithGithubCopilotSDK
— each numbered folder is a demo you can run on its own.
Everything in this SDK starts with one object: the client. So that's where we start.
What the client is
The CopilotClient is the entry point. It owns the underlying Copilot process (over a
Stdio transport), handles authentication, and is the thing you query for everything else.
Before you can create a session or send a single message, you have to start the client
and make sure it's connected.
So this first demo is the whole lifecycle:
Create → Start → Use → Stop → Dispose.
Plus the difference between a polite shutdown and a hard kill.
Create it
var client = new CopilotClient(new CopilotClientOptions
{
UseLoggedInUser = true, // reuse your VS Code / `gh auth login` credentials
Logger = logger
});
UseLoggedInUser = true is the friendly path. It reuses the GitHub credentials you're
already logged in with — no auth plumbing by hand.
At this point the client exists but isn't connected. Its state is Created.
Start it, and prove it's alive
await client.StartAsync(); // connect — state becomes Running
var pong = await client.PingAsync("hello"); // health check — echoes back + a timestamp
StartAsync spins up the process and connects. The state moves Created → Running.
PingAsync is your basic health check: send a message, get the same message back plus a
server timestamp. If ping works, the pipe is open.
Look before you leap
Before doing real work, confirm three things — version, auth, and the models you actually
have:
var status = await client.GetStatusAsync(); // SDK + protocol version
var auth = await client.GetAuthStatusAsync(); // IsAuthenticated, auth type, message
var models = await client.ListModelsAsync(); // gpt-4o, claude-sonnet-4, ...
Two things I learned the hard way:
If
GetAuthStatusAsyncsays you're not authenticated — stop.
Nothing past that point will work, and the errors downstream won't point you back here.
ListModelsAsyncis subscription-dependent.
What you see depends on your Copilot plan. Don't hard-code a model name without checking
it's in the list. (This is also how you'll pick a model when we create sessions in Part 2.)
Shut it down — nicely
await client.StopAsync(); // graceful: request shutdown, wait for cleanup
await client.DisposeAsync(); // release resources
// emergency brake:
await client.ForceStopAsync(); // hard kill, immediate
The state machine is small enough to keep in your head:
Created → Starting → Running → Stopping → Stopped
↑ ForceStop (immediate)
Prefer StopAsync. It asks the server to shut down and waits for cleanup, which frees
resources on the server side too. Keep ForceStopAsync for when something is wedged.
Takeaways
- The
CopilotClientis the root object: create →StartAsync→ use →StopAsync→DisposeAsync. UseLoggedInUser = truereuses your GitHub login. Least friction.Ping,GetStatus,GetAuthStatus,ListModelsare your "is everything OK?" toolkit
before you do anything real.- Shut down gracefully. Keep
ForceStopfor emergencies.
That's the foundation. In Part 2 we actually use the client — creating sessions,
handling the event stream, and holding a real multi-turn conversation with the model.
Want to follow along? You'll need the .NET 10 SDK and GitHub Copilot access (log in
via VS Code orgh auth login). Thendotnet run --project 01.ClientDemofrom the
course repo.