There are many articles about Claude and its surrounding, but being honest and transparent I do use GitHub Copilot and at least for my work it’s a very helpful assistant. However I also try to understand its internals so that I could optimize my usage and become more effective at what I do. Mainly DevOps/SRE related tasks.
Let’s have a look at a few pieces about it.
There is a durable content that get’s written to our file system for each session that we start with Copilot. For example
~/.copilot/session-state/f3bca8c1-0eb8-4b73-8ea5-9fbb7659c494$ t1.├── checkpoints├── events.jsonl├── files├── research├── rewind-snapshots├── session.db├── vscode.metadata.json└── workspace.yaml
Now let’s start with f3bca8c1-0eb8-4b73-8ea5-9fbb7659c494. This is a unique session ID (UUID).
What is grabbing my attention is the session.db. Now if we dump this database into the sqlite3 cli we are going to see 3 tables.
sqlite3 ~/.copilot/session-state/f3bca8c1-0eb8-4b73-8ea5-9fbb7659c494/session.db
SQLite version 3.45.1 2024-01-30 16:01:20
Enter ".help" for usage hints.
sqlite> .tables
inbox_entries todo_deps todos
Now I will put the schema for each table, just to see what’s being stored. That might be a long list fyi ;]
sqlite> .schema inbox_entriesCREATE TABLE inbox_entries ( id TEXT PRIMARY KEY, recipient_session_id TEXT NOT NULL, sender_id TEXT NOT NULL, sender_name TEXT NOT NULL, sender_type TEXT NOT NULL, interaction_id TEXT NOT NULL, sequence INTEGER NOT NULL DEFAULT 0, summary TEXT NOT NULL, content TEXT NOT NULL, unread INTEGER NOT NULL DEFAULT 1, sent_at INTEGER NOT NULL, read_at INTEGER, notified_at INTEGER );sqlite> .schema todo_depsCREATE TABLE todo_deps ( todo_id TEXT NOT NULL, depends_on TEXT NOT NULL, PRIMARY KEY (todo_id, depends_on), FOREIGN KEY (todo_id) REFERENCES todos(id), FOREIGN KEY (depends_on) REFERENCES todos(id) );sqlite> .schema todosCREATE TABLE todos ( id TEXT PRIMARY KEY, title TEXT NOT NULL, description TEXT, status TEXT DEFAULT 'pending' CHECK(status IN ('pending', 'in_progress', 'done', 'blocked')), created_at TEXT DEFAULT (datetime('now')), updated_at TEXT DEFAULT (datetime('now')) );
Do we know when Copilot is writing exactly to those tables ? We do not know. So the best thing is to ask it.

From the local sqlite3 db for a session we could summarize that we keep track of ours:
- todos – Copilot breaking our desire request into multiple sub-steps.
- todo_deps – Dependency edges between todos. For example we have to create the Azure DB first in Terraform, before we deploy the application in an Auto Scaling Group in AWS again using Terraform.
- inbox_entries – A notification table which is populated when some results/updates are done by a background agent and the result is send asynchronously.
As you could see here we do not maintain some form of a very detailed summary about what happened, what is the result of our tool call number 43 … It’s more or less a general information about the tasks that might be written.
Now if you want the full log of everything that has happened in the session it’s being stored in events.jsonl.
It is the full, append-only event log of the entire session — the raw source of truth for everything that happened in the session so far. Any tool called, its result, the sequence of inputs and the tool calls, pretty much a very detailed journal about what has happened. This is from the Copilot itself about the JSON structure that we have in this events.jsonl file.
`Here's the schema (top-level fields common to every event, plus the tool-specific ones):Common envelope (all event types):type - event category, e.g. "tool.execution_start"id - unique event UUIDparentId - id of the event that caused/preceded this one (chains events together)timestamp - ISO8601 UTC timestampdata - type-specific payload tool.execution_start.data :toolCallId - correlates start↔complete (e.g. "toolu_01PGY...")toolName - "bash", "view", "edit", "sql", etc.arguments - the exact tool call args (command, description, path, etc.)turnId - which conversation turn this belongs tomodel - model handling this turnrte - remote tool execution flagshellToolInfo - (bash-specific) possiblePaths, hasWriteFileRedirection tool.execution_complete.data :toolCallId - matches the start eventmodel, turnId - same contextinteractionId - groups events within one assistant "thinking" passsuccess - true/falseresult.content / result.detailedContent - actual output returnedtoolTelemetry - execution metadata (timeout, sync/async, sandbox flags, duration metrics)
Now regarding the checkpoint it’s very interesting because for all the sessions that I hold only one of them has some entries there. This is the structure it holds. Contains restore points (index.md) allowing you to revert back to specific states if a sequence of edits or shell executions fails.
`/.copilot/session-state/f3b872f3-3af6-42e0-b0b6-9e7df1479e72$ cat checkpoints/index.md# Checkpoint HistoryCheckpoints are listed in chronological order. Checkpoint 1 is the oldest, higher numbers are more recent.| # | Title | File ||---|-------|------|
The final thing that I would like to mention in terms of state is the files directory for each session.
Now based on all of that what would be a good way to stop and the continue a session with the Copilot buddy ? Or just start a new one ?
For example inputting the whole jsonl file would be too much, you would trigger way too many parameters immediately and to some extend the model might loose focus. At the same time the sqlite3 entries are too general.
Now this is what is working well for me:
right before ending the session I ask it to create a balanced summary of what we did, tried, succeeded and failed ( balanced between the details and the major points ) and then place those file either in the session files directory or just inside the repository itself.
Another thing that I find very effective is to try to divide your repository into layers or some other form of logical abstraction that makes sense for you. For example if you have Front Door logic expressed in Terraform and there are also many other Terraform Azure resources, you could ask it to create a dedicated file just for Front Door logic and its dependencies. Then on each input request for Front Door issue you provide that file as an initial context. Here the catch is that you have to always maintain those files, which is fine with LLM :)
Copilot SKILLS
I am using the Skills from the official github repo awesome-copilot. A skill is a function that gets triggered on some user input, like for example if you prompt it with “Please analyze my code”, Copilot calls the acquire-codebase-knowledge skill.
https://github.com/github/awesome-copilot/tree/main/skills
https://awesome-copilot.github.com/skills
For example those are the first skills that I installed.
`Available Skillspersonal-copilot: - acquire-codebase-knowledge Use this skill when the user explicitly asks to map, document, or onboard into an existing codebase. Trigger for prompts like "map this codebase", "document this architecture", "onboard me to this repo", or "create codebase docs". Do not trigger for routine feature implementation, bug fixes, or narrow code edits unless the user asks for repository-level discovery. - ai-ready Make any repo AI-ready — analyzes your codebase and generates AGENTS.md, copilot-instructions.md, CI workflows, issue templates, and more. Mines your PR review patterns and creates files customized to your stack. USE THIS SKILL when the user asks to "make this repo ai-ready", "set up AI config", or "prepare this repo for AI contributions". - azure-devops-cli Manage Azure DevOps resources via CLI including projects, repos, pipelines, builds, pull requests, work items, artifacts, and service endpoints. Use when working with Azure DevOps, az commands, devops automation, CI/CD, or when user mentions Azure DevOps CLI.
MCP
The only MCP that I am using so far in read only mode is the MCP Kubernetes from Azure.
https://github.com/Azure/mcp-kubernetes
This setup at least for me is very productive. I do not want to install each skill just to feel more productive and AI aligned, I try to stay active when I am talking with Copilot, I would think on its output and if there is a need will direct it to go somewhere else or start a session from scratch.
I do not hurry up just to click go to the next instruction. For me AI is a very helpful assistant tool, but in the end of the day I would like to know that the control is on my side and more importantly I am cultivating the knowledge and I know how the internals are working.
The internals are not expressed in probability distribution of tokens. Yes, it’s a very powerful technology, yes it works in a big majority of the cases, but it does not deal in the same way with pure knowledge concept like Kubernetes Deployment that I have to deal with. In your head you could envision how the flow from one http request is goiing from a client to a server, the stages it has to pass, cloud load-balancer, firewall rules, k8s httroute, k8s service, k8s pod … all of that is really different expressed in my thought vs the probability distribution representation.
And sure, you could make the argument that this does not matter, because you end up with a working flow. And that would been true, if that flow was static once set and it was always working, but once the flow is broken someone needs to fix it and the abstraction in your head together with all the context and good practices you have cultivated using AI is the best warrior for this.



Leave a comment