Werkruimtes en isolatie
Wat is een werkruimte?
Sectie getiteld “Wat is een werkruimte?”Een werkruimte is de isolatietenant op het hoogste niveau in Control Center. Hij groepeert agenten, repositories, ruimtes, tickets, geheugen, pipelines en leden in één begrensde context. Alles wat binnen een werkruimte gebeurt, blijft erbinnen.
Een typische werkruimte komt overeen met één project of één codebase. Je kunt aparte werkruimtes hebben voor “api-service”, “frontend-v2” en “infrastructure”.
Gegevens met werkruimtescope
Sectie getiteld “Gegevens met werkruimtescope”De rijen van een werkruimte staan in het eigen SQLite-bestand van die werkruimte, op <dataDir>/<workspaceId>/workspace.db. Elke werkruimte krijgt een map in plaats van een kaal bestand, omdat een werkruimte meer verzamelt dan een database — worktrees per gesprek, de agent- en skillbestanden, chatbotreferenties — en een map geven betekent dat dat allemaal samen leeft en samen wordt verwijderd.
| Entiteit | Scope |
|---|---|
| Agenten | Horen bij precies één werkruimte |
| Repository’s | Geregistreerd in één werkruimte (zie hieronder) |
| Ruimtes, gesprekken en berichten | Werkruimtegebonden |
| Tickets, projecten, plannen, orkestraties | Werkruimtegebonden |
| Geheugenfeiten, beleidsregels, domeinen, toegangsrechten | Werkruimtegebonden |
| Pipeline-runs, sjablonen, triggers | Werkruimtegebonden |
| Pull request-status, reviewruimtes, reviewcohorten | Werkruimtegebonden |
| Agent-runlogs en werkgeheugen | Werkruimtegebonden |
| Leden, uitnodigingen, rechten per repo | Werkruimtegebonden |
| Symbolen en randen van de codegraph | Afgebakend op repoId binnen het werkruimtebestand |
De meeste van deze rijen hebben een workspaceId-kolom; aparte databasebestanden handhaven de isolatie. Zie de isolatie-invariant hieronder.
Repo’s zijn werkruimtegebonden; identiteit over werkruimtes loopt via het pad
Sectie getiteld “Repo’s zijn werkruimtegebonden; identiteit over werkruimtes loopt via het pad”Een rij voor een repo staat in het eigen databasebestand van zijn werkruimte — het bestand is de scope, dus de tabel heeft geen workspaceId-kolom en geen koppeltabel.
Je voegt een repo aan een werkruimte toe via Instellingen → Werkruimte → Repository’s. Dezelfde checkout in twee werkruimtes registreren maakt twee onafhankelijke rijen met twee id’s; de identiteit van een repo over werkruimtes loopt via het bestandssysteempad (of GitHub-eigenaar/naam), nooit via het id.
Registratie is strikt: het pad moet binnen een git-worktree liggen, er moet een origin-remote zijn en die remote moet naar een ondersteunde forge wijzen (github.com, gitlab.com of bitbucket.org). De forge wordt uit de remote gelezen en op de repo opgeslagen, dus één werkruimte kan repo’s van alle drie bevatten. Al het andere wordt geweigerd. De mappenbrowser waarin je kiest toont het bestandssysteem van de serverhost, beperkt tot de allow-list --repo-roots van de server (die standaard de homedirectory van de servergebruiker is).
Een repository uit een werkruimte verwijderen wist de rij in één keer en laat de symbolen, randen, bestanden, indexcheckpoints en rechten per lid van de codegraph mee verwijderen. De checkout op schijf blijft onaangeroerd.
De codegraph staat in hetzelfde bestand, gesleuteld op repoId, omdat verschillende werkruimtes dezelfde repository op verschillende branches met verschillende code kunnen hebben.
De isolatie-invariant
Sectie getiteld “De isolatie-invariant”Gegevenslekken tussen werkruimtes worden als bugs behandeld. Isolatie is structureel en wordt op meerdere niveaus gehandhaafd:
- Databaselaag. Elke werkruimte heeft zijn eigen SQLite-bestand, uitgedeeld door
WorkspaceDatabaseManager.of(workspaceId). Een werkruimtedatabase declareertusers,workspacesof de tabellen van een andere werkruimte niet, dus een cross-workspace-leesopdracht is geen bug die je kunt schrijven — hij compileert niet. Repositories zoeken hun DAO per call op in plaats van er een te cachen, en omdat elke repositorymethode een verplichteworkspaceIdaanneemt, kan de werkruimte nooit worden afgeleid of standaard gekozen. - Het werkruimte-id is een padsegment. Omdat het id een mapnaam wordt, moet het overeenkomen met een veilig patroon van één segment (begint alfanumeriek, daarna alfanumerieke tekens, punten, underscores, koppeltekens; geen
..). Id’s zijn overal in het product UUID’s. Al het andere gooit een fout in plaats van te worden opgeschoond — dat is de pad-traversal-guard, en hij faalt luidruchtig in plaats van de gegevens van een werkruimte naar een pad te schrijven dat iemand anders heeft gekozen. - Verdediging in de diepte. De
workspaceId-kolommen staan er nog steeds en worden nog steeds geschreven. Hoewel ze binnen één bestand overbodig zijn, houden ze de sync-feed-triggers, FTS-indexen en bestaande rijvormen ongewijzigd, en maken ze een bestand zelfbeschrijvend wanneer je het op zichzelf bekijkt — precies waarop export en import vertrouwen. - Domeinlaag. Services die entiteiten op id muteren, controleren
entity.workspaceId == workspaceIdop één chokepoint voordat ze doorgaan, en gooienWorkspaceMismatchExceptionbij een mismatch — de luidruchtige fout voor een id dat uit de verkeerde context kwam. Luidruchtig weigeren is belangrijk: een stille no-op verbergt de bug en doorgaan lekt. - RPC-laag. De repo-RPC-dispatcher is het chokepoint. Elke operatie met werkruimtescope moet
workspace_idin zijn eigen argumenten meedragen — er is geen “huidige werkruimte” per sessie om te lekken, en een onbekend id wordt al als niet-gevonden geweigerd voordat er iets een database opent, zodat een slecht id geen spook-workspace.dbkan materialiseren. Echt globale operaties (de nieuwsfeed, de fleetwachtrij) verklaren zichzelf unscoped als een expliciete, getoetste beslissing. MCP-tools volgen dezelfde regel: elke tool die gegevens met werkruimtescope aanraakt, vereistworkspace_id. - Cross-workspace-fan-out is opsombaar. Een vraag over meerdere werkruimtes beantwoorden betekent meerdere databases openen. Die fan-out is beperkt tot één helper,
CrossWorkspaceQueries, zodat de volledige lijst van zaken die de grens legitiem overschrijden in de call sites van één bestand woont in plaats van te verdwijnen achter doc-comments. Die call sites zijn: serverbrede aggregatie, opstart-reconcilers, retentie- en GC-sweeps, back-up, event-routers — en de lidmaatschapzoekopdracht hieronder. - Alleen toegang op id is niet genoeg. Een entiteit opzoeken op zijn UUID bewijst niet dat hij bij de werkruimte van de aanroeper hoort. De bestandssplitsing maakt het verkeerde bestand onbereikbaar; de validatie in de domeinlaag vangt een verkeerd id af dat via een legitiem bestand binnenkomt.
Lidmaatschap geeft toegang, niet de koppelingssleutel
Sectie getiteld “Lidmaatschap geeft toegang, niet de koppelingssleutel”Het bezitten van een apparaatreferentie authenticeert een apparaat. Het machtigt niets binnen een werkruimte. Elke operatie met werkruimtescope bepaalt de lidmaatschapsrol van de aanroeper en handhaaft een ondergrens die van het soort operatie is afgeleid — lezen vereist guest, een mutatie vereist member, een destructieve bewerking vereist admin — en operaties die repo-inhoud blootstellen controleren daarnaast de toegang per repo van de aanroeper. Een geldige koppelingssleutel zonder lidmaatschap krijgt Not a member of this workspace.
Het gevolg voor isolatie is fraai: lidmaatschapsrijen staan in het eigen bestand van de werkruimte, dus “wie zit in deze werkruimte?” is een gewone leesopdracht met werkruimtescope. De omgekeerde vraag — “in welke werkruimtes zit ik?” — is per definitie over bestanden verdeeld, dus het is een van de weinige goedgekeurde fan-outs van CrossWorkspaceQueries, en dat is wat de werkruimtekiezer uitvoert voordat er een werkruimte is gekozen.
Zie Multiplayer voor de rollenladder en de rechten per repo.
Het globale register
Sectie getiteld “Het globale register”Niet alles is werkruimtegebonden. Een tweede database, <dataDir>/global.db, bevat wat echt serverbreed is:
- het werkruimteregister, zodat de wisselaar elke werkruimte kan tonen zonder ook maar één werkruimtebestand te openen — en zodat de naam, het logo, de eigenaar, de handmatige volgorde en de markering voor zachte verwijdering van een werkruimte buiten het bestand wonen dat ze beschrijven;
- identiteit: gebruikers, gebruikersvoorkeuren en gekoppelde apparaten, omdat één mens één gebruiker is in elke werkruimte en een gekoppeld apparaat het verwijderen van een werkruimte overleeft;
- de fleetwachtrij (workers, jobs, plaatsingslog), waarvan de scheduler bij elke tick de hele wachtrij tegen elke worker matcht;
- de nieuwsfeed, die per gebruiker is (niet per werkruimte) — een feed toevoegen volgt je in elke werkruimte;
workspace_routes, de pre-auth-index die antwoordt op “welke werkruimte bezit deze sleutel?” voor entreepunten die alleen met een secret of een ondoorzichtig id aankomen (een uitnodigingshash, een webhooktoken, een deeplink) en zonder werkruimte. Een misser daar is een niet-gevonden; er is bewust geen scan-fallback;- installatiebrede instellingen en identiteit: het installatie-id, instellingen op hostniveau, SSO-verbindingen en beheerde actiebeleidsregels (een installatiebrede begrenzing die de beveiligingen van werkruimtes alleen maar strenger kan maken).
Bij het opstarten wordt alleen dit bestand geopend. Werkruimtebestanden worden lazy geopend bij het eerste gebruik, zodat de opstartkosten vlak blijven ongeacht hoeveel geschiedenis de werkruimtes opbouwen, en de quick_check per bestand wordt betaald bij het eerste gebruik in plaats van op de weg naar de ready-banner.
Een werkruimtebestand bevat alleen een workspace_meta met één rij voor zelfidentificatie (het id, de installatie die het heeft aangemaakt, de schemaversie waarmee het is aangemaakt, en wanneer). Alles wat een werkruimte beschrijft, staat in het register.
Een werkruimte aanmaken
Sectie getiteld “Een werkruimte aanmaken”Een werkruimte aanmaken doet meer dan een rij in het register invoegen. In één bewerking stempelt de server de aanmakende gebruiker als ownerUserId, legt hij het lidmaatschap met de eigenaarsrol van die gebruiker vast en publiceert hij een WorkspaceCreated-domeingebeurtenis. Luisteraars op die gebeurtenis zaaien vervolgens, idempotent en op de achtergrond:
- een CEO-agent plus vier specialisten —
qa,architect,engineer,librarian— waarbij de specialisten aan de CEO rapporteren; - de ingebouwde pipelinesjablonen en hun triggers (triggers op gebeurtenissen en handmatige triggers worden ingeschakeld geleverd; geplande zijn opt-in, behalve de dagelijkse worktree-GC-sweep);
- de starter-evalsuites.
Dit gebeurt voor elke werkruimte, niet alleen de eerste. De geseede agenten worden zonder adapter aangemaakt, dus ze draaien op Control Center (built-in) met Anthropics standaardmodel (claude-opus-4-8, tenzij je een ander vastzet) totdat je per agent een adapter en model instelt via Instellingen → Werkruimte → Agenten. Zie Het agentmodel.
Het wegschrijven van het eigenaarslidmaatschap is belangrijker dan het lijkt: zonder dat zou de pas aangemaakte werkruimte geen leden hebben en zou elke call met werkruimtescope die de maker daarna doet, worden geweigerd.
Verwijderen, exporteren, importeren
Sectie getiteld “Verwijderen, exporteren, importeren”Een werkruimte verwijderen markeert de registerrij en ontkoppelt de map. De werkruimte verdwijnt uit elke lijst en zoekopdracht. De registerrij blijft staan (zacht verwijderd), zodat het id nog bekend is bij back-up en onderhoud, maar workspace.delete gooit de map van die werkruimte onmiddellijk weg — database, worktrees, agentbestanden en de rest — via WorkspaceDatabaseManager.dropAndClose. Alleen de eigenaar van de werkruimte kan hem verwijderen.
Omdat één werkruimte één bestand is, is een werkruimte doorgeven een bestandsbewerking in plaats van een dump tabel voor tabel:
workspace.exportis éénVACUUM INTO— een consistente, gedefragmenteerde momentopname die onder een leestransactie wordt gemaakt terwijl de server blijft serveren.workspace.importneemt zo’n bestand over en vervangt alles wat de doelwerkruimte nu bevat. De ingebeddeworkspace_metalaat een import onderscheid maken tussen “mijn eigen bestand, opnieuw overgenomen” en “een bestand van een andere installatie” (dat laatste is toegestaan, maar wordt gelogd in plaats van onzichtbaar te blijven).server.backupNowmaakt een momentopname van de hele installatie in een map met tijdstempel die de live datadir spiegelt —manifest.json,global.dben één<workspaceId>/workspace.dbper werkruimte — dus herstellen is hem terugkopiëren.server.listBackupsleest die map terug, nieuwste eerst, met de grootte en de werkruimtelijst van elke momentopname. Een momentopname waarvan het manifest ontbreekt of bestanden noemt die er niet zijn, wordt nog steeds gerapporteerd, gemarkeerd als onvolledig — hem verbergen is hoe een operator gaat geloven dat hij een back-up heeft die hij niet heeft.
De back-upbewerkingen staan onder Instellingen → Server → Back-up en herstel:
Nu back-uppen maakt een momentopname van de installatie, de lijst toont welke momentopnamen
volledig zijn en laat de eigenaar van de installatie er na bevestiging een verwijderen, en elke
werkruimte biedt exporteren en importeren. De ingebouwde pipeline Workspace backup
neemt volgens een wekelijks schema alleen de database van die werkruimte mee en verwijdert zijn eigen
back-ups die ouder zijn dan de ingestelde bewaartermijn. Een werkruimte herstellen uit een
momentopname van de installatie is workspace.import richten op de
<workspaceId>/workspace.db van de momentopname; een hele installatie herstellen blijft een
terugkopieeractie van de momentopnamemap met de server gestopt.
Wat geen van alle meeneemt, is de rest van de werkruimtemap. Een werkruimte verzamelt meer dan een database — geplakte afbeeldingen, skill- en agentbestanden, chatreferenties, worktrees — en export en import verplaatsen het bestand, dus alles ernaast blijft waar het staat. Dat is bewust voor referenties en wegwerpbaar voor worktrees; voor de rest is het een grens die je moet kennen in plaats van een functie. De back-upreferentie bevat de volledige tabel.
Een back-up verplaatsen tussen de server en je apparaat
Sectie getiteld “Een back-up verplaatsen tussen de server en je apparaat”Elke operatie hierboven spreekt in paden op de server, wat alleen een volledig antwoord is als de server je eigen machine is. Drie ondertekende HTTP-routes — /backup/workspace, /backup/snapshot en /backup/restore — dragen de bytes voor elke andere topologie, op dezelfde geauthenticeerde baan die de mediaproxy en het afbeeldingsarchief al gebruiken. Op de pagina is dit een knop Downloaden naast elke export en elke momentopname (jij kiest waar hij landt), en Bestand kiezen en uploaden om te herstellen uit een bestand dat op de machine staat die je gebruikt. De upload is degene die werkt als de server niet je machine is: workspace.import heeft het bestand al op de host nodig, en zo komt het daar.
Drie eigenschappen zijn het kennen waard:
- Een download maakt een verse kopie en de server houdt er niets van. Downloaden is niet “het bestand ophalen dat de exportknop heeft gemaakt” — er wordt opnieuw geëxporteerd, dat wordt gestreamd en daarna verwijderd. Het antwoord is
no-storemetAccept-Ranges: noneom dezelfde reden: een hervat bereik zou twee verschillende exports aan elkaar plakken tot één bestand dat geldig lijkt maar het niet is. - Een upload wordt naar schijf gestreamd, nooit gebufferd, aan beide kanten, en de klaargezette kopie wordt op elk uitpad verwijderd — ook bij een weigering. Een werkruimtedatabase is geen schermafbeelding.
- Een doorgestuurde verbinding heeft geen HTTP-origin, dus daar zijn de overdrachtsbedieningselementen uitgeschakeld met een melding waarom. Alles wat in paden aan de serverkant spreekt, blijft via de relay werken; alleen de byte-banen hebben een directe verbinding nodig.
Meerdere werkruimtes
Sectie getiteld “Meerdere werkruimtes”Je kunt meerdere werkruimtes naast elkaar draaien. Elke werkruimte werkt onafhankelijk: agenten in de ene werkruimte kunnen geen berichten sturen naar agenten in een andere, kunnen het geheugen van een andere werkruimte niet lezen en zien de tickets ervan niet. Het bepalen van de ontvanger voor berichten tussen agenten is exact en gaat nooit een werkruimte over.
Er is geen dashboard over werkruimtes heen. Het analytics-oppervlak op /workspaces/:workspaceId/observability abonneert zich op een begrensde globale feed van recente runs en vernauwt die meteen tot de actieve werkruimte, dus wat je daar ziet is één werkruimte tegelijk. De enige echt multi-werkruimte-oppervlakken die een mens aanraakt, zijn de werkruimtekiezer en de wisselaar.
Eén praktische grens die het kennen waard is: een werkruimte die iemand gebruikt blijft open — er is geen LRU. Voorbij 32 daarvan waarschuwt de server in plaats van te weigeren, omdat elk geopend bestand een achtergrond-isolate en een page-cache vasthoudt. Cross-workspace-fan-out opent bestanden kortstondig en sluit ze daarna als niets anders ze heeft opgeëist.
Gerelateerde concepten
Sectie getiteld “Gerelateerde concepten”- Multiplayer: lidmaatschap, rollen en rechten per repo — de toegangskant van isolatie
- Het agentmodel: agenten horen bij precies één werkruimte
- Geheugen en kennis: geheugen is werkruimtegebonden
- Architectuur: waar de databases zitten in de client/server-splitsing
- Back-uppen en herstellen: een momentopname maken, een werkruimte verplaatsen, kopieën elders bewaren
- Backup, export en import: elke bewerking, route, manifestveld en limiet
- Repos toevoegen aan een werkruimte: een checkout in een werkruimte registreren