Skip to main content

GitHub Copilot CLI Tips & Tricks — Part 2: Session management

In the first post we covered the different modes in Copilot CLI. This time we're looking at something that becomes essential once you're doing serious work in the CLI: session management. Sessions let you pause, resume, and organize your work — across terminal restarts, across machines, and across multiple concurrent workstreams.

What is a session?

Every time you launch Copilot CLI, you're working inside a session. A session captures your full conversation history, the tool calls Copilot made, the files it touched, and the permissions you granted — all stored locally under ~/.copilot/session-state/. Sessions are identified by a UUID and automatically receive an AI-generated name based on your first message, making them easy to identify later.

Most important is that sessions persist after you close the CLI. That means nothing is lost when you shut down your terminal — you can always pick up right where you left off.

Resuming a session

Pick up where you left off

The most important session management flag. When you launch with --resume, Copilot presents an interactive picker listing your saved sessions — searchable with / — so you can select the one you want to continue.

copilot --resume

All your conversation context, granted permissions, and history are restored exactly as you left them.

Jump straight back in

If you just want to resume your most recent session without going through the picker, use --continue:

copilot --continue

This is the fastest way back into an active workstream after a restart or a break.

Switch sessions without exiting

You don't have to exit the CLI to switch sessions. The /resume slash command lets you jump to a different session mid-conversation — it opens the same picker UI as --resume, without breaking your current terminal process.

/resume

This is particularly useful when you're juggling multiple features or bugs at the same time.

Naming and organizing sessions

By default, sessions are named based on your first message. But for longer-running workstreams, you'll want to give them meaningful names yourself.

Use the /session slash command to rename the current session:

/session rename "Upgrade to .NET 10"

Named sessions are much easier to find in the /resume picker, especially when you have several active workstreams going at once.


Monitoring your session

Check your token and request consumption

At any point during a session you can call /usage to see a summary of how much you've used:

  • Premium requests consumed in the current session
  • Session duration
  • Number of files modified

This is handy for keeping an eye on consumption during long autopilot runs.

Context window management

Copilot CLI automatically compresses your conversation history in the background as it approaches 95% of the token limit, without interrupting your work. If you want to trigger this manually — for example, after completing a big chunk of work and starting a new phase — you can use:

/compact

This keeps things lean for the next part of the task.


Use /session checkpoints #checkpointnumber to view the compaction summary.





Sharing and exporting sessions

Export to Markdown

The /share command exports the current session to a Markdown file, including the full conversation history, tool calls, and outputs. This is useful for documentation, handoffs, or just keeping a record of a complex debugging session.

/share

Copilot will write the session history to disk.




Publish to GitHub gist

For non-interactive use cases — like CI/CD pipelines or automated documentation — you can export a session directly to a GitHub Gist using the /share-gist slash command:

/share-gist

Copilot returns a URL to the created Gist, making it easy to share with teammates or link in a PR.

Wrapping up

Sessions are what make Copilot CLI feel like a persistent coding partner rather than a stateless tool. Once you get into the habit of naming sessions, using --continue to resume quickly, and switching between workstreams with /resume, it becomes a natural part of how you manage work in the terminal.

In the next post, we'll look at running tasks in parallel.

More information

Session State & Lifecycle Management | github/copilot-cli | DeepWiki

Session Management & History | github/copilot-cli | DeepWiki

Tracking GitHub Copilot's sessions - GitHub Docs

Popular posts from this blog

Podman– Command execution failed with exit code 125

After updating WSL on one of the developer machines, Podman failed to work. When we took a look through Podman Desktop, we noticed that Podman had stopped running and returned the following error message: Error: Command execution failed with exit code 125 Here are the steps we tried to fix the issue: We started by running podman info to get some extra details on what could be wrong: >podman info OS: windows/amd64 provider: wsl version: 5.3.1 Cannot connect to Podman. Please verify your connection to the Linux system using `podman system connection list`, or try `podman machine init` and `podman machine start` to manage a new Linux VM Error: unable to connect to Podman socket: failed to connect: dial tcp 127.0.0.1:2655: connectex: No connection could be made because the target machine actively refused it. That makes sense as the podman VM was not running. Let’s check the VM: >podman machine list NAME         ...

Cache stampede: when our cache turned against us

While investigating some performance issues, we ran into an ASP.NET Core API that cached a fairly expensive aggregation query for 60 seconds. Under normal load, that was fine: one request rebuilds the cache, everyone else reads from it. Under peak load, dozens of requests would arrive in that same expiry window, all see a cache miss, and all fire the same expensive query in parallel. The database didn't like that. That was the moment when our caching layer stopped helping and started hurting. A burst of requests comes in at the same time, all miss the cache, and all go hammer the database or the downstream API at once. That's a cache stampede . The cache was supposed to protect our backend, and for a few hundred milliseconds it did the opposite. Why this happens IMemoryCache.GetOrCreate (and its async sibling) looks like it protects you, but it doesn't add any locking on its own. Look at the naive version: public async Task<Report> GetReportAsync(string key) ...

A complex system designed from scratch never works

A few years ago, I worked as an architect on a big mainframe rewrite. I still count it as one of my failures. Not because the technology was wrong, but because I couldn't convince the management team to simplify the approach. Years later, the organization is still struggling to get the new system up and running. I left the project at the time, because I couldn't put my name behind an approach that would take very long and cost a lot of money without a working system to show for it along the way. Gall’s Law That memory keeps coming back to me, because it's a textbook case of Gall's Law playing out in real life. Gall's Law , from John Gall's Systemantics , states it plainly: A complex system that works is invariably found to have evolved from a simple system that worked. A complex system designed from scratch never works, and it cannot be patched to make it work. You have to start over with a simple system that works. What does that mean in practice,...