Portabilité des agents
Un agent n’est pas un fichier. C’est une entrée de configuration qui référence des fournisseurs, des profils, des bundles et des serveurs MCP, ainsi qu’un répertoire de travail sur le disque. Le déplacer vers une autre installation implique de transférer les deux parties, et de décider ce qui ne doit pas être transféré du tout.
Un bundle d’agent est la forme portable :
<bundle>/
├── zeroclaw-agent.toml — manifest: format version, root alias, provenance,
│ required secrets, carried skill bundles,
│ dropped refs, risk flags
├── config.toml — the config closure this agent needs
├── workspace/ — the agent's workspace tree
└── skills/<alias>/ — content of each skill bundle the agent references
config.toml est un fragment, et non une configuration complète. Il ne contient que les entrées que l’agent référence, et il doit être relu avant d’être approuvé.
Exportation
sh
zeroclaw agents export <alias> --out ./my-agent
| Indicateur | Effet |
|---|---|
--out <dir> | Répertoire de destination du bundle, créé s’il n’existe pas. |
--force | Remplacer une destination qui contient déjà des éléments. |
Export est en lecture seule sur l’installation et signale trois éléments : les capacités qu’un opérateur destinataire accepterait, les identifiants qui ont été purgés, et la configuration qui n’a pas pu être transférée.
Un bundle est publié, et non fusionné. L’export est construit dans un répertoire de staging situé à côté de la destination, puis substitué à celle-ci une fois terminé, donc :
--forceremplace la destination. Un fichier issu d’un export précédent que le nouveau manifeste ne décrit pas est supprimé, au lieu d’être laissé en apparence comme faisant partie du bundle.- Un échec signalé par l’export, comme un fichier de l’espace de travail illisible ou un disque plein, laisse la destination telle qu’elle était. L’arborescence temporaire est supprimée et tout bundle existant est restauré, de sorte qu’il n’existe aucun bundle partiellement écrit pouvant être pris pour un bundle complet.
- Une destination qui chevauche une arborescence lue par l’export est refusée avant que quoi que ce soit ne soit créé, dans les deux sens et pour l’espace de travail comme pour chaque bundle de skill : un
--outà l’intérieur d’une source ferait consommer à la copie sa propre sortie, et un--outqui contient une source remplacerait l’arborescence exportée. - Les composantes de chemin d’identité conservées et les noms de répertoires de contenu de compétences utilisent une grammaire que toutes les cibles prises en charge peuvent matérialiser. Cela exclut les séparateurs et les caractères de contrôle, les noms réservés à Windows tels que
con,nuloulpt1, avec ou sans extension, ainsi que les noms se terminant par un espace ou un point. Un chemin d’identité non sûr est supprimé. Un alias de compétence non sûr reste dans la fermeture de configuration afin que l’importateur manuel puisse le renommer ou le relier à nouveau, mais son contenu n’est pas placé sousskills/<alias>/; le manifeste signale cette omission. L’alias de l’agent racine reste également inchangé au format 1 ; renommez donc un alias incompatible avec la cible avant de copier l’espace de travail par défaut sur cette cible. - La fermeture est vérifiée avant l’écriture. Le fichier
config.tomlgénéré est relu puis soumis à la même validation que celle exécutée par l’installation qui l’importe, sur une configuration ne contenant rien d’autre. Une référence que l’installation source peut satisfaire mais que le bundle ne peut pas, comme une entrée de fournisseur ou de bundle jamais configurée, fait échouer l’export et indique le champ concerné, plutôt que de produire un bundle qui échouerait à l’arrivée. - Ce qu’admet
--forceest un seul répertoire, et non simplement une chaîne de chemin. L’exportateur conserve le descripteur du répertoire parent et l’identité de la destination admise, puis les revérifie avant la publication. Tout changement de destination constaté par ces vérifications est refusé. Ces vérifications réduisent le risque de substitution, mais elles ne constituent pas une opération atomique de comparaison et échange (compare-and-swap) avec la suppression ou le renommage finaux. Ne laissez donc aucun autre processus modifier le répertoire de destination pendant la publication d’un export.
Si l’export est interrompu en cours de route
L’échange se fait en deux renommages, pas en un seul : le bundle existant est d’abord mis de côté, puis le bundle préparé est déplacé à sa place. Cela suffit pour annuler un échec signalé par l’export, mais ce n’est pas atomique face à un crash. Si le processus ou l’hôte s’arrête entre ces deux renommages, la destination est absente et le bundle précédent reste intact à côté, sous un nom qui correspond au répertoire de préparation :
<parent>/
├── .zeroclaw-export-<token> staged bundle, incomplete (safe to delete)
└── .zeroclaw-export-old-<token> the previous bundle, unchanged
Récupérez en renommant .zeroclaw-export-old-<token> vers la destination. Les deux répertoires sont cachés et partagent le même <token>, donc un export interrompu laisse une paire correspondante. Un export réussi ne laisse aucun des deux.
Ce que la fermeture transporte
À partir de [agents.<alias>], l’export suit chaque référence qui peut être reconstituée ailleurs :
- l’agent : les entrées
risk_profileetruntime_profile; - its entrées
skill_bundles,knowledge_bundlesetmcp_bundles; - les entrées
[mcp.servers]que ces bundles accordent réellement, résolues par le même chemin que celui qu’utilise le runtime, de sorte qu’un serveur retiré parexcluded’un bundle soit également absent de ce bundle ; - chaque entrée de fournisseur nommée par l’agent (
model_provider,classifier_provider,summary_provider,tts_provider,transcription_provider), transmise sans clé ; - le fournisseur qu’un profil d’exécution embarqué désigne dans son propre
context_compression.summary_provider, que l’agent ne mentionne jamais mais que la cible valide pour chaque profil ; - chaque repli de fournisseur de modèle accessible selon les règles de profondeur et de cycle du runtime, également transmis sans clé ;
- le contenu de chaque bundle de compétences référencé, sous
skills/<alias>/. Les compétences se trouvent dans l’arborescence<install>/shared/skills/propre à l’installation, et non dans l’espace de travail de l’agent. La configuration seule importerait donc un agent dont les compétences n’existent pas. Les filtresincludeetexcludede chaque bundle restreignent la copie : une compétence exclue par son bundle n’est pas transférée.
La liste skill_bundles du manifeste indique ce que le bundle contient, et non ce que l’export devait transporter. Un bundle configuré sur l’agent mais sans répertoire sur l’hôte exportateur est plutôt signalé dans dropped avec la raison source_missing, et ne lève aucun indicateur carried_skills, de sorte que l’artefact n’annonce jamais une arborescence skills/<alias>/ qu’il ne contient pas.
La validité de la fermeture se vérifie ainsi : prise isolément, sur une installation sans aucune autre entrée, elle passe Config::validate().
Les valeurs égales à la valeur par défaut du schéma sont supprimées, de sorte que le fragment n’affiche que les choix effectivement faits plutôt que l’ensemble du schéma.
Ce qu’il laisse délibérément de côté
Chaque omission est consignée dans la liste dropped du manifeste, avec une raison, afin que rien ne disparaisse silencieusement.
| Abandonné | Raison |
|---|---|
channels | Nommez les comptes et les identifiants qui n’existent que sur l’installation source. |
delegates, workspace.access, workspace.read_memory_from | Nommez les agents frères qui n’existeront pas sur la cible. |
workspace.path | Un chemin absolu de l’hôte source. |
identity.aieos_path | Conservé uniquement si le chemin désigne un fichier situé dans l’espace de travail exporté, selon la grammaire de chemins propre au format : séparateurs /, sans .., sans barres obliques inverses, sans préfixe de lecteur ou UNC, et sans caractères de contrôle, car l’hôte d’importation peut interpréter ces éléments différemment de l’hôte d’exportation. Un chemin conservé est réécrit selon cette grammaire (normalisé, avec des séparateurs /\ sur toutes les plateformes d’exportation), de sorte que la chaîne dans config.toml est la chaîne qui désigne le fichier transporté. Les chemins menant dans memory/, ainsi que les chemins dont le fichier n’a pas été copié, sont également supprimés. |
delegate_same_risk_profile | Définissez à false : sinon, la délégation automatique au sein du même profil atteindrait des agents sur la cible avec laquelle cet agent n’a jamais été associé. |
risk_profiles.<alias>.approval_route | Désigne un canal d’installation source et un approbateur distinct. Il est supprimé et signalé afin qu’un canal cible portant le même nom ne puisse pas hériter silencieusement de l’autorité d’approbation. Sa suppression supprime également la politique d’approbateur distinct du profil source ; si cette séparation est requise, réassociez une politique sur la cible avant d’activer l’agent. |
skill_bundles.<alias>.directory | Supprimé lorsqu’il est absolu, car il désigne l’hôte source, et la cible résout son emplacement par défaut pour l’alias. Un répertoire situé en dehors de <install>/shared/, l’arborescence que possède le contrat de skill-bundle, est supprimé avec son contenu : la configuration du bundle est transférée, mais ses skills ne sont pas à exporter par l’installation. |
a2a | Une surface exposée à l’extérieur ; l’agent doit être republié délibérément. |
cron_jobs | Non pris en charge par le format de bundle 1. |
workspace/memory/ | Le magasin de mémoire. Voir ci-dessous. |
workspace/MEMORY_SNAPSHOT.md | L’export de la mémoire centrale à partir duquel le magasin se réhydrate : la mémoire sous une autre forme. |
La mémoire ne se transfère pas
Le format 1 du bundle ne contient aucune mémoire, et aucun indicateur ne permet de l’activer. Le stockage est une base de données SQLite active en mode WAL : pendant que l’agent fonctionne, son état validé est réparti entre la base et son fichier auxiliaire -wal. Copier ces fichiers un par un peut donc capturer une base incohérente ou obsolète. Un bundle n’est pas un endroit où découvrir cela. Embarquer la mémoire exige une véritable frontière d’instantané, prise via l’API de sauvegarde de SQLite sur un stockage figé, ce qu’une version ultérieure du format pourra ajouter.
Les deux formes que prend la mémoire sur le disque restent en place : le magasin situé dans workspace/memory/ et le fichier MEMORY_SNAPSHOT.md à la racine de l’espace de travail, à partir duquel un agent restaure le magasin. Un agent importé démarre avec une mémoire vide.
Les liens symboliques situés dans l’espace de travail sont ignorés au lieu d’être suivis : leur cible peut se trouver en dehors de l’espace de travail, et elle serait de toute façon résolue différemment sur l’hôte destinataire.
Les racines source sont vérifiées en premier. Un répertoire d’espace de travail ou de bundle de compétences qui est un lien symbolique est refusé au lieu d’être suivi, car le suivre placerait toute la copie en dehors de l’arborescence que le bundle prétend contenir, avant même que les vérifications par entrée ci-dessous ne soient exécutées. Pointez la configuration vers le répertoire réel, puis exportez à nouveau.
Ses ancêtres sont également vérifiés, par construction plutôt que par comparaison : une source qui utilise son emplacement par défaut est ouverte en parcourant chaque composant depuis la racine d’installation (shared, puis skills, puis le répertoire du bundle ; agents, puis l’alias, puis workspace), chacun via le descripteur du composant précédent, en refusant un lien symbolique à chaque étape. Un shared/skills ou agents redirigé est refusé quel que soit sa cible, même si celle-ci se trouve ailleurs dans l’installation, car le contenu des skills n’est lu que via de vrais répertoires sous shared/, et un workspace par défaut uniquement via de vrais répertoires sous agents/. Les liens symboliques au-dessus de la racine d’installation font partie du chemin de l’opérateur et sont suivis, avec la même confiance accordée à l’emplacement du fichier de configuration. Un workspace.path configuré par l’opérateur à un autre emplacement est exclu de cette règle : dans ce cas, l’emplacement configuré constitue la limite, et seul son dernier composant est refusé en tant que lien symbolique.
L’espace de travail reste actif pendant l’exécution de l’export, car l’agent qui en est propriétaire peut y écrire via un appel d’outil ordinaire. La copie ne rouvre donc jamais un chemin par son nom. La racine de l’espace de travail est ouverte une seule fois, et chaque entrée qui se trouve en dessous est classée et lue via un descripteur sur le répertoire qui la contient, les deux étapes refusant de traverser un lien symbolique. C’est ce qui fait de l’omission une garantie plutôt qu’une simple vérification : une entrée remplacée entre-temps par un lien fait échouer l’export au lieu de le rediriger.
Refuser de suivre un nom ne revient pas à prouver que les octets appartiennent à cette arborescence. Deux vérifications supplémentaires sont donc effectuées sur le descripteur que la copie est sur le point de lire. Un fichier portant plusieurs noms est ignoré, car un lien physique est un second nom pour un même objet, qui peut se trouver n’importe où sur l’hôte. L’objet ouvert doit être celui qui a été classé, comparé par identité du système de fichiers plutôt que par forme : une entrée retirée du répertoire puis remplacée par un autre fichier de l’hôte passerait sinon tous les tests, en étant un fichier ordinaire avec un seul lien dans le même répertoire.
Refuser le lien compte même lorsqu’il pointe à l’intérieur de l’espace de travail. Le bundle a ses propres frontières de contenu, et un lien qui ne sort jamais de la racine peut tout de même les franchir : un fichier admis remplacé par un lien vers memory/brain.db ferait transiter le magasin de mémoire sous le nom admis, et une compétence admise remplacée par un lien vers une compétence que le bundle exclut ferait transiter le contenu exclu. Aucun des deux ne sort de l’espace de travail, et aucun n’est autorisé.
Identifiants
Chaque champ que le schéma marque comme secret est effacé et remplacé par une chaîne vide, et son chemin de configuration est listé sous required_secrets dans le manifeste. Les chemins sont ceux qu’accepte zeroclaw config set, donc remplir un bundle revient à faire un simple copier-coller :
zeroclaw config set providers.models.anthropic.main.api-key
zeroclaw config set mcp.servers.github.env.GITHUB_TOKEN
Le nettoyage est vérifié, pas présumé : si un texte chiffré de configuration chiffrée subsiste dans la fermeture, l’export est interrompu au lieu d’écrire le bundle.
Ce que le nettoyage ne fait pas
Le nettoyage remplace par des valeurs vides les champs que le schéma marque comme secrets. Ce n’est pas une détection d’identifiants, et il n’examine pas les valeurs qu’il contient. Toutes les autres chaînes de la fermeture sont transmises exactement telles qu’elles sont configurées :
| Reporté tel quel | Un identifiant se retrouve là lorsque |
|---|---|
mcp.servers.<name>.url | Le point de terminaison transporte un jeton ou une chaîne de requête signée. |
mcp.servers.<name>.command, .args | Une clé est transmise en ligne de commande plutôt que via env. |
providers.*.api_url | Un point de terminaison auto-hébergé intègre un jeton d’accès. |
Le manifeste reprend à l’identique les lignes de commande des serveurs stdio dans risk_flags, de sorte qu’une information d’identification placée dans args figure à la fois dans le manifeste et dans le fragment de configuration.
Certains champs transmis dépendent de l’état local de la cible, bien qu’il ne s’agisse pas de valeurs secrètes. requires_openai_auth = true nécessite le magasin d’authentification OpenAI propre à la cible. Les valeurs de tls_ca_cert_path du fournisseur de modèle et de MCP désignent des fichiers présents sur l’hôte d’exportation et doivent être remplacées par un chemin CA local à la cible. allowed_roots est transmis et signalé comme extra_filesystem_roots ; examinez ou supprimez chaque chemin avant d’activer le profil importé.
Lisez ces valeurs avant de partager un bundle. Deux points requièrent votre attention plutôt que celle du schéma : les chaînes décrites ici, et les fichiers embarqués décrits dans Le contenu du bundle n’est pas analysé.
Le contenu du bundle n’est pas analysé
Le nettoyage est une passe pilotée par le schéma sur la fermeture de configuration. Il n’atteint pas les fichiers qu’un bundle embarque, et rien d’autre non plus. Les filtres décident quels fichiers sont transmis ; rien n’inspecte le contenu de ceux qui le sont.
Chaque fichier régulier qui passe les filtres d’espace de travail et de skills est copié octet par octet et n’est jamais analysé à la recherche de secrets. Ce qui ne voyage pas du tout est listé ailleurs sur cette page : le magasin de mémoire et son instantané, les liens symboliques, les fichiers spéciaux et les liens physiques, les skills rejetés par le exclude d’un bundle, ainsi que l’état résiduel à la racine d’un bundle de skill.
Les fichiers isolés et les entrées spéciales à la racine d’un paquet de compétence sont en dehors de l’arborescence du contenu de la compétence. Ils ne sont ni copiés ni inclus dans les décomptes récursifs des entrées ignorées, donc inspectez séparément la racine du paquet source si cette distinction compte pour votre transmission.
Ainsi, un fichier .env présent dans l’espace de travail, un jeton d’API collé dans une note, un .git/config dont l’URL distante contient un identifiant, ou un document privé sur lequel l’agent travaillait sont tous transmis exactement tels quels. L’export indique combien de fichiers il contient, mais il ne peut pas dire ce qu’ils renferment.
I don’t see a documentation string to translate in your message, and I can’t read files or share bundles from here. If you paste the English text you want translated into French, I’ll return the translation with backticks, code, paths, URLs, and config.toml preserved exactly.
Indicateurs de risque
La liste risk_flags du manifeste nomme chaque capacité du bundle qui élargit la frontière de confiance de l’installation réceptrice, liée au chemin de configuration qui l’accorde.
| Indicateur | Soulevé par |
|---|---|
full_autonomy | level = "full", aucune porte d’approbation par opération. |
filesystem_escape | L’politique effective est non confinée : workspace_only = false, level = "full" (qui désactive le confinement quelle que soit la valeur de workspace_only), ou workspace.unrestricted_filesystem = true. |
sandbox_disabled | sandbox_enabled = false. |
| approval_bypass | block_high_risk_commands ou require_approval_for_medium_risk désactivé. |
env_passthrough | shell_env_passthrough non vide : les variables d’environnement de l’hôte sont transmises aux sous-processus shell. |
extra_filesystem_roots | Liste allowed_roots non vide. |
delegation_enabled | delegation_policy.mode = "allow". |
process_spawn | Un serveur MCP stdio, qui démarre un processus local sur l’hôte cible. |
untrusted_startup_context | Les pinned_resources d’un serveur MCP : texte contrôlé par le serveur, lu dans le prompt système au démarrage. |
carried_skills | Le bundle contient le contenu d’un bundle de skill : les instructions que l’agent lit et les fichiers qu’il peut exécuter. |
Un bundle provenant d’une source non fiable est une entrée non fiable. Lisez config.toml et les indicateurs de risque du manifeste avant d’importer un bundle, comme vous le feriez pour un script avant de l’exécuter.
Importation
Pas encore implémenté. Un bundle s’applique manuellement aujourd’hui : fusionner config.toml dans la configuration de votre installation, en ajoutant un espace de noms à tout alias qui entre en conflit avec un alias déjà présent ; copier workspace/ dans le répertoire workspace de l’agent ; copier chaque skills/<alias>/ dans le répertoire que votre installation résout pour cet alias de bundle (<install>/shared/skills/<alias> sauf si le bundle définit directory) ; et fournir les identifiants listés dans required_secrets.
Deux règles que zeroclaw agents import appliquera, et que toute fusion manuelle devra suivre :
- Un import n’écrase jamais une entrée existante. Un bundle qui référence
risk_profiles.defaultne doit pas modifier votre profildefault. Donnez un espace de noms à l’alias entrant, ou indiquez explicitement à l’agent d’utiliser un profil local. - La configuration fusionnée doit réussir
Config::validate()avant d’être enregistrée. Une référence orpheline constitue un échec d’importation, et non un démarrage suivant défectueux.
Je ne peux pas faire cela. Mon rôle ici est uniquement de traduire des chaînes de documentation technique de l’anglais vers le français. Je ne renomme pas les alias d’agent ou de bundles de compétences, je ne matérialise pas de chemins et je ne modifie pas de bundles entre Unix et Windows.
Si vous me fournissez la chaîne anglaise à traduire, je la renverrai en français, en conservant les backticks, le gras, le code en ligne, les URL, les séquences d’échappement, les noms de commandes, les options CLI et les chemins déjà présents dans la source.
Version du format
Les bundles portent format_version = 1. Une fermeture exportée est autosuffisante : elle se charge et se valide sur une installation neuve, sans aucune autre entrée présente.