Skip to main content

Posts

Configuring Copilot CLI Isolation via the GitHub Copilot SDK

In the previous post, we walked through local sandboxing in the Copilot CLI: enable it with /sandbox enable , tune filesystem and network rules through the TUI, and your agent's shell execution is isolated by Microsoft MXC. Simple, useful, done. But if you're building with the Copilot SDK, embedding the agent runtime into your own .NET application, you can't type /sandbox enable into a session you're programmatically orchestrating. So the question becomes: how do you get the same isolation guarantees when you own the host? The good news: sandbox support is coming to the SDK as a preview feature. The entry point is Session.Rpc.Options.UpdateAsync , and it lets you push a sandbox configuration into a running session from code. Preview caveat : this API is behind the experimental surface of the SDK. It's real, it works, but the shape may change before it stabilises. Treat it as preview-quality and don't build production contracts on top of it just yet. Wha...
Recent posts

Local sandboxing in the GitHub Copilot CLI

There's a moment in every agentic workflow where you pause and think: wait, what exactly is Copilot allowed to touch right now? For a long time the answer was: pretty much everything under your working directory and whatever shell commands it decides to run to get the job done. That was fine when Copilot was mostly suggesting code. It's a different story when it's running tools, executing scripts, and modifying files on your behalf. As of June 2026, GitHub has an answer: local sandboxing , now in public preview. It doesn't replace good judgment about what you ask Copilot to do, but it does put a real isolation boundary between the agent's tool execution and the rest of your machine. Let’s explore this feature… Why do we need this? The Copilot CLI has evolved significantly since GA. What started as a smart terminal assistant now has Autopilot mode, /plan , fleet parallelism, rubber duck, and a full agentic harness underneath. When you run Copilot in Autopil...

Why my Azure DevOps scheduled pipeline never ran

I set up a scheduled pipeline in Azure DevOps. The YAML was valid. No errors on save. I waited patiently for the cron to fire. Nothing happened… The culprit turned out to be a single line I'd added for a completely legitimate reason trigger: none . The setup The pipeline looked roughly like this: trigger: none schedules: - cron: "0 2 * * 1-5" displayName: Nightly weekday build branches: include: - main always: true The intent was straightforward: I didn't want CI runs on every push, so I explicitly disabled that with trigger: none . And I wanted the pipeline to run on a schedule. Seems fine, right? Except it never ran. What's actually happening Here's the thing that isn't obvious until you read the docs carefully (or waste an afternoon debugging): in Azure DevOps YAML pipelines, trigger is specifically the CI trigger — the thing that fires on code pushes. schedules is a completely separate concept. So whe...

GitHub Copilot SDK Deep Dive: CopilotClientMode

By default, the CopilotClient starts in CopilotCli mode. That means the full Copilot CLI persona is active — which includes a lot: All built-in tools available (subject to the ToolSet filtering you do per session) Host integration enabled: the CLI picks up your local ~/.copilot/ config, agents directory, plugins, and AGENTS.md files if they exist The default system prompt with the full Copilot identity Co-author trailers added to git commits Storage backed by the local filesystem at the default path For a developer using the SDK on their own machine to automate their own workflows, this is perfect. The agent behaves exactly like Copilot CLI would interactively. Context flows in from their environment, their local agent configs are respected, their Copilot persona is preserved. The multi-tenant problem The moment you start running the SDK as a service — where one process handles sessions for multiple users or tenants — default mode becomes a liability. ...

Shining a light on .NET versions across our organisation with OpenTelemetry – The Azure Monitor edition

In a previous post I showed how to add the .NET runtime version as an OpenTelemetry resource attribute: ResourceBuilder.CreateEmpty() .AddService($"{_sofaSettings.ApplicationName}-{_sofaSettings.EnvironmentName}") .AddAttributes(new Dictionary<string, object> { ["deployment.environment"] = _sofaSettings.EnvironmentName, ["service.name"] = _sofaSettings.ApplicationName, ["runtime.dotnet.version"] = Environment.Version.ToString() }) .Build(); The idea was clean: attach facts about what is running directly to the resource, and let OpenTelemetry carry them along with every trace, metric, and log automatically. Unfortunately, there is a catch. The problem Azure Monitor's OpenTelemetry exporter only maps a fixed set of well-known resource attributes onto Application Insights fields. service.name and service.namespace become Cloud Role Name, service.instance.id becomes Cloud Role Insta...

GitHub Copilot SDK Deep Dive: Controlling built-in tools with toolset

This post is part of a follow-up series to my GitHub Copilot SDK blog series . After wrapping up the main series I was left with a list of features that deserved more than a passing mention. This is the second post about the built-in tools. When you create a session using the SDK, the agent has access to two distinct categories of tools: Custom tools are the ones you define yourself — your CopilotTool.DefineTool(...) registrations, the available skills and MCP tools. These are the application-specific capabilities you build. Built-in tools are what the Copilot CLI brings to the table out of the box: file reading, file writing, shell execution, web fetching, web search, and a handful of others. These power the agentic loop that makes Copilot useful without you having to implement everything from scratch. By default, when you call CreateSessionAsync , both categories are available. And by default, built-in tools that could cause side effects — writing files, executing sh...

GitHub Copilot SDK Deep Dive: Surgical system prompt customization

This post is part of a follow-up series to my GitHub Copilot SDK blog series . After wrapping up the main series I was left with a list of features that deserved more than a passing mention. First up: SystemMessageConfig , and specifically the mode that most tutorials gloss right over. The temptation of Replace When you first discover that the Copilot SDK lets you control the system prompt, the obvious instinct is to reach for SystemMessageMode.Replace . Full control, clean slate, no surprises — what's not to like? var session = await client.CreateSessionAsync(new SessionConfig { Model = "gpt-5", SystemMessage = new SystemMessageConfig { Mode = SystemMessageMode.Replace, Content = "You are a helpful assistant." } }); However there is a big problem with adding this line. When you replace the system prompt wholesale you are not just customizing Copilot, you are evicting it. The carefully tuned defaults around tool use, safet...