Hoe GitHub Copilot werkt: Context, Geheugen en Netwerkverkeer

Er is de afgelopen jaren een vloedgolf aan AI-gestuurde apps en functies verschenen. Gevestigde spelers zoals Slack hebben snel AI-functies toegevoegd, terwijl voor AI-native apps zoals Cursor, Notion, ChatGPT Desktop en Claude Desktop AI altijd al de kern van hun bestaansrecht was.

Hoe meer van deze functies werden uitgebracht, hoe meer ik nieuwsgierig werd naar de innerlijke werking ervan. Ik hoopte zo te ontdekken wat er onder de motorkap gebeurt, of in ieder geval iets te leren over de ontwikkeling van desktopapplicaties. Omdat ik merkte dat mijn Copilot-credits elke maand steeds sneller opraakten, besloot ik diep in VS Code en Copilot te duiken.

De gemeenschappelijke deler: Electron

Een overeenkomst tussen al deze apps is dat ze zijn gebouwd met Electron. Electron is een JavaScript-framework dat ontwikkelaars helpt bij het bouwen en distribueren van desktopapplicaties. In eenvoudige termen werkt het door een Node.js-runtime te bundelen met HTML-, CSS- en JavaScript-bestanden, die vervolgens worden gerenderd via Chromium.

Dit voorkomt dat er meerdere codebases in native talen nodig zijn voor verschillende platforms (bijvoorbeeld C# voor Windows en Swift voor macOS), waardoor ontwikkelaars applicaties kunnen bouwen die op meerdere platforms draaien vanuit één codebase. Hoewel native modules en bepaalde verpakkingsstappen vaak per platform verschillen, is het grootste deel van de applicatielogica gedeeld.

Omdat ze Electron delen, hebben ze ook een vergelijkbare architectuur. Dit betekent dat wat ik leer door de ene app te onderzoeken, waarschijnlijk overdraagbaar is naar de andere.

Van netwerkpakketten naar broncode

Mijn eerste instinct was om simpelweg door de broncode van VS Code te bladeren. Het probleem was dat ik nog geen volledige lijst met vragen had; het zoeken naar antwoorden in miljoenen regels code zou te veel tijd of tokens kosten. Bovendien vertelt broncode wat een app kan doen, maar het ontdekken van wat hij daadwerkelijk doet tijdens runtime is uitdagender.

Daarnaast is VS Code een uitzondering: de broncode (of het grootste deel daarvan) is open. Dit is niet het geval voor Claude, ChatGPT, Codex, Notion en Slack. Daarom koos ik voor de route van reverse engineering: eerst passief het verkeer observeren, de verzoeken en antwoorden gebruiken om te bepalen welke vragen de moeite waard zijn, en pas daarna in de broncode kijken om mijn bevindingen te bevestigen of te ontkrachten.

De netwerkarchitectuur van Electron

Electron-apps worden geleverd met Chromium. De browser biedt de rendering engine voor de webgebaseerde UI, maar ook een netwerkstack die renderer-processen kunnen gebruiken voor HTTP- en WebSocket-verbindingen. Dit is de aanbevolen optie voor communicatie met een remote backend, maar applicaties kunnen ook HTTP-verzoeken doen via Node's http/https/fetch. Welk pad het verzoek neemt, is cruciaal wanneer je dit wilt onderscheppen.

In het geval van VS Code is er sprake van een ontkoppelde architectuur, waarbij een aparte groep processen fungeert als extension host. Dit zorgt voor duidelijke grenzen tussen de UI, de IDE-functionaliteit en de plugins/extensies.

Netwerkverkeer inspecteren in Electron-apps

Een klassieke manier om het netwerkverkeer van een applicatie te onderscheppen is door een proxy-server op te zetten en de applicatie zo te configureren dat deze deze gebruikt. De proxy fungeert als een man-in-the-middle (MITM): hij onderschept HTTP-verzoeken van een cliënt, stuurt ze door naar een server en stuurt de antwoorden terug naar de cliënt.

Een veelgebruikte open-source tool hiervoor is mitmproxy. Omdat het meeste moderne verkeer via HTTPS (versleuteld via TLS) verloopt, moet de cliënt het lokaal gegenereerde certificaat van mitmproxy vertrouwen. In plaats van één end-to-end versleutelde verbinding ontstaan er twee: één tussen de applicatie en mitmproxy, en een tweede tussen mitmproxy en de doelserver. Hierdoor kan mitmproxy het verzoek ontsleutelen, inspecteren en vervolgens weer doorsturen.

Aan de slag gaan

Installatie van mitmproxy

Op macOS is de eenvoudigste manier via brew: brew install mitmproxy

VS Code configuratie

Om het verkeer via mitmproxy te routeren, moeten de volgende instellingen in VS Code worden aangepast (via Cmd+Shift+P > User Settings):

  • Http Proxy: http://localhost:8080
  • Http Proxy Strict SSL: uitvinken (om verificatie van het mitmproxy-certificaat over te slaan)
  • Http: Proxy Support: override (om proxy-ondersteuning voor extensies af te dwingen)

Start VS Code daarna opnieuw op. De webinterface van mitmproxy kan worden gestart met het commando: mitmweb

Problemen met verouderde Extension Host processen

Als er geen verkeer van extensies wordt gevangen, kan het zijn dat de Extension Host processen verouderd zijn. Controleer dit in de terminal met: ps -eo pid,ppid,lstart,command | grep -i -E "copilot|extensionHost|Code Helper"

Als de datum en tijd niet overeenkomen met het moment waarop VS Code is herstart, is het proces verouderd. Los dit op via de Command Palette (Cmd+Shift+P) door uit te voeren: "Developer: Restart Extension Host".

Wat Copilot doet voordat je begint te typen

Bij het bekijken van het verkeer in mitmweb valt op dat de meeste verzoeken betrekking hebben op GitHub of GitHub Copilot. Zelfs voordat er een toets wordt aangeslagen, worden er HTTP-verzoeken gedaan. Deze kunnen worden onderverdeeld in: Auth & Session, Config & Policy, MCP Registry, Repo & Session Context, Model Discovery en Recent repos.

Authenticatie en sessie-bootstrap

Dit is de eerste stap bij het opstarten. Copilot haalt een OAuth-token op, wisselt dit om voor een kortstondig token en valideert de rechten van de gebruiker.

Model- en functionaliteitsdetectie

Voordat er LLM-verzoeken worden gedaan, controleert Copilot welke modellen en agent-mogelijkheden beschikbaar zijn voor het account/plan:

  1. Een verzoek naar /models voor een algemene lijst met beschikbare modellen.
  2. Een verzoek naar /agents/swe/models om specifiek te bepalen welke modellen geschikt zijn voor Software Engineering (SWE) agent-functionaliteiten.

Prompts, context en het harness

De modelrouter van Copilot

Wanneer de "Auto"-modus is geselecteerd, gaat er bij elk bericht eerst een verzoek naar het /models/session/intent eindpunt voordat een model antwoordt. Je prompt wordt gescoord tegen mogelijke intenties, zoals code-generatie, debugging, redeneren of tool-gebruik. Dit resultaat bepaalt welk model de taak zal uitvoeren.

(Geheime) omgevingsvariabelen

Ik testte wat er gebeurt met gevoelige informatie door een fake secret in een .env-bestand te plaatsen: TESTENVVAR_SECRET="a realistic looking fake token"

Hoewel het bewerken van dit bestand geen HTTP-verzoeken triggerde, gebeurde er iets vreemds toen ik in een totaal ander bestand (pyproject.toml) begon te typen. Er ging een completion-verzoek uit dat het volgende bevatte:

{
"prompt":"TEST_ENV_VAR_SECRET=\"mysecretenvvar\"\n\nT",
"extra":{
"context":[
"Path: .env",
"These are recently edited files. Do not suggest code that has been deleted.\nFile: pyproject.toml...",
"File: config.ini..."
]
}
}

Zelfs als Copilot is uitgeschakeld voor .env-bestanden, kan informatie uit deze bestanden nog steeds worden verzonden in verzoeken die worden getriggerd door acties in andere bestanden.

Het geheugen van Copilot opfrissen

In de system prompts zag ik een definitie voor de tool sessionstoresql. De beschrijving luidt: "Query the local session store containing history from past coding sessions." Deze tool gebruikt SQLite-syntax en heeft toegang tot tabellen als sessions, turns en search_index.

Om dit te testen, vroeg ik in de chat: "Waar heb ik deze week aan gewerkt?". Dit leidde tot een interactie tussen het model en een lokale SQLite-database genaamd session-store.db. Copilot gebruikt de Chronicle-tool om SQL-queries uit te voeren op deze database, die sessiesamenvattingen, repositories, branches en alle prompts (inclusief LLM-antwoorden) opslaat.

Opvallend was dat het model het schema niet vooraf kende. Na een mislukte eerste query voerde het model een introspectie uit op de metadata van de SQLite-database om de tabeldefinities te vinden voordat het succesvol records kon ophalen.

Analyse van de lokale database

Ik onderzoekde de database handmatig via de terminal: sqlite3 ~/Library/Application Support/Code/User/globalStorage/github.copilot-chat/session-store.db

De tabel turns slaat usermessage en assistantresponse op als platte tekst. Toen ik berichten verstuurde met fake geheimen (een GitHub-token, een AWS-key), werden deze exact zo in de database opgeslagen:

GITHUB_TOKEN=ghp_«fake token»
DATABASE_URL=postgres://admin:«password»@db.example.com:5432/prod

De conclusie is dat AI-codingtools "stateful" systemen worden. Ze combineren de workspace, recente wijzigingen, conversaties, tools en geschiedenis. Dit verhoogt de bruikbaarheid, maar brengt uitdagingen met zich mee op het gebied van context-bloat, vertrouwelijkheid en privacy.

Bevindingen toetsen aan de broncode

Niet-versleutelde sessieopslag

De code voor de sessieopslag bevindt zich in sessionStore.ts. De tabeldefinitie bevestigt wat ik op disk zag: usermessage en assistantresponse worden als platte tekst opgeslagen. Er is geen masking of filtering aanwezig in het schrijfpad; de data gaat zoals hij is naar de database.

Lekken of niet lekken

De string "recently edited files" die ik in de MITM-capture zag, komt uit recentEdits.tsx. Het standaardgedrag is hardcoded: maximaal 20 bestanden, 8 beknopte wijzigingen en 3 regels context rondom elke wijziging. Dit verklaart hoe een regel die ik niet had aangeraakt (met het fake secret) toch onderdeel werd van een HTTP-verzoek.

Er is geen standaardregel voor .env-bestanden op individuele plannen, noch is er integratie met .gitignore. Er bestaat wel een uitsluitingsfilter, maar deze is gekoppeld aan het "repository policy" beleid, wat een functie is voor Business/Enterprise accounts die door beheerders wordt gecontroleerd.

Slotbeschouwingen

Met grote macht komt grote verantwoordelijkheid

Dit was een waardevolle oefening in het begrijpen van hoe AI-codingtools hun harness implementeren. De vragen die hieruit voortvloeien zijn essentieel voor iedereen die AI-systemen bouwt: Welke context moet worden geïnjecteerd? Wat moet lokaal blijven? Wat wordt opgeslagen in het kortetermijngeheugen versus het langetermijngeheugen?

Context wordt het product

Modellen en benchmarks zijn belangrijk, maar het echte onderscheid tussen AI-codingtools verschuift naar hoe goed ze de juiste context samenstellen: code, recente wijzigingen, acties, conversaties en geschiedenis. Dit creëert twee uitdagingen:

  1. Engineering: Meer context betekent niet automatisch betere context. De uitdaging is om het compact en relevant te houden zonder het model te overspoelen met prompt bloat.
  2. Privacy: Hoe meer een harness contextuele data verzamelt en persisteert, hoe zorgvuldiger er gedefinieerd moet worden wat de grenzen mag overschrijden — tussen bestanden, sessies, machines en uiteindelijk de model-API.

Copilot beweegt duidelijk in deze richting. Sommige oplossingen zijn slim, andere zorgen voor een ongemakkelijk gevoel. Voor wie AI-applicaties bouwt, leert het reverse engineeren van het harness rondom de modellen waarschijnlijk meer dan het bestuderen van het model zelf.