kibble

Kibble Blog

GitHub Copilot CLI logs: locations and VS Code history

GitHub Copilot CLI saves session history at ~/.copilot/session-state/<session-id>/events.jsonl and diagnostic logs in ~/.copilot/logs/. Copilot Chat in VS Code saves chat history under User/workspaceStorage/<hash>/chatSessions/ in the editor's user-data directory. The table below gives the locations; the rest of this guide explains which saved token counters you can count.

Where are GitHub Copilot logs stored?

What you needDefault location
Copilot CLI session history and usage~/.copilot/session-state/<session-id>/events.jsonl
On Windows: %USERPROFILE%\.copilot\session-state\<session-id>\events.jsonl
Copilot CLI diagnostic logs~/.copilot/logs/
Enter /session in Copilot CLI to find the current log file.
VS Code chat history on macOS~/Library/Application Support/Code/User/workspaceStorage/<hash>/chatSessions/
VS Code chat history on Windows%APPDATA%\Code\User\workspaceStorage\<hash>\chatSessions\
VS Code chat history on Linux~/.config/Code/User/workspaceStorage/<hash>/chatSessions/

COPILOT_HOME overrides the CLI root. VS Code profiles, Insiders, portable installs and --user-data-dir can change the editor paths; see VS Code locations below. These files can contain conversations and tool output, so inspect them locally before sharing anything.

For connection errors in VS Code, open View → Output and select GitHub Copilot, following GitHub's diagnostic-log instructions. Saved chat sessions are the source for the usage accounting in this guide.

What is in a Copilot CLI session log?

GitHub's configuration-directory reference puts everything Copilot CLI keeps under ~/.copilot, and COPILOT_HOME replaces that whole path when it is set. session-state/ holds one directory per session id. Each one has events.jsonl, the event log the CLI replays to resume a session, beside workspace artifacts such as plans, checkpoints and tracked files. Deleting a session directory removes the local copy only; a session synced to a GitHub account is stored separately.

The event log is one JSON record per line: a type, a timestamp, an id and a data object. The prompts, the replies, every tool's arguments and output, and the paths of edited files are all in there. So are the counters. The usage a collector can rely on is written at session.shutdown, as data.modelMetrics keyed by model name, with usage.inputTokens, usage.outputTokens, usage.cacheReadTokens, usage.cacheWriteTokens, usage.reasoningTokens and requests.count.

EventWhat a counter readsWhat it leaves alone
session.start
session.resume
session.context_changed
The session id and the working directory, reduced to a repository name on the machineThe rest of the context
session.shutdownmodelMetrics per model: token counters and request count; the cumulative lines added and removedSummaries and the final message
skill.invokedThe skill's name, whether the person or the model invoked it, and the size of the injected textThe injected text itself
tool.execution_start
tool.execution_complete
The tool name, the MCP server name, success or failure, elapsed timeArguments and output
user.message
assistant.turn_start
assistant.turn_end
hook.start
hook.end
session.compaction_complete
That the day was active; turn, hook and compaction counts; durationsMessage text and hook output

How do you count a Copilot CLI session correctly?

  1. The shutdown counters are cumulative. A resumed session appends another session.shutdown to the same file, and each one carries the running total since the session began. Diff consecutive checkpoints per model and keep the increase; a repeated event id, or a total lower than the previous one, adds nothing.
  2. Input includes the cache. Copilot's inputTokens counts cache reads and cache writes inside it. Subtract cacheReadTokens and cacheWriteTokens to get fresh input, then price the three separately. Pricing all of it at the fresh rate overstates a long session several times over.
  3. Reasoning is part of output. reasoningTokens is a subset of outputTokens, not an addition to it. Adding it on top inflates every reasoning-heavy model.
  4. The day is the shutdown's day, in UTC. The checkpoint is the only durable record, so the increase lands on the day the session shut down, even when the work started the evening before. There is no per-request timeline to spread it over.
  5. No shutdown, no total. A session still open, or one that crashed, has written no checkpoint. Its tokens are unknown, not zero; the row appears when the session ends.
  6. Sub-agent snapshots are already inside the parent. Records stamped with an agentId belong to a sub-agent whose totals the main shutdown already includes. Counting them again counts the same tokens twice.

Beside the tokens, the same file names the capabilities that fired: skill.invoked carries the skill's name and whether the person or the model chose it, and tool.execution_start carries the MCP server name separately from the arguments. Copilot CLI does not durably attribute later tokens to a skill, and its ordinary slash-command events are not written to the log, so a skill's cost share and a command's invocation count are not available from these files. Copilot skills themselves live in the personal ~/.copilot and ~/.agents directories, a project's .github, .agents and .claude, and installed plugins, which is where an inventory looks.

Where does VS Code save Copilot Chat history?

VS Code keeps chat sessions inside its user-data directory: ~/Library/Application Support/Code/User on macOS, %APPDATA%\Code\User on Windows, and ~/.config/Code/User on Linux (under $XDG_CONFIG_HOME when that is set), with Code - Insiders beside Code for the Insiders build. A portable installation puts the User/ directory under $VSCODE_PORTABLE/user-data. The --user-data-dir option selects a different user-data root.

Location under User/What is there
workspaceStorage/<hash>/chatSessions/One file per session opened in that workspace; workspace.json beside it names the folder
globalStorage/emptyWindowChatSessions/Sessions started in a window with no folder open
globalStorage/transferredChatSessions/Sessions moved between windows
profiles/<id>/globalStorage/The same two folders for each additional profile

Each session file is named by its session id with a .json or .jsonl extension. The .json form is a full snapshot that older builds rewrote on every change. Current builds keep a .jsonl mutation log instead: the first line is the initial state, and every later line is one operation on it, a set, an array splice or append, or a delete, keyed by the path it changes (the format is objectMutationLog.ts in VS Code's source). When both files exist for one session, the .jsonl is the live copy and the .json a migrated leftover, so a reader that counts both doubles the session.

Inside the replayed state, each entry of requests[] is one turn. The fields a counter needs:

Neither form records a cache write, and the older records carry no cached split at all, so a legacy request is priced with its recorded input at the input rate. The estimate can only be as complete as what the editor saved, which is why a collector should carry a flag for the measurements a record did not have rather than write a zero. workspace.json beside a workspace's sessions names its folder, and a session's own workingDirectory names it too; either becomes a repository name on the machine. A multi-root workspace has no single folder and stays unattributed.

Some usage is not in these files at all. Inline completions and next edit suggestions are not chat requests, leave no counters, and GitHub does not bill them. The cloud coding agent and Copilot code review run on GitHub's side. A session in a remote workspace belongs to the remote machine.

Why are my Copilot logs or token totals missing?

With Kibble installed, kibble doctor checks local collection setup and kibble push --dry-run previews counts without uploading them. The collector's coverage notes describe these limits.

What is a Copilot token worth?

Since 1 June 2026 GitHub bills Copilot in AI credits consumed by tokens at a published rate per model, one credit being one US cent. Four rates from GitHub's models and pricing page, read on 10 September 2026, in US dollars per million tokens for the default context tier:

ModelInputCached inputCache writeOutput
GPT-5.6 Luna (the default)$0.20$0.02$0.25$1.20
GPT-5.4$2.50$0.25not applicable$15.00
Claude Sonnet 5$2.00$0.20$2.50$10.00
Claude Opus 5$5.00$0.50$6.25$25.00

Price each counter at its own rate and add. A session whose input is mostly cache reads costs less than pricing every input token at the fresh rate; the difference depends on the cache share and the model's rates. This is the same lesson as Claude Code's four token fields. Earlier OpenAI models have no cache-write charge, so their cache-write tokens are ordinary input.

A local estimate at those rates and GitHub's bill are two different numbers. GitHub's own per-user figure, the ai_credits_used field its usage metrics API has reported since 19 June 2026, is described by GitHub as a metrics signal rather than a billed total, and it has no split by model, surface or repository. Kibble's Copilot rows are estimates priced from the same pinned rate table its Claude Code and Codex rows use, kept as integer micro-dollars, and never added to a bill. What the scenarios cost in credits works three examples through.

How do the CLI and the editor add up?

A person who used Copilot CLI and Copilot Chat on the same day with the same model produces two sets of counters for one day-and-model row. A collector must add them before it sends anything, because a per-day upsert replaces a row it has already seen: two collectors pushing the same grain would leave whichever arrived last. Kibble sums the CLI and editor totals into one copilot row per day and model on the machine, then pushes once.

What leaves the machine

These are the Copilot rows of Kibble's field list; the privacy policy is the authoritative version and the server rejects anything not on it.

SentNever sent
The day, the agent (copilot), the model namePrompts, replies, tool output
Fresh input, output, cache read,
cache write, reasoning; request count
Tool arguments; the text a skill injected
Opaque session idsPaths of edited files; plan and checkpoint artifacts
The repository's nameThe working directory itself, the username in it, the hostname
Skill, command and MCP server names
with counts, when the organization asks
The GitHub login, tokens and user ids in config.json
How Copilot is billed: GitHub login,
API provider or cloud provider
The tier or seat price, which the machine cannot tell

The counters and the conversation are in the same file. A collector's privacy is the part of its code that reads one and not the other.

How do I collect Copilot usage across a team?

Install Kibble on each participating machine and connect it with kibble login. The first sync imports today and the previous 29 UTC days where supported logs exist. With automatic collection enabled, login attempts the first upload and schedules later pushes; otherwise run kibble push manually. The team setup guide covers organization setup, addressed invitations and checking coverage.

The open-source adapters read the supported CLI and VS Code counters into one dashboard alongside your other coding agents. Missing counters remain unavailable, and the cost figures are estimates. Prompts, replies and tool output stay on the machine.