Espaces de travail et isolation
Qu’est-ce qu’un espace de travail ?
Section intitulée “Qu’est-ce qu’un espace de travail ?”Un espace de travail est le locataire d’isolation de niveau supérieur de Control Center. Il regroupe les agents, les dépôts, les espaces, les tickets, la mémoire, les pipelines et les membres dans un contexte borné. Tout ce qui se passe à l’intérieur d’un espace de travail y reste.
Un espace de travail typique correspond à un projet ou à une base de code. Vous pouvez avoir des espaces de travail distincts pour « api-service », « frontend-v2 » et « infrastructure ».
Données propres à l’espace de travail
Section intitulée “Données propres à l’espace de travail”Les lignes d’un espace de travail vivent dans le fichier SQLite de cet espace de travail, à <dataDir>/<workspaceId>/workspace.db. Chaque espace de travail obtient un répertoire plutôt qu’un simple fichier, parce qu’un espace de travail accumule plus qu’une base de données — des arbres de travail par conversation, les fichiers d’agents et de skills, les identifiants de robots de clavardage — et lui donner un dossier signifie que tout cela vit et est supprimé ensemble.
| Entité | Portée |
|---|---|
| Agents | Appartiennent à un seul espace de travail |
| Dépôts | Enregistrés dans un seul espace de travail (voir ci-dessous) |
| Espaces, conversations et messages | Propres à l’espace de travail |
| Tickets, projets, plans, orchestrations | Propres à l’espace de travail |
| Faits de mémoire, politiques, domaines, autorisations d’accès | Propres à l’espace de travail |
| Exécutions de pipeline, modèles, déclencheurs | Propres à l’espace de travail |
| État des demandes de tirage, espaces de révision, cohortes de révision | Propres à l’espace de travail |
| Journaux d’exécution des agents et mémoire de travail | Propres à l’espace de travail |
| Membres, invitations, autorisations par dépôt | Propres à l’espace de travail |
| Symboles et arêtes du graphe de code | Délimités par repoId dans le fichier de l’espace de travail |
La plupart de ces lignes portent une colonne workspaceId ; des fichiers de base de données distincts assurent l’isolation. Voir l’invariant d’isolation ci-dessous.
Les dépôts sont propres à l’espace de travail ; l’identité entre espaces de travail passe par le chemin
Section intitulée “Les dépôts sont propres à l’espace de travail ; l’identité entre espaces de travail passe par le chemin”Une ligne de dépôt vit dans le fichier de base de données de son propre espace de travail — le fichier est la portée, de sorte que la table n’a ni colonne workspaceId ni table de jointure.
Vous ajoutez un dépôt dans un espace de travail à Paramètres → Espace de travail → Dépôts. Enregistrer le même checkout dans deux espaces de travail crée deux lignes indépendantes avec deux identifiants ; l’identité d’un dépôt entre les espaces de travail passe par le chemin du système de fichiers (ou par le propriétaire/nom GitHub), jamais par l’identifiant.
L’enregistrement est strict : le chemin doit se trouver à l’intérieur d’un arbre de travail git, il doit avoir un dépôt distant origin et ce dépôt distant doit pointer vers une forge prise en charge (github.com, gitlab.com ou bitbucket.org). La forge est lue à partir du dépôt distant et stockée sur le dépôt, de sorte qu’un espace de travail peut contenir des dépôts des trois. Tout autre cas est refusé. Le navigateur de dossiers dans lequel vous choisissez affiche le système de fichiers de l’hôte du serveur, confiné à la liste d’autorisation --repo-roots du serveur (qui correspond par défaut au répertoire personnel de l’utilisateur du serveur).
Retirer un dépôt d’un espace de travail supprime la ligne d’emblée et met en cascade ses symboles de code, ses arêtes, ses fichiers, ses points de contrôle d’index et ses autorisations par membre. Le checkout sur le disque n’est pas touché.
Le graphe de code vit dans le même fichier, indexé par repoId, parce que différents espaces de travail peuvent avoir le même dépôt sur différentes branches avec du code différent.
L’invariant d’isolation
Section intitulée “L’invariant d’isolation”Les fuites de données entre espaces de travail sont traitées comme des bogues. L’isolation est structurelle, appliquée à plusieurs niveaux :
- Couche base de données. Chaque espace de travail a son propre fichier SQLite, distribué par
WorkspaceDatabaseManager.of(workspaceId). Une base de données d’espace de travail ne déclare niusers, niworkspaces, ni les tables d’un autre espace de travail, de sorte qu’une lecture entre espaces de travail n’est pas un bogue que vous pouvez écrire — elle ne compile pas. Les dépôts résolvent leur DAO à chaque appel plutôt que d’en mettre un en cache et, comme chaque méthode de dépôt prend unworkspaceIdobligatoire, l’espace de travail ne peut jamais être déduit ni obtenu par défaut. - L’identifiant d’espace de travail est un segment de chemin. Comme l’identifiant devient un nom de répertoire, il doit respecter un motif sûr à segment unique (commencement alphanumérique, puis alphanumériques, points, traits de soulignement, traits d’union ; pas de
..). Les identifiants sont des UUID partout dans le produit. Tout le reste lève une exception plutôt que d’être assaini — c’est le garde-fou contre la traversée de chemins, et il échoue bruyamment au lieu d’écrire les données d’un espace de travail dans un chemin choisi par quelqu’un d’autre. - Défense en profondeur. Les colonnes
workspaceIdsont toujours là et toujours écrites. Redondantes à l’intérieur d’un fichier, elles laissent inchangés les déclencheurs du flux de synchronisation, les index FTS et la forme existante des lignes, et elles rendent un fichier autodescriptif lorsqu’il est inspecté seul — ce sur quoi reposent l’export et l’import. - Couche domaine. Les services qui modifient des entités par identifiant valident
entity.workspaceId == workspaceIdà un point de passage unique avant de continuer et lèventWorkspaceMismatchExceptionen cas de non-concordance — l’échec bruyant pour un identifiant arrivé du mauvais contexte. Refuser bruyamment importe : une non-opération silencieuse masque le bogue, et continuer provoque une fuite. - Couche RPC. Le répartiteur repo-RPC est le point de passage. Chaque opération propre à un espace de travail doit porter
workspace_iddans ses propres arguments — il n’existe aucun « espace de travail courant » par session qui pourrait fuir, et un identifiant inconnu est refusé comme introuvable avant que quoi que ce soit n’ouvre une base de données, de sorte qu’un mauvais identifiant ne peut pas matérialiser unworkspace.dbfantôme. Les opérations réellement globales (le fil de nouvelles, la file de la flotte) se déclarent hors portée par une décision explicite et révisée. Les outils MCP suivent la même règle : tout outil qui touche des données propres à un espace de travail exigeworkspace_id. - La diffusion entre espaces de travail est énumérable. Répondre à une question sur plusieurs espaces de travail signifie ouvrir plusieurs bases de données. Cette diffusion est confinée à un seul assistant,
CrossWorkspaceQueries, de sorte que la liste complète de ce qui franchit légitimement la frontière vit dans les sites d’appel d’un seul fichier plutôt que de se diffuser derrière des commentaires de documentation. Ces sites d’appel sont : l’agrégation à l’échelle du serveur, les réconciliateurs de démarrage, les balayages de rétention et de GC, la sauvegarde, les routeurs d’événements — et la recherche d’appartenance ci-dessous. - L’accès par identifiant seul ne suffit pas. Rechercher une entité par son UUID ne prouve pas qu’elle appartient à l’espace de travail de l’appelant. La séparation des fichiers rend le mauvais fichier inatteignable ; la validation de la couche domaine attrape un mauvais identifiant qui arrive par un fichier légitime.
L’appartenance, et non la clé d’appairage, est ce qui accorde l’accès
Section intitulée “L’appartenance, et non la clé d’appairage, est ce qui accorde l’accès”Détenir un identifiant d’appareil authentifie un appareil. Cela n’autorise rien à l’intérieur d’un espace de travail. Chaque opération propre à un espace de travail résout le rôle d’appartenance de l’appelant et impose un seuil minimal dérivé du type d’opération — une lecture exige guest, une mutation exige member, une opération destructive exige admin — et les opérations qui exposent le contenu d’un dépôt vérifient en plus l’autorisation par dépôt de l’appelant. Une clé d’appairage valide sans appartenance reçoit Not a member of this workspace.
La conséquence pour l’isolation est nette : les lignes d’appartenance vivent dans le fichier de l’espace de travail lui-même, donc « qui est dans cet espace de travail ? » est une lecture délimitée ordinaire. La question inverse — « dans quels espaces de travail suis-je ? » — est par définition répartie entre les fichiers, c’est donc l’une des rares diffusions CrossWorkspaceQueries sanctionnées, et c’est ce que le sélecteur d’espaces de travail exécute avant qu’un espace de travail ait été choisi.
Voir Multijoueur pour la hiérarchie des rôles et les autorisations par dépôt.
Le registre global
Section intitulée “Le registre global”Tout n’est pas propre à un espace de travail. Une seconde base de données, <dataDir>/global.db, contient ce qui est réellement commun à tout le serveur :
- le registre des espaces de travail, pour que le commutateur puisse lister chaque espace de travail sans ouvrir un seul fichier d’espace de travail — et pour que le nom, le logo, le propriétaire, l’ordre manuel et le marqueur de suppression logique d’un espace de travail vivent à l’extérieur du fichier qu’ils décrivent ;
- l’identité : les utilisateurs, les préférences utilisateur et les appareils appairés, parce qu’un humain est un seul utilisateur dans tous les espaces de travail et qu’un appareil appairé survit à la suppression d’un espace de travail ;
- la file de la flotte (workers, tâches, journal de placement), dont l’ordonnanceur confronte toute la file à chaque worker à chaque cycle ;
- le fil de nouvelles, qui est par utilisateur (et non par espace de travail) — ajouter un fil vous suit dans chaque espace de travail ;
workspace_routes, l’index avant authentification qui répond à « quel espace de travail possède cette clé ? » pour les points d’entrée qui arrivent sans rien d’autre qu’un secret ou qu’un identifiant opaque (un hachage d’invitation, un jeton de webhook, un lien profond) et sans espace de travail. Une absence d’entrée y est un introuvable ; il n’y a délibérément aucune reprise par balayage ;- les paramètres et l’identité à l’échelle de l’installation : l’identifiant d’installation, les paramètres de l’hôte, les connexions SSO et les politiques d’actions gérées (un verrou à l’échelle de l’installation qui ne peut que resserrer les garde-fous des espaces de travail).
Le démarrage n’ouvre que ce fichier. Les fichiers d’espace de travail s’ouvrent de façon paresseuse au premier accès, de sorte que le coût de démarrage reste constant peu importe l’historique que les espaces de travail accumulent, et le quick_check par fichier est payé au premier usage plutôt que sur le chemin vers la bannière de disponibilité.
Un fichier d’espace de travail ne porte qu’une workspace_meta à ligne unique pour s’auto-identifier (son identifiant, l’installation qui l’a créé, la version de schéma avec laquelle il a été créé, quand). Tout ce qui décrit un espace de travail se trouve dans le registre.
Créer un espace de travail
Section intitulée “Créer un espace de travail”Créer un espace de travail fait plus qu’insérer une ligne dans le registre. En une seule opération, le serveur inscrit l’utilisateur créateur comme ownerUserId, enregistre l’appartenance de cet utilisateur avec le rôle de propriétaire et publie un événement de domaine WorkspaceCreated. Les écouteurs de cet événement amorcent ensuite, de façon idempotente et en arrière-plan :
- un agent CEO et quatre spécialistes —
qa,architect,engineer,librarian—, les spécialistes relevant du CEO ; - les modèles de pipeline intégrés et leurs déclencheurs (les déclencheurs par événement et manuels sont livrés activés ; ceux planifiés sont facultatifs, sauf le balayage quotidien de GC des arbres de travail) ;
- les suites d’évaluation de départ.
Cela se produit pour chaque espace de travail, pas seulement le premier. Les agents amorcés sont créés sans adaptateur, de sorte qu’ils s’exécutent sur Control Center (built-in) avec le modèle par défaut d’Anthropic (claude-opus-4-8, à moins que vous n’en épingliez un autre) jusqu’à ce que vous définissiez un adaptateur et un modèle par agent à Paramètres → Espace de travail → Agents. Voir Le modèle d’agent.
L’écriture de l’appartenance du propriétaire importe plus qu’il n’y paraît : sans elle, l’espace de travail fraîchement créé n’aurait aucun membre et chaque appel propre à un espace de travail que le créateur fait ensuite serait refusé.
Supprimer, exporter, importer
Section intitulée “Supprimer, exporter, importer”Supprimer un espace de travail marque la ligne du registre et dissocie le répertoire. L’espace de travail disparaît de toutes les listes et de toutes les recherches. La ligne du registre demeure (supprimée logiquement) pour que l’identifiant reste connu de la sauvegarde et de la maintenance, mais workspace.delete supprime immédiatement le répertoire de cet espace de travail — base de données, arbres de travail, fichiers d’agents et le reste — par WorkspaceDatabaseManager.dropAndClose. Seul le propriétaire de l’espace de travail peut le supprimer.
Comme un espace de travail correspond à un fichier, faire circuler un espace de travail est une opération sur fichier plutôt qu’un vidage table par table :
workspace.exportest un seulVACUUM INTO— un instantané cohérent et défragmenté pris dans une transaction de lecture pendant que le serveur continue de servir.workspace.importadopte un tel fichier, en remplaçant tout ce que l’espace de travail cible contient actuellement. Laworkspace_metaintégrée permet à un import de distinguer « mon propre fichier, réadopté » d’« un fichier d’une autre installation » (ce dernier cas est permis, mais journalisé plutôt que de passer inaperçu).server.backupNowprend un instantané de toute l’installation dans un répertoire horodaté qui reflète le répertoire de données actif —manifest.json,global.dbet un<workspaceId>/workspace.dbpar espace de travail — de sorte que restaurer consiste à le recopier à sa place.server.listBackupsrelit ce répertoire, du plus récent au plus ancien, avec la taille et la liste des espaces de travail de chaque instantané. Un instantané dont le manifeste manque ou qui nomme des fichiers absents est tout de même signalé, marqué comme incomplet — le masquer, c’est ainsi qu’un opérateur en vient à croire qu’il dispose d’une sauvegarde qui n’existe pas.
Les opérations de sauvegarde se trouvent sous Paramètres → Serveur → Sauvegarde et restauration :
Sauvegarder maintenant prend un instantané de l’installation, la liste montre quels instantanés sont
complets et permet au propriétaire de l’installation d’en supprimer un après confirmation, et chaque
espace de travail offre l’export et l’import. Le pipeline intégré Workspace backup
ne prend que la base de données de cet espace de travail selon un horaire hebdomadaire et supprime ses propres
sauvegardes plus anciennes que la durée de rétention configurée. Restaurer un espace de travail à partir d’un
instantané de l’installation consiste à pointer workspace.import vers le
<workspaceId>/workspace.db de l’instantané ; restaurer une installation complète demeure une
recopie du répertoire d’instantané avec le serveur arrêté.
Ce qu’aucune de ces opérations ne transporte, c’est le reste du répertoire de l’espace de travail. Un espace de travail accumule plus qu’une base de données — images collées, fichiers de skills et d’agents, identifiants de clavardage, arbres de travail — et l’export et l’import déplacent le fichier, donc tout ce qui l’accompagne reste où il est. C’est délibéré pour les identifiants et jetable pour les arbres de travail ; pour le reste, c’est une limite à connaître plutôt qu’une fonctionnalité. La référence sur la sauvegarde contient le tableau complet.
Déplacer une sauvegarde entre le serveur et votre appareil
Section intitulée “Déplacer une sauvegarde entre le serveur et votre appareil”Toutes les opérations ci-dessus s’expriment en chemins sur le serveur, ce qui n’est une réponse complète que lorsque le serveur est votre propre machine. Trois routes HTTP signées — /backup/workspace, /backup/snapshot et /backup/restore — transportent les octets pour toute autre topologie, sur la même voie authentifiée que celle qu’utilisent déjà le proxy de médias et le magasin d’images. Dans la page, cela se présente comme un bouton Télécharger à côté de chaque export et de chaque instantané (vous choisissez où il aboutit), et Choisir un fichier et l’envoyer pour restaurer à partir d’un fichier qui se trouve sur la machine que vous utilisez. C’est le téléversement qui fonctionne lorsque le serveur n’est pas votre machine : workspace.import exige que le fichier soit déjà sur l’hôte, et c’est ainsi qu’il s’y retrouve.
Trois propriétés méritent d’être connues :
- Un téléchargement crée une copie fraîche et le serveur n’en conserve rien. Télécharger, ce n’est pas « aller chercher le fichier que le bouton d’export a créé » : cela exporte de nouveau, diffuse ce résultat, puis le supprime. La réponse est
no-storeavecAccept-Ranges: nonepour la même raison : une plage reprise souderait deux exports différents en un seul fichier qui a l’air valide sans l’être. - Un téléversement est diffusé vers le disque, jamais mis en mémoire tampon, aux deux extrémités, et la copie intermédiaire est supprimée sur chaque chemin de sortie — y compris en cas de refus. Une base de données d’espace de travail n’est pas une capture d’écran.
- Une connexion relayée n’a pas d’origine HTTP, donc les commandes de transfert y sont désactivées, avec une note qui en explique la raison. Tout ce qui s’exprime en chemins côté serveur continue de fonctionner par le relais ; seules les voies d’octets ont besoin d’une connexion directe.
Plusieurs espaces de travail
Section intitulée “Plusieurs espaces de travail”Vous pouvez exécuter plusieurs espaces de travail côte à côte. Chacun fonctionne indépendamment : les agents d’un espace de travail ne peuvent pas envoyer de messages aux agents d’un autre, ne peuvent pas lire la mémoire d’un autre espace de travail et ne peuvent pas voir ses tickets. La résolution des destinataires pour la messagerie d’agent à agent est exacte et ne franchit jamais un espace de travail.
Il n’existe aucun tableau de bord entre espaces de travail. La surface d’analyse à /workspaces/:workspaceId/observability s’abonne à un flux global borné des exécutions récentes et le restreint immédiatement à l’espace de travail actif, de sorte que ce que vous y voyez porte sur un espace de travail à la fois. Les seules surfaces réellement multi-espaces de travail qu’une personne côtoie sont le sélecteur d’espaces de travail et le commutateur.
Une limite pratique mérite d’être connue : un espace de travail que quelqu’un utilise reste ouvert — il n’y a pas de LRU. Au-delà de 32 d’entre eux, le serveur avertit plutôt que de refuser, parce que chaque fichier ouvert retient un isolate en arrière-plan et un cache de pages. La diffusion entre espaces de travail ouvre des fichiers de façon transitoire et les referme ensuite si rien d’autre ne les a réclamés.
Concepts connexes
Section intitulée “Concepts connexes”- Multijoueur : l’appartenance, les rôles et les autorisations par dépôt — la moitié de l’isolation qui concerne l’accès
- Le modèle d’agent : les agents appartiennent à un seul espace de travail
- Mémoire et connaissances : la mémoire est propre à l’espace de travail
- Architecture : où se situent les bases de données dans la séparation client/serveur
- Sauvegarder et restaurer : prendre un instantané, déplacer un espace de travail, conserver des copies ailleurs
- Sauvegarde, export et import : chaque opération, route, champ de manifeste et limite
- Ajouter des dépôts : enregistrer un checkout dans un espace de travail