Oh-My-Posh Token Usage Segment

June 7, 2026 · View on GitHub

Display your AI token usage (today and last 30 days) directly in your terminal prompt, powered by the @rajbos/ai-engineering-fluency CLI.

Example output in your prompt:

 󱊤 1.2K today · 4.5K month · 45.3K 30d 

The segment reads local session files on your machine — no internet connection or API token required. It tracks tokens from VS Code Copilot Chat, Claude Code, Gemini CLI, OpenCode, and all other supported editors.


How It Works

The CLI's segment command outputs a compact formatted string. Oh-my-posh calls it via the {{ cmd }} template helper and caches the result, so your prompt stays fast.

Two caches work together:

CacheLocationTTLPurpose
Oh-my-posh segment cachein-memory, per shell session5 min (configurable)Prevents calling the CLI on every keystroke
CLI segment cache~/.copilot-token-tracker/omp-segment-cache.json5 min (configurable)Prevents re-parsing session files when OMP cache expires

Method 2 (env vars) warning: Do not add a "cache" block to the env var segment in your OMP theme. OMP's segment cache stores the rendered string for the full duration — so if Set-PoshContext updates $env:COPILOT_TOKENS_TODAY, the prompt still shows the stale cached value until the OMP cache expires. Since Set-PoshContext already controls the refresh rate, the OMP cache only adds extra staleness here without any benefit.

A session parsing run (cache miss) typically takes < 1 second.


Prerequisites

  1. Node.js 22+nodejs.org
  2. Oh-my-poshohmyposh.dev/docs/installation
  3. The CLI installed globally:
npm install -g @rajbos/ai-engineering-fluency

Verify it works:

ai-engineering-fluency segment
# e.g.: 1.2K today · 4.5K month · 45.3K 30d

Note: If you use npx instead of a global install, replace "ai-engineering-fluency" with "npx" and add "-y", "@rajbos/ai-engineering-fluency" as additional arguments in the cmd call below. npx is significantly slower due to package resolution on first run.


Method 1: Using {{ cmd }}

Note: The {{ cmd }} template function is not available in all oh-my-posh builds. If you see invalid template text in your prompt, your version does not support it — use Method 2 instead.

This is the cleanest approach if your OMP version supports it. Add the segment config to your oh-my-posh theme file.

Step 1: Find your theme file

# Show the currently active theme path
$env:POSH_THEME

# Or export your current config to edit it
oh-my-posh config export --output "$env:USERPROFILE\.omp.json"

Step 2: Add the segment

Open your theme JSON (or YAML/TOML) and add the following to a segments array inside a block. The content of segment.omp.json can be pasted directly:

{
  "type": "text",
  "style": "diamond",
  "leading_diamond": "\ue0b6",
  "trailing_diamond": "\ue0b4",
  "foreground": "#ffffff",
  "background": "#005ca5",
  "cache": {
    "duration": "5m",
    "strategy": "session"
  },
  "template": " \uec1e {{ cmd \"ai-engineering-fluency\" \"segment\" }} "
}

The \uec1e character is the Copilot icon from Nerd Fonts. Remove it (or replace with 🤖) if you are not using a Nerd Font.

Step 3: Reload your shell

# Reload your profile
. $PROFILE

# Or open a new terminal window

Use this if {{ cmd }} is not supported in your OMP version, or if you want more control over the output.

Step 1: Add the hook to your PowerShell profile

Copy the function from posh-hook.ps1 into your $PROFILE:

# Open your profile to edit
notepad $PROFILE

Paste the Set-PoshContext function at the end of the file, then add a call to it immediately after the function definition:

# ... Set-PoshContext function above ...

# Pre-populate token env vars so the first prompt render shows values
Set-PoshContext

Without this, the segment shows empty values on the first prompt after every new terminal or profile reload (OMP reads env vars before the hook fires on the very first render).

Save the file.

Step 2: Add the environment-variable segment to your theme

{
  "type": "text",
  "style": "diamond",
  "leading_diamond": "\ue0b6",
  "trailing_diamond": "\ue0b4",
  "foreground": "#ffffff",
  "background": "#005ca5",
  "template": " \uec1e {{ .Env.COPILOT_TOKENS_TODAY }} today · {{ .Env.COPILOT_TOKENS_MONTH }} month · {{ .Env.COPILOT_TOKENS_30D }} 30d "
}

The hook updates $env:COPILOT_TOKENS_TODAY, $env:COPILOT_TOKENS_MONTH, and $env:COPILOT_TOKENS_30D at most once every 5 minutes.


Style Variants

Powerline style (arrow separators)

{
  "type": "text",
  "style": "powerline",
  "powerline_symbol": "\ue0b0",
  "foreground": "#ffffff",
  "background": "#005ca5",
  "cache": { "duration": "5m", "strategy": "session" },
  "template": " \uec1e {{ cmd \"ai-engineering-fluency\" \"segment\" }} "
}

Plain / no background

{
  "type": "text",
  "style": "plain",
  "foreground": "#005ca5",
  "cache": { "duration": "5m", "strategy": "session" },
  "template": "\uec1e {{ cmd \"ai-engineering-fluency\" \"segment\" }} "
}

Hide when no data

{
  "type": "text",
  "style": "diamond",
  "leading_diamond": "\ue0b6",
  "trailing_diamond": "\ue0b4",
  "foreground": "#ffffff",
  "background": "#005ca5",
  "cache": { "duration": "5m", "strategy": "session" },
  "template": "{{ $out := cmd \"ai-engineering-fluency\" \"segment\" \"--hide-zero\" }}{{ if $out }} \uec1e {{ $out }} {{ end }}"
}

Options Reference

ai-engineering-fluency segment [options]

Options:
  --ttl <minutes>   Segment cache TTL in minutes (default: 5)
  --refresh         Force refresh — bypass the segment output cache
  --hide-zero       Output nothing when both token counts are zero
  --no-cache        Also bypass the underlying session file cache
  -h, --help        Show help

Force a refresh

# Refresh the segment output cache immediately
ai-engineering-fluency segment --refresh

# Force a full re-parse of all session files
ai-engineering-fluency --no-cache segment --refresh

Local Validation

Test the CLI output directly

# Check basic output
ai-engineering-fluency segment

# Force refresh to see current numbers
ai-engineering-fluency segment --refresh

# Inspect the cache file
Get-Content "$env:USERPROFILE\.copilot-token-tracker\omp-segment-cache.json" | ConvertFrom-Json

Preview the segment in your theme

# Export your current config (if you haven't already)
oh-my-posh config export --output "$env:TEMP\test.omp.json"

# Add the segment to test.omp.json (open in your editor)
code "$env:TEMP\test.omp.json"

# Preview the prompt without changing your active theme
oh-my-posh prompt print primary --config "$env:TEMP\test.omp.json"

# Full debug output showing all segment values
oh-my-posh debug --config "$env:TEMP\test.omp.json"

Measure render time

# Time a single prompt render (OMP cache cold)
oh-my-posh cache clear
Measure-Command { oh-my-posh prompt print primary --config "$env:TEMP\test.omp.json" }

# Time a render with OMP cache warm (should be near-instant)
Measure-Command { oh-my-posh prompt print primary --config "$env:TEMP\test.omp.json" }

Activate the test theme in your shell

oh-my-posh init pwsh --config "$env:TEMP\test.omp.json" | Invoke-Expression
# Open a new terminal to test, then restore your normal theme

Troubleshooting

SymptomLikely causeFix
Command not found: ai-engineering-fluencyCLI not installed globallynpm install -g @rajbos/ai-engineering-fluency
Segment shows 0 today · 0 month · 0 30dNo session files foundRun ai-engineering-fluency diagnostics to check paths
Segment shows invalid template text{{ cmd }} not supported in your OMP versionSwitch to Method 2
Segment shows today · month · 30d without valuesSet-PoshContext not called before first renderAdd Set-PoshContext call at end of $PROFILE after the function definition
Segment never updatesOMP cache too longSet cache.duration to "1m" or use --hide-zero
Stale numbersCLI cache still validRun ai-engineering-fluency segment --refresh
Prompt shows stale data even after refreshOMP cache block on a Method 2 env var segmentRemove the "cache" block from the env var segment — OMP caches the rendered string, bypassing env var updates from Set-PoshContext
Icon shows as a box / ?Not using a Nerd FontReplace \uec1e with 🤖 or remove the icon
Prompt slows downOMP cache not set (Method 1 only)Add "cache": {"duration": "5m", "strategy": "session"} to the {{ cmd }} segment

Publishing / Sharing

The oh-my-posh theme marketplace is closed to new submissions, but you can share your setup:

If you'd like to contribute this as a native Go segment to the oh-my-posh project (so it appears in the official docs), the contribution guide is at ohmyposh.dev/docs/contributing/segment. A native Go segment would call exec.Command("ai-engineering-fluency", "segment") and parse its output, making it available as a first-class "type": "copilot-tokens" (or similar) segment.

GitHub Copilot CLI Statusline (Experimental)

GitHub Copilot CLI has an experimental STATUS_LINE feature that calls a local command and renders its output at the bottom of the Copilot terminal UI. This folder includes ready-to-use scripts that combine the standard Copilot session data (context tokens, session duration, line changes) with your total daily / 30-day token usage from ai-engineering-fluency.

Credit: Setup pattern from Scott Hanselman's gist.

Example statusline:

main +2/-1 > ctx 123.5k/200.0k > ######.... > 00:12:34 > +42/-8 > 12.9M today · 45.3M month · 1443.5M 30d

Files

FilePurpose
statusline.cmdWindows wrapper — points statusLine.command at the PowerShell script
statusline.ps1Reads Copilot's JSON stdin, sets env vars, calls ai-engineering-fluency segment, renders via oh-my-posh
statusline.omp.jsonCompact oh-my-posh theme — git, context gauge, duration, changes, token totals

Requirements

In addition to the prerequisites above:

  • GitHub Copilot CLI with the experimental STATUS_LINE feature flag
  • oh-my-posh available on PATH (oh-my-posh version should return output)

Setup

Step 1 — Copy the files to your Copilot folder

$dest = "$env:USERPROFILE\.copilot"
New-Item -ItemType Directory -Force $dest | Out-Null

# Adjust the source path to match where you cloned this repo
$src = "path\to\ai-engineering-fluency\omp-segment"
Copy-Item "$src\statusline.cmd"      $dest
Copy-Item "$src\statusline.ps1"      $dest
Copy-Item "$src\statusline.omp.json" $dest

Step 2 — Edit %USERPROFILE%\.copilot\settings.json

Create or update the file (replace YOURUSER with your Windows username):

{
  "statusLine": {
    "type": "command",
    "command": "C:\\Users\\YOURUSER\\.copilot\\statusline.cmd",
    "padding": 1
  },
  "feature_flags": {
    "enabled": ["STATUS_LINE"]
  },
  "experimental": true
}

If you already have a feature_flags.enabled array, add "STATUS_LINE" to it instead of replacing the array.

Step 3 — Restart Copilot CLI

/restart

Test Without Copilot

Pipe a sample JSON payload directly to the command to verify output before wiring it into Copilot:

@'
{
  "cwd": "C:\\src\\my-repo",
  "context_window": {
    "current_context_tokens": 123456,
    "displayed_context_limit": 200000,
    "current_context_used_percentage": 61.7
  },
  "cost": {
    "total_duration_ms": 754000,
    "total_lines_added": 42,
    "total_lines_removed": 8
  }
}
'@ | & "$env:USERPROFILE\.copilot\statusline.cmd"

Expected output (appearance depends on your Nerd Font):

main +2/-1 > ctx 123.5k/200.0k > ######.... > 00:12:34 > +42/-8 > 12.9M today · 45.3M month · 1443.5M 30d

Customising the Theme

Open %USERPROFILE%\.copilot\statusline.omp.json to adjust colours, icons, or segments.

To use Nerd Font glyphs instead of plain ASCII separators, replace the diamond and powerline values:

"leading_diamond": "\ue0b6",
"trailing_diamond": "\ue0b0",
"powerline_symbol": "\ue0b0"

Keep the theme small. The statusline must render quickly — remove any segment that makes network calls or scans large directories.

How the Token Cache Works Here

In the standard shell prompt setup, oh-my-posh's segment-level cache block prevents calling the CLI on every keystroke. That OMP cache does not apply in the Copilot CLI statusline context — each Copilot status refresh calls the script fresh.

What does help is the CLI's own segment cache (~/.copilot-token-tracker/omp-segment-cache.json, default 5-minute TTL). After the first call, subsequent statusline renders return the cached value in ~150 ms instead of the full ~7 s cold parse.

Tune the TTL with the --ttl flag inside statusline.ps1 if you want more or less freshness:

# Inside statusline.ps1 — change the ai-engineering-fluency segment call:
$tokenOutput = & ai-engineering-fluency segment --ttl 2 2>$null   # refresh every 2 min

Claude Code CLI Statusline

Claude Code CLI has a native statusLine feature that pipes session JSON to a local command and renders its output at the bottom of the Claude Code terminal UI. This folder includes ready-to-use scripts that combine Claude Code session data (model name, context tokens, cost, duration, line changes) with your total daily / 30-day token usage from ai-engineering-fluency.

Two variants are available — pick the one that fits your setup:

VariantFilesRequirement
Plain PowerShellstatusline-claude-plain.*None beyond pwsh
oh-my-poshstatusline-claude.*oh-my-posh on PATH

JSON Fields from Claude Code

Claude Code pipes this structure to stdin on each status refresh:

FieldDescription
model.display_nameCurrent model name (e.g. claude-sonnet-4-6)
context_window.total_input_tokensCurrent input tokens used
context_window.context_window_sizeMax context window (default 200 000)
context_window.used_percentagePre-calculated percentage used
cost.total_cost_usdEstimated session cost in USD
cost.total_duration_msTotal wall-clock time since session start
cost.total_lines_added / total_lines_removedCode changes this session
rate_limits.five_hour.used_percentage5-hour rolling window usage (Claude.ai plans only)
rate_limits.five_hour.resets_atUnix timestamp when the 5-hour window resets
rate_limits.seven_day.used_percentage7-day rolling window usage (Claude.ai plans only)
rate_limits.seven_day.resets_atUnix timestamp when the 7-day window resets

Option A: Plain PowerShell (no oh-my-posh)

Credit: Approach inspired by Andrew Connell's guide.

No external tools required — pure PowerShell with ANSI truecolor output. Renders two lines:

claude-sonnet-4-6  ██████░░░░ ctx: 123.5k/200.0k 62%  time: 00:12:34  lines: +42/-8  cost: \$0.42
5h-limit: ███░░░░░ 38% resets 2h59m  |  7d-limit: ███████░░ 72% resets 3d0h  |  tokens: 12.9M today · 45.3M month · 1.4B 30d
  • Line 1: model name · color-coded context bar (green → yellow → red) · ctx: token counts · time: session duration · lines: code changes · cost: session cost
  • Line 2: 5h-limit: and 7d-limit: rate limit bars with reset countdowns · tokens: ai-engineering-fluency daily totals

Rate limit bars only appear when Claude Code provides that data (Claude.ai Pro/Max plans).

Files

FilePurpose
statusline-claude-plain.cmdWindows wrapper
statusline-claude-plain.ps1Pure-PowerShell renderer — no oh-my-posh dependency

Requirements

  • Claude Code CLInpm install -g @anthropic-ai/claude-code
  • PowerShell 7+ (pwsh) — included with Windows 11; pwsh --version to confirm

Setup

Add the statusLine key to %USERPROFILE%\.claude\settings.json:

{
  "statusLine": {
    "type": "command",
    "command": "C:\\Users\\YOURUSER\\path\\to\\ai-engineering-fluency\\omp-segment\\statusline-claude-plain.cmd"
  }
}

Restart Claude Code (or run /reload) to activate.

Test Without Claude Code

@'
{
  "model": { "id": "claude-sonnet-4-6", "display_name": "claude-sonnet-4-6" },
  "cwd": "C:\\src\\my-repo",
  "context_window": {
    "total_input_tokens": 123456,
    "context_window_size": 200000,
    "used_percentage": 61.7
  },
  "cost": {
    "total_cost_usd": 0.42,
    "total_duration_ms": 754000,
    "total_lines_added": 42,
    "total_lines_removed": 8
  },
  "rate_limits": {
    "five_hour":  { "used_percentage": 38, "resets_at": 1749340800 },
    "seven_day":  { "used_percentage": 72, "resets_at": 1749600000 }
  }
}
'@ | & "path\to\ai-engineering-fluency\omp-segment\statusline-claude-plain.cmd"

Customising

Open statusline-claude-plain.ps1 to adjust:

  • Bar width — change the $Width = 10 default in New-Bar
  • Color thresholds — the if ($bounded -lt 60) / if ($bounded -lt 80) breakpoints in New-Bar
  • Line layout — edit the Write-Host calls at the bottom of the script

Option B: oh-my-posh (rich theme)

Uses oh-my-posh's powerline rendering for a styled, multi-segment bar. Falls back to the same plain-text output as Option A when oh-my-posh is not found.

Example output (with Nerd Font):

claude-sonnet-4-6 > ctx: 123.5k/200.0k > ######.... > time: 00:12:34 > lines: +42/-8 > cost: \$0.42 > tokens: 12.9M today · 45.3M month · 1.4B 30d

Files

FilePurpose
statusline-claude.cmdWindows wrapper
statusline-claude.ps1Sets env vars, calls ai-engineering-fluency segment, renders via oh-my-posh
statusline-claude.omp.jsonCompact oh-my-posh theme — model name, context gauge, duration, changes, cost, token totals

Requirements

In addition to the prerequisites above:

  • Claude Code CLInpm install -g @anthropic-ai/claude-code
  • oh-my-posh available on PATH (oh-my-posh version should return output)

Setup

Add the statusLine key to %USERPROFILE%\.claude\settings.json:

{
  "statusLine": {
    "type": "command",
    "command": "C:\\Users\\YOURUSER\\path\\to\\ai-engineering-fluency\\omp-segment\\statusline-claude.cmd"
  }
}

Restart Claude Code (or run /reload) to activate.

Test Without Claude Code

@'
{
  "model": {
    "id": "claude-sonnet-4-6",
    "display_name": "claude-sonnet-4-6"
  },
  "cwd": "C:\\src\\my-repo",
  "context_window": {
    "total_input_tokens": 123456,
    "context_window_size": 200000,
    "used_percentage": 61.7
  },
  "cost": {
    "total_cost_usd": 0.42,
    "total_duration_ms": 754000,
    "total_lines_added": 42,
    "total_lines_removed": 8
  }
}
'@ | & "path\to\ai-engineering-fluency\omp-segment\statusline-claude.cmd"

Environment Variables Set by the Script

VariableValueExample
CLAUDE_STATUS_MODELModel display nameclaude-sonnet-4-6
CLAUDE_STATUS_CONTEXTused/limit formatted123.5k/200.0k
CLAUDE_STATUS_GAUGE10-char ASCII gauge######....
CLAUDE_STATUS_DURATIONHH:MM:SS00:12:34
CLAUDE_STATUS_CHANGES+added/-removed or empty+42/-8
CLAUDE_STATUS_COSTCost in USD or empty$0.42
COPILOT_TOKEN_USAGEOutput of ai-engineering-fluency segment12.9M today · 45.3M month · 1.4B 30d

Customising the Theme

Open statusline-claude.omp.json to adjust colours, icons, or segments.

To use Nerd Font glyphs instead of plain ASCII separators, replace the diamond and powerline values:

"leading_diamond": "",
"trailing_diamond": "",
"powerline_symbol": ""

Differences vs Copilot CLI Statusline

AspectCopilot CLIClaude Code
Context tokens fieldcontext_window.current_context_tokenscontext_window.total_input_tokens
Context limit fieldcontext_window.displayed_context_limitcontext_window.context_window_size
Percentage fieldcontext_window.current_context_used_percentagecontext_window.used_percentage
Extra fieldsgit info via oh-my-poshmodel.display_name, cost.total_cost_usd
Settings file%USERPROFILE%\.copilot\settings.json%USERPROFILE%\.claude\settings.json
Feature flag neededYes (STATUS_LINE)No — statusLine is stable