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:
| Cache | Location | TTL | Purpose |
|---|---|---|---|
| Oh-my-posh segment cache | in-memory, per shell session | 5 min (configurable) | Prevents calling the CLI on every keystroke |
| CLI segment cache | ~/.copilot-token-tracker/omp-segment-cache.json | 5 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 ifSet-PoshContextupdates$env:COPILOT_TOKENS_TODAY, the prompt still shows the stale cached value until the OMP cache expires. SinceSet-PoshContextalready 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
- Node.js 22+ — nodejs.org
- Oh-my-posh — ohmyposh.dev/docs/installation
- 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
npxinstead of a global install, replace"ai-engineering-fluency"with"npx"and add"-y","@rajbos/ai-engineering-fluency"as additional arguments in thecmdcall below.npxis 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 seeinvalid template textin 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
\uec1echaracter 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
Method 2: PowerShell Pre-Prompt Hook — Recommended
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
| Symptom | Likely cause | Fix |
|---|---|---|
Command not found: ai-engineering-fluency | CLI not installed globally | npm install -g @rajbos/ai-engineering-fluency |
Segment shows 0 today · 0 month · 0 30d | No session files found | Run ai-engineering-fluency diagnostics to check paths |
Segment shows invalid template text | {{ cmd }} not supported in your OMP version | Switch to Method 2 |
Segment shows today · month · 30d without values | Set-PoshContext not called before first render | Add Set-PoshContext call at end of $PROFILE after the function definition |
| Segment never updates | OMP cache too long | Set cache.duration to "1m" or use --hide-zero |
| Stale numbers | CLI cache still valid | Run ai-engineering-fluency segment --refresh |
| Prompt shows stale data even after refresh | OMP cache block on a Method 2 env var segment | Remove 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 Font | Replace \uec1e with 🤖 or remove the icon |
| Prompt slows down | OMP 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:
- Post in oh-my-posh Discussions → Themes
- Share in the oh-my-posh Discord
#themeschannel
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
| File | Purpose |
|---|---|
statusline.cmd | Windows wrapper — points statusLine.command at the PowerShell script |
statusline.ps1 | Reads Copilot's JSON stdin, sets env vars, calls ai-engineering-fluency segment, renders via oh-my-posh |
statusline.omp.json | Compact 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_LINEfeature flag - oh-my-posh available on
PATH(oh-my-posh versionshould 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:
| Variant | Files | Requirement |
|---|---|---|
| Plain PowerShell | statusline-claude-plain.* | None beyond pwsh |
| oh-my-posh | statusline-claude.* | oh-my-posh on PATH |
JSON Fields from Claude Code
Claude Code pipes this structure to stdin on each status refresh:
| Field | Description |
|---|---|
model.display_name | Current model name (e.g. claude-sonnet-4-6) |
context_window.total_input_tokens | Current input tokens used |
context_window.context_window_size | Max context window (default 200 000) |
context_window.used_percentage | Pre-calculated percentage used |
cost.total_cost_usd | Estimated session cost in USD |
cost.total_duration_ms | Total wall-clock time since session start |
cost.total_lines_added / total_lines_removed | Code changes this session |
rate_limits.five_hour.used_percentage | 5-hour rolling window usage (Claude.ai plans only) |
rate_limits.five_hour.resets_at | Unix timestamp when the 5-hour window resets |
rate_limits.seven_day.used_percentage | 7-day rolling window usage (Claude.ai plans only) |
rate_limits.seven_day.resets_at | Unix 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:and7d-limit:rate limit bars with reset countdowns ·tokens:ai-engineering-fluencydaily totals
Rate limit bars only appear when Claude Code provides that data (Claude.ai Pro/Max plans).
Files
| File | Purpose |
|---|---|
statusline-claude-plain.cmd | Windows wrapper |
statusline-claude-plain.ps1 | Pure-PowerShell renderer — no oh-my-posh dependency |
Requirements
- Claude Code CLI —
npm install -g @anthropic-ai/claude-code - PowerShell 7+ (
pwsh) — included with Windows 11;pwsh --versionto 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 = 10default inNew-Bar - Color thresholds — the
if ($bounded -lt 60)/if ($bounded -lt 80)breakpoints inNew-Bar - Line layout — edit the
Write-Hostcalls 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
| File | Purpose |
|---|---|
statusline-claude.cmd | Windows wrapper |
statusline-claude.ps1 | Sets env vars, calls ai-engineering-fluency segment, renders via oh-my-posh |
statusline-claude.omp.json | Compact oh-my-posh theme — model name, context gauge, duration, changes, cost, token totals |
Requirements
In addition to the prerequisites above:
- Claude Code CLI —
npm install -g @anthropic-ai/claude-code - oh-my-posh available on
PATH(oh-my-posh versionshould 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
| Variable | Value | Example |
|---|---|---|
CLAUDE_STATUS_MODEL | Model display name | claude-sonnet-4-6 |
CLAUDE_STATUS_CONTEXT | used/limit formatted | 123.5k/200.0k |
CLAUDE_STATUS_GAUGE | 10-char ASCII gauge | ######.... |
CLAUDE_STATUS_DURATION | HH:MM:SS | 00:12:34 |
CLAUDE_STATUS_CHANGES | +added/-removed or empty | +42/-8 |
CLAUDE_STATUS_COST | Cost in USD or empty | $0.42 |
COPILOT_TOKEN_USAGE | Output of ai-engineering-fluency segment | 12.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
| Aspect | Copilot CLI | Claude Code |
|---|---|---|
| Context tokens field | context_window.current_context_tokens | context_window.total_input_tokens |
| Context limit field | context_window.displayed_context_limit | context_window.context_window_size |
| Percentage field | context_window.current_context_used_percentage | context_window.used_percentage |
| Extra fields | git info via oh-my-posh | model.display_name, cost.total_cost_usd |
| Settings file | %USERPROFILE%\.copilot\settings.json | %USERPROFILE%\.claude\settings.json |
| Feature flag needed | Yes (STATUS_LINE) | No — statusLine is stable |