GitHub Copilot CLI Data Source (Beta)
GitHub Copilot CLI support is experimental. The adapter reads local session-state and OpenTelemetry JSONL files.
ccusage can read GitHub Copilot CLI session-state and OpenTelemetry files as supported local data sources. It uses the same reporting experience as the rest of ccusage: responsive tables, JSON output, LiteLLM-based pricing, cache token accounting, and all-source aggregation.
Focused Views
bunx ccusage copilot --helpnpx ccusage@latest copilot --helppnpm dlx ccusage copilot --helpData Source
The CLI reads Copilot session-state shutdown and usage-checkpoint events from ${COPILOT_HOME:-~/.copilot}/session-state/*/events.jsonl by default. It also reads OpenTelemetry JSONL files recursively from ${COPILOT_HOME:-~/.copilot}/otel/**/*.jsonl and includes the single explicit file pointed to by COPILOT_OTEL_FILE_EXPORTER_PATH. Set COPILOT_HOME to the Copilot data root when the default ~/.copilot directory has been relocated.
Session-state files do not require OpenTelemetry configuration. Shutdown usage is cumulative per canonical session/model pair, and resumed sessions emit another shutdown snapshot. ccusage reports the first snapshot as-is and each later snapshot as the difference from its predecessor, so usage follows the resume dates while totals stay unchanged. For date-bounded reports, snapshots before --since remain available as subtraction baselines, and snapshots after --until are excluded. When both sources contain the same session/model pair, the session-state usage is used and matching OpenTelemetry rows are suppressed only when their timestamps are at or before the latest raw shutdown visible through --until; rows emitted after that timestamp by a resumed session are retained. A Copilot process restores the per-model breakdown of the session's last shutdown, so the calls of a process that ended without a shutdown (killed, crashed, or restarted by the app) are missing from every later one. When the OpenTelemetry rows of a pair outnumber the requests its shutdowns report, counted from the first shutdown interval that has OpenTelemetry rows, ccusage reports those rows instead of the shutdown intervals from that interval on. This comparison covers every shutdown, so a date-bounded report shows the same usage per day as an unbounded one. OpenTelemetry rows for other session/model pairs remain available. Chat spans that the CLI exports twice, with the response ID and usage of the same call, are counted once.
For session-state token usage, only session.shutdown events are used. For each data.modelMetrics.<model> entry, ccusage reads its usage fields and uses any positive requests.count for messageCount; each retained OpenTelemetry usage row contributes one message. requests.cost is ignored and costs continue to use ccusage's normal token pricing. In session-state data, inputTokens includes both cache buckets, so ccusage derives uncached input as max(inputTokens - cacheReadTokens - cacheWriteTokens, 0) before populating inputTokens; cache reads and cache writes are then reported separately. OpenTelemetry gen_ai.usage.input_tokens includes both cache buckets as well and is normalized the same way. reasoningTokens is a subset of outputTokens, so it is not added again to output, total tokens, or cost. Copilot model IDs with -1m or -1m-internal suffixes, such as claude-opus-4.6-1m, are normalized to their priced model name for pricing and source deduplication.
For example, a claude-opus-4.7 shutdown with inputTokens=100, outputTokens=50, cacheReadTokens=10, and cacheWriteTokens=20 is reported as 70 input tokens, 50 output tokens, 20 cache-creation tokens, and 10 cache-read tokens. With the embedded Opus pricing, its calculated cost is exactly $0.00173.
Copilot also records the credits a session has used: a session-wide totalNanoAiu on every session.shutdown and on the session.usage_checkpoint events written during the session. One AIU is one GitHub AI credit, billed at $0.01. The per-model breakdown only covers the running Copilot process, so a resumed or restarted session can shut down with an empty or partial modelMetrics while its session total still includes everything. ccusage compares the session total with the per-model totalNanoAiu values reported so far, at every shutdown and at each checkpoint after a session's last shutdown, which covers sessions that are still open or ended without a shutdown. Credits that stay unexplained at every later snapshot are reported as a cost-only row for the unknown model with zero tokens, dated at the first snapshot from which they stay unexplained. A breakdown that a later shutdown catches up on is not counted twice. Sessions without checkpoints, which come from older Copilot versions that restart both totals on every resume, sessions with a shutdown that lacks either credit total, and sessions that also have OpenTelemetry rows keep token-only reporting. These rows carry a precomputed cost, so --mode calculate reports them as $0.
Enable these variables before starting or resuming a Copilot CLI session when you want OTel data. Sessions that ran without OpenTelemetry file export remain readable from their session-state files.
export COPILOT_HOME="$HOME/.copilot"
export COPILOT_OTEL_ENABLED=true
export COPILOT_OTEL_EXPORTER_TYPE=file
mkdir -p "$COPILOT_HOME/otel"
export COPILOT_OTEL_FILE_EXPORTER_PATH="$COPILOT_HOME/otel/copilot-otel-$(date +%Y%m%d-%H%M%S).jsonl"${COPILOT_HOME:-~/.copilot}/
├── session-state/
│ └── <session-id>/
│ └── events.jsonl
└── otel/
└── *.jsonlReport Views
| Focused view | Description | See also |
|---|---|---|
ccusage copilot daily | Aggregate usage by date | Daily Usage |
ccusage copilot monthly | Aggregate usage by month | Monthly Usage |
ccusage copilot session | Group usage by Copilot session IDs | Session Usage |
These views support --json for structured output, --compact for narrow terminals, and --offline for cached pricing data.
What Gets Calculated
- Token usage - cumulative session shutdown snapshots are converted into per-resume intervals, and OTel rows replace them when the shutdowns miss calls; OTel chat spans are preferred within the OTel source, with inference logs and agent-turn logs used as fallbacks.
- Cache tokens - cache read and cache creation token attributes are counted when present.
- Input tokens - session-state
inputTokensand OTelgen_ai.usage.input_tokensare normalized to uncached input after subtracting cache reads and cache writes. - Reasoning tokens - session-state reasoning tokens are already included in output tokens; OpenTelemetry reasoning is included when total usage metadata shows it is separate.
- Pricing - costs are calculated from LiteLLM pricing data using the normalized model name; both
-1mand-1m-internalsuffixes are removed. - Unattributed credits - session credits missing from the per-model breakdown are reported as
unknownrows at $0.01 per AI credit.
Environment Variables
| Variable | Description |
|---|---|
COPILOT_HOME | Copilot data root; defaults to ~/.copilot |
COPILOT_OTEL_FILE_EXPORTER_PATH | Explicit Copilot OpenTelemetry JSONL file to include |
LOG_LEVEL | Adjust verbosity (0 silent ... 5 trace) |
Troubleshooting
No Copilot usage data found
Ensure Copilot session-state files exist under ${COPILOT_HOME:-~/.copilot}/session-state/<session-id>/events.jsonl, or enable OpenTelemetry file export and place exported .jsonl files under ${COPILOT_HOME:-~/.copilot}/otel/.
If you are using copilot --resume, session-state events remain available without OpenTelemetry. OTel-only activity from sessions started without file export cannot be recovered by ccusage.
Costs showing as $0.00
If a model is not in LiteLLM's database, the cost will be $0.00. Open an issue to request alias support.