Skip to main content

Level Up Your Copilot CLI Statusline with Oh My Posh

In previous posts, I covered how to customize the GitHub Copilot CLI statusline. First with the default options, then witha dynamic script. Today we're taking it a step further: integrating Oh My Posh to bring full prompt theming support to your Copilot CLI session.

Oh My Posh has native support for GitHub Copilot CLI, so you get all its theming power (Nerd Font icons, color gradients, diamond-style segments,…) rendering right inside the Copilot CLI statusline.

What Is Oh My Posh?

Oh My Posh is a cross-shell prompt engine that lets you define richly styled prompts using a JSON (or YAML/TOML) configuration file. You probably know it from PowerShell or bash, but it also ships a dedicated copilot subcommand specifically for integration with GitHub Copilot CLI's statusLine feature.

Prerequisites

  • Oh My Posh installed (winget install JanDeDobbeleer.OhMyPosh  see docs)
  • A Nerd Font installed and set as your terminal font (for icons to render correctly)
  • GitHub Copilot CLI with statusline support (the STATUS_LINE feature flag)

Wiring it up

The integration is a one-liner in your Copilot CLI config (check your %USERPROFILe%\.copilot folder). Point the statusLine.command at oh-my-posh copilot, enable the feature flag, and set experimental: true:

{
  "statusLine": {
    "type": "command",
    "command": "oh-my-posh copilot"
  },
  "feature_flags": {
    "enabled": ["STATUS_LINE"]
  },
  "experimental": true
}

Restart Copilot CLI (or run /restart in an open session) to pick up the change. Oh My Posh will now render your configured prompt theme in the statusline on every refresh.


Tip: You can point Oh My Posh at a config file specifically tailored for Copilot CLI — keeping it separate from your shell prompt theme:

"command": "oh-my-posh copilot --config /path/to/copilot.omp.json"

The copilot_cli segment

Oh My Posh reads the session JSON that Copilot CLI pipes to stdin on every statusline refresh. It exposes that data through a dedicated copilot_cli segment type, which you add to your .omp.json theme like any other segment.

Here's the minimal sample configuration from the docs:

{
  "type": "copilot_cli",
  "style": "diamond",
  "leading_diamond": "",
  "trailing_diamond": "",
  "foreground": "#111111",
  "background": "#fee898",
  "template": "  {{ .Model.DisplayName }}  {{ .TokenGauge }} "
}

This gives you a styled, icon-adorned segment showing the active model name and a visual token gauge — out of the box.

What properties are available?

The segment exposes a rich set of properties you can reference in your template. Here are the most useful ones:

Property What it shows
.Model.DisplayName Human-readable model name, e.g. claude-sonnet-4.6 (medium)
.TokenGauge Visual gauge of remaining context capacity, e.g. ▰▰▰▱▱
.TokenGaugeUsed Visual gauge of used context capacity
.TokenUsagePercent % of context window used (0–100)
.RemainingPercent % of context window remaining
.RemainingTokensCount Raw count of remaining tokens
.FormattedTokens Human-readable total token count, e.g. 1.2K
.FormattedDuration Total session duration, e.g. 2m 5s
.SessionName Custom session name (empty if not set

Customizing the gauge

The token gauge characters are configurable via segment options:

{
  "type": "copilot_cli",
  "gauge_marked_char": "█",
  "gauge_unmarked_char": "░",
  "template": "  {{ .Model.DisplayName }} {{ .TokenGauge }} "
}

This replaces the default / with solid block characters. Use .TokenGauge and .TokenGaugeUsed — rather than the raw Percentage methods — to ensure your custom characters are respected.

A more complete example

Here's a template that surfaces model, token gauge, usage percentage, and session duration in one segment:

{
  "type": "copilot_cli",
  "style": "diamond",
  "leading_diamond": "",
  "trailing_diamond": "",
  "foreground": "#111111",
  "background": "#fee898",
  "template": "  {{ .Model.DisplayName }}  {{ .TokenGauge }} {{ .TokenUsagePercent }}%  {{ .FormattedDuration }}"
}

You can combine this with other Oh My Posh segments (git, path, time, etc.) exactly as you would in any other shell prompt config — the copilot_cli segment is just one more building block in your theme.

How it works under the hood

The oh-my-posh copilot command reads the session JSON from stdin, caches the parsed data, renders your configured prompt template, and writes the result back to Copilot CLI as the statusline output. Copilot CLI sends a fresh JSON payload on every refresh cycle, so the segment always reflects live session state.

The segment only renders when Copilot CLI is actively providing data — so it won't show up if Oh My Posh is also driving your regular shell prompt.

Wrapping up

Oh My Posh integration is the natural next step after getting comfortable with the raw statusLine JSON config. You get:

  • The full Oh My Posh theming ecosystem (styles, colors, icons, diamonds)
  • Live Copilot CLI session data (model, tokens, duration, cost) exposed as template properties
  • A config you can version and share alongside the rest of your dev environment dotfiles

The full segment reference is at ohmyposh.dev/docs/segments/cli/copilot-cli. And if you haven't set up Nerd Fonts yet, that's the one prerequisite worth doing first.

More information

Always know where you stand: Setting up a live status line in GitHub Copilot CLI - Part 1

Always know where you stand: Setting up a live status line in GitHub Copilot CLI - Part 2

Home | Oh My Posh

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,...