For several months now, I’ve been working exclusively in the GitHub Copilot app at work. When it first came out, it made managing multiple sessions across projects so much easier than many Copilot CLI windows hogging up my desktop. But it didn’t take away the fact that those sessions may have still needed supervision.

Here is how I approach that, using a small, fictional set of tasks to make the choices easier to understand.

Start with a decision, not a session

Suppose that I have three things to do:

  • Fix a percentage-formatting bug in a report,
  • Explore multiple ways to simplify a system’s configuration options,
  • Establish whether a container can load in its intended remote environment.

On the surface, they look like three implementation tasks.

The formatting bug has a bounded code change, and a testable outcome. The configuration question is still a design choice, not yet ready to implement. And the container task is primarily an evidence question, it may run locally but we can’t establish locally that it will run remotely.

With the GitHub Copilot app, I’d could easily start the configuration session as a Chat outside of a dedicated project to gain a level of context before I jumped into a dedicated session to build the plan around my repo’s shape. Chats are a dedicated place to explore without committing to dedicated branches or working trees on a repo.

Demonstrating GitHub Copilot app workflows using the Chat function

I would ask for alternatives, the constraints each one preserves, and possibly hypothesis-driven experiments that distinguishes them. I wouldn’t immediately jump into exploring two implementations in nested, parallel sessions simply because it was available. If I then authorize the experiments, that becomes a different stage of work inside a project, each with its own bounded session, the same starting source, and a comparable question to answer.

Using projects to manage your repositories

If you want to be organized, I highly recommend adding your repositories as projects in the GitHub Copilot app. This is extremely useful if you want to go from a chat into a project-driven session, as the parent session is able to create nested sessions in a project instead of you copying context over from the Chat to a dedicated session manually.

In Projects, click +, select the repo (either by local folder or from remote), and then use that registered Project in the sidebar to create a new session with either a new working tree, using the local clone, or in a cloud sandbox.

For unrelated code changes, I usually want separate working trees. They separate the cloned repo files and make diff easier to inspect. For the formatting fix example, this is a sensible choice.

Using the local clone instead means sharing its current working tree. That can be appropriate, but it needs deliberate ownership, particularly if you’re running multiple agents over that same local working tree. You don’t want two sessions independently rewriting the same files, discovering the conflict, and getting stuck in a loop of confusion. Trust me, I’ve had this happen on multiple occasions, and its not only annoying but an unnecessary waste of AI credits.

As without AI, a worktree also doesn’t isolate credentials, your cloud environments, package feeds, databases, or every accessible tool. Two perfectly separate working trees can still publish to the same destination. The container task therefore needs explicit boundaries regardless. For example:

Inspect the built container and the target environment requirements. Do not publish the container, change credentials, or modify the remote environment. If any requirements for the container are unavailable, report the missing evidence and stop.

Pick a session mode based on your certainty

The GitHub Copilot app provides three core options for session mode: Plan, Interactive, and Autopilot. I mix these into my workflows according to the decisions still open, rather than treating more autonomy as my goal.

For the configuration options, Plan is useful while the intended behavior is still unknown. For a focused fix where I want to inspect consequential choices as they arise, I can use Interactive. And for a well-specified work item with clear checks and stop conditions, Autopilot can carry more of the execution.

For the formatting session, I want the agent to know what I will accept:

Fix percentage formatting for a partial result. Preserve the existing output contract. Add a regression test, run the focused tests, and show that the new test detects the original faulty calculation. Do not change unrelated formatting or publish a release. Return the diff, the commands run, their results, and anything not established.

There is an output, a boundary, and a proof requirement. The last sentence also leaves room for an honest incomplete result.

In addition to session mode, where I already have a suitable custom agent installed or part of my repo, I can select it through the agent picker. If you haven’t already started to look at how to build custom agents, add canvases, or MCP servers to GitHub Copilot yet, I highly recommend taking a look at their documentation on this in more detail. For my standard engineering workflow, I purposefully built a plugin with a suite of dedicated agents and skills that make recurring expectations in planning and implementation easier to apply. That way, I simply supply the task-specific outcome or work item I’m expecting said agent to work on.

If you’re interested in learning more about how to setup agents and skills in your own repo, I cover my high-level setup in Teaching AI Agents to Work on Your Codebase.

Parallelize what can reach a useful result independently

If we take the examples from before being part of the same project, each of those tasks can probably proceed independently of each other. Their outputs do not carry direct dependencies, however, let’s think about scenarios where they may.

Two configuration experiments can run separately once I have approved that experiment. But I need to preserve the comparison: same starting point, explicit differences, and equivalent checks where possible. If one experiment gets extra requirements, I no longer have the original comparison.

The container investigation could also pose a challenge. If it needs an artifact that another task has not produced, asking it to keep trying does not create useful parallelism. It can inspect prerequisites now, then stop at the dependency.

Because I now have this potential to have my agents work on multiple work items simultaneously, I use a very simple question before I do anything: can this work produce something I can evaluate without guessing what another unfinished work item will do?

If not, I either make the prerequisite an explicit input or defer it. Or if you want to get really fancy with GitHub Copilot, have an orchestrator agent session manage your work item dependency chain for you, chaining from one work item to the next as their dependencies are cleared!

Intervene when session evidence answers a different question

This is where I find most of my useful human intervention happens with agents and GitHub Copilot.

In a recent experiment, I had authorized two alternatives in separate worktrees from the same starting source. Local fixtures helped exercise the implementation, but they did not establish the remote integration I was trying to investigate.

I narrowed on alternative to the smallest useful probe of that boundary. That didn’t authorize changes to the other’s agreed scope.

The remote attempt then reached an acquisition step and failed on an authentication prerequisite before the intended execution. That was useful evidence about where the attempt stopped. It was not evidence that the integration worked, and it didn’t establish a successful run between the alternatives.

If we take the container task, the equivalent intervention would be:

The fixture shows that the container at runtime can execute locally. It doesn’t show that the remote runtime host loaded this container. Keep the local result, but separate it from the runtime claim. Identify the smallest, authorized check of the boundary. If access prevents that check, stop.

Notice that the response is not simply “keep going, and try harder”. It changes the evidence question and preserves what has already been learned.

My broader AI guardrails article explains why stopping can be useful. In regular work, the practical move is to name the missing boundary before another round of activity make it harder to see.

Read completion as a claim to inspect

And when a session finishes, I inspect the artifact before accepting the agent’s summarization. The question is not whether it sounds complete, but whether the returned evidence matches the assignment.

For these three hypothetical workstream, that means different things for me:

  • Formatting fix – focused diff, executed regression test, and failure with the faulty calculation retored
  • Configuration alternatives – comparable source baselines, preserved requirements, results of the experiments
  • Remote container execution – exact analysis of attempt to retrieve remote runtime host logs, and if received, a receipt from the intended host

A real NuGet packaging workstream I was tracking remained blocked on artifact and runtime evidence after the authorized local work was exhausted. Keeping that state explicit was more useful than calling it complete or generating adjacent work to keep the session busy.

I want to finish a pass over my sessions knowing which artifacts I can accept, which decisions belong to me, and which tasks should remain untouched until a dependency changes.

That is the useful outcome of running several workstreams. Not more activity on screen, but fewer ambiguous claims about what the work has achieved.


Discover more from James Croft

Subscribe to get the latest posts sent to your email.

James Croft

Author James Croft

James is a senior software engineer at Microsoft with over 10 years experience designing and building large-scale, distributed, cloud-native systems. He's deeply experienced in C#, Python, and TypeScript, with specialization in AI agent architectures, retrieval-augmented generation (RAG), and production-grade Azure systems.

More posts by James Croft

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.